def exploreSimulationsClicked(self):
        self.lgr.info('Explore simulations clicked')

        # Check of corredt scene is opened
        currentSceneName = cmds.file(q=True, sceneName=True)
        sceneFromConfigFile = self.projectSettings.mayaFilePath
        isSameScene = ProjectDetailsViewUtils.checkIfCorrectSceneIsOpened(currentSceneName, sceneFromConfigFile)
        if not isSameScene:
            strError = 'Please open the correct maya scene first!\nPath: ' + sceneFromConfigFile
            self.lgr.warning('Please open the correct maya scene first! Path: %s', sceneFromConfigFile)
            self.showMessageBox(strError, 'warning')
            return

        # Check if xml files are available
        if not len(self.hashMapToXMLProjectFile) == int(self.projectSettings.numberOfSimulations) + 1:
            self.lgr.warning('Number of XML cache files is not correct')
            errorMsg = "The number of .xml cache files is not correct!\nPlease check the project folder or create the simulation again."
            self.showMessageBox(errorMsg, 'warning')
            return

        # Check if fluidexplorer app is running
        isFXProcessRunning = ProjectDetailsViewUtils.checkIfProcessIsRunning_WIN(self.FLUIDEXPLORER_APP_NAME)
        if isFXProcessRunning:
            return

        # Check if path exists
        pathToFXAPP = self.externalCall.pathToFluidExplorer + '/' + self.externalCall.fluidExplorerCmd
        if not os.path.exists(os.path.abspath(pathToFXAPP)):
            self.lgr.error('Cannot find the FluidExplorer application executable')
            errorMsg = "Cannot find the FluidExplorer application executable!" + "\n" + "Please check if  the executable file is available."
            self.showMessageBox(errorMsg, 'warning')
            return

        # Run the worker thread
        if self.workThread:
            self.workThread.stop()

            # Start thread again
            self.workThread = WorkThread(self.externalCall)
            self.connect(self.workThread, QtCore.SIGNAL("update(QString)"), self.updateIndexFromThread)
            self.workThread.start()

        else:
            # Start thread
            self.workThread = WorkThread(self.externalCall)
            self.connect(self.workThread, QtCore.SIGNAL("update(QString)"), self.updateIndexFromThread)
            self.workThread.start()
