1 #include <jni.h>
   2 #include <stdio.h>
   3 #include <jni_util.h>
   4 #include <string.h>
   5 #include "gtk2_interface.h"
   6 #include "sun_awt_X11_GtkFileDialogPeer.h"
   7 
   8 static JavaVM *jvm;
   9 static GtkWidget *dialog = NULL;
  10 
  11 /* To cache some method IDs */
  12 static jmethodID filenameFilterCallbackMethodID = NULL;
  13 static jmethodID setFileInternalMethodID = NULL;
  14 
  15 static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info,
  16                 gpointer obj)
  17 {
  18         JNIEnv *env;
  19         jclass cx;
  20         jstring filename;
  21 
  22         env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
  23 
  24         if (filenameFilterCallbackMethodID == NULL)
  25         {
  26                 cx = (*env)->GetObjectClass(env, (jobject) obj);
  27                 if (cx == NULL)
  28                 {
  29                         JNU_ThrowInternalError(env, "Could not get file filter class");
  30                         return 0;
  31                 }
  32 
  33                 filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx,
  34                                 "filenameFilterCallback", "(Ljava/lang/String;)Z");
  35                 if (filenameFilterCallbackMethodID == NULL)
  36                 {
  37                         JNU_ThrowInternalError(env,
  38                                         "Could not get filenameFilterCallback method id");
  39                         return 0;
  40                 }
  41         }
  42 
  43         filename = (*env)->NewStringUTF(env, filter_info->filename);
  44 
  45         return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID,
  46                         filename);
  47 }
  48 
  49 static void unlocked_quit(void)
  50 {
  51         if (dialog != NULL)
  52         {
  53                 fp_gtk_widget_hide (dialog);
  54                 fp_gtk_widget_destroy (dialog);
  55 
  56                 fp_gtk_main_quit ();
  57                 dialog = NULL;
  58         }
  59 }
  60 
  61 /*
  62  * Class:     sun_awt_X11_GtkFileDialogPeer
  63  * Method:    quit
  64  * Signature: ()V
  65  */
  66 JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
  67 (JNIEnv * env, jobject jpeer)
  68 {
  69         fp_gdk_threads_enter();
  70         unlocked_quit();
  71         fp_gdk_threads_leave();
  72 }
  73 
  74 /**
  75  * Convert a GSList to an array of filenames (without the parent folder)
  76  */
  77 static jobjectArray toFilenamesArray(JNIEnv *env, GSList* list)
  78 {
  79         jstring str;
  80         jclass stringCls;
  81         GSList *iterator;
  82         jobjectArray array;
  83         int i;
  84         char* entry;
  85 
  86         if (NULL == list)
  87         {
  88                 return NULL;
  89         }
  90 
  91         stringCls = (*env)->FindClass(env, "java/lang/String");
  92         if (stringCls == NULL)
  93         {
  94                 JNU_ThrowInternalError(env, "Could not get java.lang.String class");
  95                 return NULL;
  96         }
  97 
  98         array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls,
  99                         NULL);
 100         if (array == NULL)
 101         {
 102                 JNU_ThrowInternalError(env, "Could not instantiate array files array");
 103                 return NULL;
 104         }
 105 
 106         i = 0;
 107         for (iterator = list; iterator; iterator = iterator->next)
 108         {
 109                 entry = (char*) iterator->data;
 110                 entry = strrchr(entry, '/') + 1;
 111                 str = (*env)->NewStringUTF(env, entry);
 112                 (*env)->SetObjectArrayElement(env, array, i, str);
 113                 i++;
 114         }
 115 
 116         return array;
 117 }
 118 
 119 static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj)
 120 {
 121         JNIEnv *env;
 122         char *current_folder;
 123         GSList *filenames;
 124         jclass cx;
 125         jstring jcurrent_folder;
 126         jobjectArray jfilenames;
 127 
 128         env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
 129         current_folder = NULL;
 130         filenames = NULL;
 131 
 132         if (responseId == GTK_RESPONSE_ACCEPT)
 133         {
 134                 current_folder = fp_gtk_file_chooser_get_current_folder(
 135                                 GTK_FILE_CHOOSER(dialog));
 136                 filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
 137         }
 138 
 139         if (setFileInternalMethodID == NULL)
 140         {
 141                 cx = (*env)->GetObjectClass(env, (jobject) obj);
 142                 if (cx == NULL)
 143                 {
 144                         JNU_ThrowInternalError(env, "Could not get GTK peer class");
 145                         return;
 146                 }
 147 
 148                 setFileInternalMethodID = (*env)->GetMethodID(env, cx,
 149                                 "setFileInternal", "(Ljava/lang/String;[Ljava/lang/String;)V");
 150                 if (setFileInternalMethodID == NULL)
 151                 {
 152                         JNU_ThrowInternalError(env,
 153                                         "Could not get setFileInternalMethodID method id");
 154                         return;
 155                 }
 156         }
 157 
 158         jcurrent_folder = (*env)->NewStringUTF(env, current_folder);
 159         jfilenames = toFilenamesArray(env, filenames);
 160 
 161         (*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jcurrent_folder,
 162                         jfilenames);
 163         fp_g_free(current_folder);
 164 
 165         unlocked_quit();
 166 }
 167 
 168 /*
 169  * Class:     sun_awt_X11_GtkFileDialogPeer
 170  * Method:    run
 171  * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V
 172  */
 173 JNIEXPORT void JNICALL
 174 Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer,
 175                 jstring jtitle, jint mode, jstring jdir, jstring jfile,
 176                 jobject jfilter, jboolean multiple)
 177 {
 178         GtkFileFilter *filter;
 179 
 180         if (jvm == NULL)
 181         {
 182                 (*env)->GetJavaVM(env, &jvm);
 183         }
 184 
 185         fp_gdk_threads_init();
 186         fp_gdk_threads_enter();
 187 
 188         const char *title = (*env)->GetStringUTFChars(env, jtitle, 0);
 189 
 190         if (mode == 1)
 191         {
 192                 /* Save action */
 193                 dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
 194                                 GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
 195                                 GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
 196         }
 197         else
 198         {
 199                 /* Default action OPEN */
 200                 dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
 201                                 GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
 202                                 GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
 203 
 204                 /* Set multiple selection mode, that is allowed only in OPEN action */
 205                 if (multiple)
 206                 {
 207                         fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),
 208                                         multiple);
 209                 }
 210         }
 211 
 212         (*env)->ReleaseStringUTFChars(env, jtitle, title);
 213 
 214         /* Set the directory */
 215         if (jdir != NULL)
 216         {
 217                 const char *dir = (*env)->GetStringUTFChars(env, jdir, 0);
 218                 fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
 219                 (*env)->ReleaseStringUTFChars(env, jdir, dir);
 220         }
 221 
 222         /* Set the filename */
 223         if (jfile != NULL)
 224         {
 225                 const char *filename = (*env)->GetStringUTFChars(env, jfile, 0);
 226                 fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
 227                 (*env)->ReleaseStringUTFChars(env, jfile, filename);
 228         }
 229 
 230         /* Set the file filter */
 231         if (jfilter != NULL)
 232         {
 233                 filter = fp_gtk_file_filter_new();
 234                 fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME,
 235                                 filenameFilterCallback, jpeer, NULL);
 236                 fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
 237         }
 238 
 239         /* Other Properties */
 240         if (fp_gtk_check_version(2, 8, 0) == NULL)
 241         {
 242                 fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(
 243                                 dialog), TRUE);
 244         }
 245 
 246         fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
 247                         handle_response), jpeer);
 248         fp_gtk_widget_show(dialog);
 249 
 250         fp_gtk_main();
 251         fp_gdk_threads_leave();
 252 }