1 /* 2 * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include <com_sun_glass_ui_gtk_GtkCommonDialogs.h> 26 #include "glass_general.h" 27 #include "glass_window.h" 28 29 #include <gdk/gdk.h> 30 #include <gtk/gtk.h> 31 32 #include <cstring> 33 #include <cstdlib> 34 35 static GSList* setup_GtkFileFilters(GtkFileChooser*, JNIEnv*, jobjectArray, int default_filter_index); 36 37 static void free_fname(char* fname, gpointer unused) { 38 (void)unused; 39 40 g_free(fname); 41 } 42 43 static gboolean jstring_to_utf_get(JNIEnv *env, jstring jstr, 44 const char **cstr) { 45 const char *newstr; 46 47 if (jstr == NULL) { 48 *cstr = NULL; 49 return TRUE; 50 } 51 52 newstr = env->GetStringUTFChars(jstr, NULL); 53 if (newstr != NULL) { 54 *cstr = newstr; 55 return TRUE; 56 } 57 58 return FALSE; 59 } 60 61 static void jstring_to_utf_release(JNIEnv *env, jstring jstr, 62 const char *cstr) { 63 if (cstr != NULL) { 64 env->ReleaseStringUTFChars(jstr, cstr); 65 } 66 } 67 68 static GtkWindow *gdk_window_handle_to_gtk(jlong handle) { 69 return (handle != 0) 70 ? ((WindowContext*)JLONG_TO_PTR(handle))->get_gtk_window() 71 : NULL; 72 } 73 74 static jobject create_empty_result() { 75 jclass jFileChooserResult = (jclass) mainEnv->FindClass("com/sun/glass/ui/CommonDialogs$FileChooserResult"); 76 if (EXCEPTION_OCCURED(mainEnv)) return NULL; 77 jmethodID jFileChooserResultInit = mainEnv->GetMethodID(jFileChooserResult, "<init>", "()V"); 78 if (EXCEPTION_OCCURED(mainEnv)) return NULL; 79 jobject jResult = mainEnv->NewObject(jFileChooserResult, jFileChooserResultInit); 80 if (EXCEPTION_OCCURED(mainEnv)) return NULL; 81 return jResult; 82 } 83 84 extern "C" { 85 86 JNIEXPORT jobject JNICALL Java_com_sun_glass_ui_gtk_GtkCommonDialogs__1showFileChooser 87 (JNIEnv *env, jclass clazz, jlong parent, jstring folder, jstring name, jstring title, 88 jint type, jboolean multiple, jobjectArray jFilters, jint default_filter_index) { 89 (void)clazz; 90 91 jobjectArray jFileNames = NULL; 92 char* filename; 93 jstring jfilename; 94 95 const char* chooser_folder; 96 const char* chooser_filename; 97 const char* chooser_title; 98 const int chooser_type = type == 0 ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE; 99 100 if (!jstring_to_utf_get(env, folder, &chooser_folder)) { 101 return create_empty_result(); 102 } 103 104 if (!jstring_to_utf_get(env, title, &chooser_title)) { 105 jstring_to_utf_release(env, folder, chooser_folder); 106 return create_empty_result(); 107 } 108 109 if (!jstring_to_utf_get(env, name, &chooser_filename)) { 110 jstring_to_utf_release(env, folder, chooser_folder); 111 jstring_to_utf_release(env, title, chooser_title); 112 return create_empty_result(); 113 } 114 115 GtkWidget* chooser = gtk_file_chooser_dialog_new(chooser_title, gdk_window_handle_to_gtk(parent), 116 static_cast<GtkFileChooserAction>(chooser_type), 117 GTK_STOCK_CANCEL, 118 GTK_RESPONSE_CANCEL, 119 (chooser_type == GTK_FILE_CHOOSER_ACTION_OPEN ? GTK_STOCK_OPEN : GTK_STOCK_SAVE), 120 GTK_RESPONSE_ACCEPT, 121 NULL); 122 123 if (chooser_type == GTK_FILE_CHOOSER_ACTION_SAVE) { 124 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), chooser_filename); 125 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (chooser), TRUE); 126 } 127 128 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), (JNI_TRUE == multiple)); 129 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), chooser_folder); 130 GSList* filters = setup_GtkFileFilters(GTK_FILE_CHOOSER(chooser), env, jFilters, default_filter_index); 131 132 if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { 133 GSList* fnames_gslist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser)); 134 guint fnames_list_len = g_slist_length(fnames_gslist); 135 LOG1("FileChooser selected files: %d\n", fnames_list_len) 136 137 if (fnames_list_len > 0) { 138 jFileNames = env->NewObjectArray((jsize)fnames_list_len, jStringCls, NULL); 139 EXCEPTION_OCCURED(env); 140 for (guint i = 0; i < fnames_list_len; i++) { 141 filename = (char*)g_slist_nth(fnames_gslist, i)->data; 142 LOG1("Add [%s] into returned filenames\n", filename) 143 jfilename = env->NewStringUTF(filename); 144 EXCEPTION_OCCURED(env); 145 env->SetObjectArrayElement(jFileNames, (jsize)i, jfilename); 146 EXCEPTION_OCCURED(env); 147 } 148 g_slist_foreach(fnames_gslist, (GFunc) free_fname, NULL); 149 g_slist_free(fnames_gslist); 150 } 151 } 152 153 if (!jFileNames) { 154 jFileNames = env->NewObjectArray(0, jStringCls, NULL); 155 EXCEPTION_OCCURED(env); 156 } 157 158 int index = g_slist_index(filters, gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser))); 159 160 jclass jCommonDialogs = (jclass) env->FindClass("com/sun/glass/ui/CommonDialogs"); 161 EXCEPTION_OCCURED(env); 162 jmethodID jCreateFileChooserResult = env->GetStaticMethodID(jCommonDialogs, 163 "createFileChooserResult", 164 "([Ljava/lang/String;[Lcom/sun/glass/ui/CommonDialogs$ExtensionFilter;I)Lcom/sun/glass/ui/CommonDialogs$FileChooserResult;"); 165 166 EXCEPTION_OCCURED(env); 167 168 jobject result = 169 env->CallStaticObjectMethod(jCommonDialogs, jCreateFileChooserResult, jFileNames, jFilters, index); 170 LOG_EXCEPTION(env) 171 172 g_slist_free(filters); 173 gtk_widget_destroy(chooser); 174 175 jstring_to_utf_release(env, folder, chooser_folder); 176 jstring_to_utf_release(env, title, chooser_title); 177 jstring_to_utf_release(env, name, chooser_filename); 178 179 LOG_STRING_ARRAY(env, jFileNames); 180 return result; 181 } 182 183 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_gtk_GtkCommonDialogs__1showFolderChooser 184 (JNIEnv *env, jclass clazz, jlong parent, jstring folder, jstring title) { 185 (void)clazz; 186 187 jstring jfilename = NULL; 188 const char *chooser_folder; 189 const char *chooser_title; 190 191 if (!jstring_to_utf_get(env, folder, &chooser_folder)) { 192 return NULL; 193 } 194 195 if (!jstring_to_utf_get(env, title, &chooser_title)) { 196 jstring_to_utf_release(env, folder, chooser_folder); 197 return NULL; 198 } 199 200 GtkWidget* chooser = gtk_file_chooser_dialog_new( 201 chooser_title, 202 gdk_window_handle_to_gtk(parent), 203 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, 204 GTK_STOCK_CANCEL, 205 GTK_RESPONSE_CANCEL, 206 GTK_STOCK_OPEN, 207 GTK_RESPONSE_ACCEPT, 208 NULL); 209 210 if (chooser_folder != NULL) { 211 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), 212 chooser_folder); 213 } 214 215 if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { 216 gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); 217 jfilename = env->NewStringUTF(filename); 218 LOG1("Selected folder: %s\n", filename); 219 g_free(filename); 220 } 221 222 jstring_to_utf_release(env, folder, chooser_folder); 223 jstring_to_utf_release(env, title, chooser_title); 224 225 gtk_widget_destroy(chooser); 226 return jfilename; 227 } 228 229 } // extern "C" 230 231 /** 232 * 233 * @param env 234 * @param extFilters ExtensionFilter[] 235 * @return 236 */ 237 static GSList* setup_GtkFileFilters(GtkFileChooser* chooser, JNIEnv* env, jobjectArray extFilters, int default_filter_index) { 238 int i; 239 LOG0("Setup filters\n") 240 //setup methodIDs 241 jclass jcls = env->FindClass("com/sun/glass/ui/CommonDialogs$ExtensionFilter"); 242 if (EXCEPTION_OCCURED(env)) return NULL; 243 jmethodID jgetDescription = env->GetMethodID(jcls, 244 "getDescription", "()Ljava/lang/String;"); 245 if (EXCEPTION_OCCURED(env)) return NULL; 246 jmethodID jextensionsToArray = env->GetMethodID(jcls, 247 "extensionsToArray", "()[Ljava/lang/String;"); 248 if (EXCEPTION_OCCURED(env)) return NULL; 249 250 jsize jfilters_size = env->GetArrayLength(extFilters); 251 LOG1("Filters: %d\n", jfilters_size) 252 if (jfilters_size == 0) return NULL; 253 254 GSList* filter_list = NULL; 255 256 for(i = 0; i<jfilters_size; i++) { 257 GtkFileFilter* ffilter = gtk_file_filter_new(); 258 jobject jfilter = env->GetObjectArrayElement(extFilters, i); 259 EXCEPTION_OCCURED(env); 260 261 //setup description 262 jstring jdesc = (jstring)env->CallObjectMethod(jfilter, jgetDescription); 263 const char * description = env->GetStringUTFChars(jdesc, NULL); 264 LOG2("description[%d]: %s\n", i, description) 265 gtk_file_filter_set_name(ffilter, (gchar*)const_cast<char*>(description)); 266 env->ReleaseStringUTFChars(jdesc, description); 267 268 //add patterns 269 jobjectArray jextensions = (jobjectArray)env->CallObjectMethod(jfilter, jextensionsToArray); 270 jsize jextarray_size = env->GetArrayLength(jextensions); 271 LOG1("Patterns: %d\n", jextarray_size) 272 int ext_idx; 273 for(ext_idx = 0; ext_idx < jextarray_size; ext_idx++) { 274 jstring jext = (jstring)env->GetObjectArrayElement(jextensions, ext_idx); 275 EXCEPTION_OCCURED(env); 276 const char * ext = env->GetStringUTFChars(jext, NULL); 277 LOG2("pattern[%d]: %s\n", ext_idx, ext) 278 gtk_file_filter_add_pattern(ffilter, (gchar*)const_cast<char*>(ext)); 279 env->ReleaseStringUTFChars(jext, ext); 280 } 281 LOG0("Filter ready\n") 282 gtk_file_chooser_add_filter(chooser, ffilter); 283 284 if (default_filter_index == i) { 285 gtk_file_chooser_set_filter(chooser, ffilter); 286 } 287 288 filter_list = g_slist_append(filter_list, ffilter); 289 } 290 return filter_list; 291 }