This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Modal FileDialog implementation.


For the record, this was the patch checked in with Tom Tromey's and Tom Fitzsimmon's suggestions/requests.


-- Fernando Nasser Red Hat Canada Ltd. E-Mail: fnasser@redhat.com 2323 Yonge Street, Suite #300 Toronto, Ontario M4P 2C9
? .snprj
? DIFF
? DIFF2
? libjava.proj
? gnu/java/awt/peer/gtk/TestAWT
Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/libjava/ChangeLog,v
retrieving revision 1.2532
diff -c -p -r1.2532 ChangeLog
*** ChangeLog	8 Jan 2004 09:46:49 -0000	1.2532
--- ChangeLog	8 Jan 2004 21:11:46 -0000
***************
*** 1,3 ****
--- 1,33 ----
+ 2004-01-08  Fernando Nasser  <fnasser@redhat.com>
+ 
+ 	* gnu/java/awt/peer/gtk/GtkFileDialogPeer.java (nativeSetFile):
+ 	New name for the former setFile native method.
+ 	(setFile): New method.
+ 	(setDirectory): Implemented.
+ 	(connectSignals): New native method.
+ 	(setFilenameFilter): Improve comment.
+ 	(getGraphics): Comment.
+ 	(gtkHideFileDialog): New method.
+ 	(gtkDisposeFileDialog): New method.
+ 	(gtkSetFilename): New method.
+ 	* java/awt/Dialog.java (show): Block on modal dialogs, but only
+ 	for FileDialog for now.
+ 	(hide): New method.
+ 	(dispose): New method.
+ 	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
+ 	(Java_gnu_java_awt_peer_gtk_GtkFileDialog_create): Replace
+ 	deprecated creation functions.  Make dialog modal.  Add it to the
+ 	window group.
+ 	(Java_gnu_java_awt_peer_gtk_GtkFileDialog_connectSignals): New
+ 	function.
+ 	(Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename):
+ 	Rename to...
+ 	(Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFile): New
+ 	name.
+ 	(window_closed): New function.
+ 	(ok_clicked): New function.
+ 	(cancel_clicked): New function.
+ 
  2004-01-08  Michael Koch  <konqueror@gmx.de>
  
  	* javax/swing/JLayeredPane.java: Revert changes to standard
Index: gnu/java/awt/peer/gtk/GtkFileDialogPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java,v
retrieving revision 1.3
diff -c -p -r1.3 GtkFileDialogPeer.java
*** gnu/java/awt/peer/gtk/GtkFileDialogPeer.java	11 Dec 2003 13:50:50 -0000	1.3
--- gnu/java/awt/peer/gtk/GtkFileDialogPeer.java	8 Jan 2004 21:11:46 -0000
*************** exception statement from your version. *
*** 38,50 ****
--- 38,58 ----
  
  package gnu.java.awt.peer.gtk;
  
+ import java.awt.AWTEvent;
+ import java.awt.Dialog;
  import java.awt.FileDialog;
  import java.awt.Graphics;
+ import java.awt.event.WindowEvent;
  import java.awt.peer.FileDialogPeer;
  import java.io.FilenameFilter;
  
  public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer
  {
+   static final String FS = System.getProperty("file.separator");
+   
+   private String currentFile = null;
+   private String currentDirectory = null;
+ 
    native void create ();
  
    public GtkFileDialogPeer (FileDialog fd)
*************** public class GtkFileDialogPeer extends G
*** 52,72 ****
      super (fd);
    }
  
!   public void setDirectory (String directory)
    {
!     setFile (directory);
    }
  
!   public native void setFile (String file);
!   public native void connectJObject ();
  
    public void setFilenameFilter (FilenameFilter filter)
    {
!     /* GTK has no filters. */
    }
  
    public Graphics getGraphics ()
    {
      return null;
    }
  }
--- 60,193 ----
      super (fd);
    }
  
