#!/usr/bin/env python
# -*- coding: utf-8 -*-
#############################################################
# Images Converter
# Gael Goret for the European Synchrotron Radiation Facility
# gael.goret@esrf.fr
#############################################################

""" 
Fabio_viewer is a portable diffraction images viewer/converter:
* Written in Python, it combines the functionalities of the I/O library fabIO with a user friendly Qt4 GUI.
* Image converter is also a light viewer based on the visualization tool provided by the module matplotlib.
"""
from __future__ import with_statement, print_function
__version__ = "1.0"
__author__ = u"Gaël Goret"
__copyright__ = "2012 ESRF"
__licence__ = "GPL"
import sys, os, random, time
import h5py
from PyQt4.QtCore import *
from PyQt4.QtGui import *      

try:
    _fromUtf8 = QString.fromUtf8
except AttributeError:
    _fromUtf8 = lambda s: s

import numpy
import fabio
numpy.seterr(divide='ignore')

import matplotlib
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt4agg import NavigationToolbar2QTAgg as NavigationToolbar
from matplotlib.figure import Figure

try:
    from argparse import ArgumentParser
except ImportError:
    from fabio.argparse import ArgumentParser

output_format = ['*.bin','*.cbf','*.edf','*.h5','*.img','*.mar2300','*.mar3450','*.marccd','*.tiff']

#--------------------------------------------------------------------------------------------------------
# Application Form
#--------------------------------------------------------------------------------------------------------

class AppForm(QMainWindow):
    def __init__(self, parent=None):
    
        # Main window
        QMainWindow.__init__(self, parent)
        self.setWindowTitle('FabIO Viewer')
        self.setSizePolicy(QSizePolicy().Expanding,QSizePolicy().Expanding)
        # Menu and widget
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()
        
        # Active Data
        self.data = numpy.array([])
        self.header = []
        
        #Data Series
        self.imgDict = {}
        self.data_series = []
        self.header_series = []
        self.sequential_file_list = []
        self.sequential_file_dict = {}
        
        #Miscelaneous
        self.mask = None
        self.transform_data_series = False
        self.transform_list = []
        self.sequential_file_mode = False
        self.h5_loaded = False
        self.counter_format = '%03d'
#--------------------------------------------------------------------------------------------------------
# Opening
#--------------------------------------------------------------------------------------------------------
        
    def format_header(self,d):
        res=''
        keys=[]
        keys[:] = d.keys()
        keys.sort()
        for k in keys:
            res += '%s : %s \n'%(k,d[k])
        return res

#--------------------------------------------------------------------------------------------------------   
        
    def open_data_series(self, series=None):
        if series is None:
            series = QFileDialog.getOpenFileNames(self, 'Select and open series of files')
        series = [str(f) for f in list(series)]
        total=len(series)
        if len(series)!= 0:
            self.data_series = []
            self.header_series = []
            self.sequential_file_list = []
            iid = 0
            self.imgDict = {}
            self.sequential_file_dict = {}
            self.images_list.clear()
            self.imagelistWidget.clear()
            self.headerTextEdit.clear()
            self.axes.clear()
            self.canvas.draw()
            self.h5_loaded = False
            for fname in series:
                if fname:
                    if self.sequential_file_mode:
                        self.statusBar().showMessage('Adding path %s to batch image list, please wait ...'%fname)
                        self.log.appendPlainText('Adding path %s to batch image list'%fname)
                        QCoreApplication.processEvents()
                        extract_fname = self.extract_fname_from_path(fname)
                        self.imagelistWidget.addItem(extract_fname)
                        self.sequential_file_list += [extract_fname]
                        self.sequential_file_dict[extract_fname]=fname
                        iid +=1
                    else:
                        self.statusBar().showMessage('Opening file %s, please wait ...'%fname)
                        self.log.appendPlainText('Opening file %s'%fname)
                        QCoreApplication.processEvents()
                        try :
                            img = fabio.open(fname)
                        except:
                            QMessageBox.warning(self, 'Message','Automatic format recognition procedure failed or pehaps you are trying to open a binary data block...\n\n     ...Switch to manual procedure ')                
                            Dial = binDialog(self)
                            dim1,dim2,offset,bytecode,endian = Dial.exec_()
                            if dim1 != None and dim2 != None:
                                if endian == 'Short':
                                    endian = '<'
                                else :
                                    enfian = '>'
                                img = fabio.binaryimage.binaryimage()
                                img.read(fname,dim1,dim2,offset,bytecode,endian)
                                img.header = {'Info':'No header information available in binary data blocks'}
                            else :
                                continue     
                        self.data_series += [img.data[:]]
                        self.header_series += [img.header.copy()]
                        extract_fname = self.extract_fname_from_path(fname)
                        self.images_list.addItem(extract_fname)
                        self.imagelistWidget.addItem(extract_fname)
                        self.imgDict[extract_fname]=iid
                        self.sequential_file_list += [extract_fname]
                        self.sequential_file_dict[extract_fname]=fname
                        iid +=1
                self.progressBar.setValue(float(iid+1)/(total)*100.)
            self.statusBar().clearMessage()
            self.progressBar.setValue(0)
            self.log.appendPlainText('Opening procedure : Complete')
            if self.data_series:
                self.select_new_image(None,imgID=0)

#--------------------------------------------------------------------------------------------------------   

    def open_h5_data_series(self): #TODO batch mode compatibility
        fname = QFileDialog.getOpenFileName(self, 'Select and open series of files')
        fname = str(fname)
        self.h5_loaded = True
        if self.filecheckBox.checkState():
            self.filecheckBox.stateChanged.disconnect()
            self.filecheckBox.setCheckState(False)
            self.sequential_file_mode = False
            self.filecheckBox.stateChanged.connect(self.sequential_option)
            QMessageBox.warning(self, 'Message','Sequential file mode is not compatible with hdf5 input file : option removed')    
        if fname:
            self.data_series = []
            self.header_series = []
            self.sequential_file_list = []
            self.sequential_file_dict = {}
            self.imagelistWidget.clear()
            self.headerTextEdit.clear()
            hdf = h5py.File(fname,'r')
            iids = numpy.int32(hdf['data'].keys())
            iids.sort()
            total = len(iids)
            imgDict = {}
            extract_fname = self.extract_fname_from_path(self.remove_extention_if_present(fname))
            self.images_list.clear()
            safeiid = 0
            for iid in iids:
                self.progressBar.setValue((float(iid+1)/(total))*100.)
                self.log.appendPlainText('Extracting data from hdf5 archive, image number %d'%iid)
                QCoreApplication.processEvents()
                self.data_series += [numpy.array(hdf['data'][str(iid)])]
                self.header_series +=[{'Info':'No header information available in hdf5 Archive'}]
                imgDict[extract_fname+str(iid)]= safeiid
                self.images_list.addItem(extract_fname+str(iid))
                safeiid += 1
            self.statusBar().clearMessage()
            self.progressBar.setValue(0)
            self.log.appendPlainText('Hdf5 Extraction : Complete')
            self.imgDict = imgDict.copy()
            hdf.close()
        if self.data_series:
            self.select_new_image(None,imgID=0)
        
