jdk/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c
author anthony
Wed, 28 Apr 2010 17:16:05 +0400
changeset 5444 f7c5aeb82a14
child 5759 6d02dbbc2974
permissions -rw-r--r--
6913179: The java.awt.FileDialog should use native GTK file chooser on linux distros Summary: Introduce a GTK-based alternative implementation of the FileDialogPeer on X11 Reviewed-by: anthony, peterz Contributed-by: Costantino Cerbo <c.cerbo@gmail.com>

#include <jni.h>
#include <stdio.h>
#include <jni_util.h>
#include <string.h>
#include "gtk2_interface.h"
#include "sun_awt_X11_GtkFileDialogPeer.h"

static JavaVM *jvm;
static GtkWidget *dialog = NULL;

/* To cache some method IDs */
static jmethodID filenameFilterCallbackMethodID = NULL;
static jmethodID setFileInternalMethodID = NULL;

static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gpointer obj)
{
    JNIEnv *env;
    jclass cx;
    jstring filename;

    env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);

    if (filenameFilterCallbackMethodID == NULL) {
        cx = (*env)->GetObjectClass(env, (jobject) obj);
        if (cx == NULL) {
            JNU_ThrowInternalError(env, "Could not get file filter class");
            return 0;
        }

        filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx,
                "filenameFilterCallback", "(Ljava/lang/String;)Z");
        if (filenameFilterCallbackMethodID == NULL) {
            JNU_ThrowInternalError(env,
                    "Could not get filenameFilterCallback method id");
            return 0;
        }
    }

    filename = (*env)->NewStringUTF(env, filter_info->filename);

    return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID,
            filename);
}

/*
 * Class:     sun_awt_X11_GtkFileDialogPeer
 * Method:    quit
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
(JNIEnv * env, jobject jpeer)
{
    if (dialog != NULL)
    {
        fp_gtk_widget_hide (dialog);
        fp_gtk_widget_destroy (dialog);

        fp_gtk_main_quit ();
        dialog = NULL;
    }
}

/**
 * Convert a GSList to an array of filenames (without the parent folder)
 */
static jobjectArray toFilenamesArray(JNIEnv *env, GSList* list)
{
    jstring str;
    jclass stringCls;
    GSList *iterator;
    jobjectArray array;
    int i;
    char* entry;

    if (NULL == list) {
        return NULL;
    }

    stringCls = (*env)->FindClass(env, "java/lang/String");
    if (stringCls == NULL) {
        JNU_ThrowInternalError(env, "Could not get java.lang.String class");
        return NULL;
    }

    array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls,
            NULL);
    if (array == NULL) {
        JNU_ThrowInternalError(env, "Could not instantiate array files array");
        return NULL;
    }

    i = 0;
    for (iterator = list; iterator; iterator = iterator->next) {
        entry = (char*) iterator->data;
        entry = strrchr(entry, '/') + 1;
        str = (*env)->NewStringUTF(env, entry);
        (*env)->SetObjectArrayElement(env, array, i, str);
        i++;
    }

    return array;
}

static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj)
{
    JNIEnv *env;
    char *current_folder;
    GSList *filenames;
    jclass cx;
    jstring jcurrent_folder;
    jobjectArray jfilenames;

    env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
    current_folder = NULL;
    filenames = NULL;

    if (responseId == GTK_RESPONSE_ACCEPT) {
        current_folder = fp_gtk_file_chooser_get_current_folder(
                GTK_FILE_CHOOSER(dialog));
        filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
    }

    if (setFileInternalMethodID == NULL) {
        cx = (*env)->GetObjectClass(env, (jobject) obj);
        if (cx == NULL) {
            JNU_ThrowInternalError(env, "Could not get GTK peer class");
            return;
        }

        setFileInternalMethodID = (*env)->GetMethodID(env, cx,
                "setFileInternal", "(Ljava/lang/String;[Ljava/lang/String;)V");
        if (setFileInternalMethodID == NULL) {
            JNU_ThrowInternalError(env,
                    "Could not get setFileInternalMethodID method id");
            return;
        }
    }

    jcurrent_folder = (*env)->NewStringUTF(env, current_folder);
    jfilenames = toFilenamesArray(env, filenames);

    (*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jcurrent_folder,
            jfilenames);
    fp_g_free(current_folder);

    Java_sun_awt_X11_GtkFileDialogPeer_quit(NULL, NULL);
}

/*
 * Class:     sun_awt_X11_GtkFileDialogPeer
 * Method:    run
 * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V
 */
JNIEXPORT void JNICALL
Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer,
        jstring jtitle, jint mode, jstring jdir, jstring jfile,
        jobject jfilter, jboolean multiple)
{
    GtkFileFilter *filter;

    if (jvm == NULL) {
        (*env)->GetJavaVM(env, &jvm);
    }

    fp_gdk_threads_init();
    fp_gdk_threads_enter();

    const char *title = (*env)->GetStringUTFChars(env, jtitle, 0);

    if (mode == 1) {
        /* Save action */
        dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
                GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
                GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
    }
    else {
        /* Default action OPEN */
        dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
                GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
                GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);

        /* Set multiple selection mode, that is allowed only in OPEN action */
        if (multiple) {
            fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),
                    multiple);
        }
    }

    (*env)->ReleaseStringUTFChars(env, jtitle, title);

    /* Set the directory */
    if (jdir != NULL) {
        const char *dir = (*env)->GetStringUTFChars(env, jdir, 0);
        fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
        (*env)->ReleaseStringUTFChars(env, jdir, dir);
    }

    /* Set the filename */
    if (jfile != NULL) {
        const char *filename = (*env)->GetStringUTFChars(env, jfile, 0);
        fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
        (*env)->ReleaseStringUTFChars(env, jfile, filename);
    }

    /* Set the file filter */
    if (jfilter != NULL) {
        filter = fp_gtk_file_filter_new();
        fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME,
                filenameFilterCallback, jpeer, NULL);
        fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
    }

    /* Other Properties */
    if (fp_gtk_check_version(2, 8, 0) == NULL) {
        fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(
                dialog), TRUE);
    }

    fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
            handle_response), jpeer);
    fp_gtk_widget_show(dialog);

    fp_gtk_main();
    fp_gdk_threads_leave();
}