1 /***************************************************************************
2  *   Copyright (C) 2007 by PCMan (Hong Jen Yee)   *
3  *   pcman.tw@gmail.com   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 
21 #ifdef HAVE_CONFIG_H
22 #  include <config.h>
23 #endif
24 
25 #include "image-list.h"
26 #include "glib-mem.h"
27 
28 #include <string.h>
29 #include <gdk-pixbuf/gdk-pixbuf.h>
30 
31 static GSList* supported_formats = NULL;
32 
33 static gboolean image_list_is_file_supported( const char* name );
34 
image_list_new()35 ImageList* image_list_new()
36 {
37     ImageList* il = g_slice_new0( ImageList );
38 
39     if( ! supported_formats )
40     {
41         GSList* formats = gdk_pixbuf_get_formats();
42         GSList* format;
43         for( format = formats; format; format = format->next )
44         {
45             char** exts = gdk_pixbuf_format_get_extensions( (GdkPixbufFormat*)format->data );
46             char** ext;
47             for( ext  = exts; *ext ; ++ext )
48                 supported_formats = g_slist_prepend( supported_formats, *ext );
49             g_free( exts ); // g_strfreev is not needed since we stole its stirngs
50         }
51         // supported_formats = g_slist_reverse( supported_formats, *ext );
52     }
53 
54     return il;
55 }
56 
image_list_free(ImageList * il)57 void image_list_free( ImageList* il )
58 {
59     g_slice_free( ImageList, il );
60 }
61 
image_list_get_dir(ImageList * il)62 const char* image_list_get_dir( ImageList* il )
63 {
64     return il->dir_path;
65 }
66 
image_list_get_current(ImageList * il)67 const char* image_list_get_current( ImageList* il )
68 {
69     return il->current ? (char*)il->current->data : NULL;
70 }
71 
image_list_is_empty(ImageList * il)72 gboolean image_list_is_empty( ImageList* il )
73 {
74     return (il->list == NULL);
75 }
76 
image_list_has_multiple_files(ImageList * il)77 gboolean image_list_has_multiple_files( ImageList* il )
78 {
79     return (il->list && il->list->next);
80 }
81 
image_list_open_dir(ImageList * il,const char * path,GError ** error)82 gboolean image_list_open_dir( ImageList* il, const char* path, GError** error )
83 {
84     const char* name = NULL;
85     GDir* dir;
86     struct stat stbuf;
87 
88     if( il->dir_path && 0 == strcmp( path, il->dir_path ) )
89         return TRUE;
90 
91     image_list_close( il );
92 
93     if( stat( path, &stbuf ) == -1 )
94         return FALSE;
95 
96     dir = g_dir_open( path, 0, error );
97     if( ! dir )
98         return FALSE;
99 
100     il->dir_path = g_strdup( path );
101     il->mtime = stbuf.st_mtime;
102 
103     while( ( name = g_dir_read_name ( dir ) ) )
104     {
105 //        char* file_path = g_build_filename( dir_path, name, NULL );
106         if( image_list_is_file_supported( name ) )
107             il->list = g_list_prepend( il->list, g_strdup(name) );
108 //        g_free( file_path );
109     }
110     g_dir_close( dir );
111     il->list = g_list_reverse( il->list );
112     il->current = il->list;
113     return TRUE;
114 }
115 
image_list_set_current(ImageList * il,const char * name)116 gboolean image_list_set_current(  ImageList* il,const char* name )
117 {
118     if( ! il->list || !name )
119         return FALSE;
120 
121     GList* cur = g_list_find_custom( il->list, name, (GCompareFunc)strcmp );
122     if( ! cur )
123         return FALSE;
124     il->current = cur;
125     return TRUE;
126 }
127 
image_list_get_first(ImageList * il)128 const char* image_list_get_first( ImageList* il )
129 {
130     il->current = il->list;
131     return image_list_get_current( il );
132 }
133 
image_list_get_next(ImageList * il)134 const char* image_list_get_next( ImageList* il )
135 {
136     if( il->current && il->current->next )
137     {
138         il->current = il->current->next;
139         return image_list_get_current( il );
140     }
141     return NULL;
142 }
143 
image_list_get_prev(ImageList * il)144 const char* image_list_get_prev( ImageList* il )
145 {
146     if( il->current && il->current->prev )
147     {
148         il->current = il->current->prev;
149         return image_list_get_current( il );
150     }
151     return NULL;
152 }
153 
image_list_get_last(ImageList * il)154 const char* image_list_get_last( ImageList* il )
155 {
156     il->current = g_list_last( il->list );
157     return image_list_get_current( il );
158 }
159 
image_list_close(ImageList * il)160 void image_list_close( ImageList* il )
161 {
162     g_list_foreach( il->list, (GFunc)g_free, NULL );
163     g_list_free( il->list );
164     il->list = NULL;
165     il->mtime = 0;
166 
167     g_free( il->dir_path );
168     il->dir_path = NULL;
169 }
170 
image_list_is_file_supported(const char * name)171 static gboolean image_list_is_file_supported( const char* name )
172 {
173     const char* ext = strrchr( name, '.' );
174     if( ! ext )
175         return FALSE;
176     ++ext;
177 
178     return !!g_slist_find_custom ( supported_formats, ext,  (GCompareFunc)g_ascii_strcasecmp);
179 }
180 
image_list_get_current_file_path(ImageList * il)181 char* image_list_get_current_file_path( ImageList* il )
182 {
183     const char* name;
184     if( il->dir_path && (name = image_list_get_current( il )) )
185         return g_build_filename( il->dir_path, name, NULL );
186     return NULL;
187 }
188 
comp_by_name(char * name1,char * name2,GtkSortType type)189 static int comp_by_name( char* name1, char* name2, GtkSortType type )
190 {
191     // According to the glib API doc, UTF-8 should be considered here,
192     // So the simple strcmp couldn't be used here. What a pity!
193 
194     char* utf8;
195 
196     utf8 = g_filename_display_name(name1);
197     name1 = g_utf8_casefold( utf8, -1 );
198     g_free( utf8 );
199 
200     utf8 = g_filename_display_name(name2);
201     name2 = g_utf8_casefold( utf8, -1 );
202     g_free( utf8 );
203     int ret = g_utf8_collate( name1, name2 );
204     g_free( name1 );
205     g_free( name2 );
206     return type == GTK_SORT_ASCENDING ? -ret : ret;
207 }
208 
image_list_sort_by_name(ImageList * il,GtkSortType type)209 void image_list_sort_by_name(  ImageList* il, GtkSortType type )
210 {
211     il->list = g_list_sort_with_data( il->list, (GCompareDataFunc)comp_by_name, (gpointer)type );
212 }
213 
214 
image_list_remove(ImageList * il,const char * name)215 void image_list_remove( ImageList* il, const char* name )
216 {
217     il->list = g_list_remove( il->list, name );
218 }
219 
220 /* FIXME: currently only GTK_SORT_ASCENDING is supported */
image_list_add_sorted(ImageList * il,const char * name,gboolean set_current)221 void image_list_add_sorted( ImageList* il, const char* name, gboolean set_current )
222 {
223     il->list = g_list_insert_sorted_with_data( il->list, g_strdup(name), (GCompareDataFunc)comp_by_name, (gpointer)GTK_SORT_ASCENDING );
224 }
225