#--------------------------------------------------------------------------------------------------------   

    def extract_fname_from_path(self,name ):
	    posslash=name.rfind("/")
	    if(posslash>-1):
		    return name[posslash+1:]
	    else:
		    return name

#--------------------------------------------------------------------------------------------------------
# Convertion
#--------------------------------------------------------------------------------------------------------

    def save_as(self):
        info = QFileDialog.getSaveFileNameAndFilter(self, "Save active image as", QDir.currentPath(), filter=self.tr("binary data block (*.bin);;cbf image (*.cbf);;edf image (*.edf);;oxford diffraction image (*.img);;mar2300 image(*.mar2300);;mar3450 image (*.mar3450);;marccd image (*.marccd));;tiff image (*.tiff)"))
        if self.data.any():
            if str(info[0])!='' and str(info[0])!='':
                format = self.extract_format_from_string(str(info[1]))
                fname = self.add_extention_if_absent(str(info[0]),format)
                self.convert_and_write(fname,format,self.data,self.header)
        else:
            if str(info[0])!='' and str(info[1])!='':
                QMessageBox.warning(self,'Warning',"Could not save image as file if no data have been loaded")

#--------------------------------------------------------------------------------------------------------

    def save_data_series_as_multiple_file(self):
        info = QFileDialog.getSaveFileNameAndFilter(self, "Save data series as multiple files", QDir.currentPath(), filter=self.tr("binary data block (*.bin);;cbf image (*.cbf);;edf image (*.edf);;oxford diffraction image (*.img);;mar2300 image(*.mar2300);;mar3450 image (*.mar3450);;marccd image (*.marccd));;tiff image (*.tiff)"))
        if self.data_series or self.sequential_file_list:
            if str(info[0])!='' and str(info[1])!='':
                format = self.extract_format_from_string(str(info[1]))
                fname = self.remove_extention_if_present(str(info[0]))
                self.convert_and_write_multiple_files(fname,format)
        else:
            if str(info[0])!='' and str(info[1])!='':
                QMessageBox.warning(self,'Warning',"Could not save image as file if no data have been loaded")

#--------------------------------------------------------------------------------------------------------
    
    def save_data_series_as_singlehdf(self):
        info = QFileDialog.getSaveFileNameAndFilter(self, "Save data series as single high density file", QDir.currentPath(), filter=self.tr("HDF5 archive (*.h5)"))
        if self.data_series or self.sequential_file_list:
            if str(info[0])!='' and str(info[1])!='':
                format = self.extract_format_from_string(str(info[1]))
                fname = self.add_extention_if_absent(str(info[0]),format)
                if format == '*.h5':
                    self.convert_and_save_to_h5(fname)
                else:
                    QMessageBox.warning(self,'Warning',"Unknown format : %s"%format)
                    return
        else:
            if str(info[0])!='' and str(info[1])!='':
                QMessageBox.warning(self,'Warning',"Could not save image as file if no data have been loaded")

#--------------------------------------------------------------------------------------------------------

    def convert_and_save_to_h5(self,fname): 

        hdf = h5py.File(fname,'w')
        group = hdf.create_group('data')
        iid = 0
        if self.sequential_file_mode:
            total = len(self.sequential_file_list)
            for imgkey in self.sequential_file_list:
                tmpfname = self.sequential_file_dict[imgkey]
                try :
                    img = fabio.open(tmpfname)
                except:
                    QMessageBox.warning(self, 'Message','Automatic format recognition procedure failed or pehaps you are trying to open a binary data block...\n\n     ...Switch to manual procedure ')                
                    Dial = binDialog(self)
                    dim1,dim2,offset,bytecode,endian = Dial.exec_()
                    if dim1 != None and dim2 != None:
                        if endian == 'Short':
                            endian = '<'
                        else :
                            enfian = '>'
                        img = fabio.binaryimage.binaryimage()
                        img.read(tmpfname,dim1,dim2,offset,bytecode,endian)
                        img.header = {'Info':'No header information available in binary data blocks'}
                    else :
                        continue
                self.progressBar.setValue((float(iid+1)/(total))*100.)
                self.log.appendPlainText('Converting and saving file %s. saving file number %d'%(tmpfname,iid))
                QCoreApplication.processEvents()
                if self.transform_data_series:
                    tmpdata = self.apply_queued_transformations(img.data)
                else:
                    tmpdata = img.data
                dataset = group.create_dataset(str(iid), tmpdata.shape,'f')
                dataset[:] = tmpdata
                iid +=1
        else:
            total = len(self.data_series)
            for data in self.data_series:
                self.log.appendPlainText('Saving file number %d'%iid)
                self.progressBar.setValue((float(iid+1)/(total))*100.)
                QCoreApplication.processEvents()
                if self.transform_data_series:
                    tmpdata = self.apply_queued_transformations(data)
                else:
                    tmpdata = data
                dataset = group.create_dataset(str(iid), tmpdata.shape,'f')
                dataset[:] = tmpdata
                iid +=1
        self.statusBar().clear()
        self.progressBar.setValue(0)
        self.log.appendPlainText('Hdf5 Recording : Complete')
        hdf.close()
#--------------------------------------------------------------------------------------------------------

    def add_extention_if_absent(self,fname,format):
        posslash=fname.rfind("/")
        posdot  =fname.rfind(".")
        if posdot>posslash:
            return  fname
        else:
            return fname + format[1:]

#--------------------------------------------------------------------------------------------------------

    def convert_and_write(self,fname,format,data,header):

        if format == '*.bin':
            out = open(fname, mode="wb")
            out.write(data.tostring())
            out.close()
            return
        elif format == '*.marccd':
            out = fabio.marccdimage.marccdimage(data=data, header=header)
        elif format == '*.edf':
            out = fabio.edfimage.edfimage(data=data, header=header)
        elif format == '*.tiff':
            out = fabio.tifimage.tifimage(data=data, header=header)
        elif format == '*.cbf':
            out = fabio.cbfimage.cbfimage(data=data, header=header)
        elif format in ['*.mar3450','*.mar2300']:
            data = self.padd_mar(data,format)
            out = fabio.mar345image.mar345image(data=data, header=header)
        elif format == '*.img':
            out = fabio.OXDimage.OXDimage(data=data, header=header)
        else:
            raise Warning, ("Unknown format : %s"%format)
        self.statusBar().showMessage('Writing file %s to %s format, please wait ...'%(fname,format[2:]))
        self.log.appendPlainText('Writing file %s to %s format'%(fname,format[2:]))
        QCoreApplication.processEvents()
        out.write(fname)
        self.statusBar().clearMessage()
        

