Browse Source

Initial work on updating the internal ACE editor settings from the application preferences file in userprefs.json

Shaddock Heath 9 years ago
parent
commit
abf8a2955e

+ 2 - 2
Data/AtomicEditor/CodeEditor/Editor.html

@@ -67,9 +67,9 @@
         });
         });
     }
     }
 
 
-    function HOST_loadPreferences(prefUrl) {
+    function HOST_preferencesChanged() {
         System.import('./source/editorCore/interop').then((module) => {
         System.import('./source/editorCore/interop').then((module) => {
-            module.default.getInstance().loadPreferences(prefUrl);
+            module.default.getInstance().preferencesChanged();
         });
         });
     }
     }
 
 

+ 4 - 0
Script/AtomicEditor/editor/Editor.ts

@@ -161,6 +161,7 @@ class Editor extends Atomic.ScriptObject {
      */
      */
     setUserPreference(extensionName: string, preferenceName: string, value: number | boolean | string) {
     setUserPreference(extensionName: string, preferenceName: string, value: number | boolean | string) {
         Preferences.getInstance().setUserPreference(extensionName, preferenceName, value);
         Preferences.getInstance().setUserPreference(extensionName, preferenceName, value);
+        WebView.WebBrowserHost.setGlobalStringProperty("HOST_Preferences", "ProjectPreferences", JSON.stringify(Preferences.getInstance().cachedProjectPreferences, null, 2 ));
         this.sendEvent(EditorEvents.UserPreferencesChangedNotification);
         this.sendEvent(EditorEvents.UserPreferencesChangedNotification);
     }
     }
 
 
@@ -173,6 +174,7 @@ class Editor extends Atomic.ScriptObject {
      */
      */
     setUserPreferenceGroup(settingsGroup: string, groupPreferenceValues: Object) {
     setUserPreferenceGroup(settingsGroup: string, groupPreferenceValues: Object) {
         Preferences.getInstance().setUserPreferenceGroup(settingsGroup, groupPreferenceValues);
         Preferences.getInstance().setUserPreferenceGroup(settingsGroup, groupPreferenceValues);
+        WebView.WebBrowserHost.setGlobalStringProperty("HOST_Preferences", "ProjectPreferences", JSON.stringify(Preferences.getInstance().cachedProjectPreferences, null, 2 ));
         this.sendEvent(EditorEvents.UserPreferencesChangedNotification);
         this.sendEvent(EditorEvents.UserPreferencesChangedNotification);
     }
     }
 
 
@@ -189,6 +191,8 @@ class Editor extends Atomic.ScriptObject {
         }
         }
         const loaded = system.loadProject(event.path);
         const loaded = system.loadProject(event.path);
         if (loaded) {
         if (loaded) {
+            WebView.WebBrowserHost.setGlobalStringProperty("HOST_Preferences", "ProjectPreferences", JSON.stringify(Preferences.getInstance().cachedProjectPreferences, null, 2 ));
+            WebView.WebBrowserHost.setGlobalStringProperty("HOST_Preferences", "ApplicationPreferences", JSON.stringify(Preferences.getInstance().cachedApplicationPreferences, null, 2 ));
             this.sendEvent(EditorEvents.LoadProjectNotification, event);
             this.sendEvent(EditorEvents.LoadProjectNotification, event);
         }
         }
         return loaded;
         return loaded;

+ 70 - 12
Script/AtomicEditor/editor/Preferences.ts

@@ -31,7 +31,7 @@ class Preferences {
     private static instance: Preferences;
     private static instance: Preferences;
     private _prefs: PreferencesFormat;
     private _prefs: PreferencesFormat;
 
 
-    private cachedProjectPreferences: Object = null;
+    private _cachedProjectPreferences: Object = null;
 
 
     constructor() {
     constructor() {
         this.fileSystem = Atomic.getFileSystem();
         this.fileSystem = Atomic.getFileSystem();
@@ -97,14 +97,15 @@ class Preferences {
             prefs = null;
             prefs = null;
         }
         }
 
 
-        if (prefs && (!prefs.editorWindow || !prefs.playerWindow || !prefs.recentProjects)) {
-            prefs = null;
-        }
-
         if (prefs) {
         if (prefs) {
+            const defaultPrefs = new PreferencesFormat();
+            const shouldWrite = defaultPrefs.applyMissingDefaults(prefs);
             this._prefs = prefs;
             this._prefs = prefs;
+            if (shouldWrite) {
+                this.write();
+            }
         } else {
         } else {
-            console.log("Editor preference file invalid, regenerating default configuration");
+            console.log("Editor preference file missing or invalid, regenerating default configuration");
             this.useDefaultConfig();
             this.useDefaultConfig();
             this.write();
             this.write();
         }
         }
@@ -132,6 +133,14 @@ class Preferences {
         this._prefs = new PreferencesFormat();
         this._prefs = new PreferencesFormat();
     }
     }
 
 
+    get cachedProjectPreferences():any {
+        return this._cachedProjectPreferences;
+    }
+
+    get cachedApplicationPreferences():PreferencesFormat {
+        return this._prefs;
+    }
+
     get editorWindow(): WindowData {
     get editorWindow(): WindowData {
         return this._prefs.editorWindow;
         return this._prefs.editorWindow;
     }
     }
@@ -161,21 +170,21 @@ class Preferences {
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: any): any {
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: any): any {
 
 
         // Cache the settings so we don't keep going out to the file
         // Cache the settings so we don't keep going out to the file
-        if (this.cachedProjectPreferences == null) {
+        if (this._cachedProjectPreferences == null) {
             const prefsFileLoc = ToolCore.toolSystem.project.userPrefsFullPath;
             const prefsFileLoc = ToolCore.toolSystem.project.userPrefsFullPath;
             if (Atomic.fileSystem.fileExists(prefsFileLoc)) {
             if (Atomic.fileSystem.fileExists(prefsFileLoc)) {
                 let prefsFile = new Atomic.File(prefsFileLoc, Atomic.FILE_READ);
                 let prefsFile = new Atomic.File(prefsFileLoc, Atomic.FILE_READ);
                 try {
                 try {
                     let prefs = JSON.parse(prefsFile.readText());
                     let prefs = JSON.parse(prefsFile.readText());
-                    this.cachedProjectPreferences = prefs;
+                    this._cachedProjectPreferences = prefs;
                 } finally {
                 } finally {
                     prefsFile.close();
                     prefsFile.close();
                 }
                 }
             }
             }
         }
         }
 
 
-        if (this.cachedProjectPreferences && this.cachedProjectPreferences[settingsGroup]) {
-            return this.cachedProjectPreferences[settingsGroup][preferenceName] || defaultValue;
+        if (this._cachedProjectPreferences && this._cachedProjectPreferences[settingsGroup]) {
+            return this._cachedProjectPreferences[settingsGroup][preferenceName] || defaultValue;
         }
         }
 
 
         // if all else fails
         // if all else fails
@@ -214,7 +223,7 @@ class Preferences {
         }
         }
 
 
         // Cache the update
         // Cache the update
-        this.cachedProjectPreferences = prefs;
+        this._cachedProjectPreferences = prefs;
     }
     }
 
 
 
 
