a8cb22dd51cacb4a6ad8efe791d3d66d010902ec
[geeqie.git] / src / filecluster.c
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include "filecluster.h"
20
21 #include "filedata.h"
22
23 static gboolean check_list_contains_sublist(GList *haystack, GList *needle)
24 {
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)
28         {
29                 gboolean found = FALSE;
30                 for (h_work = haystack; h_work; h_work = h_work->next)
31                 {
32                         if (n_work == h_work)
33                                 {
34                                 found = TRUE;
35                                 break;
36                                 }
37                 }
38
39                 if (!found) return FALSE;
40         }
41
42         return TRUE;
43 }
44
45 FileClusterList *fileclusterlist_new()
46 {
47         FileClusterList *fcl = g_new0(FileClusterList, 1);
48         fcl->clusters = g_hash_table_new(&g_direct_hash, &g_direct_equal);
49 }
50
51 FileCluster *filecluster_new()
52 {
53         FileCluster *fc = g_new0(FileCluster, 1);
54 }
55
56 void fileclusterlist_free(FileClusterList *fcl)
57 {
58         if (fcl->fd_list) g_list_free_full(fcl->fd_list, (GDestroyNotify)&filecluster_free);
59         g_hash_table_destroy(fcl->clusters);
60         g_free(fcl);
61 }
62
63 void filecluster_free(FileCluster *fc)
64 {
65         g_free(fc);
66 }
67
68 FileCluster *fileclusterlist_create_cluster(FileClusterList *fcl, GList *fd_items)
69 {
70         GList *work;
71
72         // Check preconditions.
73         if (!fd_items) return NULL;
74         // TODO(xsdg): Is this actually necessary?
75         // if (!check_list_contains_sublist(fcl->fd_list, fd_items)) return NULL;
76         for (work = fd_items; work; work = work->next)
77                 {
78                 FileData *fd = work->data;
79                 if (g_hash_table_contains(fcl->clusters, fd))
80                         {
81                         // TODO(xsdg): Show this warning in the UI.
82                         g_warning("Tried to create a cluster with a file that is already clustered.");
83                         return NULL;
84                         }
85                 }
86
87         FileCluster *new_fc = filecluster_new();
88         new_fc->items = g_list_copy(fd_items);
89         new_fc->head = new_fc->items;
90
91         for (GList *item = new_fc->items; item; item = item->next)
92                 {
93                 FileData *fd = item->data;
94                 g_hash_table_insert(fcl->clusters, fd, new_fc);
95                 }
96
97         return new_fc;
98 }
99
100 gboolean fileclusterlist_has_head(FileClusterList *fcl, FileData *fd)
101 {
102         FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
103         if (!fc) return FALSE;
104         return fc->head->data == fd;
105 }
106
107 gboolean fileclusterlist_has_child(FileClusterList *fcl, FileData *fd)
108 {
109         FileCluster *fc = g_hash_table_lookup(fcl->clusters, fd);
110         if (!fc) return FALSE;
111         return fc->head->data != fd;
112 }
113
114 GList *filecluster_remove_children_from_list(FileClusterList *fcl, GList *list)
115 {
116         GList *work = list;
117
118         while (work)
119         {
120                 FileData *fd = work->data;
121                 GList *link = work;
122                 // Advance early in case link needs to be removed/freed.
123                 work = work->next;
124
125                 if (fileclusterlist_has_child(fcl, fd))
126                 {
127                         list = g_list_remove_link(list, link);
128                         file_data_unref(fd);
129                         g_list_free(link);
130                 }
131         }
132
133         return list;
134 }