#--------------------------------------------------------------------------------------------------------

    def remove_extention_if_present(self,fname):
        posslash=fname.rfind("/")
        posdot  =fname.rfind(".")
        if posdot>posslash:
            return  fname[:posdot]
        else:
            return fname
               
#--------------------------------------------------------------------------------------------------------
    
    def convert_and_write_multiple_files(self,fname,format):

        if self.sequential_file_mode:
            total = len(self.sequential_file_list)
            ii = 0
            for imgkey in self.sequential_file_list:
                tmpfname = self.sequential_file_dict[imgkey]
                try :
                    img = fabio.open(tmpfname)
                except:
                    QMessageBox.warning(self, 'Message','Automatic format recognition procedure failed or pehaps you are trying to open a binary data block...\n\n     ...Switch to manual procedure ')                
                    Dial = binDialog(self)
                    dim1,dim2,offset,bytecode,endian = Dial.exec_()
                    if dim1 != None and dim2 != None:
                        if endian == 'Short':
                            endian = '<'
                        else :
                            enfian = '>'
                        img = fabio.binaryimage.binaryimage()
                        img.read(tmpfname,dim1,dim2,offset,bytecode,endian)
                        img.header = {'Info':'No header information available in binary data blocks'}
                    else :
                        continue
                self.progressBar.setValue((float(ii+1)/(total))*100.)
                self.log.appendPlainText('Converting file %s'%tmpfname)
                QCoreApplication.processEvents()
                if self.transform_data_series:
                    tmpdata = self.apply_queued_transformations(img.data)
                else:
                    tmpdata = img.data
                self.convert_and_write(('%s_%s%s'%(fname,self.counter_format,format[1:]))%ii,format,tmpdata,img.header)
                ii += 1
        else:
            total = len(self.data_series)
            for i in range(len(self.data_series)):
                tmpdata = self.data_series[i]
                tmpheader = self.header_series[i]
                tmpfname = ('%s_%s%s'%(fname,self.counter_format,format[1:]))%i
                self.progressBar.setValue((float(i+1)/(total))*100.)
                self.log.appendPlainText('Converting file %s'%i)
                QCoreApplication.processEvents()
                if self.transform_data_series:
                    tmpdata = self.apply_queued_transformations(tmpdata)
                self.convert_and_write(tmpfname,format,tmpdata,tmpheader)
        self.progressBar.setValue(0)
        self.log.appendPlainText('Convertion to %s : Complete'%format[2:])  
#--------------------------------------------------------------------------------------------------------

    def extract_format_from_string(self,format_long):
        for fmt in output_format:
            if fmt in format_long:
                return fmt
        raise Warning, ("Unknown format : %s"%format_long)

