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