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