private void OnRemoveDCCToolButtonClicked(EventBase evt)
        {
            DCCToolInfo dccToolInfo = GetEventButtonUserDataAs <DCCToolInfo>(evt.target);

            if (null == dccToolInfo || string.IsNullOrEmpty(dccToolInfo.AppPath))
            {
                Debug.LogWarning("[MeshSync] Failed to remove DCC Tool");
                return;
            }

            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            if (settings.RemoveDCCTool(dccToolInfo.AppPath))
            {
                //Delete install info too
                string installInfoPath = DCCPluginInstallInfo.GetInstallInfoPath(dccToolInfo);
                if (File.Exists(installInfoPath))
                {
                    DCCPluginInstallInfo installInfo = FileUtility.DeserializeFromJson <DCCPluginInstallInfo>(installInfoPath);
                    installInfo.RemovePluginVersion(dccToolInfo.AppPath);
                    FileUtility.SerializeToJson(installInfo, installInfoPath);
                }

                if (!m_dccContainers.TryGetValue(dccToolInfo.AppPath, out VisualElement container))
                {
                    SetupInternal(m_root);
                    return;
                }

                container.parent.Remove(container); //Remove the VisualElement container from the UI
            }
        }
        void OnRemoveDCCToolButtonClicked(EventBase evt)
        {
            Button button = evt.target as Button;

            if (null == button)
            {
                Debug.LogWarning("[MeshSync] Failed to Remove DCC Tool");
                return;
            }

            DCCToolInfo info = button.userData as DCCToolInfo;

            if (null == info || string.IsNullOrEmpty(info.AppPath))
            {
                Debug.LogWarning("[MeshSync] Failed to Remove DCC Tool");
                return;
            }

            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            if (settings.RemoveDCCTool(info.AppPath))
            {
                //Delete install info too
                string installInfoPath = DCCPluginInstallInfo.GetInstallInfoPath(info);
                if (File.Exists(installInfoPath))
                {
                    File.Delete(installInfoPath);
                }

                Setup(m_root);
            }
        }
//----------------------------------------------------------------------------------------------------------------------

        #region Button callbacks
        void OnAddDCCToolButtonClicked()
        {
            string folder = EditorUtility.OpenFolderPanel("Add DCC Tool", m_lastOpenedFolder, "");

            if (string.IsNullOrEmpty(folder))
            {
                return;
            }

            m_lastOpenedFolder = folder;

            //Find the path to the actual app
            DCCToolType lastDCCToolType = DCCToolType.AUTODESK_MAYA;
            DCCToolInfo dccToolInfo     = null;

            for (int i = 0; i < (int)(DCCToolType.NUM_DCC_TOOL_TYPES) && null == dccToolInfo; ++i)
            {
                lastDCCToolType = (DCCToolType)(i);
                dccToolInfo     = DCCFinderUtility.FindDCCToolInDirectory(lastDCCToolType, null, m_lastOpenedFolder);
            }

            if (null == dccToolInfo)
            {
                EditorUtility.DisplayDialog("MeshSync Project Settings", "No DCC Tool is detected", "Ok");
                return;
            }

            //Add
            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            if (settings.AddDCCTool(dccToolInfo))
            {
                Setup(m_root);
            }
        }
        private void OnAutoDetectDCCButtonClicked()
        {
            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            if (settings.AddInstalledDCCTools())
            {
                SetupInternal(m_root);
            }
        }
//----------------------------------------------------------------------------------------------------------------------

    #region File Load/Save for Serialization/deserialization
    static MeshSyncEditorSettings LoadEditorSettings() {
        string path = MESHSYNC_EDITOR_SETTINGS_PATH;
        if (!File.Exists(path)) {
            return null;
        }
        
        string json = File.ReadAllText(path);
        MeshSyncEditorSettings settings = JsonUtility.FromJson<MeshSyncEditorSettings>(json);
        
        return settings;
    }
    internal static MeshSyncEditorSettings GetOrCreateSettings() {
        MeshSyncEditorSettings settings = LoadEditorSettings();
        if (null != settings) {
            return settings;
        }

        settings = new MeshSyncEditorSettings();
        settings.AddInstalledDCCTools();
        settings.SaveEditorSettings();
        return settings;
            
    }
        void OnAddDCCToolButtonClicked(EventBase evt)
        {
            string path = null;

            if (Application.platform == RuntimePlatform.OSXEditor)
            {
                path = OpenFilePanel();
            }
            else
            {
                path = OpenFolderPanel();
            }

            if (string.IsNullOrEmpty(path))
            {
                return;
            }

            //Find the path to the actual app
            DCCToolType lastDCCToolType = DCCToolType.AUTODESK_MAYA;
            DCCToolInfo dccToolInfo     = null;

            for (int i = 0; i < (int)(DCCToolType.NUM_DCC_TOOL_TYPES) && null == dccToolInfo; ++i)
            {
                lastDCCToolType = (DCCToolType)(i);
                dccToolInfo     = DCCFinderUtility.FindDCCToolInDirectory(lastDCCToolType, null, path);
            }

            if (null == dccToolInfo)
            {
                EditorUtility.DisplayDialog("MeshSync Project Settings", "No DCC Tool is detected", "Ok");
                return;
            }

            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            if (settings.AddDCCTool(dccToolInfo))
            {
                //Add to ScrollView
                VisualTreeAsset dccToolInfoTemplate = UIElementsEditorUtility.LoadVisualTreeAsset(
                    MeshSyncEditorConstants.DCC_TOOL_INFO_TEMPLATE_PATH
                    );
                ScrollView scrollView = GetEventButtonUserDataAs <ScrollView>(evt.target);
                Assert.IsNotNull(scrollView);
                AddDCCToolSettingsContainer(dccToolInfo, scrollView, dccToolInfoTemplate);
            }
        }