!   native void connectJObject ();
!   native void connectSignals ();
!   native void nativeSetFile (String file);
! 
!   public void setFile (String fileName)
    {
!     /* If nothing changed do nothing.  This usually happens because
!        the only way we have to set the file name in FileDialog is by
!        calling its SetFile which will call us back. */
!     if ((fileName == null && currentFile == null)
!         || (fileName != null && fileName.equals (currentFile)))
!       return;
! 
!     if (fileName == null || fileName.equals (""))
!       {
!         currentFile = "";
!         nativeSetFile ("");
!         return;
!       }
! 
!     // Remove any directory path from the filename
!     int sepIndex = fileName.lastIndexOf (FS);
!     if (sepIndex < 0)
!       {
!         currentFile = fileName;
!         nativeSetFile (fileName);
!       }
!     else
!       {
!         if (fileName.length() > (sepIndex + 1))
! 	  {
! 	    String fn = fileName.substring (sepIndex + 1);
!             currentFile = fn;
!             nativeSetFile (fn);
! 	  }
! 	else
! 	  {
!             currentFile = "";
!             nativeSetFile ("");
! 	  }
!       }
    }
  
!   public void setDirectory (String directory)
!   {
!     /* If nothing changed so nothing.  This usually happens because
!        the only way we have to set the directory in FileDialog is by
!        calling its setDirectory which will call us back. */
!     if ((directory == null && currentDirectory == null)
!         || (directory != null && directory.equals (currentDirectory)))
!       return;
! 
!     if (directory == null || directory.equals (""))
!       {
!         currentDirectory = FS;
!         nativeSetFile (FS);
! 	return;
!       }
!       
!     currentDirectory = directory;
! 
!     // Gtk expects the directory to end with a file separator
!     if (directory.substring (directory.length () - 1).equals (FS))
!       nativeSetFile (directory);
!     else
!       nativeSetFile (directory + FS);
!   }
  
    public void setFilenameFilter (FilenameFilter filter)
    {
!     /* GTK has no filter callbacks yet.  It works by setting a pattern
!      * (see gtk_file_selection_complete), which we can't convert
!      * to the callback paradigm. With GTK-2.4 there will be a
!      * gtk_file_filter_add_custom function that we can use. */
    }
  
    public Graphics getGraphics ()
    {
+     // GtkFileDialog will repaint by itself
      return null;
+   }
+   
+   void gtkHideFileDialog () 
+   {
+     ((Dialog) awtComponent).hide();
+   }
+   
+   void gtkDisposeFileDialog () 
+   {
+     ((Dialog) awtComponent).dispose();
+   }
+ 
+   /* Callback to set the file and directory values when the user is finished
+    * with the dialog.
+    */
+   void gtkSetFilename (String fileName)
+   {
+     FileDialog fd = (FileDialog) awtWidget;
+     if (fileName == null)
+       {
+         currentFile = null;
+         fd.setFile(null);
+         return;
+       }
+ 
+     int sepIndex = fileName.lastIndexOf (FS);
+     if (sepIndex < 0)
+       {
+         /* This should never happen on Unix (all paths start with '/') */
+ 	currentFile = fileName;
+       }
+     else
+       {
+         if (fileName.length() > (sepIndex + 1))
+ 	  {
+ 	    String fn = fileName.substring (sepIndex + 1);
+ 	    currentFile = fn;
+ 	  }
+ 	else
+ 	  {
+             currentFile = null;
+ 	  }
+ 
+         String dn = fileName.substring (0, sepIndex + 1);
+         currentDirectory = dn;
+         fd.setDirectory(dn);
+       }
+ 
+     fd.setFile (currentFile);
    }
  }
Index: java/awt/Dialog.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Dialog.java,v
retrieving revision 1.11
diff -c -p -r1.11 Dialog.java
*** java/awt/Dialog.java	5 Jan 2004 21:23:12 -0000	1.11
--- java/awt/Dialog.java	8 Jan 2004 21:11:46 -0000
*************** private boolean resizable = true;
*** 78,87 ****
    */
  private String title;
  
!   /**
!    * This field indicates whether the dialog is undecorated or not.
!    */
!   private boolean undecorated = false;
  
  /*************************************************************************/
  
--- 78,92 ----
    */
  private String title;
  
! /**
!   * This field indicates whether the dialog is undecorated or not.
!   */
! private boolean undecorated = false;
! 
! /**
!   * Indicates that we are blocked for modality in show
!   */
! private boolean blocked = false;
  
  /*************************************************************************/
  
*************** addNotify()
*** 380,390 ****
  
  /**
    * Makes this dialog visible and brings it to the front.
    */
! public void
  show()
  {
    super.show();
  }
  
  /*************************************************************************/
--- 385,462 ----
  
  /**
    * Makes this dialog visible and brings it to the front.
+   * If the dialog is modal and is not already visible, this call will not
+   *  return until the dialog is hidden by someone calling hide or dispose.
+   * If this is the event dispatching thread we must ensure that another event
+   *  thread runs while the one which invoked this method is blocked. 
    */
