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 = glass_file_chooser_dialog( 116 chooser_title, 117 gdk_window_handle_to_gtk(parent), 118 static_cast<GtkFileChooserAction>(chooser_type), 119 (chooser_type == GTK_FILE_CHOOSER_ACTION_OPEN ? GTK_STOCK_OPEN : GTK_STOCK_SAVE) 120 ); 121 122 if (chooser_type == GTK_FILE_CHOOSER_ACTION_SAVE) { 123 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser), chooser_filename); 124 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER (chooser), TRUE); 125 } 126 127 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(chooser), (JNI_TRUE == multiple)); 128 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), chooser_folder); 129 GSList* filters = setup_GtkFileFilters(GTK_FILE_CHOOSER(chooser), env, jFilters, default_filter_index); 130 131 if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { 132 GSList* fnames_gslist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(chooser)); 133 guint fnames_list_len = g_slist_length(fnames_gslist); 134 LOG1("FileChooser selected files: %d\n", fnames_list_len) 135 136 if (fnames_list_len > 0) { 137 jFileNames = env->NewObjectArray((jsize)fnames_list_len, jStringCls, NULL); 138 EXCEPTION_OCCURED(env); 139 for (guint i = 0; i < fnames_list_len; i++) { 140 filename = (char*)g_slist_nth(fnames_gslist, i)->data; 141 LOG1("Add [%s] into returned filenames\n", filename) 142 jfilename = env->NewStringUTF(filename); 143 EXCEPTION_OCCURED(env); 144 env->SetObjectArrayElement(jFileNames, (jsize)i, jfilename); 145 EXCEPTION_OCCURED(env); 146 } 147 g_slist_foreach(fnames_gslist, (GFunc) free_fname, NULL); 148 g_slist_free(fnames_gslist); 149 } 150 } 151 152 if (!jFileNames) { 153 jFileNames = env->NewObjectArray(0, jStringCls, NULL); 154 EXCEPTION_OCCURED(env); 155 } 156 157 int index = g_slist_index(filters, gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser))); 158 159 jclass jCommonDialogs = (jclass) env->FindClass("com/sun/glass/ui/CommonDialogs"); 160 EXCEPTION_OCCURED(env); 161 jmethodID jCreateFileChooserResult = env->GetStaticMethodID(jCommonDialogs, 162 "createFileChooserResult", 163 "([Ljava/lang/String;[Lcom/sun/glass/ui/CommonDialogs$ExtensionFilter;I)Lcom/sun/glass/ui/CommonDialogs$FileChooserResult;"); 164 165 EXCEPTION_OCCURED(env); 166 167 jobject result = 168 env->CallStaticObjectMethod(jCommonDialogs, jCreateFileChooserResult, jFileNames, jFilters, index); 169 LOG_EXCEPTION(env) 170 171 g_slist_free(filters); 172 gtk_widget_destroy(chooser); 173 174 jstring_to_utf_release(env, folder, chooser_folder); 175 jstring_to_utf_release(env, title, chooser_title); 176 jstring_to_utf_release(env, name, chooser_filename); 177 178 LOG_STRING_ARRAY(env, jFileNames); 179 return result; 180 } 181 182 JNIEXPORT jstring JNICALL Java_com_sun_glass_ui_gtk_GtkCommonDialogs__1showFolderChooser 183 (JNIEnv *env, jclass clazz, jlong parent, jstring folder, jstring title) { 184 (void)clazz; 185 186 jstring jfilename = NULL; 187 const char *chooser_folder; 188 const char *chooser_title; 189 190 if (!jstring_to_utf_get(env, folder, &chooser_folder)) { 191 return NULL; 192 } 193 194 if (!jstring_to_utf_get(env, title, &chooser_title)) { 195 jstring_to_utf_release(env, folder, chooser_folder); 196 return NULL; 197 } 198 199 GtkWidget* chooser = glass_file_chooser_dialog( 200 chooser_title, 201 gdk_window_handle_to_gtk(parent), 202 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, 203 GTK_STOCK_OPEN 204 ); 205 206 if (chooser_folder != NULL) { 207 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser), 208 chooser_folder); 209 } 210 211 if (gtk_dialog_run(GTK_DIALOG(chooser)) == GTK_RESPONSE_ACCEPT) { 212 gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser)); 213 jfilename = env->NewStringUTF(filename); 214 LOG1("Selected folder: %s\n", filename); 215 g_free(filename); 216 } 217 218 jstring_to_utf_release(env, folder, chooser_folder); 219 jstring_to_utf_release(env, title, chooser_title); 220 221 gtk_widget_destroy(chooser); 222 return jfilename; 223 } 224 225 } // extern "C" 226 227 /** 228 * 229 * @param env 230 * @param extFilters ExtensionFilter[] 231 * @return 232 */ 233 static GSList* setup_GtkFileFilters(GtkFileChooser* chooser, JNIEnv* env, jobjectArray extFilters, int default_filter_index) { 234 int i; 235 LOG0("Setup filters\n") 236 //setup methodIDs 237 jclass jcls = env->FindClass("com/sun/glass/ui/CommonDialogs$ExtensionFilter"); 238 if (EXCEPTION_OCCURED(env)) return NULL; 239 jmethodID jgetDescription = env->GetMethodID(jcls, 240 "getDescription", "()Ljava/lang/String;"); 241 if (EXCEPTION_OCCURED(env)) return NULL; 242 jmethodID jextensionsToArray = env->GetMethodID(jcls, 243 "extensionsToArray", "()[Ljava/lang/String;"); 244 if (EXCEPTION_OCCURED(env)) return NULL; 245 246 jsize jfilters_size = env->GetArrayLength(extFilters); 247 LOG1("Filters: %d\n", jfilters_size) 248 if (jfilters_size == 0) return NULL; 249 250 GSList* filter_list = NULL; 251 252 for(i = 0; i<jfilters_size; i++) { 253 GtkFileFilter* ffilter = gtk_file_filter_new(); 254 jobject jfilter = env->GetObjectArrayElement(extFilters, i); 255 EXCEPTION_OCCURED(env); 256 257 //setup description 258 jstring jdesc = (jstring)env->CallObjectMethod(jfilter, jgetDescription); 259 const char * description = env->GetStringUTFChars(jdesc, NULL); 260 LOG2("description[%d]: %s\n", i, description) 261 gtk_file_filter_set_name(ffilter, (gchar*)const_cast<char*>(description)); 262 env->ReleaseStringUTFChars(jdesc, description); 263 264 //add patterns 265 jobjectArray jextensions = (jobjectArray)env->CallObjectMethod(jfilter, jextensionsToArray); 266 jsize jextarray_size = env->GetArrayLength(jextensions); 267 LOG1("Patterns: %d\n", jextarray_size) 268 int ext_idx; 269 for(ext_idx = 0; ext_idx < jextarray_size; ext_idx++) { 270 jstring jext = (jstring)env->GetObjectArrayElement(jextensions, ext_idx); 271 EXCEPTION_OCCURED(env); 272 const char * ext = env->GetStringUTFChars(jext, NULL); 273 LOG2("pattern[%d]: %s\n", ext_idx, ext) 274 gtk_file_filter_add_pattern(ffilter, (gchar*)const_cast<char*>(ext)); 275 env->ReleaseStringUTFChars(jext, ext); 276 } 277 LOG0("Filter ready\n") 278 gtk_file_chooser_add_filter(chooser, ffilter); 279 280 if (default_filter_index == i) { 281 gtk_file_chooser_set_filter(chooser, ffilter); 282 } 283 284 filter_list = g_slist_append(filter_list, ffilter); 285 } 286 return filter_list; 287 }