class ProjectDetailsView(QtGui.QDialog):

    PERSPECTIVE_CAMERA_AVAILABLE = '1'
    PERSPECTIVE_CAMERA_NOT_AVAILABLE = '0'

    def __init__(self, args, pathToXMLFile):

        QtGui.QDialog.__init__(self, args)

        # Logger
        self.lgr = logging.getLogger('FluidExplorerPlugin')

        # Stores th path to the XML file
        self.pathToXMLFile = pathToXMLFile
        self.PathToXMLCache = ''

        # Members
        self.projectSettings = None
        self.hashMapToXMLProjectFile = {}
        self.hashMapToGIF = {}
        self.currentAnimationLoaded = None

        # Thread which starts the FX app
        self.workThread = None
        self.FLUIDEXPLORER_APP_NAME = "fluidexplorer"

        # Set up the user interface from the ui file
        self.ui = Ui_ProjectDetailsView()
        self.ui.setupUi(self)

        # Move window to the 'modelPanel1' position
        [xPos, yPos] = self.moveWindowToPanel()
        self.move(xPos, yPos)

        # QMovie
        self.movie = QtGui.QMovie(self)

        # Create connections
        self.createConnections()

        # Initialize widget
        self.initializewidget()
        self.setWindowHeightWithoutPreview()
        self.initializeComponentss()
        self.setWindowTitle('Fluid Explorer - Project View')

        # Window flags - top and buttons
        self.setWindowFlags(self.windowFlags() |
            QtCore.Qt.WindowMinimizeButtonHint |
            QtCore.Qt.WindowStaysOnTopHint)

        self.show()

        # Set values from project configuration file
        statusCode = self.projectSettings = self.readProjectProperties(self.pathToXMLFile)
        if statusCode:
            canSetAllFields = self.setValuesFromConfigurationFile(self.projectSettings)
            if not canSetAllFields:
                self.showMessageBox('Could not read all project attributes from the\nconfiguration file!', 'warning')
        else:
            self.setAllFieldsEnabled()

        # Initialize the combo box and the preview functionality
        if self.projectSettings:
            self.initComboBoxSimulations(self.projectSettings)
            self.initPreview(self.projectSettings)

        # Register scriptJob
        self.FXScriptJob()
        self._rcwin = 1

        # External call
        self.externalCall = ExternalCallSetting()
        self.setupExternallCall()

        self.lgr.info('Load project view created')
        self.lgr.info('Project path: %s', pathToXMLFile)


    def setPathToProjectFile(self, path):
        self.pathToXMLFile = path

    def setAllFieldsEnabled(self):
        self.ui.pushButton_applyCache.setEnabled(False)
        self.ui.pushButton_exploreSimulations.setEnabled(False)
        self.ui.checkBox_showPreview.setEnabled(False)
        self.ui.comboBox_simulations.setEnabled(False)
        self.update()

    def moveWindowToPanel(self):
        try:
            panelPtr = omui.MQtUtil.findControl('modelPanel1')

            if not panelPtr:
                xPos = 0
                yPos = 0
            else:
                panel = wrapInstance(long(panelPtr), QtGui.QWidget)
                position = panel.mapToGlobal(panel.pos())
                if not panelPtr:
                    xPos = 0
                    yPos = 0
                else:
                    xPos = position.x()
                    yPos = position.y()
        except:
            xPos = 0
            yPos = 0

        return [xPos, yPos]

    def initializewidget(self):
        self.setMinimumWidth(340)
        self.setMaximumWidth(340)

    def setWindowHeightWithPreview(self):
        self.setMinimumHeight(620-25)
        self.setMaximumHeight(620-25)

    def setWindowHeightWithoutPreview(self):
        self.setMinimumHeight(360-0)
        self.setMaximumHeight(360-0)

    def initializeComponentss(self):
        icon_help = QtGui.QIcon(QtGui.QPixmap(':/help_icon_orange.png'))
        self.ui.pushButton_help.setIcon(icon_help)

        self.setWindowTitle('Fluid Explorer - Simulation Details View')
        self.changeHLineStyle()
        self.setLineEditEnabledAndReadOnly(self.ui.lineEdit_projectName)
        self.setLineEditEnabledAndReadOnly(self.ui.lineEdit_projectPath)
        self.setLineEditEnabledAndReadOnly(self.ui.lineEdit_fluidContainer)
        self.setLineEditEnabledAndReadOnly(self.ui.lineEdit_startTime)
        self.setLineEditEnabledAndReadOnly(self.ui.lineEdit_endTime)

        self.ui.label_moviePreview.setAlignment(QtCore.Qt.AlignCenter)
        self.ui.label_moviePreview.setStyleSheet("background-color: black;")

        self.scaleMovieLabel()
        self.ui.label_moviePreview.setMaximumHeight(170)
        self.ui.label_moviePreview.setMinimumHeight(170)

    def setupExternallCall(self):
        # e.g. fluidexplorer.exe /settings path=E:/TMP/ANNAANNA/ANNAANNA.fxp /load path=E:/FluidExplorer_Code/FlameShape/FlameShape1

        # FluidExplorer
        self.externalCall.pathToFluidExplorer = ProjectDetailsViewUtils.getPathFluidExplorer()
        if sys.platform.startswith('win'):
            self.externalCall.fluidExplorerCmd = 'fluidExplorer.exe'
        elif sys.platform.startswith(''):
            # TODO: UNIX
            pass

        # Settings file
        settingXMLFile = self.pathToXMLFile

        # Path to cached files
        cacheFile = ProjectDetailsViewUtils.getPathCacheFiles(self.pathToXMLFile)

        # Args
        self.externalCall.fluidExplorerArgs = '/settings path=' + str(settingXMLFile) + ' ' + '/load path=' + str(cacheFile)

        # For testing
        self.externalCall.pathToFluidExplorer = 'E:/FluidExplorer_Code/Release/'
        self.externalCall.pathToFluidExplorer = 'E:/Workspace_VisualStudio/fluidexplorer/Backup/fluidexplorer/bin/Win32/Debug/'
        self.externalCall.fluidExplorerCmd = 'fluidExplorer.exe'
        self.externalCall.fluidExplorerArgs = '/load path=E:\FluidExplorer_Code\FlameShape\FlameShape1'


    def scaleMovieLabel(self):
        # Is supposed to be: 960x540
        # Width = 300
        size = self.ui.label_moviePreview.size()
        newSize = QtCore.QSize(300, 169)
        self.movie.setScaledSize(newSize)

    def setValuesFromConfigurationFile(self, projectSettings):
        canReadAllAttributes = True

        self.lgr.info('Read projects attributes:')
        for attr, value in projectSettings.__dict__.iteritems():
            # txt = attr + ": " + value
            self.lgr.info('%s : %s', attr, value)
            if value == None:
                canReadAllAttributes = False
                self.lgr.warning('Cannot read attribute %s', attr)

        if projectSettings:
            self.ui.lineEdit_projectName.setText(projectSettings.projectName)
            self.ui.lineEdit_projectPath.setText(projectSettings.projectPath)
            self.ui.lineEdit_fluidContainer.setText(projectSettings.fluidContainerName)
            self.ui.lineEdit_startTime.setText(projectSettings.animationStartTime)
            self.ui.lineEdit_endTime.setText(projectSettings.animationEndTime)

        return canReadAllAttributes

    def initComboBoxSimulations(self, projectSettings):

        # Stores animation index and path
        haspMap = {}

        # First item
        self.ui.comboBox_simulations.addItem('Select Sequence ...')

        try:
            num = int(projectSettings.numberOfSimulations)
        except:
            num = 0

        if num > 0:
            for i in range(num):

                # Firste entry
                tmpNameForElement = 'Sequence ' + str(i+1)

                # Folders
                tmpProject = projectSettings.projectName + '.fxp'
                index = self.pathToXMLFile.find(tmpProject)
                tmp = self.pathToXMLFile[0:index]
                tmp = tmp + '/' + str(i) + '/'
                #tmp = projectSettings.projectPath + "/" + str(i) + "/"
                if os.path.exists(tmp):
                    pathToXMLProjectFileList = ProjectDetailsViewUtils.getPathToXMLFile(tmp)

                    if len(pathToXMLProjectFileList) == 1:
                        if os.path.exists(pathToXMLProjectFileList[0]):
                            haspMap[i] = pathToXMLProjectFileList[0]
                            self.ui.comboBox_simulations.addItem(tmpNameForElement)

            self.hashMapToXMLProjectFile = haspMap

    def initPreview(self, projectSettings):
        if projectSettings.cam_persp == '1' or projectSettings.cam_persp == '1':
            self.hashMapToGIF = ProjectDetailsViewUtils.getGIFHashMap(projectSettings)
        else:
            self.ui.checkBox_showPreview.setEnabled(False)

    def createConnections(self):
        self.connect(self.ui.pushButton_applyCache, QtCore.SIGNAL("clicked()"), self.applyCacheClicked)
        self.connect(self.ui.pushButton_exploreSimulations, QtCore.SIGNAL("clicked()"), self.exploreSimulationsClicked)
        self.connect(self.ui.checkBox_showPreview, QtCore.SIGNAL("stateChanged(int)"), self.checkBoxPreviewValueChanged)
        self.connect(self.ui.comboBox_simulations, QtCore.SIGNAL("currentIndexChanged(QString)"), self.comboBoxSimulationsIndexChanged)
        self.connect(self.ui.pushButton_help, QtCore.SIGNAL("clicked()"), self.helpButtonClicked)
        self.connect(self.movie, QtCore.SIGNAL("frameChanged(int)"), self.frameChangedHandler)

    def playAnimation(self, simulationIndex):

        if self.hashMapToGIF == None:
            return

        # Index for the hash map
        hashIndex = simulationIndex - 1

        if simulationIndex == 0:
            self.stopPlayingAnimation()
            return

        fileName = self.hashMapToGIF[hashIndex]

        if not os.path.exists(fileName):
            self.ui.label_moviePreview.setText("<b>[ Cannot find animation ... ]</b>")
            self.stopPlayingAnimation()
            return
        else:
            self.ui.label_moviePreview.setText("")
            self.ui.label_moviePreview.setMovie(self.movie)

        # Play animation
        currentState = self.movie.state()

        if currentState == QtGui.QMovie.Running:
            self.movie.stop()
            self.movie.setFileName(fileName)
            self.movie.start()

        elif currentState == QtGui.QMovie.NotRunning:
            self.movie.setFileName(fileName)
            self.movie.start()

    def stopPlayingAnimation(self):
        self.movie.stop()
        self.ui.label_moviePreview.setText("<b>[ No Simulation selected ... ]</b>")

    # - Event handlers -
    @QtCore.Slot()
    def applyCacheClicked(self):
        # Check of corredt scene is opened
        currentSceneName = cmds.file(q=True, sceneName=True)
        sceneFromConfigFile = self.projectSettings.mayaFilePath
        isSameScene = ProjectDetailsViewUtils.checkIfCorrectSceneIsOpened(currentSceneName, sceneFromConfigFile)
        if not isSameScene:
            strError = 'Please open the correct maya scene first!\nPath: ' + sceneFromConfigFile
            self.lgr.warning('Please open the correct maya scene first! Path: %s', sceneFromConfigFile)
            self.showMessageBox(strError, 'warning')
            return

        # Same scene ...
        currentIndex = self.ui.comboBox_simulations.currentIndex()
        if currentIndex >= 1:
            self.PathToXMLCache = self.hashMapToXMLProjectFile[currentIndex-1]
            if self.PathToXMLCache == self.currentAnimationLoaded:
                # Do not load the cache which is already loaded! -> pass
                cmds.select(self.projectSettings.fluidContainerName, r=True)
                pass
            else:
                self.lgr.info('Load cache file: %s', self.PathToXMLCache)
                self.currentAnimationLoaded = self.PathToXMLCache

                # Set animation start and edn time
                canSetTime = ProjectDetailsViewUtils.setAnimationStartEndTime(self.projectSettings.animationStartTime, self.projectSettings.animationEndTime)
                if not canSetTime:
                    self.lgr.warning('Cannot set the start / end time of the animation')
                    self.showMessageBox('Cannot set the start / end time of the animation.', 'warning')

                # Load cache file
                try:
                    LoadFluidCacheFile.applyCacheFile(self.PathToXMLCache, self.projectSettings.fluidContainerName)
                except Exception as e:
                    self.lgr.error('%s', e.message)
                    self.showMessageBox(e.message, 'critical')

            # Set the values
            ProjectDetailsViewUtils.applyValuesFromXMLFile(self.PathToXMLCache, self.projectSettings.fluidContainerName)

    @QtCore.Slot()
    def exploreSimulationsClicked(self):
        self.lgr.info('Explore simulations clicked')

        # Check of corredt scene is opened
        currentSceneName = cmds.file(q=True, sceneName=True)
        sceneFromConfigFile = self.projectSettings.mayaFilePath
        isSameScene = ProjectDetailsViewUtils.checkIfCorrectSceneIsOpened(currentSceneName, sceneFromConfigFile)
        if not isSameScene:
            strError = 'Please open the correct maya scene first!\nPath: ' + sceneFromConfigFile
            self.lgr.warning('Please open the correct maya scene first! Path: %s', sceneFromConfigFile)
            self.showMessageBox(strError, 'warning')
            return

        # Check if xml files are available
        if not len(self.hashMapToXMLProjectFile) == int(self.projectSettings.numberOfSimulations) + 1:
            self.lgr.warning('Number of XML cache files is not correct')
            errorMsg = "The number of .xml cache files is not correct!\nPlease check the project folder or create the simulation again."
            self.showMessageBox(errorMsg, 'warning')
            return

        # Check if fluidexplorer app is running
        isFXProcessRunning = ProjectDetailsViewUtils.checkIfProcessIsRunning_WIN(self.FLUIDEXPLORER_APP_NAME)
        if isFXProcessRunning:
            return

        # Check if path exists
        pathToFXAPP = self.externalCall.pathToFluidExplorer + '/' + self.externalCall.fluidExplorerCmd
        if not os.path.exists(os.path.abspath(pathToFXAPP)):
            self.lgr.error('Cannot find the FluidExplorer application executable')
            errorMsg = "Cannot find the FluidExplorer application executable!" + "\n" + "Please check if  the executable file is available."
            self.showMessageBox(errorMsg, 'warning')
            return

        # Run the worker thread
        if self.workThread:
            self.workThread.stop()

            # Start thread again
            self.workThread = WorkThread(self.externalCall)
            self.connect(self.workThread, QtCore.SIGNAL("update(QString)"), self.updateIndexFromThread)
            self.workThread.start()

        else:
            # Start thread
            self.workThread = WorkThread(self.externalCall)
            self.connect(self.workThread, QtCore.SIGNAL("update(QString)"), self.updateIndexFromThread)
            self.workThread.start()


    @QtCore.Slot()
    def checkBoxPreviewValueChanged(self, state):
        # State starts with 0
        if self.ui.checkBox_showPreview.checkState() == QtCore.Qt.Checked:
            # active
            self.setWindowHeightWithPreview()
            self.playAnimation(self.ui.comboBox_simulations.currentIndex())
        elif self.ui.checkBox_showPreview.checkState() == QtCore.Qt.Unchecked:
            # not active
            self.setWindowHeightWithoutPreview()
            self.movie.stop()

    @QtCore.Slot()
    def comboBoxSimulationsIndexChanged(self, index):
        if self.ui.checkBox_showPreview.checkState() == QtCore.Qt.Checked:
            currentIndex = self.ui.comboBox_simulations.currentIndex()
            #hashMapIndex = currentIndex-1

            # Play animation
            self.playAnimation(currentIndex)

    @QtCore.Slot()
    def helpButtonClicked(self):
        self.lgr.info('Help clicked')

    @QtCore.Slot()
    def frameChangedHandler(self, frameNumber):
        pass

    # - Event handlers end -

    # - Help functions -
    def updateIndexFromThread(self, text):
        # print "UPDATE INDEX: " + text
        self.lgr.info('Update index: %s', text)

        # If the thread sends am error -> stop
        if text == "ERROR":
            self.lgr.error('Cannot execute the FluidExplorer application')
            self.showMessageBox('Cannot execute the FluidExplorer application!\nSee editor output for details.', 'critical')
            return

        # Else, update the combo box
        try:
            intIndex = int(text)
        except:
            intIndex = 0
        finally:
            # TODO
            if intIndex > 2:
                self.ui.comboBox_simulations.setCurrentIndex(0)
                self.update()
            else:
                self.ui.comboBox_simulations.setCurrentIndex(1)
                self.update()

    def setLineEditEnabledAndReadOnly(self, component):
        component.setStyleSheet(self.getStyle())
        component.setReadOnly(True)

    def changeHLineStyle(self):
        self.ui.line_1.setGeometry(20, 40, 300, 1)
        self.ui.line_2.setGeometry(20, 240, 300, 1)
        self.ui.line_3.setGeometry(20, 390, 300, 1)
        self.ui.line_1.setLineWidth(1)
        self.ui.line_2.setLineWidth(1)
        self.ui.line_3.setLineWidth(1)
        self.ui.line_1.setStyleSheet("QFrame{background-color: gray;}")
        self.ui.line_2.setStyleSheet("QFrame{background-color: gray;}")
        self.ui.line_3.setStyleSheet("QFrame{background-color: gray;}")

    def getStyle(self):
        styleEnabled = ("QLineEdit:read-only{"
            "font-size: 12px;"
            "/*font-weight: bold;*/"
            "}"
            )

        return styleEnabled

    def readProjectProperties(self, pathToXMLFile):
        xmReader = ProjectDetailsViewUtils()

        projectSettings = None
        try:
            projectSettings = xmReader.getProjectSubSettings(pathToXMLFile)
        except Exception as e:
            errorText = "An error occured while loading the project configuration file!\nDetails: " + str(e.message)
            self.showMessageBox(errorText, 'critical')
            self.lgr.error('Loading the project configuration file: %s', errorText)
            return projectSettings

        return projectSettings

    def showMessageBox(self, errorMsg, type):
        msgBox = QtGui.QMessageBox(self)
        msgBox.setText(errorMsg)
        if type == 'critical':
            msgBox.setWindowTitle("Error")
            msgBox.setIcon(QtGui.QMessageBox.Critical)
        if type == 'warning':
            msgBox.setWindowTitle("Warning")
            msgBox.setIcon(QtGui.QMessageBox.Warning)

        msgBox.setStyleSheet(DefaultUIParameters.buttonStyleBold)
        msgBox.exec_()

    def closeEvent(self, event):

        # ProjectDetailsViewUtils.killProcess_WIN('fluidexplorer')

        # Stop thread if running
        if self.workThread:
            self.workThread.stop()
            # self.workThread.terminate()
        FluidExplorerUtils.killProcess('fluidexplorer')
    # - Help functions end -

    # ScriptJob
    def FXScriptJob(self):
            #self.close()
            #import maya.cmds as cmds
            sJob = cmds.scriptJob(event=['deleteAll', self.ScriptJobMethodCall])
            sJob = cmds.scriptJob(event=['quitApplication', self.ScriptJobMethodCall])


    def ScriptJobMethodCall(self):
        if self.workThread:
            self.workThread.stop()
        ProjectDetailsViewUtils.checkIfProcessExistsAndClose(self.FLUIDEXPLORER_APP_NAME)
        self.PathToXMLCache = ''