Samples/Referencing/MBFileRefDemo/ReferencingSample.py

import os

from pyfbsdk import *
from pyfbsdk_additions import *

from PySide import QtCore, QtGui
from ReferencingSampleUI2 import Ui_ReferencingSample

import NamespaceTableModel

######################################################
# Functions
######################################################
def PickRefName():
    lFileRefName = ''
    lBtnClicked, lFileRefName = FBMessageBoxGetUserValue( 'File Reference', 'Enter your file reference name', '', FBPopupInputType.kFBPopupString, 'OK', 'Cancel', None, 1, True )
    if lBtnClicked == 2: return lBtnClicked, lFileRefName

    lFileRefName = lFileRefName.replace(' ','')
    while lFileRefName is '':
        FBMessageBox('File Reference', 'Error, please enter a file reference name', "OK")
        lBtnClicked, lFileRefName = PickRefName()
        if lBtnClicked == 2: break
    
    return lBtnClicked, lFileRefName

class MainForm( QtGui.QWidget, Ui_ReferencingSample ):
    def __init__( self, parent ):
        QtGui.QWidget.__init__( self, parent )
        
        self.setupUi( self )

        import inspect
        self.mDefaultPath = inspect.currentframe().f_code.co_filename
        self.mSingleSelection = False
        
        self.mSys = FBSystem()
        self.mApp = FBApplication()
        self.mApp.OnFileNew.Add( self.OnFileNew )
        
        self.mNSModel = NamespaceTableModel.NamespaceTableModel( self )
        self.uiTableNamespace.setModel( self.mNSModel )
        
        self.mTimer = QtCore.QTimer( self )
        
        self.mIsInitialized = False
        self.Init()
        
    def Init( self ):
        self.mNSModel.namespaceRenamed.connect( self.OnNamespaceRenamed )

        lSelectionModel = self.uiTableNamespace.selectionModel()
        QtCore.QObject.connect( lSelectionModel, QtCore.SIGNAL( 'selectionChanged(const QItemSelection&, const QItemSelection&)' ), self.OnTableNamespaceSelectionChanged )
        
        QtCore.QObject.connect( self.mTimer, QtCore.SIGNAL( 'timeout()' ), self.OnTimer )
        self.mTimer.start( 2000 )
        self.UpdateUI()

        self.mIsInitialized = True
    
    def Fini( self ):
        # disconnecting the update timer
        self.mTimer.stop()
        QtCore.QObject.disconnect( self.mTimer, QtCore.SIGNAL( 'timeout()' ), self.OnTimer )
        
        # disconnecting the selectionChanged signal
        lSelectionModel = self.uiTableNamespace.selectionModel()
        QtCore.QObject.disconnect( lSelectionModel, QtCore.SIGNAL( 'selectionChanged(const QItemSelection&, const QItemSelection&)' ), self.OnTableNamespaceSelectionChanged )
        
        self.mNSModel.namespaceRenamed.disconnect( self.OnNamespaceRenamed )
        
        self.mIsInitialized = False

    def OnShow( self ):
        if not self.mIsInitialized:
            self.Init()
            self.mNSModel.Connect()
        
    def OnHide( self ):
        if self.mIsInitialized:
            self.Fini()
            self.mNSModel.Disconnect()
    
    def OnFileNew( self, pControl, pEvent ):
        self.mNSModel.Fini()
        self.mNSModel.Init()

    def OnNamespaceRenamed( self, pOldName, pNewName ):
        self.UpdateTreeNamespace()

    def OnBtnBrowsePathClicked( self ):
        lFileToLoad = QtGui.QFileDialog.getOpenFileName(self, "Pick FBX to reference", self.mDefaultPath, "*.fbx" )[0]      # Returns a Tuple. Get the filename only
        lQFileInfo = QtCore.QFileInfo( lFileToLoad )
        if lQFileInfo.exists() and lQFileInfo.suffix() == 'fbx':
            self.uiEditFilePath.setText( lFileToLoad )
            self.mDefaultPath = lQFileInfo.filePath()
        self.UpdateUI()

    def OnBtnLoadClicked( self ):
        print 'Load as a file reference'
        
        lLoadCount = self.uiSpinLoadTimes.value()
        lBtnClicked, lName = PickRefName()
        if lBtnClicked == 2: return

        lNameList = FBStringList()
        if lLoadCount == 1:
            lNameList.Add( lName )
        else:
            for lCount in range( 0, lLoadCount ):
                if self.mSys.Scene.NamespaceGet( lName + str(lCount+1) ) <> None:
                    lMsgBox = QtGui.QMessageBox( QtGui.QMessageBox.Information, 'Loading', 'Creation of file reference %s will be skipped as it is already there.' % ( lName + str(lCount+1) ), QtGui.QMessageBox.Ok, self )
                    lMsgBox.exec_()
                else:
                    lNameList.Add( lName + str(lCount+1) )
        
        self.mSys.Scene.NamespaceImportToMultiple( lNameList, str(self.uiEditFilePath.text()), True )
        self.mNSModel.Refresh()
        self.UpdateUI()

    def OnBtnUnloadClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                self.mNSModel.RemoveFileFromWatcher( lNSObj )
                lNSObj.IsLoaded = False

            self.mNSModel.Refresh( lIndex )
        self.UpdateUI()
        self.UpdateTreeNamespace()

    def OnBtnReloadClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                lNSObj.IsLoaded = True
            self.mNSModel.Refresh( lIndex )
        self.UpdateUI()
        self.UpdateTreeNamespace()

    def OnBtnDeleteClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        lNameList = []
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                lNameList.append( lNSObj.LongName )
                self.mNSModel.RemoveFileFromWatcher( lNSObj )

        for lName in lNameList:
            self.mSys.Scene.NamespaceDelete( lName )
        
        self.mNSModel.Refresh()
        self.UpdateUI()
        self.UpdateTreeNamespace()
        
    def OnBtnInstanceClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]

        lInstanceCount = self.uiSpinInstanceTimes.value()
        lBtnClicked, lName = PickRefName()
        if lBtnClicked == 2: return

        lNameList = FBStringList()
        if lInstanceCount == 1:
            lNameList.Add( lName )
        else:
            for lCount in range( 0, lInstanceCount ):
                lNameList.Add( lName + str(lCount+1) )

        lApplyRefEdits = False
        if lNSObj.GetContentModified( FBPlugModificationFlag.kFBContentAllModifiedMask ):
            lMsgBox = QtGui.QMessageBox( QtGui.QMessageBox.Question, 'Instancing', 'Do you want to apply reference edits after instancing?', QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, self )
            if lMsgBox.exec_() == QtGui.QMessageBox.Yes:
                lApplyRefEdits = True

        lNSObj.DuplicateFileRef( lNameList, lApplyRefEdits )

        self.mNSModel.Refresh()
        self.UpdateUI()
        self.UpdateTreeNamespace()
        
    def OnBtnRestoreClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                lNSObj.RevertRefEdit()
                self.mNSModel.Refresh( lIndex )
        self.UpdateUI()

    def OnBtnShowEditsClicked( self ):
        lIndexes = self.uiTableNamespace.selectedIndexes()
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                if lNSObj.GetContentModified( FBPlugModificationFlag.kFBContentAllModifiedMask ):
                    lMsgBox = QtGui.QMessageBox( self )
                    lMsgBox.setText( lNSObj.GetRefEdit() )
                    lMsgBox.exec_()

    def OnTableNamespaceSelectionChanged( self, pSelected, pUnselected ):
        self.UpdateUI()
        self.UpdateTreeNamespace()
    
    def UpdateTreeNamespace( self ):
        self.uiTreeNamespace.clear()

        if self.mSingleSelection:
            lIndexes = self.uiTableNamespace.selectedIndexes()
            lNSObj = self.mSys.Scene.Namespaces[lIndexes[0].row()]
            
            lStrList = [lNSObj.LongName]
            if lNSObj.ClassGroupName <> '':
                lStrList.append( lNSObj.ClassGroupName )

            lItem = QtGui.QTreeWidgetItem( lStrList )
            self.uiTreeNamespace.addTopLevelItem( lItem )
            self.UpdateTreeNamespaceRecursively( lItem, lNSObj )
            self.uiTreeNamespace.expandItem( lItem )

    def UpdateTreeNamespaceRecursively( self, pParentItem, pNSObj ):
        lList = FBComponentList()
        pNSObj.GetContentList( lList, FBPlugModificationFlag.kFBPlugAllContent, False )
        for lPlug in lList:
            lStrList = [lPlug.LongName]
            if lPlug.ClassGroupName <> '':
                lStrList.append( lPlug.ClassGroupName )

            lItem = QtGui.QTreeWidgetItem( lStrList )
            pParentItem.addChild( lItem )
            self.uiTreeNamespace.expandItem( lItem )
            if lPlug.TypeInfo == FBNamespace.TypeInfo:
                self.UpdateTreeNamespaceRecursively( lItem, lPlug )


    #def OnSceneChanged( self, pComp, pEvent ):
    #    self.UpdateRefEditStatus()

    #def UpdateRefEditStatus( self ):
    #    lRowSize = self.mNSModel.rowCount()
    #    for lRow in range( 0, lRowSize ):
    #        lIndex = self.mNSModel.index( lRow, 0 )
    #        self.mNSModel.dataChanged.emit( lIndex, lIndex )

    def UpdateUI( self ):
        luiBtnBrowsePath = True
        luiBtnLoad = False
        luiSpinLoadTimes = False
        luiBtnUnload = False
        luiBtnReload = False
        luiBtnDelete = False
        luiBtnInstance = False
        luiBtnRestore = False
        luiBtnShowEdits = False
        luiSpinInstanceTimes = False

        if os.path.exists( self.uiEditFilePath.text() ):
            luiBtnLoad = True
            luiSpinLoadTimes = True

        #
        # Update file reference related UI
        #
        lIndexes = self.uiTableNamespace.selectedIndexes()
        
        lRows = []
        lHasSelection = False
        if len( lIndexes ) > 0:
            lHasSelection = True

        lAllSelectionFileReference = True
        lAllSelectionLoaded = True
        lAllSelectionUnLoaded = True
        lSelectionHasRefEdits = False
        for lIndex in lIndexes:
            if lIndex.column() == 0:
                lRows.append( lIndex.row() )
                lNSObj = self.mSys.Scene.Namespaces[lIndex.row()]
                if lNSObj.TypeInfo == FBNamespace.TypeInfo:
                    lAllSelectionFileReference = False
                else:
                    if lNSObj.IsLoaded:
                        if lNSObj.GetContentModified( FBPlugModificationFlag.kFBContentAllModifiedMask ):
                            lSelectionHasRefEdits = True
                        lAllSelectionUnLoaded = False
                    else:
                        lAllSelectionLoaded = False

        self.mSingleSelection = False
        if len( lRows ) == 1:
            self.mSingleSelection = True

        if lHasSelection:
            luiBtnDelete = True

            if lAllSelectionFileReference:
                if lSelectionHasRefEdits:
                    luiBtnRestore = True

                if self.mSingleSelection:
                    if lSelectionHasRefEdits:
                        luiBtnShowEdits = True
                    luiBtnInstance = True
                    luiSpinInstanceTimes = True

                luiBtnUnload = True
                luiBtnReload = True
                if lAllSelectionLoaded:
                    luiBtnReload = False
                if lAllSelectionUnLoaded:
                    luiBtnUnload = False

        self.uiBtnBrowsePath.setEnabled( luiBtnBrowsePath )
        self.uiBtnLoad.setEnabled( luiBtnLoad )
        self.uiSpinLoadTimes.setEnabled( luiSpinLoadTimes )
        self.uiBtnUnload.setEnabled( luiBtnUnload )
        self.uiBtnReload.setEnabled( luiBtnReload )
        self.uiBtnDelete.setEnabled( luiBtnDelete )
        self.uiBtnInstance.setEnabled( luiBtnInstance )
        self.uiBtnRestore.setEnabled( luiBtnRestore )
        self.uiBtnShowEdits.setEnabled( luiBtnShowEdits )
        self.uiSpinInstanceTimes.setEnabled( luiSpinInstanceTimes )

    def OnTimer( self ):
        for lFilePath, lReload in self.mNSModel.mRefFileReload.items():
            if lReload:
                FBMessageBox( "External File Changed", "The referenced file '%s' has been changed externally!" % ( lFilePath ), "OK" )
                if lFilePath in self.mNSModel.mRefFilePath:
                    for lFileRefName in self.mNSModel.mRefFilePath[lFilePath]:
                        lFileRefObj = FBFindObjectByFullName( 'FileReference::' + lFileRefName )
                        lOption = FBMessageBox( "External File Changed", "Please choose the following action for Reference: %s!" % ( lFileRefName ), "Load", "Merge", "Ignore" )
                        if lOption <> 3:
                            lUndo = FBUndoManager()
                            lUndo.Clear()
                            lFileRefObj.IsLoaded = False
                            lFileRefObj.IsLoaded = True

                            if lOption == 2:
                                if lFileRefObj.GetContentModified( FBPlugModificationFlag.kFBContentAllModifiedMask ):
                                    lFileRefObj.ApplyRefEditPyScriptFromString( lFileRefObj.GetRefEdit() )

                self.mNSModel.mRefFileReload[lFilePath] = False

        self.mNSModel.UpdateFileWatcher()