@@ -253,7 +262,7 @@ class Preferences {
         }
         }
 
 
         // Cache the update
         // Cache the update
-        this.cachedProjectPreferences = prefs;
+        this._cachedProjectPreferences = prefs;
     }
     }
 }
 }
 
 
@@ -266,6 +275,15 @@ interface WindowData {
     maximized: boolean;
     maximized: boolean;
 }
 }
 
 
+interface AceEditorSettings {
+    theme: string;
+    keyboardHandler: string;
+    fontSize: number;
+    showInvisibles: boolean;
+    useSoftTabs: boolean;
+    tabSize: number;
+}
+
 class PreferencesFormat {
 class PreferencesFormat {
 
 
     constructor() {
     constructor() {
@@ -295,11 +313,51 @@ class PreferencesFormat {
             maximized: false
             maximized: false
         };
         };
 
 
+        this.codeEditorSettings = {
+            theme: "ace/theme/monokai",
+            keyboardHandler: "ace/keyboard/textinput",
+            fontSize: 12,
+            showInvisibles: false,
+            useSoftTabs: true,
+            tabSize: 4
+        };
+    }
+
+    /**
+     * Run through a provided prefs block and verify that all the sections are present.  If any
+     * are missing, add the defaults in
+     * @param  {PreferencesFormat} prefs
+     * @return boolean returns true if any missing defaults were updated
+     */
+    applyMissingDefaults(prefs: PreferencesFormat) {
+        let updatedMissingDefaults = false;
+        if (!prefs.recentProjects) {
+            prefs.recentProjects = this.recentProjects;
+            updatedMissingDefaults = true;
+        }
+
+        if (!prefs.editorWindow) {
+            prefs.editorWindow = this.editorWindow;
+            updatedMissingDefaults = true;
+        }
+
+        if (!prefs.playerWindow) {
+            prefs.playerWindow = this.playerWindow;
+            updatedMissingDefaults = true;
+        }
+
+        if (!prefs.codeEditorSettings) {
+            prefs.codeEditorSettings = this.codeEditorSettings;
+            updatedMissingDefaults = true;
+        }
+
+        return updatedMissingDefaults;
     }
     }
 
 
     recentProjects: string[];
     recentProjects: string[];
     editorWindow: WindowData;
     editorWindow: WindowData;
     playerWindow: WindowData;
     playerWindow: WindowData;
+    codeEditorSettings: AceEditorSettings;
 }
 }
 
 
 export = Preferences;
 export = Preferences;

