]> git.rm.cloudns.org Git - xonotic/netradiant.git/commitdiff
This is a big big GTK file dialog change in Rambetter-temp-fixes branch.
authorrambetter <rambetter>
Sun, 19 Dec 2010 03:44:26 +0000 (03:44 +0000)
committerrambetter <rambetter>
Sun, 19 Dec 2010 03:44:26 +0000 (03:44 +0000)
Thank you to Markus Fischer who provided some example code on how to
use the "new" method of GTK file dialogs.  I then did a lot of research into
how to shape his code into exactly what I wanted.

This is an incomplete change in that I have not cleaned up the code such
as removing unused local variables and unused functions yet.  However, I
wanted to commit this now because it really works beautifully (the GTK file
dialog that is).

- In CFileType, m_pstrGTKMasks now contains string like
"quake3 maps (*.map)" instead of like "quake3 maps <*.map>".  Nobody else
is using this code except in gtkmisc.cpp so it's a safe change.

- Removing all FILEDLG_DBG blocks in gtkmisc.cpp.  It really clutters up the
code and since it's completely overhauled, it's OK to remove.

- Instead of the "old" way of gtk_file_selection_new(), now using
gtk_file_chooser_dialog_new() instead.  Thx to Markus Fischer for examples.

- Actually adding GTK file dialog filters.  It works really nice!  :-)

- Now using the same file extension logic on Windows file dialogs and GTK
file dialogs.

- Improved file extension logic.  "No file extension specified in file to
be saved.  Attempt to save anyways?"

Tested on Win7 and Linux.
More related changes on the way.

THIS SHOULD BE MERGED INTO TRUNK.

git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/Rambetter-temp-fixes@355 8a3a26a2-13c4-0310-b231-cf6edde360e5

radiant/gtkmisc.cpp

index dbcd3633caf966eed845038958614860c25585b5..9d584f43247bd93f6cc15be16da3a3ee7e29c80b 100644 (file)
@@ -1025,8 +1025,6 @@ int WINAPI gtk_MessageBox (void *parent, const char* lpText, const char* lpCapti
 
 // fenris #3078 WHENHELLISFROZENOVER
 
-//#define FILEDLG_DBG
-
 static void file_sel_callback (GtkWidget *widget, gpointer data)
 {
   GtkWidget *parent;
@@ -1040,11 +1038,6 @@ static void file_sel_callback (GtkWidget *widget, gpointer data)
   if (GPOINTER_TO_INT (data) == IDOK)
     *success = true;
 
-#ifdef FILEDLG_DBG
-  else
-    Sys_Printf("file_sel_callback != IDOK\n");
-#endif
-
   *loop = 0;
 }
 
@@ -1197,10 +1190,10 @@ private:
       for(r = m_pTypes[i].m_name.c_str(); *r!='\0'; r++, w++)
         *w = *r;
       *w++ = ' ';
-      *w++ = '<';
+      *w++ = '(';
       for(r = m_pTypes[i].m_pattern.c_str(); *r!='\0'; r++, w++)
         *w = *r;
-      *w++ = '>';
+      *w++ = ')';
       *w++ = '\0';
     }
     m_pstrGTKMasks[m_nTypes] = NULL;
@@ -1253,31 +1246,15 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
   char *new_path = NULL;
 
   const char* r;
-  charw;
+  char *v, *w;
   filetype_t type;
   CFileType typelist;
   if(pattern != NULL)
     GetFileTypeRegistry()->getTypeList(pattern, &typelist);
 
