From 6f63f5d4f817459db1561ee522787e105b863a9d Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 9 Jul 2014 18:03:43 +0000 Subject: [PATCH] - Linux: cefclient: Add a GTK implementation of CefDialogHandler (issue #1258). - Add new CefGetExtensionsForMimeType function. git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1761 5089003a-bbd8-11dd-ad1f-f1f9622dbc98 --- include/capi/cef_url_capi.h | 7 + include/cef_url.h | 10 ++ libcef/common/url_impl.cc | 11 ++ libcef_dll/libcef_dll.cc | 28 ++++ libcef_dll/wrapper/libcef_dll_wrapper.cc | 29 ++++ tests/cefclient/client_handler.cpp | 13 ++ tests/cefclient/client_handler.h | 12 ++ tests/cefclient/client_handler_gtk.cpp | 184 +++++++++++++++++++++++ 8 files changed, 294 insertions(+) diff --git a/include/capi/cef_url_capi.h b/include/capi/cef_url_capi.h index 648697b10..c9e22aad7 100644 --- a/include/capi/cef_url_capi.h +++ b/include/capi/cef_url_capi.h @@ -68,6 +68,13 @@ CEF_EXPORT int cef_create_url(const struct _cef_urlparts_t* parts, CEF_EXPORT cef_string_userfree_t cef_get_mime_type( const cef_string_t* extension); +// Get the extensions associated with the given mime type. This should be passed +// in lower case. There could be multiple extensions for a given mime type, like +// "html,htm" for "text/html", or "txt,text,html,..." for "text/*". Any existing +// elements in the provided vector will not be erased. +CEF_EXPORT void cef_get_extensions_for_mime_type(const cef_string_t* mime_type, + cef_string_list_t extensions); + #ifdef __cplusplus } #endif diff --git a/include/cef_url.h b/include/cef_url.h index a3863a44b..d2def08e9 100644 --- a/include/cef_url.h +++ b/include/cef_url.h @@ -38,6 +38,8 @@ #define CEF_INCLUDE_CEF_URL_H_ #pragma once +#include + #include "include/cef_base.h" /// @@ -64,4 +66,12 @@ bool CefCreateURL(const CefURLParts& parts, /*--cef()--*/ CefString CefGetMimeType(const CefString& extension); +// Get the extensions associated with the given mime type. This should be passed +// in lower case. There could be multiple extensions for a given mime type, like +// "html,htm" for "text/html", or "txt,text,html,..." for "text/*". Any existing +// elements in the provided vector will not be erased. +/*--cef()--*/ +void CefGetExtensionsForMimeType(const CefString& mime_type, + std::vector& extensions); + #endif // CEF_INCLUDE_CEF_URL_H_ diff --git a/libcef/common/url_impl.cc b/libcef/common/url_impl.cc index fc35dae6c..d2660fcf2 100644 --- a/libcef/common/url_impl.cc +++ b/libcef/common/url_impl.cc @@ -74,3 +74,14 @@ CefString CefGetMimeType(const CefString& extension) { net::GetMimeTypeFromExtension(extension, &mime_type); return mime_type; } + +void CefGetExtensionsForMimeType(const CefString& mime_type, + std::vector& extensions) { + typedef std::vector VectorType; + VectorType ext; + net::GetExtensionsForMimeType(mime_type, &ext); + VectorType::const_iterator it = ext.begin(); + for (; it != ext.end(); ++it) + extensions.push_back(*it); +} + diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 960d68a87..279255082 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -104,6 +104,7 @@ #include "libcef_dll/ctocpp/web_plugin_info_visitor_ctocpp.h" #include "libcef_dll/ctocpp/web_plugin_unstable_callback_ctocpp.h" #include "libcef_dll/ctocpp/write_handler_ctocpp.h" +#include "libcef_dll/transfer_util.h" // GLOBAL FUNCTIONS - Body may be edited by hand. @@ -593,6 +594,33 @@ CEF_EXPORT cef_string_userfree_t cef_get_mime_type( return _retval.DetachToUserFree(); } +CEF_EXPORT void cef_get_extensions_for_mime_type(const cef_string_t* mime_type, + cef_string_list_t extensions) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: mime_type; type: string_byref_const + DCHECK(mime_type); + if (!mime_type) + return; + // Verify param: extensions; type: string_vec_byref + DCHECK(extensions); + if (!extensions) + return; + + // Translate param: extensions; type: string_vec_byref + std::vector extensionsList; + transfer_string_list_contents(extensions, extensionsList); + + // Execute + CefGetExtensionsForMimeType( + CefString(mime_type), + extensionsList); + + // Restore param: extensions; type: string_vec_byref + cef_string_list_clear(extensions); + transfer_string_list_contents(extensionsList, extensions); +} + CEF_EXPORT int cef_register_extension(const cef_string_t* extension_name, const cef_string_t* javascript_code, struct _cef_v8handler_t* handler) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 94f69577e..23aa75ade 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -105,6 +105,7 @@ #include "libcef_dll/ctocpp/web_plugin_info_ctocpp.h" #include "libcef_dll/ctocpp/xml_reader_ctocpp.h" #include "libcef_dll/ctocpp/zip_reader_ctocpp.h" +#include "libcef_dll/transfer_util.h" // Define used to facilitate parsing. #define CEF_GLOBAL @@ -546,6 +547,34 @@ CEF_GLOBAL CefString CefGetMimeType(const CefString& extension) { return _retvalStr; } +CEF_GLOBAL void CefGetExtensionsForMimeType(const CefString& mime_type, + std::vector& extensions) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: mime_type; type: string_byref_const + DCHECK(!mime_type.empty()); + if (mime_type.empty()) + return; + + // Translate param: extensions; type: string_vec_byref + cef_string_list_t extensionsList = cef_string_list_alloc(); + DCHECK(extensionsList); + if (extensionsList) + transfer_string_list_contents(extensions, extensionsList); + + // Execute + cef_get_extensions_for_mime_type( + mime_type.GetStruct(), + extensionsList); + + // Restore param:extensions; type: string_vec_byref + if (extensionsList) { + extensions.clear(); + transfer_string_list_contents(extensionsList, extensions); + cef_string_list_free(extensionsList); + } +} + CEF_GLOBAL bool CefRegisterExtension(const CefString& extension_name, const CefString& javascript_code, CefRefPtr handler) { // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING diff --git a/tests/cefclient/client_handler.cpp b/tests/cefclient/client_handler.cpp index 64c444088..5cfe0b752 100644 --- a/tests/cefclient/client_handler.cpp +++ b/tests/cefclient/client_handler.cpp @@ -178,6 +178,19 @@ bool ClientHandler::OnContextMenuCommand( } } +#if !defined(OS_LINUX) + +bool ClientHandler::OnFileDialog(CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_name, + const std::vector& accept_types, + CefRefPtr callback) { + return false; +} + +#endif // !defined(OS_LINUX) + bool ClientHandler::OnConsoleMessage(CefRefPtr browser, const CefString& message, const CefString& source, diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index ee2ec7f96..6b3b23c88 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -29,6 +29,7 @@ // ClientHandler implementation. class ClientHandler : public CefClient, public CefContextMenuHandler, + public CefDialogHandler, public CefDisplayHandler, public CefDownloadHandler, public CefDragHandler, @@ -55,6 +56,9 @@ class ClientHandler : public CefClient, virtual CefRefPtr GetContextMenuHandler() OVERRIDE { return this; } + virtual CefRefPtr GetDialogHandler() OVERRIDE { + return this; + } virtual CefRefPtr GetDisplayHandler() OVERRIDE { return this; } @@ -101,6 +105,14 @@ class ClientHandler : public CefClient, int command_id, EventFlags event_flags) OVERRIDE; + // CefDialogHandler methods + virtual bool OnFileDialog(CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_name, + const std::vector& accept_types, + CefRefPtr callback) OVERRIDE; + // CefDisplayHandler methods virtual void OnAddressChange(CefRefPtr browser, CefRefPtr frame, diff --git a/tests/cefclient/client_handler_gtk.cpp b/tests/cefclient/client_handler_gtk.cpp index 27f0997cf..2247eac96 100644 --- a/tests/cefclient/client_handler_gtk.cpp +++ b/tests/cefclient/client_handler_gtk.cpp @@ -3,6 +3,7 @@ // can be found in the LICENSE file. #include +#include #include #include #undef Success // Definition conflicts with cef_message_router.h @@ -12,6 +13,7 @@ #include "cefclient/client_handler.h" #include "include/cef_browser.h" #include "include/cef_frame.h" +#include "include/cef_url.h" namespace { @@ -27,8 +29,190 @@ std::string GetPromptText(GtkDialog* dialog) { return std::string(); } +std::string GetDescriptionFromMimeType(const std::string& mime_type) { + // Check for wild card mime types and return an appropriate description. + static const struct { + const char* mime_type; + const char* label; + } kWildCardMimeTypes[] = { + { "audio", "Audio Files" }, + { "image", "Image Files" }, + { "text", "Text Files" }, + { "video", "Video Files" }, + }; + + for (size_t i = 0; + i < sizeof(kWildCardMimeTypes) / sizeof(kWildCardMimeTypes[0]); ++i) { + if (mime_type == std::string(kWildCardMimeTypes[i].mime_type) + "/*") + return std::string(kWildCardMimeTypes[i].label); + } + + return std::string(); +} + +void AddFiltersForAcceptTypes(GtkFileChooser* chooser, + const std::vector& accept_types, + bool include_all_files) { + bool has_filter = false; + + for (size_t i = 0; i < accept_types.size(); ++i) { + std::string ascii_type = accept_types[i]; + if (ascii_type.length()) { + // Just treat as extension if contains '.' as the first character. + if (ascii_type[0] == '.') { + GtkFileFilter* filter = gtk_file_filter_new(); + std::string pattern = "*" + ascii_type; + gtk_file_filter_add_pattern(filter, pattern.c_str()); + gtk_file_filter_set_name(filter, pattern.c_str()); + gtk_file_chooser_add_filter(chooser, filter); + if (!has_filter) + has_filter = true; + } else { + // Otherwise convert mime type to one or more extensions. + GtkFileFilter* filter = NULL; + std::string description = GetDescriptionFromMimeType(ascii_type); + bool description_from_ext = description.empty(); + + std::vector ext; + CefGetExtensionsForMimeType(ascii_type, ext); + for (size_t x = 0; x < ext.size(); ++x) { + if (!filter) + filter = gtk_file_filter_new(); + std::string pattern = "*." + ext[x].ToString(); + gtk_file_filter_add_pattern(filter, pattern.c_str()); + + if (description_from_ext) { + if (x != 0) + description += ";"; + description += pattern; + } + } + + if (filter) { + gtk_file_filter_set_name(filter, description.c_str()); + gtk_file_chooser_add_filter(chooser, filter); + if (!has_filter) + has_filter = true; + } + } + } + } + + // Add the *.* filter, but only if we have added other filters (otherwise it + // is implied). + if (include_all_files && has_filter) { + GtkFileFilter* filter = gtk_file_filter_new(); + gtk_file_filter_add_pattern(filter, "*"); + gtk_file_filter_set_name(filter, "All Files"); + gtk_file_chooser_add_filter(chooser, filter); + } +} + } // namespace +bool ClientHandler::OnFileDialog(CefRefPtr browser, + FileDialogMode mode, + const CefString& title, + const CefString& default_file_name, + const std::vector& accept_types, + CefRefPtr callback) { + std::vector files; + + GtkFileChooserAction action; + const gchar* accept_button; + if (mode == FILE_DIALOG_OPEN || mode == FILE_DIALOG_OPEN_MULTIPLE) { + action = GTK_FILE_CHOOSER_ACTION_OPEN; + accept_button = GTK_STOCK_OPEN; + } else if (mode == FILE_DIALOG_SAVE) { + action = GTK_FILE_CHOOSER_ACTION_SAVE; + accept_button = GTK_STOCK_SAVE; + } else { + ASSERT(false); // Not reached + return false; + } + + std::string base_name; + if (!default_file_name.empty()) { + base_name = + basename(const_cast(default_file_name.ToString().c_str())); + } + + std::string title_str; + if (!title.empty()) { + title_str = title; + } else { + switch (mode) { + case FILE_DIALOG_OPEN: + title_str = "Open File"; + break; + case FILE_DIALOG_OPEN_MULTIPLE: + title_str = "Open Files"; + break; + case FILE_DIALOG_SAVE: + title_str = "Save File"; + break; + default: + break; + } + } + + GtkWidget* window = + gtk_widget_get_ancestor(GTK_WIDGET(GetMainHwnd()), GTK_TYPE_WINDOW); + GtkWidget* dialog = gtk_file_chooser_dialog_new( + title_str.c_str(), + GTK_WINDOW(window), + action, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + accept_button, GTK_RESPONSE_ACCEPT, + NULL); + + if (mode == FILE_DIALOG_OPEN_MULTIPLE) { + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); + } else if (mode == FILE_DIALOG_SAVE) { + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), + TRUE); + } + + if (mode == FILE_DIALOG_SAVE && !base_name.empty()) { + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), + base_name.c_str()); + } + + AddFiltersForAcceptTypes(GTK_FILE_CHOOSER(dialog), accept_types, true); + + bool success = false; + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + if (mode == FILE_DIALOG_OPEN || mode == FILE_DIALOG_SAVE) { + char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + files.push_back(std::string(filename)); + success = true; + } else if (mode == FILE_DIALOG_OPEN_MULTIPLE) { + GSList* filenames = + gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + if (filenames) { + for (GSList* iter = filenames; iter != NULL; + iter = g_slist_next(iter)) { + std::string path(static_cast(iter->data)); + g_free(iter->data); + files.push_back(path); + } + g_slist_free(filenames); + success = true; + } + } + } + + gtk_widget_destroy(dialog); + + if (success) + callback->Continue(files); + else + callback->Cancel(); + + return true; +} + void ClientHandler::OnAddressChange(CefRefPtr browser, CefRefPtr frame, const CefString& url) {