+ 2 - 13
Script/AtomicEditor/ui/resourceEditors/AbstractTextResourceEditorBuilder.ts

@@ -74,24 +74,13 @@ export abstract class AbstractTextResourceEditorBuilder implements Editor.Extens
         });
         });
 
 
         editor.subscribeToEvent(EditorEvents.UserPreferencesChangedNotification, (data) => {
         editor.subscribeToEvent(EditorEvents.UserPreferencesChangedNotification, (data) => {
-            this.getUserPrefs(editor);
+            const webClient = editor.webView.webClient;
+            webClient.executeJavaScript("HOST_preferencesChanged();");
         });
         });
 
 
         return editor;
         return editor;
     }
     }
 
 
-    /**
-     * Send the url of the user prefs to the web view so that it can request it
-     */
-    getUserPrefs(editor: Editor.JSResourceEditor) {
-        let prefsPath = ToolCore.toolSystem.project.userPrefsFullPath;
-        if (Atomic.fileSystem.fileExists(prefsPath)) {
-            // Get a reference to the web client so we can call the load preferences method
-            const webClient = editor.webView.webClient;
-            webClient.executeJavaScript(`HOST_loadPreferences("atomic://${prefsPath}");`);
-        }
-    }
-
     /**
     /**
      * Send the url of the code to the web view so that it can request it
      * Send the url of the code to the web view so that it can request it
      */
      */

+ 30 - 6
Script/AtomicWebViewEditor/clientExtensions/ClientExtensionServices.ts