//----------------------------------------------------------------------------------------------------------------------
        private void SetupInternal(VisualElement root)
        {
            m_dccStatusLabels.Clear();
            m_dccContainers.Clear();

            m_root = root;
            m_root.Clear();
            m_installPluginButtons.Clear();

            VisualTreeAsset container = UIElementsEditorUtility.LoadVisualTreeAsset(
                MeshSyncEditorConstants.DCC_TOOLS_SETTINGS_CONTAINER_PATH
                );

            VisualTreeAsset dccToolInfoTemplate = UIElementsEditorUtility.LoadVisualTreeAsset(
                MeshSyncEditorConstants.DCC_TOOL_INFO_TEMPLATE_PATH
                );

            TemplateContainer containerInstance = container.CloneTree();
            ScrollView        scrollView        = containerInstance.Query <ScrollView>().First();


            //Buttons
            Button autoDetectDCCButton = containerInstance.Query <Button>("AutoDetectDCCButton").First();

            autoDetectDCCButton.clickable.clicked        += OnAutoDetectDCCButtonClicked;
            m_checkPluginUpdatesButton                    = containerInstance.Query <Button>("ChecksPluginUpdatesButton").First();
            m_checkPluginUpdatesButton.clickable.clicked += OnCheckPluginUpdatesButtonClicked;
            Button addDCCToolButton = containerInstance.Query <Button>("AddDCCToolButton").First();

            addDCCToolButton.userData = scrollView;
            addDCCToolButton.clickable.clickedWithEventInfo += OnAddDCCToolButtonClicked;

            //Label
            m_footerStatusLabel = containerInstance.Query <Label>("FooterStatusLabel").First();

            //Add detected DCCTools to ScrollView
            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            foreach (KeyValuePair <string, DCCToolInfo> dccToolInfo in settings.GetDCCToolInfos())
            {
                AddDCCToolSettingsContainer(dccToolInfo.Value, scrollView, dccToolInfoTemplate);
            }

            //Add the container of this tab to root
            root.Add(containerInstance);
        }
//----------------------------------------------------------------------------------------------------------------------
        public void Setup(VisualElement root)
        {
            m_dccStatusLabels.Clear();
            m_dccContainers.Clear();

            m_root = root;
            m_root.Clear();

            VisualTreeAsset container = UIElementsEditorUtility.LoadVisualTreeAsset(
                MeshSyncEditorConstants.DCC_TOOLS_SETTINGS_CONTAINER_PATH
                );

            VisualTreeAsset dccToolInfoTemplate = UIElementsEditorUtility.LoadVisualTreeAsset(
                MeshSyncEditorConstants.DCC_TOOL_INFO_TEMPLATE_PATH
                );

            TemplateContainer containerInstance = container.CloneTree();
            ScrollView        scrollView        = containerInstance.Query <ScrollView>().First();

            //[TODO-sin: 2020-4-24] Auto detect installed DCC tools + check MeshSync status
            MeshSyncEditorSettings settings = MeshSyncEditorSettings.GetOrCreateSettings();

            foreach (var dccToolInfo in settings.GetDCCToolInfos())
            {
                AddDCCToolSettingsContainer(dccToolInfo.Value, scrollView, dccToolInfoTemplate);
            }

            //Buttons
            Button autoDetectButton = containerInstance.Query <Button>("AutoDetectButton").First();

            autoDetectButton.clickable.clicked += OnAutoDetectButtonClicked;
            Button addDCCToolButton = containerInstance.Query <Button>("AddDCCToolButton").First();

            addDCCToolButton.clickable.clicked += OnAddDCCToolButtonClicked;


            //Add the container of this tab to root
            root.Add(containerInstance);
        }