#--------------------------------------------------------------------------------------------------------
# Transformation
#--------------------------------------------------------------------------------------------------------
    def horizontal_mirror(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('horizontal_mirror')
                self.transform_list += ['horizontal_mirror']
                self.log.appendPlainText('Add horizontal mirror to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = numpy.flipud(self.data_series[i])[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying horizontal mirror to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            
            if self.data.any():
                self.data = numpy.flipud(self.data)[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying horizontal mirror to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")   
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------                       
    
    def vertical_mirror(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('vertical_mirror')
                self.transform_list += ['vertical_mirror']
                self.log.appendPlainText('Add vertical mirror to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = numpy.fliplr(self.data_series[i])[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying vertical mirror to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            if self.data.any():
                self.data = numpy.fliplr(self.data)[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying vertical mirror to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")            
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------
        
    def transposition(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('transposition')
                self.transform_list += ['transposition']
                self.log.appendPlainText('Add transposition to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = self.data_series[i].transpose()[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying transposition to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            if self.data.any():
                self.data = self.data.transpose()[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying transposition to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")             
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------
        
    def rotation_90(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('rotation(+90)')
                self.transform_list += ['rotation(+90)']
                self.log.appendPlainText('Add + 90 rotation to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = numpy.rot90(self.data_series[i])[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying + 90 rotation to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            if self.data.any():
                self.data = numpy.rot90(self.data)[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying + 90 rotation to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")            
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------
        
    def rotation_180(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('rotation(+180)')
                self.transform_list += ['rotation(+180)']
                self.log.appendPlainText('Add + 180 rotation to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = numpy.rot90(self.data_series[i], 2)[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying + 180 rotation to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            if self.data.any():
                self.data = numpy.rot90(self.data, 2)[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying + 180 rotation to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")            
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------
        
    def rotation_270(self):
        if self.transform_data_series:
            if self.sequential_file_mode:
                self.transformation_queue.addItem('rotation(-90)')
                self.transform_list += ['rotation(-90)']
                self.log.appendPlainText('Add - 90 rotation to transformations queue')
                QCoreApplication.processEvents()
            else:
                total = len(self.data_series)
                if not total:
                    QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                    return
                for i in range(len(self.data_series)):
                    self.data_series[i] = numpy.rot90(self.data_series[i], 3)[:]
                    self.progressBar.setValue((float(i+1)/(total))*100.)
                    self.log.appendPlainText('Applying - 90 rotation to data series : image %d'%i)
                    QCoreApplication.processEvents()
                iid = self.imgDict[str(self.images_list.currentText())]
                self.select_new_image(None,imgID=iid) 
        else:
            if self.data.any():
                self.data = numpy.rot90(self.data, 3)[:]
                iid = self.imgDict[str(self.images_list.currentText())]
                self.data_series[iid] =  self.data[:]
                self.log.appendPlainText('Applying - 90 rotation to current data')
                self.on_draw()
            else:
                QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")            
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------
        
    def mask(self):
        fname = QFileDialog.getOpenFileName(self, 'Select and import a boolean mask from binary data block file')
        fname = str(fname)
        if fname:
            Dial = binDialog(self)
            dim1,dim2,offset,bytecode,endian = Dial.exec_()
            if dim1 != None and dim2 != None:
                if endian == 'Short':
                    endian = '<'
                else :
                    enfian = '>'
                img = fabio.binaryimage.binaryimage()
                img.read(fname,dim1,dim2,offset,bytecode,endian)
                self.mask = img.data[:]
                if self.transform_data_series:
                    if self.sequential_file_mode:
                        self.transformation_queue.addItem('masking')
                        self.transform_list += ['masking']
                        self.log.appendPlainText('Add masking to transformations queue')
                        QCoreApplication.processEvents()
                    else:
                        total = len(self.data_series)
                        if not total:
                            QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
                            return
                        for i in range(len(self.data_series)):
                            if self.data_series[i].shape != self.mask.shape:
                                QMessageBox.warning(self,'Warning',"Mask and image have different shapes, skipping image %d"%i)
                                self.log.appendPlainText('Mask and image have different shapes, skipping image %d'%i)
                            else:
                                self.data_series[i] = self.mask*self.data_series[i]
                                self.progressBar.setValue((float(i+1)/(total))*100.)
                                self.log.appendPlainText('Applying mask to data series : image %d'%i)
                                QCoreApplication.processEvents()
                        iid = self.imgDict[str(self.images_list.currentText())]
                        self.select_new_image(None,imgID=iid) 
                else:
                    if self.data.any():
                        self.data = self.mask*self.data
                        iid = self.imgDict[str(self.images_list.currentText())]
                        self.data_series[iid] =  self.data[:]
                        self.on_draw()
                        self.statusBar().showMessage('Binary boolean mask loaded and applied',2000)
                        self.log.appendPlainText('Binary boolean mask loaded and applied')
                        QCoreApplication.processEvents()
                    else:
                        QMessageBox.warning(self,'Warning',"Could not transform image if no data have been loaded")
            else:
                return     
        self.progressBar.setValue(0)
        
#--------------------------------------------------------------------------------------------------------

    def apply_queued_transformations(self,data):
        transformations = ['horizontal_mirror','vertical_mirror','transposition','rotation(+90)','rotation(+180)','rotation(-90)','masking','downsampling']
        for t in self.transform_list:
                if t in transformations:
                    if t =='horizontal_mirror':
                        data = numpy.flipud(data)[:]
                        self.log.appendPlainText('horizontal_mirror Done')
                    elif t =='vertical_mirror':
                        data = numpy.fliplr(data)[:]
                        self.log.appendPlainText('vertical_mirror Done')
                    elif t =='transposition':
                        data = data.transpose()[:]
                        self.log.appendPlainText('transposition Done')
                    elif t =='rotation(+90)':
                        data = numpy.rot90(data)[:]
                        self.log.appendPlainText('rotation(+90) Done')
                    elif t =='rotation(+180)':
                        data = numpy.rot90(data, 2)[:]
                        self.log.appendPlainText('rotation(+180) Done')
                    elif t =='rotation(-90)':
                        data = numpy.rot90(data, 3)[:]
                        self.log.appendPlainText('rotation(-90) Done')
                    elif t =='masking':
                        data = self.mask*data
                        self.log.appendPlainText('masking Done')
                else:
                    raise Warning, 'Unknown transformation %s'%t
        return data       
             
#--------------------------------------------------------------------------------------------------------
             
    def transformation_options(self):
        if self.transform_option_action.isChecked ():
            self.transform_data_series = True
        else:
            self.transform_data_series = False

#--------------------------------------------------------------------------------------------------------

    def clear_transform_list(self):
        self.transform_list=[]
        self.transformation_queue.clear()



#--------------------------------------------------------------------------------------------------------        
        
    def downsample(self):
        Dial = down_sampling_Dialog()
        thick,start_angle,step_angle = Dial.exec_()
        if thick != None :
            info = QFileDialog.getSaveFileNameAndFilter(self, "Save downsampled data series as multiple files", QDir.currentPath(), filter=self.tr("binary data block (*.bin);;cbf image (*.cbf);;edf image (*.edf);;oxford diffraction image (*.img);;mar2300 image(*.mar2300);;mar3450 image (*.mar3450);;marccd image (*.marccd));;tiff image (*.tiff)"))
            if self.data_series or self.sequential_file_list:
                if str(info[0])!='' and str(info[1])!='':
                    format = self.extract_format_from_string(str(info[1]))
                    fname = self.remove_extention_if_present(str(info[0]))

                    if self.sequential_file_mode:
                        total = len(self.sequential_file_list)
                        img =  fabio.open( self.sequential_file_dict[self.sequential_file_list[0]])
                        stack = numpy.zeros_like(img.data)
                        t0 = time.time()
                        subtotal = (total//thick)*thick
                        for i in range(subtotal):
                            j=i%thick
                            k = i//thick
                            imgkey = self.sequential_file_list[i]
                            tmpfname = self.sequential_file_dict[imgkey]
                            try :
                                img = fabio.open(tmpfname)
                            except:
                                QMessageBox.warning(self, 'Message','Automatic format recognition procedure failed or pehaps you are trying to open a binary data block...\n\n     ...Switch to manual procedure ')                
                                Dial = binDialog(self)
                                dim1,dim2,offset,bytecode,endian = Dial.exec_()
                                if dim1 != None and dim2 != None:
                                    if endian == 'Short':
                                        endian = '<'
                                    else :
                                        enfian = '>'
                                        img = fabio.binaryimage.binaryimage()
                                        img.read(tmpfname,dim1,dim2,offset,bytecode,endian)
                                        img.header = {'Info':'No header information available in binary data blocks'}
                                else :
                                    continue
                            if img.data.shape != stack.shape:
                                self.log.appendPlainText("Error image shape: %s summed data shape: %s"%(img.data.shape,stack.shape))
                                continue
                            numpy.add(stack , img.data, stack)
                            self.progressBar.setValue((float(i+1)/(subtotal))*100.)
                            self.log.appendPlainText('File %s stacked'%imgkey)
                            QCoreApplication.processEvents()
                            if j==thick-1:
                                self.log.appendPlainText('stack number %d summing up'%k)
                                QCoreApplication.processEvents()
                                if format in ['*.mar3450','*.mar2300']:
                                       img.header["PHI_START"]='%.3f'%(start_angle+step_angle*(i-thick+1))
                                       img.header["PHI_END"]='%.3f'%(start_angle+step_angle*(i))
                                self.convert_and_write(('%s_%s%s'%(fname,self.counter_format,format[1:]))%k,format,stack,img.header)
                                t1 = time.time()
                                print('time : %s' % (t1 - t0))
                                stack = numpy.zeros_like(img.data)
                                t0 = time.time()
                    else:
                        total = len(self.data_series)
                        stack = numpy.zeros_like(self.data_series[0])
                        subtotal = (total//thick)*thick
                        for i in range(subtotal):
                            j=i%thick
                            k = i//thick
                            data = self.data_series[i]    
                            if data.shape != stack.shape:
                                self.log.appendPlainText("Error image shape: %s summed data shape: %s"%(img.data.shape,stack.shape))
                                continue
                            numpy.add(stack , data, stack)
                            self.progressBar.setValue((float(i+1)/(subtotal))*100.)
                            self.log.appendPlainText('File number %d stacked'%i)
                            QCoreApplication.processEvents()
                            if j==thick-1:
                                self.log.appendPlainText('stack number %d summing up'%k)
                                QCoreApplication.processEvents()
                                if format in ['*.mar3450','*.mar2300']:
                                       self.header_series[i]["PHI_START"]='%.3f'%(start_angle+step_angle*(i-thick+1))
                                       self.header_series[i]["PHI_END"]='%.3f'%(start_angle+step_angle*(i))
                                self.convert_and_write(('%s_%s%s'%(fname,self.counter_format,format[1:]))%k,format,stack,self.header_series[i])
                                stack = numpy.zeros_like(data)
                    self.progressBar.setValue(0)
                    self.log.appendPlainText('Downsampling : Complete')
                    QCoreApplication.processEvents()
            else:
                if str(info[0])!='' and str(info[1])!='':
                    QMessageBox.warning(self,'Warning',"Could not save image as file if no data have been loaded")

       
#--------------------------------------------------------------------------------------------------------
# Miscelaneous
#--------------------------------------------------------------------------------------------------------
             
    def select_new_image(self, name,imgID=None):
        if imgID != None:
            iid = imgID
        else :
            iid = self.imgDict[str(name)]
        self.data = self.data_series[iid]
        self.header = self.header_series[iid]

        self.headerTextEdit.setPlainText(str(self.format_header(self.header)))
        self.on_draw()
        
#--------------------------------------------------------------------------------------------------------
    
    def on_pick(self, event):
        if event.inaxes and self.data.any():
            if int(event.xdata) <= self.data.shape[1] and int(event.ydata) <= self.data.shape[0]:
                x = int(round(event.xdata))
                y = int(round(event.ydata))
                i = self.data[y,x]
                self.pix_coords_label.setText("Pixel coordinates and intensity : x =%6d, y =%6d, i =%6g"%(x,y,i))
            else :
                self.pix_coords_label.setText("Pixel coordinates and intensity : x = None , y = None , i = None ")
        else : 
            self.pix_coords_label.setText("Pixel coordinates and intensity : x = None , y = None , i = None ")

#--------------------------------------------------------------------------------------------------------  
    
    def on_draw(self):
        """ Redraws the figure"""
        self.statusBar().showMessage('Loading display ...')
        QCoreApplication.processEvents()
        # clear the axes and redraw a new plot 
        self.axes.clear()        
        # self.axes.imshow(numpy.log(numpy.clip(self.data,1.0e-12,1.0e260) ),interpolation = 'nearest')
        self.axes.imshow(numpy.log(self.data), interpolation='nearest')

        self.axes.set_visible(True) 
        if self.axes.get_ylim()[0]<self.axes.get_ylim()[1]:
            self.axes.set_ylim(self.axes.get_ylim()[::-1])   
        self.canvas.draw()
        self.statusBar().clearMessage()

#--------------------------------------------------------------------------------------------------------  

    def batch_to_view(self):
        items = self.imagelistWidget.selectedItems()
        iid = 0 
        item = items[0]
        item = str(item.text())
        hdfxtens = ['.h5','.H5','.hdf','.HDF','hdf5','.HDF5']
        for xtens in hdfxtens:
            if xtens in item:
                QMessageBox.warning(self, 'Message',"Can't display hdf archive from batch mode ")
                return
        if self.sequential_file_mode:
            self.data_series = []
            self.header_series = []
            self.imgDict = {}
            self.images_list.clear()
            self.headerTextEdit.clear()
            self.axes.clear()
            self.canvas.draw()
            self.statusBar().showMessage('Import image %s in the View Mode tab, please wait ...'%item)
            self.log.appendPlainText('Import image %s in the View Mode tab'%item)
            QCoreApplication.processEvents()
            fname = self.sequential_file_dict[item]
            try :
                img = fabio.open(fname)
            except:
                QMessageBox.warning(self, 'Message','Automatic format recognition procedure failed or pehaps you are trying to open a binary data block...\n\n     ...Switch to manual procedure ')                
                Dial = binDialog(self)
                dim1,dim2,offset,bytecode,endian = Dial.exec_()
                if dim1 != None and dim2 != None:
                    if endian == 'Short':
                        endian = '<'
                    else :
                        enfian = '>'
                    img = fabio.binaryimage.binaryimage()
                    img.read(fname,dim1,dim2,offset,bytecode,endian)
                    img.header = {'Info':'No header information available in binary data blocks'}
                else :
                    return     
            self.data_series += [img.data[:]]
            self.header_series += [img.header.copy()]
            extract_fname = self.extract_fname_from_path(fname)
            self.images_list.addItem(extract_fname)
            self.imgDict[extract_fname]=iid
            iid +=1
        self.statusBar().clearMessage()
        if self.data_series:
            self.select_new_image(None,imgID=0)
        self.tabWidget.setCurrentIndex(0)

#--------------------------------------------------------------------------------------------------------  

    def set_counter_format_option(self):
        Dial = counter_format_option_Dialog(self.counter_format)
        self.counter_format = Dial.exec_()
        
#--------------------------------------------------------------------------------------------------------  

    def padd_mar(self,data,format):
        dim1,dim2 = data.shape
        
        if format == '*.mar2300':
            size = 2300
        else:
            size = 3450
                
        left = (size - dim1)//2
        right = size - (dim1 + left)
        up = (size - dim2)//2
        down = size - (dim2 + up) 
        
        out = numpy.zeros((size, size))
        
        if left > 0 : #pad
            outlm = left 
            inlm =  0
        else: #crop
            outlm = 0
            inlm = - left
        if right > 0: #pad
            outrm = -right
            inrm = dim1
        else: #crop
            outrm = size
            inrm = right
        if up > 0 : #pad
            outum = up 
            inum =  0
        else: #crop
            outum = 0
            inum = - up
        if down > 0: #pad
            outdm = - down
            indm = dim2
        else: #crop
            outdm = size
            indm = down
        
        out[outlm:outrm,outum:outdm] = data[inlm:inrm,inum:indm]
        return out


#--------------------------------------------------------------------------------------------------------  
    def sequential_option(self,state):
        if not self.h5_loaded:
            if state == Qt.Checked:
                self.sequential_file_mode = True
            else:
                self.sequential_file_mode = False
        else:
            self.filecheckBox.stateChanged.disconnect()
            self.filecheckBox.setCheckState(False)
            self.sequential_file_mode = False
            self.filecheckBox.stateChanged.connect(self.sequential_option)
            QMessageBox.warning(self, 'Message','Sequential file mode is not compatible with hdf5 input file : option removed')    
                  
#--------------------------------------------------------------------------------------------------------
# Main Frame
#--------------------------------------------------------------------------------------------------------
   
    def create_main_frame(self):

        self.tabWidget = QTabWidget()
        tab1 = QWidget()
        self.tabWidget.addTab(tab1,"View Mode")
        tab2 = QWidget()
        self.tabWidget.addTab(tab2, "Batch Mode")
        #--------------------------------------------------------------------------------------------------------
        # Tab 1
        #--------------------------------------------------------------------------------------------------------

        # Create the mpl Figure and FigCanvas objects. 
        # 100 dots-per-inch
        self.dpi = 100
        #self.fig = Figure((100, 100), dpi=self.dpi)
        self.fig = Figure(dpi = self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(tab1)
        
        # Since we have only one plot, we can use add_axes 
        # instead of add_subplot, but then the subplot
        # configuration tool in the navigation toolbar wouldn't
        # work.
        #
        self.axes = self.fig.add_subplot(111)
        self.axes.set_visible(False)
        # Bind the 'pick' event for clicking on one of the bars
        self.canvas.mpl_connect('motion_notify_event', self.on_pick)
        
        # Create the navigation toolbar, tied to the canvas
        self.mpl_toolbar = NavigationToolbar(self.canvas, tab1,coordinates=False)

        # Other GUI controls
        selector_label = QLabel('Active Image :')
        self.images_list = QComboBox(self)
        self.images_list.activated[str].connect(self.select_new_image)
        
        viewer_label = QLabel("Images Viewer : ", self)
        self.pix_coords_label = QLabel("Pixel coordinates and intensity : x = None , y = None , i = None ", self)
        self.mpl_toolbar.addWidget(self.pix_coords_label)
        
        self.headerTextEdit = QPlainTextEdit(tab1)
        self.headerTextEdit.setReadOnly(True)
        # Layout with box sizers
       
        header_vbox = QVBoxLayout()
        header_label = QLabel("Header Info :", self)
        header_vbox.addWidget(header_label)
        header_vbox.addWidget(self.headerTextEdit)
        
        hbox = QHBoxLayout()
        hbox.addWidget(selector_label,alignment=Qt.AlignRight)
        hbox.addWidget(self.images_list)
        
        vbox = QVBoxLayout()
        vbox.addWidget(viewer_label,alignment=Qt.AlignVCenter)
        vbox.addWidget(self.canvas,alignment=Qt.AlignVCenter)
        vbox.addWidget(self.mpl_toolbar,alignment=Qt.AlignVCenter)
        vbox.addLayout(hbox)
        
        left = QWidget()
        right = QWidget()
       
        left.setLayout(header_vbox)
        right.setLayout(vbox)
        splitter = QSplitter(Qt.Horizontal)
        splitter.addWidget(left)
        splitter.addWidget(right)
        Bighbox = QHBoxLayout()
        Bighbox.addWidget(splitter)
        
        tab1.setLayout(Bighbox)
        
        #--------------------------------------------------------------------------------------------------------
        # Tab 2
        #--------------------------------------------------------------------------------------------------------
        
        imagelistvbox = QVBoxLayout()
        
        imagelistlabel = QLabel(tab2)
        imagelistlabel.setText("Images List :")
        self.imagelistWidget = QListWidget(tab2)
        import_view_button = QPushButton('Export image to View Mode', tab2)
        import_view_button.clicked.connect(self.batch_to_view)

        imagelistvbox.addWidget(imagelistlabel)
        imagelistvbox.addWidget(self.imagelistWidget)
        imagelistvbox.addWidget(import_view_button)
        
        rightsidevbox = QVBoxLayout()
        
        optiongroupBox = QGroupBox(tab2)
        optiongroupBox.setTitle("File Modes :")
        
        optionbox = QVBoxLayout()
        
        self.butttonGroup = QButtonGroup()
        
        self.filecheckBox = QCheckBox()
        self.filecheckBox.setText("Sequential access (for large data series)")
        self.filecheckBox.stateChanged.connect(self.sequential_option)
        self.butttonGroup.addButton(self.filecheckBox)
        
        self.filecheckBox2 = QCheckBox()
        self.filecheckBox2.setText("Direct access (all images are store in memory simultaneously)")
        self.filecheckBox2.setChecked(True)
        self.butttonGroup.addButton(self.filecheckBox2)
        
        self.butttonGroup.setExclusive(True)
        
        optionbox.addWidget(self.filecheckBox)
        optionbox.addWidget(self.filecheckBox2)
        
        optiongroupBox.setLayout(optionbox)
        
        rightsidevbox.addWidget(optiongroupBox)
        
        splitter3 = QSplitter(Qt.Vertical)
        
        
        queuegroupBox = QGroupBox(tab2)
        queuegroupBox.setTitle("Transformations Queue :")
        
        queuebox = QVBoxLayout()
        self.transformation_queue = QListWidget(tab2)
        queuebox.addWidget(self.transformation_queue)
        clear_trans_list_button = QPushButton('Clear Transformation List', tab2)
        clear_trans_list_button.clicked.connect(self.clear_transform_list)
        queuebox.addWidget(clear_trans_list_button)
        
        queuegroupBox.setLayout(queuebox)
        
        splitter3.addWidget(queuegroupBox)        
               

        loggroupBox = QGroupBox(tab2)
        loggroupBox.setTitle("Log View :")
        
        logbox = QHBoxLayout()
        self.log = QPlainTextEdit()
        logbox.addWidget(self.log)
        
       
        loggroupBox.setLayout(logbox)
        splitter3.addWidget(loggroupBox)
        splitter3.setStretchFactor(1, 1)
        
        rightsidevbox.addWidget(splitter3)
        
        
        self.progressBar = QProgressBar(tab2)
        self.progressBar.setProperty("value", 0)
        rightsidevbox.addWidget(self.progressBar)
        
        left2 = QWidget()
        right2 = QWidget() 
        left2.setLayout(imagelistvbox)
        right2.setLayout(rightsidevbox)  
        splitter2 = QSplitter(Qt.Horizontal)
        splitter2.addWidget(left2)
        splitter2.addWidget(right2)
        splitter2.setStretchFactor(1, 2)
        
        Bighbox2 = QHBoxLayout()
        Bighbox2.addWidget(splitter2)
        
        tab2.setLayout(Bighbox2)
        
        self.setCentralWidget(self.tabWidget)
        
#--------------------------------------------------------------------------------------------------------        
        
    def create_status_bar(self):
        self.status_text = QLabel('')
        self.statusBar().addWidget(self.status_text, 1)
        self.statusBar().showMessage('Thanks for using FabIO viewer.', 5000)

#--------------------------------------------------------------------------------------------------------        

    def on_about(self):
#        msg = """Image Converter v 1.0\n\nA portable diffraction images converter :\n\n* Written in python, it combines the functionalities of the I/O library fabIO with a user friendly Qt4 GUI.\n\n* Image converter is also a light viewer based on the visualisation tool provided by the module matplotlib.\n"""
        msg = [__doc__,
               "",
               "Version: \t\t%s" % __version__,
               "FabIO version: \t%s" % fabio.version,
               "Author: \t\t%s" % __author__,
               "Copyright: \t\t%s" % __copyright__,
               "License: \t\t%s" % __licence__]


        QMessageBox.about(self, "About FabIO Viewer", os.linesep.join(msg))   
     
#--------------------------------------------------------------------------------------------------------
# Menu
#--------------------------------------------------------------------------------------------------------
        
    def create_menu(self):
        #0----------------------------------------------     
        self.file_menu = self.menuBar().addMenu("&File")
        #1----------------------------------------------
        self.open_menu =  self.file_menu.addMenu("&Open")
        #2----------------------------------------------
        load_data_series_action = self.create_action("&Image(s)",
            shortcut="", slot=self.open_data_series, 
            tip="Load single file and data series (files sequence)")
        
        self.add_actions(self.open_menu,(load_data_series_action,))
        #2----------------------------------------------
        load_h5_data_series_action = self.create_action("&Hdf5 data series",
            shortcut="", slot=self.open_h5_data_series, 
            tip="Load single file and data series (files sequence)")
        
        self.add_actions(self.open_menu,(load_h5_data_series_action,))
        #1----------------------------------------------
        self.save_as_menu =  self.file_menu.addMenu("&Save")
        #2----------------------------------------------
        save_as_action = self.create_action("&Active image", slot=self.save_as, 
            shortcut="", tip="Save/Convert the image which is currently displayed")
            
        self.add_actions(self.save_as_menu, (save_as_action,))
        
        #2----------------------------------------------
        self.save_data_series_menu =  self.save_as_menu.addMenu("&Data series as")
        #3---------------------------------------------- 
        save_data_series_as_multiplefile_action = self.create_action("&Multiple files", slot=self.save_data_series_as_multiple_file, 
            shortcut="", tip="Save/Convert the set of images currently loaded into the images list")
            
        self.add_actions(self.save_data_series_menu, (save_data_series_as_multiplefile_action,))
        #3---------------------------------------------- 
        save_data_series_as_singlehdf_action = self.create_action("&Hdf5 archive", slot=self.save_data_series_as_singlehdf, 
            shortcut="", tip="Save/Convert the set of images currently loaded into the images list")
            
        self.add_actions(self.save_data_series_menu, (save_data_series_as_singlehdf_action,))
        
        #1----------------------------------------------
        quit_action = self.create_action("&Quit", slot=self.close, 
            shortcut="Ctrl+Q", tip="Close the application")

        self.add_actions(self.file_menu, (quit_action,))
        
        #1----------------------------------------------
        self.transform_menu = self.menuBar().addMenu("&Transform")
        #2----------------------------------------------
        self.mirror_menu = self.transform_menu.addMenu("&Mirror")
        #3----------------------------------------------
        horizontal_mirror_action = self.create_action("&Horizontal",
            shortcut='', slot=self.horizontal_mirror, 
            tip="Horizontal mirror")
        
        self.add_actions(self.mirror_menu,(horizontal_mirror_action,))
        
        #3 ----------------------------------------------
        vertical_mirror_action = self.create_action("&Vertical",
            shortcut='', slot=self.vertical_mirror, 
            tip="Vertical mirror")
        
        self.add_actions(self.mirror_menu,(vertical_mirror_action,))
        
        #3----------------------------------------------
        transposition_action = self.create_action("&Transposition",
            shortcut='', slot=self.transposition, 
            tip="Transposition")
        
        self.add_actions(self.mirror_menu,(transposition_action,))
        
        #2----------------------------------------------
        self.rotation_menu = self.transform_menu.addMenu("&Rotation")
        
        #3---------------------------------------------- 
        rotation_90_action = self.create_action("+90",
            shortcut='', slot=self.rotation_90, 
            tip="Rotation of +90 degrees (counter-clockwise)")
        
        self.add_actions(self.rotation_menu,(rotation_90_action,))
        
        #3---------------------------------------------- 
        rotation_180_action = self.create_action("+180",
            shortcut='', slot=self.rotation_180, 
            tip="Rotation of +180 degrees (counter-clockwise)")
        
        self.add_actions(self.rotation_menu,(rotation_180_action,))
        
        #3---------------------------------------------- 
        rotation_270_action = self.create_action("- 90",
            shortcut='', slot=self.rotation_270, 
            tip="Rotation of -90 degrees (counter-clockwise)")
        
        self.add_actions(self.rotation_menu,(rotation_270_action,))
        
        #2----------------------------------------------
        import_mask_action = self.create_action("&Mask",
            shortcut='', slot=self.mask, 
            tip="Import a mask from file and apply it to image(s)")

        self.add_actions(self.transform_menu,(import_mask_action,))
        #2----------------------------------------------
        downsample_action = self.create_action("&Downsample",
            shortcut='', slot=self.downsample, 
            tip="Summation over groups of images")

        self.add_actions(self.transform_menu,(downsample_action,))
        #2----------------------------------------------
        self.transform_option_action = self.create_action("&Apply transform to the whole data series",
            shortcut='', slot=self.transformation_options, 
            tip="Define if transformations are Applied to the whole data series (checked) or only to the active image (unchecked) ")
        self.transform_option_action.setCheckable(True)
        
        self.add_actions(self.transform_menu,(self.transform_option_action,))
        #0----------------------------------------------
        self.options = self.menuBar().addMenu("&Options")
        #1----------------------------------------------
        about_action = self.create_action("&Counter format", 
            shortcut='', slot=self.set_counter_format_option, 
            tip='Allow to define the format for the counter in multiple saving')
        
        self.add_actions(self.options, (about_action,))
        #0----------------------------------------------
        self.help_menu = self.menuBar().addMenu("&Help")
        #1----------------------------------------------
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About Images Converter')
        
        self.add_actions(self.help_menu, (about_action,))

#--------------------------------------------------------------------------------------------------------
    
    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

#--------------------------------------------------------------------------------------------------------

    def create_action(self,text,slot=None,shortcut=None,icon=None,tip=None,checkable=False,signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action

#--------------------------------------------------------------------------------------------------------  
# External top level window class
#--------------------------------------------------------------------------------------------------------

class counter_format_option_Dialog(QDialog):#option doivent refleter l etat des couche du dessous
    """Dialog containing entry for down sampling"""    
    def __init__(self,counter_format, parent=None):
        QDialog.__init__(self,parent)           
        self.resize(350, 100)
        self.setWindowTitle('Options')
        self.counter_format = counter_format
        buttonBox = QDialogButtonBox(self)
        buttonBox.setGeometry(QRect(0, 60, 341, 32))
        buttonBox.setOrientation(Qt.Horizontal)
        buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        
        label = QLabel(self)
        label.setGeometry(QRect(38, 23, 181, 16))
        label.setText("File Counter format :")
        
        self.lineEdit = QLineEdit(self)
        self.lineEdit.setGeometry(QRect(175, 18, 113, 25))
        self.lineEdit.setText(counter_format)
        
        QObject.connect(buttonBox, SIGNAL(_fromUtf8("accepted()")), self.accept)
        QObject.connect(buttonBox, SIGNAL(_fromUtf8("rejected()")), self.reject)
        
    def exec_(self):
        if QDialog.exec_(self) == QDialog.Accepted:
            if str(self.lineEdit.text()) !='' :
                return str(self.lineEdit.text())
            else:
                QMessageBox.warning(self,'Warning',"All informations are mandatory, please fill the blanks")
        else:
            return self.counter_format
            
#--------------------------------------------------------------------------------------------------------    

class down_sampling_Dialog(QDialog):
    """Dialog containing entry for down sampling"""    
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)           
        self.resize(407, 250)
        self.setWindowTitle('Downsampling')
        buttonBox = QDialogButtonBox(self)
        buttonBox.setGeometry(QRect(45, 200, 341, 32))
        buttonBox.setOrientation(Qt.Horizontal)
        buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        
        label = QLabel(self)
        label.setGeometry(QRect(38, 63, 181, 16))
        label.setText("Number of files to sum up :")
        
        self.lineEdit = QLineEdit(self)
        self.lineEdit.setGeometry(QRect(220, 58, 113, 25))
        
        label2 = QLabel(self)
        label2.setGeometry(QRect(90, 100, 131, 20))
        label2.setText("Starting Phi angle :")
        
        self.lineEdit2 = QLineEdit(self)
        self.lineEdit2.setGeometry(QRect(220, 95, 113, 25))
        
        label3 = QLabel(self)
        label3.setGeometry(QRect(151, 133, 101, 16))
        label3.setText("Phi step :")
        
        self.lineEdit3 = QLineEdit(self)
        self.lineEdit3.setGeometry(QRect(219, 130, 113, 25))
        
        QObject.connect(buttonBox, SIGNAL(_fromUtf8("accepted()")), self.accept)
        QObject.connect(buttonBox, SIGNAL(_fromUtf8("rejected()")), self.reject)
        
    def exec_(self):
        if QDialog.exec_(self) == QDialog.Accepted:
            if str(self.lineEdit.text()) !='' and str(self.lineEdit2.text()) != '' and str(self.lineEdit3.text()) != '':
                return int(str(self.lineEdit.text())),float(str(self.lineEdit2.text())),float(str(self.lineEdit3.text()))
            else:
                QMessageBox.warning(self,'Warning',"All informations are mandatory, please fill the blanks")
        else:
            return None,None,None
            
#--------------------------------------------------------------------------------------------------------            
            
class binDialog(QDialog):
    """Dialog containing entry for binary data block opening"""    
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.resize(410, 270)
        self.setWindowTitle("Binary data block opening")
        
        self.dim1 = None
        self.dim2 = None
        self.offset = None
        self.bytecode = None
        self.endian = None
        
        buttonBox = QDialogButtonBox(self)
        buttonBox.setGeometry(QRect(50, 230, 341, 32))
        buttonBox.setOrientation(Qt.Horizontal)
        buttonBox.setStandardButtons(QDialogButtonBox.Cancel|QDialogButtonBox.Ok)
        
        groupBox = QGroupBox(self)
        groupBox.setGeometry(QRect(10, 10, 370, 191))
        groupBox.setTitle("Binary data block required informations :")
        label = QLabel(self)
        label.setGeometry(QRect(67, 48, 91, 16))
        label.setText("Dimention 1 :")
        label_2 = QLabel(self)
        label_2.setGeometry(QRect(66, 76, 91, 16))
        label_2.setText("Dimention 2 :")
        self.lineEdit = QLineEdit(self)
        self.lineEdit.setGeometry(QRect(185, 40, 91, 25))
        self.lineEdit_2 = QLineEdit(self)
        self.lineEdit_2.setGeometry(QRect(185, 70, 91, 25))
        label_5 = QLabel(self)
        label_5.setGeometry(QRect(105, 106, 51, 16))
        label_5.setText("Offset :")
        self.lineEdit_3 = QLineEdit(self)
        self.lineEdit_3.setGeometry(QRect(184, 100, 91, 25))
        self.lineEdit_3.setText('0')
        label_3 = QLabel(groupBox)
        label_3.setGeometry(QRect(70, 130, 91, 16))
        label_3.setText("ByteCode :")
        self.comboBox = QComboBox(groupBox)
        self.comboBox.setGeometry(QRect(173, 123, 91, 25))
        bytecodes = ["int8","int16","int32","int64","uint8","uint16","uint32","uint64","float32","float64"]
        for bytecode in bytecodes:
            self.comboBox.addItem(_fromUtf8(bytecode))
        self.comboBox.setCurrentIndex(2)
        label_4 = QLabel(self)
        label_4.setGeometry(QRect(98, 170, 61, 16))
        label_4.setText("Endian :")
        self.comboBox_2 = QComboBox(self)
        self.comboBox_2.setGeometry(QRect(182, 166, 91, 25))
        self.comboBox_2.addItem(_fromUtf8("Short"))
        self.comboBox_2.addItem(_fromUtf8("Long"))
        
        self.connect(buttonBox, SIGNAL('rejected()'), self.cancel);
        self.connect(buttonBox, SIGNAL('accepted()'), self.binary_block_info);
   
    def binary_block_info(self):
        if str(self.lineEdit.text()) !='' and str(self.lineEdit_2.text()) != '' and str(self.lineEdit_3.text()) != '':
            self.dim1 = int(str(self.lineEdit.text()))
            self.dim2 = int(str(self.lineEdit_2.text()))
            self.offset = int(str(self.lineEdit_3.text()))
        else:
            QMessageBox.warning(self,'Warning',"All informations are mandatory, please fill the blanks")
            return 
        self.bytecode = str(self.comboBox.currentText())
        self.endian = str(self.comboBox_2.currentText())
        #dim1,dim2,offset,bytecode,endian
        self.accept()
        
    def cancel(self):
        self.close()
    
    def exec_(self):
        if QDialog.exec_(self) == QDialog.Accepted:
            return  self.dim1,self.dim2,self.offset,self.bytecode,self.endian
        else:
            return None,None,None,None,None

#--------------------------------------------------------------------------------------------------------
# Main
#--------------------------------------------------------------------------------------------------------

def main():
    parser = ArgumentParser(prog="fabio_viewer", usage="fabio_viewer img1 img2 ... imgn",
                            description=__doc__,
                            epilog="Based on FabIO version %s" % fabio.version)
    parser.add_argument("images", nargs="*")
    parser.add_argument("-V", "--version", action='version', version=__version__, help="Print version & quit")
    args = parser.parse_args()
    QApplication.setStyle(QStyleFactory.create("Cleanlooks"))
    app = QApplication([])
    form = AppForm()
    if args.images:
        form.open_data_series(args.images)
    form.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()
