2 * Copyright (C) 2008 - 2016 The Geeqie Team
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "filecluster.h"
23 static gboolean check_list_contains_sublist(GList *haystack, GList *needle)
25 // TODO(xsdg): Optimize this! Sort, then scan?
26 GList *h_work, *n_work;
27 for (n_work = needle; n_work; n_work = n_work->next)
29 gboolean found = FALSE;
30 for (h_work = haystack; h_work; h_work = h_work->next)
39 if (!found) return FALSE;
45 static gboolean filecluster_fd_equal(gconstpointer ptr_a, gconstpointer ptr_b)
47 // TODO(xsdg): Is there anything we can/should do to validate inputs?
48 FileData *fd_a = (FileData *)ptr_a;
49 FileData *fd_b = (FileData *)ptr_b;
50 return !filelist_sort_compare_filedata(fd_a, fd_b);
53 // TODO(xsdg): Move this into filedata.h
54 static guint filecluster_fd_hash(gconstpointer ptr)
57 FileData *fd = (FileData *)ptr;
58 return 7 * g_str_hash(fd->original_path);
61 FileClusterList *fileclusterlist_new()
63 FileClusterList *fcl = g_new0(FileClusterList, 1);
64 fcl->clusters = g_hash_table_new(&filecluster_fd_hash, &filecluster_fd_equal);
68 FileCluster *filecluster_new()
70 FileCluster *fc = g_new0(FileCluster, 1);
71 fc->show_children = FALSE;
75 void fileclusterlist_free(FileClusterList *fcl)
77 // TODO(xsdg): don't leak stuff
78 // if (fcl->fd_list) g_list_free_full(fcl->fd_list, (GDestroyNotify)&filecluster_free);
79 g_hash_table_destroy(fcl->clusters);
83 void filecluster_free(FileCluster *fc)
85 filelist_free(fc->items);
89 gboolean filecluster_toggle_show_children(FileCluster *fc)
91 fc->show_children = !fc->show_children;
92 return fc->show_children;
95 FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_items)
99 // Check preconditions.
100 if (!fd_items) return NULL;
101 for (work = fd_items; work; work = work->next)
103 FileData *fd = work->data;
104 if (g_hash_table_contains(fcl->clusters, fd))
106 // TODO(xsdg): Show this warning in the UI.
107 g_warning("Tried to create a cluster with a file that is already clustered.");
112 FileCluster *new_fc = filecluster_new();
113 new_fc->items = filelist_copy(fd_items);
114 new_fc->head = new_fc->items;
116 for (GList *item = new_fc->items; item; item = item->next)
118 FileData *fd = item->data;
119 g_hash_table_insert(fcl->clusters, fd, new_fc);
125 gboolean filecluster_has_head(FileCluster *fc, FileData *fd)
127 if (!fd) return FALSE;
128 return filecluster_fd_equal(fc->head->data, fd);
131 gboolean filecluster_has_child(FileCluster *fc, FileData *fd)
133 if (!fd) return FALSE;
134 return !filecluster_fd_equal(fc->head->data, fd);
137 gboolean fileclusterlist_has_head(FileClusterList *fcl, FileData *fd)
139 FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
140 if (!fc) return FALSE;
141 return filecluster_has_head(fc, fd);
144 gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd)
146 FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
147 if (!fc) return FALSE;
148 return filecluster_has_child(fc, fd);
151 static gboolean fileclusterlist_should_hide(FileClusterList *fcl, FileData *fd)
153 FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
154 if (!fc) return FALSE;
155 // Only difference vs. fileclusterlist_has_child. Basically, if the node is a child, but
156 // we're showing children, then don't hide.
157 if (fc->show_children) return FALSE;
158 return filecluster_has_child(fc, fd);
161 // TODO(xsdg): pick a better name for this function
162 GList *fileclusterlist_next_non_child(FileClusterList *fcl, GList *list)
165 if (!list || !g_hash_table_size(fcl->clusters)) return list;
167 // Clusters are being used, so we have to actually check things.
168 for (; list; list = list->next)
170 FileData *fd = list->data;
171 if (!fileclusterlist_has_child(fcl, fd)) return list;
177 GList *fileclusterlist_remove_children_from_list(FileClusterList *fcl, GList *list)
183 FileData *fd = work->data;
185 // Advance early in case link needs to be removed/freed.
188 if (fileclusterlist_should_hide(fcl, fd))
190 list = g_list_remove_link(list, link);