/* * Copyright (C) 2012 Igalia S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include "webkitfilechooserrequest.h" #include "FileChooser.h" #include "FileSystem.h" #include "webkitfilechooserrequestprivate.h" #include "webkitglobalsprivate.h" #include #include #include #include using namespace WebCore; /** * SECTION:webkitfilechooserrequest * @Short_description: A request to open a file chooser * @Title: WebKitFileChooserRequest * @See_also: #WebKitWebView * * Whenever the user interacts with an <input type='file' /> * HTML element, WebKit will need to show a dialog to choose one or * more files to be uploaded to the server along with the rest of the * form data. For that to happen in a general way, instead of just * opening a #GtkFileChooserDialog (which might be not desirable in * some cases, such as when an embedding applications prefers to use * its own file chooser dialog), WebKit will fire the * #WebKitWebView::run-file-chooser signal with a * #WebKitFileChooserRequest object, which will allow the client * application to specify the files to be selected, to inspect the * details of the request (e.g. if multiple selection should be * allowed) and to cancel the request, in case nothing was selected. * * In case the client application does not wish to handle this signal, * WebKit will provide a default handler which will asynchronously run * a regular #GtkFileChooserDialog for the user to interact with. */ G_DEFINE_TYPE(WebKitFileChooserRequest, webkit_file_chooser_request, G_TYPE_OBJECT) struct _WebKitFileChooserRequestPrivate { RefPtr chooser; GRefPtr filter; GRefPtr mimeTypes; GRefPtr selectedFiles; }; enum { PROP_0, PROP_FILTER, PROP_MIME_TYPES, PROP_SELECT_MULTIPLE, PROP_SELECTED_FILES, }; static void webkit_file_chooser_request_init(WebKitFileChooserRequest* request) { request->priv = G_TYPE_INSTANCE_GET_PRIVATE(request, WEBKIT_TYPE_FILE_CHOOSER_REQUEST, WebKitFileChooserRequestPrivate); new (request->priv) WebKitFileChooserRequestPrivate(); } static void webkit_file_chooser_request_finalize(GObject* object) { WebKitFileChooserRequest* request = WEBKIT_FILE_CHOOSER_REQUEST(object); request->priv->~WebKitFileChooserRequestPrivate(); G_OBJECT_CLASS(webkit_file_chooser_request_parent_class)->finalize(object); } static void webkit_file_chooser_request_get_property(GObject* object, guint propId, GValue* value, GParamSpec* paramSpec) { WebKitFileChooserRequest* request = WEBKIT_FILE_CHOOSER_REQUEST(object); switch (propId) { case PROP_FILTER: g_value_set_object(value, webkit_file_chooser_request_get_mime_types_filter(request)); break; case PROP_MIME_TYPES: g_value_set_boxed(value, webkit_file_chooser_request_get_mime_types(request)); break; case PROP_SELECT_MULTIPLE: g_value_set_boolean(value, webkit_file_chooser_request_get_select_multiple(request)); break; case PROP_SELECTED_FILES: g_value_set_boxed(value, webkit_file_chooser_request_get_selected_files(request)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propId, paramSpec); break; } } static void webkit_file_chooser_request_class_init(WebKitFileChooserRequestClass* requestClass) { GObjectClass* objectClass = G_OBJECT_CLASS(requestClass); objectClass->finalize = webkit_file_chooser_request_finalize; objectClass->get_property = webkit_file_chooser_request_get_property; g_type_class_add_private(requestClass, sizeof(WebKitFileChooserRequestPrivate)); /** * WebKitFileChooserRequest:filter: * * The filter currently associated with the request. See * webkit_file_chooser_request_get_mime_types_filter() for more * details. * * Since: 1.10 */ g_object_class_install_property(objectClass, PROP_FILTER, g_param_spec_object("filter", _("MIME types filter"), _("The filter currently associated with the request"), GTK_TYPE_FILE_FILTER, WEBKIT_PARAM_READABLE)); /** * WebKitFileChooserRequest:mime-types: * * A %NULL-terminated array of strings containing the list of MIME * types the file chooser dialog should handle. See * webkit_file_chooser_request_get_mime_types() for more details. * * Since: 1.10 */ g_object_class_install_property(objectClass, PROP_MIME_TYPES, g_param_spec_boxed("mime-types", _("MIME types"), _("The list of MIME types associated with the request"), G_TYPE_STRV, WEBKIT_PARAM_READABLE)); /** * WebKitFileChooserRequest:select-multiple: * * Whether the file chooser should allow selecting multiple * files. See * webkit_file_chooser_request_get_select_multiple() for * more details. * * Since: 1.10 */ g_object_class_install_property(objectClass, PROP_SELECT_MULTIPLE, g_param_spec_boolean("select-multiple", _("Select multiple files"), _("Whether the file chooser should allow selecting multiple files"), FALSE, WEBKIT_PARAM_READABLE)); /** * WebKitFileChooserRequest:selected-files: * * A %NULL-terminated array of strings containing the list of * selected files associated to the current request. See * webkit_file_chooser_request_get_selected_files() for more details. * * Since: 1.10 */ g_object_class_install_property(objectClass, PROP_SELECTED_FILES, g_param_spec_boxed("selected-files", _("Selected files"), _("The list of selected files associated with the request"), G_TYPE_STRV, WEBKIT_PARAM_READABLE)); } WebKitFileChooserRequest* webkit_file_chooser_request_create(PassRefPtr chooser) { WebKitFileChooserRequest* request = WEBKIT_FILE_CHOOSER_REQUEST(g_object_new(WEBKIT_TYPE_FILE_CHOOSER_REQUEST, NULL)); request->priv->chooser = chooser; return request; } /** * webkit_file_chooser_request_get_mime_types: * @request: a #WebKitFileChooserRequest * * Get the list of MIME types the file chooser dialog should handle, * in the format specified in RFC 2046 for "media types". Its contents * depend on the value of the 'accept' attribute for HTML input * elements. This function should normally be called before presenting * the file chooser dialog to the user, to decide whether to allow the * user to select multiple files at once or only one. * * Returns: (array zero-terminated=1) (transfer none): a * %NULL-terminated array of strings if a list of accepted MIME types * is defined or %NULL otherwise, meaning that any MIME type should be * accepted. This array and its contents are owned by WebKitGTK+ and * should not be modified or freed. * * Since: 1.10 */ const gchar* const* webkit_file_chooser_request_get_mime_types(WebKitFileChooserRequest* request) { g_return_val_if_fail(WEBKIT_IS_FILE_CHOOSER_REQUEST(request), 0); if (request->priv->mimeTypes) return reinterpret_cast(request->priv->mimeTypes->pdata); FileChooserSettings settings = request->priv->chooser->settings(); size_t numOfMimeTypes = settings.acceptMIMETypes.size(); if (!numOfMimeTypes) return 0; request->priv->mimeTypes = adoptGRef(g_ptr_array_new_with_free_func(g_free)); for (size_t i = 0; i < numOfMimeTypes; ++i) { String mimeTypeString = settings.acceptMIMETypes[i]; if (mimeTypeString.isEmpty()) continue; g_ptr_array_add(request->priv->mimeTypes.get(), g_strdup(mimeTypeString.utf8().data())); } g_ptr_array_add(request->priv->mimeTypes.get(), 0); return reinterpret_cast(request->priv->mimeTypes->pdata); } /** * webkit_file_chooser_request_get_mime_types_filter: * @request: a #WebKitFileChooserRequest * * Get the filter currently associated with the request, ready to be * used by #GtkFileChooser. This function should normally be called * before presenting the file chooser dialog to the user, to decide * whether to apply a filter so the user would not be allowed to * select files with other MIME types. * * See webkit_file_chooser_request_get_mime_types() if you are * interested in getting the list of accepted MIME types. * * Returns: (transfer none): a #GtkFileFilter if a list of accepted * MIME types is defined or %NULL otherwise. The returned object is * owned by WebKitGTK+ should not be modified or freed. * * Since: 1.10 */ GtkFileFilter* webkit_file_chooser_request_get_mime_types_filter(WebKitFileChooserRequest* request) { g_return_val_if_fail(WEBKIT_IS_FILE_CHOOSER_REQUEST(request), 0); if (request->priv->filter) return request->priv->filter.get(); FileChooserSettings settings = request->priv->chooser->settings(); size_t numOfMimeTypes = settings.acceptMIMETypes.size(); if (!numOfMimeTypes) return 0; // Do not use adoptGRef here, since we want to sink the floating // reference for the new instance of GtkFileFilter, so we make // sure we keep the ownership during the lifetime of the request. request->priv->filter = gtk_file_filter_new(); for (size_t i = 0; i < numOfMimeTypes; ++i) { String mimeTypeString = settings.acceptMIMETypes[i]; if (mimeTypeString.isEmpty()) continue; gtk_file_filter_add_mime_type(request->priv->filter.get(), mimeTypeString.utf8().data()); } return request->priv->filter.get(); } /** * webkit_file_chooser_request_get_select_multiple: * @request: a #WebKitFileChooserRequest * * Determine whether the file chooser associated to this * #WebKitFileChooserRequest should allow selecting multiple files, * which depends on the HTML input element having a 'multiple' * attribute defined. * * Returns: %TRUE if the file chooser should allow selecting multiple files or %FALSE otherwise. * * Since: 1.10 */ gboolean webkit_file_chooser_request_get_select_multiple(WebKitFileChooserRequest* request) { g_return_val_if_fail(WEBKIT_IS_FILE_CHOOSER_REQUEST(request), FALSE); return request->priv->chooser->settings().allowsMultipleFiles; } /** * webkit_file_chooser_request_select_files: * @request: a #WebKitFileChooserRequest * @files: (array zero-terminated=1) (transfer none): a * %NULL-terminated array of strings, containing paths to local files. * * Ask WebKit to select local files for upload and complete the * request. * * Since: 1.10 */ void webkit_file_chooser_request_select_files(WebKitFileChooserRequest* request, const gchar* const* files) { g_return_if_fail(WEBKIT_IS_FILE_CHOOSER_REQUEST(request)); g_return_if_fail(files); Vector names; GRefPtr selectedFiles = adoptGRef(g_ptr_array_new_with_free_func(g_free)); for (int i = 0; files[i]; i++) { names.append(filenameToString(files[i])); g_ptr_array_add(selectedFiles.get(), g_strdup(files[i])); } g_ptr_array_add(selectedFiles.get(), 0); request->priv->chooser->chooseFiles(names); request->priv->selectedFiles = selectedFiles; } /** * webkit_file_chooser_request_get_selected_files: * @request: a #WebKitFileChooserRequest * * Get the list of selected files currently associated to the * request. Initially, the return value of this method contains any * files selected in previous file chooser requests for this HTML * input element. Once webkit_file_chooser_request_select_files, the * value will reflect whatever files are given. * * This function should normally be called only before presenting the * file chooser dialog to the user, to decide whether to perform some * extra action, like pre-selecting the files from a previous request. * * Returns: (array zero-terminated=1) (transfer none): a * %NULL-terminated array of strings if there are selected files * associated with the request or %NULL otherwise. This array and its * contents are owned by WebKitGTK+ and should not be modified or * freed. * * Since: 1.10 */ const gchar* const* webkit_file_chooser_request_get_selected_files(WebKitFileChooserRequest* request) { g_return_val_if_fail(WEBKIT_IS_FILE_CHOOSER_REQUEST(request), 0); if (request->priv->selectedFiles) return reinterpret_cast(request->priv->selectedFiles->pdata); FileChooserSettings settings = request->priv->chooser->settings(); size_t numOfFiles = settings.selectedFiles.size(); if (!numOfFiles) return 0; request->priv->selectedFiles = adoptGRef(g_ptr_array_new_with_free_func(g_free)); for (size_t i = 0; i < numOfFiles; ++i) { if (settings.selectedFiles[i].isEmpty()) continue; CString filename = fileSystemRepresentation(settings.selectedFiles[i]); g_ptr_array_add(request->priv->selectedFiles.get(), g_strdup(filename.data())); } g_ptr_array_add(request->priv->selectedFiles.get(), 0); return reinterpret_cast(request->priv->selectedFiles->pdata); }