@@ -76,15 +76,18 @@ class ServicesProvider<T extends Editor.Extensions.ServiceEventListener> impleme
 
 
 export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExtensions.WebViewServiceEventListener> {
 export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExtensions.WebViewServiceEventListener> {
 
 
-    private userPreferences = {};
+    private projectPreferences = {};
+    private applicationPreferences = {};
 
 
     /**
     /**
      * Sets the preferences for the service locator
      * Sets the preferences for the service locator
-     * @param  {any} prefs
+     * @param  {any} projectPreferences
+     * @param  {any} applicationPreferences
      * @return {[type]}
      * @return {[type]}
      */
      */
-    setPreferences(prefs : any) {
-        this.userPreferences = prefs;
+    setPreferences(projectPreferences?: any, applicationPreferences?: any) {
+        this.projectPreferences = projectPreferences || this.projectPreferences;
+        this.applicationPreferences = applicationPreferences || this.applicationPreferences;
     }
     }
 
 
     /**
     /**
@@ -222,8 +225,8 @@ export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExten
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: any): any {
     getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: any): any {
-        if (this.userPreferences) {
-            let prefs = this.userPreferences[settingsGroup];
+        if (this.projectPreferences) {
+            let prefs = this.projectPreferences[settingsGroup];
             if (prefs) {
             if (prefs) {
                 return prefs[preferenceName] || defaultValue;
                 return prefs[preferenceName] || defaultValue;
             }
             }
@@ -233,5 +236,26 @@ export class WebViewServicesProvider extends ServicesProvider<Editor.ClientExten
         return defaultValue;
         return defaultValue;
     }
     }
 
 
+    /**
+     * Return a preference value or the provided default from the user settings file
+     * @param  {string} settignsGroup name of the group the preference lives under
+     * @param  {string} preferenceName name of the preference to retrieve
+     * @param  {number | boolean | string} defaultValue value to return if pref doesn't exist
+     * @return {number|boolean|string}
+     */
+    getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: number): number;
+    getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
+    getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
+    getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: any): any {
+        if (this.applicationPreferences) {
+            let prefs = this.applicationPreferences[settingsGroup];
+            if (prefs) {
+                return prefs[preferenceName] || defaultValue;
+            }
+        }
+
+        // if all else fails
+        return defaultValue;
+    }
 
 
 }
 }

+ 22 - 9
Script/AtomicWebViewEditor/editor/editorCommands.ts

