[gtk+] GtkFileChooserNativeQuartz: add support for filters



commit a4775f8e924b5672b1698fea5441e949a7b70afa
Author: Tom Schoonjans <Tom Schoonjans diamond ac uk>
Date:   Sun Jul 9 17:06:12 2017 +0100

    GtkFileChooserNativeQuartz: add support for filters
    
    Includes:
    * Simple glob patterns (*.ext, *.*,...)
    * MIME types
    * pixbuf formats
    
    https://bugzilla.gnome.org/show_bug.cgi?id=784723

 gtk/gtkfilechoosernativequartz.c |  120 ++++++++++++++++++++++++++++++++------
 gtk/gtkfilefilter.c              |   78 ++++++++++++++++++++++++
 gtk/gtkfilefilterprivate.h       |   10 +++
 3 files changed, 190 insertions(+), 18 deletions(-)
---
diff --git a/gtk/gtkfilechoosernativequartz.c b/gtk/gtkfilechoosernativequartz.c
index 1499fb5..aca29d0 100644
--- a/gtk/gtkfilechoosernativequartz.c
+++ b/gtk/gtkfilechoosernativequartz.c
@@ -63,18 +63,46 @@ typedef struct {
   char *title;
   char *message;
 
-  GSList *shortcut_uris;
-
   GFile *current_folder;
   GFile *current_file;
   char *current_name;
 
-  NSArray<NSString *> *filters;
+  NSMutableArray<NSArray<NSString *> *> *filters;
+  NSMutableArray<NSString *> *filter_names;
+  NSComboBox *filter_combo_box;
 
   GSList *files;
   int response;
 } FileChooserQuartzData;
 