-#ifdef FILEDLG_DBG
-  Sys_Printf("file_dialog: open = %d title = %s path = %s\n", open, title, path);
-  if (pattern)
-  {
-    Sys_Printf("Patterns:\n");
-    char** p = typelist.m_pstrGTKMasks;
-    while(*p!=NULL)
-      Sys_Printf("%s\n", *p++);
-  }
-  else
-    Sys_Printf("no patterns\n");
-#endif
-
 #ifdef _WIN32
   if (g_PrefsDlg.m_bNativeGUI)
   {
-#ifdef FILEDLG_DBG
-    Sys_Printf("Doing win32 file dialog...");
-#endif
     // do that the native way
 
     if (in_file_dialog) return NULL; // Avoid recursive entry.
@@ -1354,9 +1331,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
     if(pattern != NULL)
       type = typelist.GetTypeForIndex(ofn.nFilterIndex - 1);
 
-#ifdef FILEDLG_DBG
-    Sys_Printf("Done.\n");
-#endif
   }
   else
   {
@@ -1366,9 +1340,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
     if (title == NULL)
       title = open ? _("Open File") : _("Save File");
 
-#ifdef FILEDLG_DBG
-    Sys_Printf("Doing Gtk file dialog:\nBuilding new_path..");
-#endif
     // we expect an actual path below, if the path is NULL we might crash
     if (!path || path[0] == '\0')
     {
@@ -1390,101 +1361,51 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
     // terminate string
     *w = '\0';
 
-#ifdef FILEDLG_DBG
-       Sys_Printf("Done.\n");
-       Sys_Printf("Calling gtk_file_selection_new with title: %s...", title);
-#endif
-    file_sel = gtk_file_selection_new (title);
-#ifdef FILEDLG_DBG
-       Sys_Printf("Done.\n");
-       Sys_Printf("Set the masks...");
-#endif
-
-#if 0 //!\todo Add masks to GtkFileSelection in gtk-2.0
-    // set the masks
-    if (pattern)
-    {
-      gtk_file_selection_clear_masks (GTK_FILE_SELECTION (file_sel));
-      gtk_file_selection_set_masks (GTK_FILE_SELECTION (file_sel), const_cast<const char**>(typelist.m_pstrGTKMasks));
+    file_sel = gtk_file_chooser_dialog_new(title,
+                                           GTK_WINDOW(parent),
+                                           open ? GTK_FILE_CHOOSER_ACTION_OPEN : GTK_FILE_CHOOSER_ACTION_SAVE,
+                                           GTK_STOCK_CANCEL,
+                                           GTK_RESPONSE_CANCEL,
+                                           open ? GTK_STOCK_OPEN : GTK_STOCK_SAVE,
+                                           GTK_RESPONSE_ACCEPT,
+                                           NULL);
+    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_sel), new_path);
+    delete[] new_path;
+
+    // Setting the file chooser dialog to modal and centering it on the parent is done automatically.
+
+    if (pattern != NULL) {
+      for (int i = 0; i < typelist.GetNumTypes(); i++) {
+        GtkFileFilter *filter = gtk_file_filter_new();
+        type = typelist.GetTypeForIndex(i);
+        // We can use type.name here, or m_pstrGTKMasks[i], which includes the actual pattern.
+        gtk_file_filter_set_name(filter, typelist.m_pstrGTKMasks[i]);
+        gtk_file_filter_add_pattern(filter, type.pattern);
+        // "Note that the chooser takes ownership of the filter, so
+        // you have to ref and sink it if you want to keep a reference."
+        // So I guess we won't need to garbage collect this.
+        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(file_sel), filter);
+      }
     }
-#endif
-
-#ifdef FILEDLG_DBG
-    Sys_Printf("Done.\n");
-#endif
-
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked",
-      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK));
-    gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked",
-      GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL));
-    gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event",
-      GTK_SIGNAL_FUNC (dialog_delete_callback), NULL);
-    gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel));
-
-    if (parent != NULL)
-      gtk_window_set_transient_for (GTK_WINDOW (file_sel), GTK_WINDOW (parent));
-
-#ifdef FILEDLG_DBG
-    Sys_Printf("set_data...");
-#endif
-    bool success = false;
-    g_object_set_data (G_OBJECT (file_sel), "loop", &loop);
-    g_object_set_data (G_OBJECT (file_sel), "success", &success);
-#ifdef FILEDLG_DBG
-    Sys_Printf("Done.\n");
-#endif
 
-    if (!open)
-    {
-#ifdef FILEDLG_DBG
-      Sys_Printf("set_data \"overwrite\" ...");
-#endif
-      g_object_set_data (G_OBJECT (file_sel), "overwrite", GINT_TO_POINTER (1));
-#ifdef FILEDLG_DBG
-      Sys_Printf("Done.\n");
-#endif
+    if (gtk_dialog_run(GTK_DIALOG(file_sel)) == GTK_RESPONSE_ACCEPT) {
+      strcpy(szFile, gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(file_sel)));
     }
-
-    if (new_path != NULL)
-    {
-#ifdef FILEDLG_DBG
-      Sys_Printf("gtk_file_selection_set_filename... %p (%s)", file_sel, new_path);
-#endif
-      gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), new_path);
-      delete[] new_path;
-#ifdef FILEDLG_DBG
-      Sys_Printf("Done.\n");
-#endif
+    else {
+      szFile[0] = '\0';
     }
 
