diff --git a/appshell/appshell_extensions.cpp b/appshell/appshell_extensions.cpp index ccacbd5bd..ad3f21385 100644 --- a/appshell/appshell_extensions.cpp +++ b/appshell/appshell_extensions.cpp @@ -150,6 +150,42 @@ class ProcessMessageDelegate : public ClientHandler::ProcessMessageDelegate { // Set response args for this function responseArgs->SetList(2, directoryContents); + } else if (message_name == "MakeDir") { + // Parameters: + // 0: int32 - callback id + // 1: string - directory path + // 2: number - mode + if (argList->GetSize() != 3 || + argList->GetType(1) != VTYPE_STRING || + argList->GetType(2) != VTYPE_INT) { + error = ERR_INVALID_PARAMS; + } + + if (error == NO_ERROR) { + ExtensionString pathname = argList->GetString(1); + int32 mode = argList->GetInt(2); + + error = MakeDir(pathname, mode); + } + // No additional response args for this function + } else if (message_name == "Rename") { + // Parameters: + // 0: int32 - callback id + // 1: string - old path + // 2: string - new path + if (argList->GetSize() != 3 || + argList->GetType(1) != VTYPE_STRING || + argList->GetType(2) != VTYPE_STRING) { + error = ERR_INVALID_PARAMS; + } + + if (error == NO_ERROR) { + ExtensionString oldName = argList->GetString(1); + ExtensionString newName = argList->GetString(2); + + error = Rename(oldName, newName); + } + // No additional response args for this function } else if (message_name == "GetFileModificationTime") { // Parameters: // 0: int32 - callback id diff --git a/appshell/appshell_extensions.js b/appshell/appshell_extensions.js index 34e849953..0fe88c60f 100644 --- a/appshell/appshell_extensions.js +++ b/appshell/appshell_extensions.js @@ -94,6 +94,11 @@ if (!appshell.app) { */ appshell.fs.ERR_NOT_DIRECTORY = 9; + /** + * @constant Specified file already exists. + */ + appshell.fs.ERR_FILE_EXISTS = 10; + /** * Display the OS File Open dialog, allowing the user to select * files or directories. @@ -144,7 +149,35 @@ if (!appshell.app) { appshell.fs.readdir = function (path, callback) { var resultString = ReadDir(callback, path); }; - + + /** + * Create a new directory. + * + * @param {string} path The path of the directory to create. + * @param {number} mode The permissions for the directory, in numeric format (ie 0777) + * @param {function(err)} callback Asynchronous callback function. The callback gets one argument. + * + * @return None. This is an asynchronous call that sends all return information to the callback. + **/ + native function MakeDir(); + appshell.fs.makedir = function (path, mode, callback) { + MakeDir(callback, path, mode); + }; + + /** + * Rename a file or directory. + * + * @param {string} oldPath The old name of the file or directory. + * @param {string} newPath The new name of the file or directory. + * @param {function(err)} callback Asynchronous callback function. The callback gets one argument. + * + * @return None. This is an asynchronous call that sends all return information to the callback. + **/ + native function Rename(); + appshell.fs.rename = function(oldPath, newPath, callback) { + Rename(callback, oldPath, newPath); + }; + /** * Get information for the selected file or directory. * diff --git a/appshell/appshell_extensions_mac.mm b/appshell/appshell_extensions_mac.mm index 2ac96281d..a7da50c0b 100644 --- a/appshell/appshell_extensions_mac.mm +++ b/appshell/appshell_extensions_mac.mm @@ -312,11 +312,13 @@ int32 ShowOpenDialog(bool allowMulitpleSelection, [openPanel setAllowedFileTypes:allowedFileTypes]; + [openPanel beginSheetModalForWindow:[NSApp mainWindow] completionHandler:nil]; if ([openPanel runModal] == NSOKButton) { NSArray* files = [openPanel filenames]; NSArrayToCefList(files, selectedFiles); } + [NSApp endSheet:openPanel]; return NO_ERROR; } @@ -337,6 +339,28 @@ int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents) return ConvertNSErrorCode(error, true); } +int32 MakeDir(ExtensionString path, int32 mode) +{ + NSError* error = nil; + NSString* pathStr = [NSString stringWithUTF8String:path.c_str()]; + + // TODO (issue #1759): honor mode + [[NSFileManager defaultManager] createDirectoryAtPath:pathStr withIntermediateDirectories:FALSE attributes:nil error:&error]; + + return ConvertNSErrorCode(error, false); +} + +int32 Rename(ExtensionString oldName, ExtensionString newName) +{ + NSError* error = nil; + NSString* oldPathStr = [NSString stringWithUTF8String:oldName.c_str()]; + NSString* newPathStr = [NSString stringWithUTF8String:newName.c_str()]; + + [[NSFileManager defaultManager] moveItemAtPath:oldPathStr toPath:newPathStr error:&error]; + + return ConvertNSErrorCode(error, false); +} + int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir) { NSString* path = [NSString stringWithUTF8String:filename.c_str()]; @@ -493,6 +517,9 @@ int32 ConvertNSErrorCode(NSError* error, bool isReading) case NSFileWriteOutOfSpaceError: return ERR_OUT_OF_SPACE; break; + case NSFileWriteFileExistsError: + return ERR_FILE_EXISTS; + break; } // Unknown error diff --git a/appshell/appshell_extensions_platform.h b/appshell/appshell_extensions_platform.h index 22131451c..71fc7e369 100644 --- a/appshell/appshell_extensions_platform.h +++ b/appshell/appshell_extensions_platform.h @@ -42,6 +42,7 @@ static const int ERR_CANT_WRITE = 6; static const int ERR_OUT_OF_SPACE = 7; static const int ERR_NOT_FILE = 8; static const int ERR_NOT_DIRECTORY = 9; +static const int ERR_FILE_EXISTS = 10; #if defined(OS_WIN) typedef std::wstring ExtensionString; @@ -67,6 +68,10 @@ int32 ShowOpenDialog(bool allowMulitpleSelection, int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents); +int32 MakeDir(ExtensionString path, int32 mode); + +int32 Rename(ExtensionString oldName, ExtensionString newName); + int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir); int32 ReadFile(ExtensionString filename, ExtensionString encoding, std::string& contents); diff --git a/appshell/appshell_extensions_win.cpp b/appshell/appshell_extensions_win.cpp index e198cd62a..142456b85 100644 --- a/appshell/appshell_extensions_win.cpp +++ b/appshell/appshell_extensions_win.cpp @@ -554,6 +554,23 @@ int32 ReadDir(ExtensionString path, CefRefPtr& directoryContents) return NO_ERROR; } +int32 MakeDir(ExtensionString path, int32 mode) +{ + // TODO (issue #1759): honor mode + if (!CreateDirectory(path.c_str(), NULL)) + return ConvertWinErrorCode(GetLastError(), false); + + return NO_ERROR; +} + +int32 Rename(ExtensionString oldName, ExtensionString newName) +{ + if (!MoveFile(oldName.c_str(), newName.c_str())) + return ConvertWinErrorCode(GetLastError()); + + return NO_ERROR; +} + int32 GetFileModificationTime(ExtensionString filename, uint32& modtime, bool& isDir) { DWORD dwAttr = GetFileAttributes(filename.c_str()); @@ -740,6 +757,8 @@ int ConvertWinErrorCode(int errorCode, bool isReading) return ERR_CANT_WRITE; case ERROR_HANDLE_DISK_FULL: return ERR_OUT_OF_SPACE; + case ERROR_ALREADY_EXISTS: + return ERR_FILE_EXISTS; default: return ERR_UNKNOWN; } diff --git a/appshell/cefclient_mac.mm b/appshell/cefclient_mac.mm index 09559853e..349e0f753 100644 --- a/appshell/cefclient_mac.mm +++ b/appshell/cefclient_mac.mm @@ -353,23 +353,41 @@ - (void)createApp:(id)object { settings.web_security_disabled = true; - window_info.SetAsChild(contentView, 0, 0, kWindowWidth, kWindowHeight); + [[mainWnd windowController] setShouldCascadeWindows: NO]; + + // Set the initial default size of the window. + NSRect defSize = [mainWnd contentRectForFrameRect:[mainWnd frame]]; + defSize.size.width = kWindowWidth; + defSize.size.height = kWindowHeight +#ifdef SHOW_TOOLBAR_UI + + URLBAR_HEIGHT +#endif + ; + + [mainWnd setFrame:[mainWnd frameRectForContentRect:defSize] display:NO]; + + // Set the "autosave" name for the window. If there is a previously stored + // size for the window, it will be loaded here. + [mainWnd setFrameAutosaveName:APP_NAME @"MainWindow"]; + + // Get the actual content size of the window since setFrameAutosaveName could + // result in the window size changing. + NSRect r = [mainWnd contentRectForFrameRect:[mainWnd frame]]; + + window_info.SetAsChild(contentView, 0, 0, + r.size.width, + r.size.height +#ifdef SHOW_TOOLBAR_UI + + URLBAR_HEIGHT +#endif + ); + CefBrowserHost::CreateBrowser(window_info, g_handler.get(), [[startupUrl absoluteString] UTF8String], settings); // Show the window. + [mainWnd display]; [mainWnd makeKeyAndOrderFront: nil]; - - // Size the window. - NSRect r = [mainWnd contentRectForFrameRect:[mainWnd frame]]; - r.size.width = kWindowWidth; - r.size.height = kWindowHeight -#ifdef SHOW_TOOLBAR_UI - + URLBAR_HEIGHT -#endif - ; - - [mainWnd setFrame:[mainWnd frameRectForContentRect:r] display:YES]; } // Sent by the default notification center immediately before the application