@@ -32,12 +32,17 @@ import ClientExtensionEventNames from "../clientExtensions/ClientExtensionEventN
  */
  */
 export function configure(fileExt: string, filename: string) {
 export function configure(fileExt: string, filename: string) {
 
 
-    // set a default theme
-    editor.setTheme("ace/theme/monokai");
-
     // set a default mode
     // set a default mode
     editor.session.setMode("ace/mode/javascript");
     editor.session.setMode("ace/mode/javascript");
 
 
+    // Grab the configured editor defaults and apply them
+    editor.setTheme(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "theme", "ace/theme/monokai"));
+    editor.setKeyboardHandler(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "keyboardHandler", "ace/keyboard/textinput"));
+    editor.setFontSize(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "fontSize", 12).toString() + "px");
+    editor.setShowInvisibles(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "showInvisibles", false));
+    editor.session.setUseSoftTabs(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "useSoftTabs", true));
+    editor.session.setTabSize(serviceLocator.clientServices.getApplicationPreference("codeEditorSettings", "tabSize", 4));
+
     // give the language extensions the opportunity to configure the editor based upon the file type
     // give the language extensions the opportunity to configure the editor based upon the file type
     serviceLocator.sendEvent(ClientExtensionEventNames.ConfigureEditorEvent, {
     serviceLocator.sendEvent(ClientExtensionEventNames.ConfigureEditorEvent, {
         fileExt: fileExt,
         fileExt: fileExt,
@@ -50,7 +55,7 @@ export function configure(fileExt: string, filename: string) {
  * Returns the text in the editor instance
  * Returns the text in the editor instance
  * @return {string}
  * @return {string}
  */
  */
-export function getSourceText() : string {
+export function getSourceText(): string {
     return editor.session.getValue();
     return editor.session.getValue();
 }
 }
 
 
@@ -83,7 +88,7 @@ export function loadCodeIntoEditor(code: string, filename: string, fileExt: stri
  * @param  {string} newPath
  * @param  {string} newPath
  */
  */
 export function resourceRenamed(path: string, newPath: string) {
 export function resourceRenamed(path: string, newPath: string) {
-    let data:Editor.EditorEvents.RenameResourceEvent = {
+    let data: Editor.EditorEvents.RenameResourceEvent = {
         path: path,
         path: path,
         newPath: newPath
         newPath: newPath
     };
     };
@@ -95,7 +100,7 @@ export function resourceRenamed(path: string, newPath: string) {
  * @param  {string} path
  * @param  {string} path
  */
  */
 export function resourceDeleted(path: string) {
 export function resourceDeleted(path: string) {
-    let data:Editor.EditorEvents.DeleteResourceEvent = {
+    let data: Editor.EditorEvents.DeleteResourceEvent = {
         path: path
         path: path
     };
     };
     serviceLocator.sendEvent(ClientExtensionEventNames.ResourceDeletedEvent, data);
     serviceLocator.sendEvent(ClientExtensionEventNames.ResourceDeletedEvent, data);
@@ -108,7 +113,7 @@ export function resourceDeleted(path: string) {
  * @param {string} contents
  * @param {string} contents
  */
  */
 export function codeSaved(path: string, fileExt: string, contents: string) {
 export function codeSaved(path: string, fileExt: string, contents: string) {
-    let data:Editor.EditorEvents.CodeSavedEvent = {
+    let data: Editor.EditorEvents.CodeSavedEvent = {
         filename: path,
         filename: path,
         fileExt: fileExt,
         fileExt: fileExt,
         editor: editor,
         editor: editor,
@@ -117,11 +122,19 @@ export function codeSaved(path: string, fileExt: string, contents: string) {
     serviceLocator.sendEvent(ClientExtensionEventNames.CodeSavedEvent, data);
     serviceLocator.sendEvent(ClientExtensionEventNames.CodeSavedEvent, data);
 }
 }
 
 
+/**
+ * Called when the editor has finished it's initial load
+ */
+export function editorLoaded() {
+    // let's grab the prefs and seed the service locator
+    serviceLocator.clientServices.setPreferences(JSON.parse(window.HOST_Preferences.ProjectPreferences), JSON.parse(window.HOST_Preferences.ApplicationPreferences));
+}
+
 /**
 /**
  * Called when new preferences are available (or initially with current prefs)
  * Called when new preferences are available (or initially with current prefs)
  * @param  {any} prefs
  * @param  {any} prefs
  */
  */
-export function loadPreferences(prefs: any) {
-    serviceLocator.clientServices.setPreferences(prefs);
+export function preferencesChanged() {
+    serviceLocator.clientServices.setPreferences(JSON.parse(window.HOST_Preferences.ProjectPreferences), JSON.parse(window.HOST_Preferences.ApplicationPreferences));
     serviceLocator.sendEvent(ClientExtensionEventNames.PreferencesChangedEvent, null);
     serviceLocator.sendEvent(ClientExtensionEventNames.PreferencesChangedEvent, null);
 }
 }

+ 3 - 8
Script/AtomicWebViewEditor/interop.ts

@@ -144,6 +144,7 @@ export default class HostInteropType {
         if (DEBUG_ALERT) {
         if (DEBUG_ALERT) {
             alert(`Attach chrome dev tools to this instance by navigating to http://localhost:${DEBUG_PORT}`);
             alert(`Attach chrome dev tools to this instance by navigating to http://localhost:${DEBUG_PORT}`);
         }
         }
+        editorCommands.editorLoaded();
         window.atomicQueryPromise(HostInteropType.EDITOR_LOAD_COMPLETE);
         window.atomicQueryPromise(HostInteropType.EDITOR_LOAD_COMPLETE);
     }
     }
 
 
@@ -206,14 +207,8 @@ export default class HostInteropType {
      * of the prefs.
      * of the prefs.
      * @param  {string} prefUrl
      * @param  {string} prefUrl
      */
      */
-    loadPreferences(prefUrl: string) {
-        // load prefs
-        this.getResource(prefUrl).then((prefsJson: string) => {
-            let prefs = JSON.parse(prefsJson);
-            editorCommands.loadPreferences(prefs);
-        }).catch((e: Editor.ClientExtensions.AtomicErrorMessage) => {
-            console.log("Error loading preferences: " + e.error_message);
-        });
+    preferencesChanged() {
+        editorCommands.preferencesChanged();
     }
     }
 
 
     /**
     /**

+ 9 - 1
Script/AtomicWebViewEditor/typings/WindowExt.d.ts

@@ -44,5 +44,13 @@ interface Window {
 
 
     HOST_resourceRenamed: (path: string, newPath: string) => void;
     HOST_resourceRenamed: (path: string, newPath: string) => void;
     HOST_resourceDeleted: (path: string) => void;
     HOST_resourceDeleted: (path: string) => void;
-    HOST_loadPreferences: (path: string) => void;
+    HOST_preferencesChanged: () => void;
+
+    /**
+     * Preferences set by the host.  Each preference category is a JSON string of all the prefs
+     */
+    HOST_Preferences: {
+        ApplicationPreferences: string,
+        ProjectPreferences: string
+    };
 }
 }

+ 11 - 0
Script/TypeScript/EditorWork.d.ts

@@ -439,6 +439,17 @@ declare module Editor.ClientExtensions {
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: number): number;
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: number): number;
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
         getUserPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
+
+        /**
+         * Return a preference value or the provided default from the application settings file
+         * @param  {string} extensionName name of the extension the preference lives under
+         * @param  {string} preferenceName name of the preference to retrieve
+         * @param  {number | boolean | string} defaultValue value to return if pref doesn't exist
+         * @return {number|boolean|string}
+         */
+        getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: number): number;
+        getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: string): string;
+        getApplicationPreference(settingsGroup: string, preferenceName: string, defaultValue?: boolean): boolean;
     }
     }
 
 
     export interface AtomicErrorMessage {
     export interface AtomicErrorMessage {

+ 0 - 11
Source/AtomicEditor/Editors/JSResourceEditor.cpp

@@ -121,7 +121,6 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
     const String& EDITOR_CHANGE = "editorChange";
     const String& EDITOR_CHANGE = "editorChange";
     const String& EDITOR_SAVE_CODE = "editorSaveCode";
     const String& EDITOR_SAVE_CODE = "editorSaveCode";
     const String& EDITOR_SAVE_FILE = "editorSaveFile";
     const String& EDITOR_SAVE_FILE = "editorSaveFile";
-    const String& EDITOR_GET_USER_PREFS = "editorGetUserPrefs";
 
 
     WebMessageHandler* handler = static_cast<WebMessageHandler*>(eventData[P_HANDLER].GetPtr());
     WebMessageHandler* handler = static_cast<WebMessageHandler*>(eventData[P_HANDLER].GetPtr());
 
 
@@ -160,16 +159,6 @@ void JSResourceEditor::HandleWebMessage(StringHash eventType, VariantMap& eventD
                 LOGWARNING("Ignoring attempt to write file: " + fn);
                 LOGWARNING("Ignoring attempt to write file: " + fn);
             }
             }
         }
         }
-        else if (message == EDITOR_GET_USER_PREFS)
-        {
-            ToolSystem* tsys = GetSubsystem<ToolSystem>();
-            Project* proj = tsys->GetProject();
-            FileSystem* fileSystem = GetSubsystem<FileSystem>();
-            if (fileSystem->FileExists(proj->GetUserPrefsFullPath()))
-            {
-                webClient_->ExecuteJavaScript(ToString("HOST_loadPreferences(\"atomic://%s\");", proj->GetUserPrefsFullPath().CString()));
-            }
-        }
     }
     }
 
 
     handler->Success();
     handler->Success();