-    gtk_grab_add (file_sel);
-#ifdef FILEDLG_DBG
-    Sys_Printf("gtk_widget_show... %p", file_sel);
-#endif
-    gtk_widget_show (file_sel);
-#ifdef FILEDLG_DBG
-    Sys_Printf("Done.\n");
-#endif
-
-#ifdef FILEDLG_DBG
-    Sys_Printf("gtk_main_iteration...");
-#endif
-    while (loop)
-      gtk_main_iteration ();
-    if(success)
-    {
-#if 0 //!\todo Add masks to GtkFileSelection in gtk2
-      if(pattern!=NULL)
-        type = typelist.GetTypeForGTKMask(GTK_FILE_SELECTION (file_sel)->mask);
-#endif
-      strcpy(szFile, gtk_file_selection_get_filename (GTK_FILE_SELECTION (file_sel)));
+    if (pattern != NULL) {
+      GtkFileFilter *filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(file_sel));
+      if (filter == NULL) {
+        type = filetype_t();
+      }
+      else {
+        type = typelist.GetTypeForGTKMask(gtk_file_filter_get_name(filter));
+      }
     }
-#ifdef FILEDLG_DBG
-    Sys_Printf("Done.\n");
-#endif
+    gtk_widget_destroy(file_sel);
 
-    gtk_grab_remove (file_sel);
-    gtk_widget_destroy (file_sel);
 #ifdef _WIN32
   }
 #endif
@@ -1497,37 +1418,42 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
     if(*w=='\\')
       *w = '/';
 
-#if defined(WIN32)
-  if (g_PrefsDlg.m_bNativeGUI)
-  {
-    /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
-    if(!open && pattern != NULL)
-    {
-      // last ext separator
-      w = strrchr(szFile, '.');
-      if (w == NULL) { // No extension.
+  /* \todo SPoG - file_dialog should return filetype information separately.. not force file extension.. */
+  if(!open && pattern != NULL) {
+    v = strrchr(szFile, '/');
+    w = strrchr(szFile, '.');
+    if ((v && w && w < v) || // Last '.' is before the file.
+        w == NULL) { // Extension missing.
+      if (type.pattern[0]) {
         w = szFile + strlen(szFile);
         strcpy(w, type.pattern + 1); // Add extension of selected filter type.
       }
-      else { // An extension was explicitly in the filename.
-        int knownExtension = 0;
-        for (int i = typelist.GetNumTypes() - 1; i >= 0; i--) {
-          type = typelist.GetTypeForIndex(i);
-          if (strcmp(w, type.pattern + 1) == 0) {
-            knownExtension = 1;
-            break;
-          }
+      else {
+        // type will be empty if for example there were no filters for pattern,
+        // or if some other UI inconsistencies happen.
+        if (gtk_MessageBox(parent, "No file extension specified in file to be saved.\nAttempt to save anyways?",
+                           "GtkRadiant", MB_YESNO) == IDNO) {
+          return NULL;
         }
-        if (!knownExtension) {
-          if (gtk_MessageBox(parent, "Unknown file extension for this save operation.\nAttempt to save anyways?",
-                             "GtkRadiant", MB_YESNO) == IDNO) {
-            return NULL;
-          }
+      }
+    }
+    else { // An extension was explicitly in the filename.
+      bool knownExtension = false;
+      for (int i = typelist.GetNumTypes() - 1; i >= 0; i--) {
+        type = typelist.GetTypeForIndex(i);
+        if (type.pattern[0] && strcmp(w, type.pattern + 1) == 0) {
+          knownExtension = true;
+          break;
+        }
+      }
+      if (!knownExtension) {
+        if (gtk_MessageBox(parent, "Unknown file extension for this save operation.\nAttempt to save anyways?",
+                           "GtkRadiant", MB_YESNO) == IDNO) {
+          return NULL;
         }
       }
     }
   }
-#endif
 
   // prompt to overwrite existing files
   if (!open)
@@ -1535,11 +1461,6 @@ const char* file_dialog (void *parent, gboolean open, const char* title, const c
       if (gtk_MessageBox (parent, "File already exists.\nOverwrite?", "GtkRadiant", MB_YESNO) == IDNO)
         return NULL;
 
-#ifdef FILEDLG_DBG
-  // ... let's use a static filename
-  Sys_Printf("filename: %p\n", szFile);
-#endif
-
   return szFile;
 }