/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
if (!image_filename) {
gtk_file_chooser_set_preview_widget_active(file_chooser, FALSE); return;
}
gint preview_width = 0;
gint preview_height = 0; /* check type of file * if file is named pipe, Open is blocking which may lead to UI * nonresponsiveness; if file is directory/socket, it also isn't
* likely to get preview */ if (stat(image_filename, &st_buf) || (!S_ISREG(st_buf.st_mode))) {
g_free(image_filename);
gtk_file_chooser_set_preview_widget_active(file_chooser, FALSE); return; /* stat failed or file is not regular */
}
// This is the easiest way to do center alignment without worrying about // containers Minimum 3px padding each side (hence the 6) just to make things // nice
gint x_padding =
(MAX_PREVIEW_SIZE + 6 - gdk_pixbuf_get_width(preview_pixbuf)) / 2;
gtk_misc_set_padding(GTK_MISC(preview_widget), x_padding, 0);
static nsAutoCString MakeCaseInsensitiveShellGlob(constchar* aPattern) { // aPattern is UTF8
nsAutoCString result; unsignedint len = strlen(aPattern);
for (unsignedint i = 0; i < len; i++) { if (!g_ascii_isalpha(aPattern[i])) { // non-ASCII characters will also trigger this path, so unicode // is safely handled albeit case-sensitively
result.Append(aPattern[i]); continue;
}
// add the lowercase and uppercase version of a character to a bracket // match, so it matches either the lowercase or uppercase char.
result.Append('[');
result.Append(g_ascii_tolower(aPattern[i]));
result.Append(g_ascii_toupper(aPattern[i]));
result.Append(']');
}
NS_IMETHODIMP
nsFilePicker::AppendFilter(const nsAString& aTitle, const nsAString& aFilter) { if (aFilter.EqualsLiteral("..apps")) { // No platform specific thing we can do here, really.... return NS_OK;
}
if (mMode == nsIFilePicker::modeOpenMultiple) { return NS_NewArrayEnumerator(aFiles, mFiles, NS_GET_IID(nsIFile));
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsFilePicker::Open(nsIFilePickerShownCallback* aCallback) { // Can't show two dialogs concurrently with the same filepicker if (mFileChooser) { return NS_ERROR_NOT_AVAILABLE;
}
if (MaybeBlockFilePicker(aCallback)) { return NS_OK;
}
// Don't attempt to open a real file-picker in headless mode. if (gfxPlatform::IsHeadless()) { return NS_ERROR_NOT_AVAILABLE;
}
// If we have --enable-proxy-bypass-protection, then don't allow // remote URLs to be used. #ifndef MOZ_PROXY_BYPASS_PROTECTION if (mAllowURLs) {
gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(file_chooser), FALSE);
} #endif
if (defaultPath) { if (!defaultName.IsEmpty() && mMode != nsIFilePicker::modeSave) { // Try to select the intended file. Even if it doesn't exist, GTK still // switches directories.
defaultPath->AppendNative(defaultName);
nsAutoCString path;
defaultPath->GetNativePath(path);
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(file_chooser), path.get());
} else {
nsAutoCString directory;
defaultPath->GetNativePath(directory);
// Workaround for problematic refcounting in GTK3 before 3.16. // We need to keep a reference to the dialog's internal delegate. // Otherwise, if our dialog gets destroyed, we'll lose the dialog's // delegate by the time this gets processed in the event loop. // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1166741 if (GTK_IS_DIALOG(file_chooser)) {
GtkDialog* dialog = GTK_DIALOG(file_chooser);
GtkContainer* area = GTK_CONTAINER(gtk_dialog_get_content_area(dialog));
gtk_container_forall(
area,
[](GtkWidget* widget, gpointer data) { if (GTK_IS_FILE_CHOOSER_WIDGET(widget)) { auto result = static_cast<GtkFileChooserWidget**>(data);
*result = GTK_FILE_CHOOSER_WIDGET(widget);
}
},
&mFileChooserDelegate);
if (GTK_IS_DIALOG(file_chooser)) {
gtk_dialog_set_default_response(GTK_DIALOG(file_chooser),
GTK_RESPONSE_ACCEPT);
}
int32_t count = mFilters.Length(); for (int32_t i = 0; i < count; ++i) { // This is fun... the GTK file picker does not accept a list of filters // so we need to split out each string, and add it manually.
if (!mFilterNames[i].IsEmpty()) { // If we have a name for our filter, let's use that. constchar* filter_name = mFilterNames[i].get();
gtk_file_filter_set_name(filter, filter_name);
} else { // If we don't have a name, let's just use the filter pattern. constchar* filter_pattern = mFilters[i].get();
gtk_file_filter_set_name(filter, filter_pattern);
}
nsIFilePicker::ResultCode result; switch (response) { case GTK_RESPONSE_OK: case GTK_RESPONSE_ACCEPT:
ReadValuesFromFileChooser(file_chooser);
result = nsIFilePicker::returnOK; if (mMode == nsIFilePicker::modeSave) {
nsCOMPtr<nsIFile> file;
GetFile(getter_AddRefs(file)); if (file) { bool exists = false;
file->Exists(&exists); if (exists) {
result = nsIFilePicker::returnReplace;
}
}
} elseif (mMode == nsIFilePicker::modeOpen) { if (WarnForNonReadableFile(file_chooser)) {
result = nsIFilePicker::returnCancel;
}
} break;
case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_CLOSE: case GTK_RESPONSE_DELETE_EVENT:
result = nsIFilePicker::returnCancel; break;
default:
NS_WARNING("Unexpected response");
result = nsIFilePicker::returnCancel; break;
}
// A "response" signal won't be sent again but "destroy" will be.
g_signal_handlers_disconnect_by_func(file_chooser, FuncToGpointer(OnDestroy), this);
// When response_id is GTK_RESPONSE_DELETE_EVENT or when called from // OnDestroy, the widget would be destroyed anyway but it is fine if // gtk_widget_destroy is called more than once. gtk_widget_destroy has // requests that any remaining references be released, but the reference // count will not be decremented again if GtkWindow's reference has already // been released.
GtkFileChooserDestroy(file_chooser);
if (mFileChooserDelegate) { // Properly deref our acquired reference. We call this after // gtk_widget_destroy() to try and ensure that pending file info // queries caused by updating the current folder have been cancelled. // However, we do not know for certain when the callback will run after // cancelled.
g_idle_add(
[](gpointer data) -> gboolean {
g_object_unref(data); return G_SOURCE_REMOVE;
},
mFileChooserDelegate);
mFileChooserDelegate = nullptr;
}
if (mCallback) {
mCallback->Done(result);
mCallback = nullptr;
}
NS_RELEASE_THIS();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.