+@interface FilterComboBox : NSObject<NSComboBoxDelegate>
+{
+  FileChooserQuartzData *data;
+}
+- (id) initWithData:(FileChooserQuartzData *) quartz_data;
+- (void)comboBoxSelectionDidChange:(NSNotification *)notification;
+@end
+
+@implementation FilterComboBox
+
+- (id) initWithData:(FileChooserQuartzData *) quartz_data
+{
+  [super init];
+  data = quartz_data;
+  return self;
+}
+- (void)comboBoxSelectionDidChange:(NSNotification *)notification
+{
+  NSInteger selected_index = [data->filter_combo_box indexOfSelectedItem];
+  NSArray<NSString *> *filter = [data->filters objectAtIndex:selected_index];
+  // check for empty strings in filter -> indicates all filetypes should be allowed!
+  if ([filter containsObject:@""])
+    [data->panel setAllowedFileTypes:nil];
+  else
+    [data->panel setAllowedFileTypes:filter];
+}
+@end
+
 static GFile *
 ns_url_to_g_file (NSURL *url)
 {
@@ -150,16 +178,21 @@ chooser_set_current_name (FileChooserQuartzData *data,
 static void
 filechooser_quartz_data_free (FileChooserQuartzData *data)
 {
-  int i;
+  
   if (data->filters)
     {
+      [data->filters release];
     }
 
+  if (data->filter_names)
+    {
+      [data->filter_names release];
+    }
+  
   g_clear_object (&data->current_folder);
   g_clear_object (&data->current_file);
   g_free (data->current_name);
 
-  g_slist_free_full (data->shortcut_uris, g_free);
   g_slist_free_full (data->files, g_object_unref);
   if (data->self)
     g_object_unref (data->self);
@@ -174,17 +207,9 @@ static gboolean
 filechooser_quartz_launch (FileChooserQuartzData *data)
 {
 
-  // GTK_FILE_CHOOSER_ACTION_SAVE and GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
   if (data->save)
     {
 
-      /*if ([panel respondsToSelector:@selector(setShowsTagField:)])
-        {
-          [(id<CanSetShowsTagField>)panel setShowsTagField:NO];
-        }
-      */
-
-      // GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
       if (data->folder)
         {
           NSOpenPanel *panel = [[NSOpenPanel openPanel] retain];
@@ -193,7 +218,6 @@ filechooser_quartz_launch (FileChooserQuartzData *data)
           [panel setCanCreateDirectories:YES];
           data->panel = panel;
         }
-      // GTK_FILE_CHOOSER_ACTION_SAVE
       else
         {
           NSSavePanel *panel = [[NSSavePanel savePanel] retain];
@@ -208,7 +232,6 @@ filechooser_quartz_launch (FileChooserQuartzData *data)
           data->panel = panel;
         }
     }
-    // GTK_FILE_CHOOSER_ACTION_OPEN and GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
   else
     {
       NSOpenPanel *panel = [[NSOpenPanel openPanel] retain];
@@ -274,7 +297,20 @@ filechooser_quartz_launch (FileChooserQuartzData *data)
 
   if (data->filters)
     {
-      // TODO
+      // when filters have been provided, a combobox needs to be added
+      data->filter_combo_box = [[NSComboBox alloc] initWithFrame:NSMakeRect(0.0, 0.0, 200, 20)];
+      [data->filter_combo_box addItemsWithObjectValues:data->filter_names];
+      [data->filter_combo_box setEditable:NO];
+      [data->filter_combo_box setDelegate:[[FilterComboBox alloc] initWithData:data]];
+      [data->filter_combo_box selectItemAtIndex:0];
+      [data->filter_combo_box setToolTip:[NSString stringWithUTF8String:_("Select which types of files are 
shown")]];
+      [data->panel setAccessoryView:data->filter_combo_box];
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_11_AND_LATER
+      if (!data->save)
+        {
+          [(NSOpenPanel *) data->panel setAccessoryViewDisclosed:YES];
+        }
+#endif
     }
 
   data->response = GTK_RESPONSE_CANCEL;
@@ -342,6 +378,36 @@ strip_mnemonic (const gchar *s)
     }
 } 
 
+static gboolean
+file_filter_to_quartz (GtkFileFilter *file_filter,
+                       NSMutableArray<NSArray<NSString *> *> *filters,
+                      NSMutableArray<NSString *> *filter_names)
+{
+  const char *name;
+  NSArray<NSString *> *pattern_nsstrings;
+
+  pattern_nsstrings = _gtk_file_filter_get_as_pattern_nsstrings (file_filter);
+  if (pattern_nsstrings == NULL)
+    return FALSE;
+
+  name = gtk_file_filter_get_name (file_filter);
+  NSString *name_nsstring;
+  if (name == NULL)
+    {
+      name_nsstring = [pattern_nsstrings componentsJoinedByString:@","];;
+    }
+  else
+    {
+      name_nsstring = [NSString stringWithUTF8String:name];
+      [name_nsstring retain];
+    }
+
+  [filter_names addObject:name_nsstring];
+  [filters addObject:pattern_nsstrings];
+
+  return TRUE;
+}
+
 gboolean
 gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
 {
@@ -371,12 +437,30 @@ gtk_file_chooser_native_quartz_show (GtkFileChooserNative *self)
 
   data = g_new0 (FileChooserQuartzData, 1);
 
-  // examine filters! TODO
+  // examine filters!
+  filters = gtk_file_chooser_list_filters (GTK_FILE_CHOOSER (self));
+  n_filters = g_slist_length (filters);
+  if (n_filters > 0)
+    {
+      data->filters = [NSMutableArray<NSArray<NSString *> *> arrayWithCapacity:n_filters];
+      [data->filters retain];
+      data->filter_names = [NSMutableArray<NSString *> arrayWithCapacity:n_filters];
+      [data->filter_names retain];
+
+      for (l = filters, i = 0; l != NULL; l = l->next, i++)
+        {
+          if (!file_filter_to_quartz (l->data, data->filters, data->filter_names))
+            {
+              filechooser_quartz_data_free (data);
+              return FALSE;
+            }
+        }
+    }
 
   self->mode_data = data;
   data->self = g_object_ref (self);
 
-  data->create_folders = gtk_file_chooser_get_create_folders( GTK_FILE_CHOOSER (self));
+  data->create_folders = gtk_file_chooser_get_create_folders (GTK_FILE_CHOOSER (self));
 
   // shortcut_folder_uris support seems difficult if not impossible 
 
diff --git a/gtk/gtkfilefilter.c b/gtk/gtkfilefilter.c
index 5339ac7..e45406c 100644
--- a/gtk/gtkfilefilter.c
+++ b/gtk/gtkfilefilter.c
@@ -592,6 +592,84 @@ gtk_file_filter_get_needed (GtkFileFilter *filter)
   return filter->needed;
 }
 
+#ifdef GDK_WINDOWING_QUARTZ
+
+#import <Foundation/Foundation.h>
+
+NSArray<NSString *> * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter)
+{
+  NSMutableArray<NSString *> *array = [[NSMutableArray alloc] init];
+  GSList *tmp_list;
+
+  for (tmp_list = filter->rules; tmp_list; tmp_list = tmp_list->next)
+    {
+      FilterRule *rule = tmp_list->data;
+
+      switch (rule->type)
+       {
+       case FILTER_RULE_CUSTOM:
+         [array release];
+          return NULL;
+         break;
+       case FILTER_RULE_MIME_TYPE:
+         {
+           // convert mime-types to UTI
+           NSString *mime_type_nsstring = [NSString stringWithUTF8String: rule->u.mime_type];
+           NSString *uti_nsstring = (NSString *) UTTypeCreatePreferredIdentifierForTag (kUTTagClassMIMEType, 
(CFStringRef) mime_type_nsstring, NULL);
+           if (uti_nsstring == NULL)
+             {
+               [array release];
+               return NULL;
+             }
+           [array addObject:uti_nsstring];
+         }
+         break;
+       case FILTER_RULE_PATTERN:
+         {
+           // patterns will need to be stripped of their leading *.
+           GString *pattern = g_string_new (rule->u.pattern);
+           if (strncmp (pattern->str, "*.", 2) == 0)
+             {
+               pattern = g_string_erase (pattern, 0, 2);
+             }
+           else if (strncmp (pattern->str, "*", 1) == 0)
+             {
+               pattern = g_string_erase (pattern, 0, 1);
+             }
+           gchar *pattern_c = g_string_free (pattern, FALSE);
+           NSString *pattern_nsstring = [NSString stringWithUTF8String:pattern_c];
+           g_free (pattern_c);
+           [pattern_nsstring retain];
+           [array addObject:pattern_nsstring];
+         }
+         break;
+       case FILTER_RULE_PIXBUF_FORMATS:
+         {
+           GSList *list;
+
+           for (list = rule->u.pixbuf_formats; list; list = list->next)
+             {
+               int i;
+               gchar **extensions;
+
+               extensions = gdk_pixbuf_format_get_extensions (list->data);
+
+               for (i = 0; extensions[i] != NULL; i++)
+                 {
+                   NSString *extension = [NSString stringWithUTF8String: extensions[i]];
+                   [extension retain];
+                   [array addObject:extension];
+                 }
+               g_strfreev (extensions);
+             }
+           break;
+         }
+       }
+    }
+  return array;
+}
+#endif
+
 char **
 _gtk_file_filter_get_as_patterns (GtkFileFilter      *filter)
 {
diff --git a/gtk/gtkfilefilterprivate.h b/gtk/gtkfilefilterprivate.h
index 0a3d4a4..ce8a715 100644
--- a/gtk/gtkfilefilterprivate.h
+++ b/gtk/gtkfilefilterprivate.h
@@ -20,11 +20,21 @@
 #define __GTK_FILE_FILTER_PRIVATE_H__
 
 #include <gtk/gtkfilefilter.h>
+#include <gdk/gdkconfig.h>
+
+#ifdef GDK_WINDOWING_QUARTZ
+#import <Foundation/Foundation.h>
+#endif
 
 G_BEGIN_DECLS
 
 char ** _gtk_file_filter_get_as_patterns (GtkFileFilter      *filter);
 
+#ifdef GDK_WINDOWING_QUARTZ
+NSArray<NSString *> * _gtk_file_filter_get_as_pattern_nsstrings (GtkFileFilter *filter);
+#endif
+
+
 G_END_DECLS
 
 #endif /* __GTK_FILE_FILTER_PRIVATE_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]