! public synchronized void
  show()
  {
    super.show();
+   if (isModal())
+     {
+       // If already shown (and blocked) just return
+       if (blocked)
+ 	return;
+ 
+       /* FIXME: Currently this thread may block forever if it called from
+          the event dispatch thread, so we only do this for FileDialog which
+          only depends on a signal which is delivered in the Gtk thread.
+          Remove this test when we add code to start another event
+          dispatch thread. */
+       if ((Thread.currentThread () instanceof EventDispatchThread) &&
+           !(this instanceof FileDialog))
+         return;
+       
+       try 
+         {
+ 	  blocked = true;
+ 	  wait ();
+ 	  blocked = false;
+         } 
+       catch (InterruptedException e)
+         {
+ 	  blocked = false;
+ 	  return;
+         }
+     }  
+ }
+ 
+ /*************************************************************************/
+ 
+ /**
+   * Hides the Dialog and then
+   * causes show() to return if it is currently blocked.
+   */
+ 
+ public synchronized void 
+ hide ()
+ {
+   if (blocked)
+     {
+       notifyAll ();
+     }
+ 
+   super.hide();
+ }
+ 
+ /*************************************************************************/
+ 
+ /**
+   * Disposes the Dialog and then causes show() to return
+   * if it is currently blocked.
+   */
+ 
+ public synchronized void 
+ dispose ()
+ {
+   if (blocked)
+     {
+       notifyAll ();
+     }
+ 
+   super.dispose();
  }
  
  /*************************************************************************/
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c,v
retrieving revision 1.3
diff -c -p -r1.3 gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
*** jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c	13 Dec 2003 01:15:47 -0000	1.3
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c	8 Jan 2004 21:11:47 -0000
*************** exception statement from your version. *
*** 37,44 ****
--- 37,53 ----
  
  
  #include "gtkpeer.h"
+ #include "gnu_java_awt_peer_gtk_GtkComponentPeer.h"
  #include "gnu_java_awt_peer_gtk_GtkFileDialogPeer.h"
  
+ static void window_closed (GtkDialog *dialog,
+                            gint responseId,
+                            jobject peer_obj);
+ static void ok_clicked (GtkButton *button,
+ 	                jobject peer_obj);
+ static void cancel_clicked (GtkButton *button,
+ 	                    jobject peer_obj);
+ 
  /*
   * Make a new file selection dialog
   */
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 54,60 ****
  
    gdk_threads_enter ();
    
!   widget = gtk_type_new (gtk_file_selection_get_type ());
  
    gdk_threads_leave ();
  
--- 63,75 ----
  
    gdk_threads_enter ();
    
!   widget = gtk_file_selection_new ("");
!   /* GtkFileSelect is not modal by default */
!   gtk_window_set_modal (GTK_WINDOW (widget), TRUE);
! 
!   /* We must add this window to the group so input in the others are
!      disable while it is being shown */
!   gtk_window_group_add_window (global_gtk_window_group, GTK_WINDOW (widget));
  
    gdk_threads_leave ();
  
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 76,87 ****
    gdk_threads_leave ();
  }
  
  /*
   * Set the filename in the file selection dialog.
   */
  
  JNIEXPORT void JNICALL 
! Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename 
      (JNIEnv *env, jobject obj, jstring filename)
  {
    void *ptr;
--- 91,134 ----
    gdk_threads_leave ();
  }
  
+ JNIEXPORT void JNICALL 
+ Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_connectSignals
+   (JNIEnv *env, jobject obj)
+ {
+   void *ptr = NSA_GET_PTR (env, obj);
+   jobject *gref = NSA_GET_GLOBAL_REF (env, obj);
+   g_assert (gref);
+ 
+   gdk_threads_enter ();
+ 
+   gtk_widget_realize (GTK_WIDGET (ptr));
+ 
+   /* connect buttons to handlers */
+ 
+   g_signal_connect (G_OBJECT (GTK_DIALOG (ptr)),
+                     "response", 
+ 		    GTK_SIGNAL_FUNC (window_closed), *gref);
+ 
+   g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (ptr)->ok_button),
+                     "clicked", 
+ 		    GTK_SIGNAL_FUNC (ok_clicked), *gref);
+ 
+   g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (ptr)->cancel_button),
+                     "clicked", 
+ 		    GTK_SIGNAL_FUNC (cancel_clicked), *gref);
+ 		    
+   gdk_threads_leave ();
+ 
+   /* Connect the superclass signals.  */
+   Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals (env, obj);
+ }
+ 
  /*
   * Set the filename in the file selection dialog.
   */
  
  JNIEXPORT void JNICALL 
! Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFile 
      (JNIEnv *env, jobject obj, jstring filename)
  {
    void *ptr;
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 89,97 ****
  
    ptr = NSA_GET_PTR (env, obj);
      
!   str = (*env)->GetStringUTFChars (env, filename, 0);      
    gdk_threads_enter ();
    gtk_file_selection_set_filename (GTK_FILE_SELECTION (ptr), str);
    gdk_threads_leave ();
    (*env)->ReleaseStringUTFChars (env, filename, str);
  }
--- 136,247 ----
  
    ptr = NSA_GET_PTR (env, obj);
      
!   str = (*env)->GetStringUTFChars (env, filename, 0);
!      
    gdk_threads_enter ();
+ 
    gtk_file_selection_set_filename (GTK_FILE_SELECTION (ptr), str);
+ 
    gdk_threads_leave ();
+ 
    (*env)->ReleaseStringUTFChars (env, filename, str);
  }
+ 
+ static void
+ window_closed (GtkDialog *dialog __attribute__((unused)),
+                gint responseId,
+                jobject peer_obj)
+ {
+   static int isIDSet = 0;
+   static jmethodID disposeID;
+   void *ptr;
+ 
+   // We only need this for the case when the user closed the window
+   if (responseId != GTK_RESPONSE_DELETE_EVENT)
+     return;
+ 
+   ptr = NSA_GET_PTR (gdk_env, peer_obj);
+   
+   if (!isIDSet)
+     {
+       jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj);
+       disposeID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkDisposeFileDialog", "()V");
+       isIDSet = 1;
+     }
+     
+   gdk_threads_leave ();
+ 
+   /* We can dispose of the dialog now (and unblock show) */
+   (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, disposeID);
+ 
+   gdk_threads_enter ();
+ }
+ 
+ static void
+ ok_clicked (GtkButton *button __attribute__((unused)),
+ 	                jobject peer_obj)
+ {
+   static int isIDSet = 0;
+   static jmethodID gtkSetFilenameID;
+   static jmethodID hideID;
+   void *ptr;
+   G_CONST_RETURN gchar *fileName;
+ 
+   ptr = NSA_GET_PTR (gdk_env, peer_obj);
+   
+   fileName = gtk_file_selection_get_filename (
+                GTK_FILE_SELECTION (GTK_WIDGET (ptr)));
+   
+   if (!isIDSet)
+     {
+       jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj);
+       hideID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkHideFileDialog", "()V");
+       gtkSetFilenameID = (*gdk_env)->GetMethodID (gdk_env, cx,
+                                    "gtkSetFilename", "(Ljava.lang.String;)V");
+       isIDSet = 1;
+     }
+     
+   gdk_threads_leave ();
+   
+   /* Set the Java object field 'file' with this value. */
+   jstring str_fileName = (*gdk_env)->NewStringUTF (gdk_env, fileName);
+   (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, gtkSetFilenameID, str_fileName);
+ 
+   /* We can hide the dialog now (and unblock show) */
+   (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, hideID);
+ 
+   gdk_threads_enter ();
+ }
+ 
+ static void
+ cancel_clicked (GtkButton *button __attribute__((unused)),
+ 	                    jobject peer_obj)
+ {
+   static int isIDSet = 0;
+   static jmethodID gtkSetFilenameID;
+   static jmethodID hideID;
+   void *ptr;
+ 
+   ptr = NSA_GET_PTR (gdk_env, peer_obj);
+   
+   if (!isIDSet)
+     {
+       jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj);
+       hideID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkHideFileDialog", "()V");
+       gtkSetFilenameID = (*gdk_env)->GetMethodID (gdk_env, cx,
+                                    "gtkSetFilename", "(Ljava.lang.String;)V");
+       isIDSet = 1;
+     }
+     
+   gdk_threads_leave ();
+ 
+   /* Set the Java object field 'file' with the null value. */
+   (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, gtkSetFilenameID, NULL);
+ 
+   /* We can hide the dialog now (and unblock show) */
+   (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, hideID);
+ 
+   gdk_threads_enter ();
+ }
+ 
+ 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]