Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
grouping.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2012, 2014, 2016 Tobias Ellinghaus.
4 Copyright (C) 2013 Simon Spannagel.
5 Copyright (C) 2014 johannes hanika.
6 Copyright (C) 2016 Roman Lebedev.
7 Copyright (C) 2019-2020 Philippe Weyland.
8 Copyright (C) 2020 Hanno Schwalm.
9 Copyright (C) 2020-2021 Hubert Kowalski.
10 Copyright (C) 2020-2021 Pascal Obry.
11 Copyright (C) 2021 Ralf Brown.
12 Copyright (C) 2022 Aldric Renaudin.
13 Copyright (C) 2022, 2025 Aurélien PIERRE.
14 Copyright (C) 2022 Martin Bařinka.
15
16 darktable is free software: you can redistribute it and/or modify
17 it under the terms of the GNU General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 darktable is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with darktable. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#include "common/grouping.h"
31#include "common/collection.h"
32#include "common/darktable.h"
33#include "common/debug.h"
34#include "common/image_cache.h"
35#include "common/selection.h"
36#include "control/signal.h"
37#include "gui/gtk.h"
38
39int32_t dt_grouping_get_image_group(const int32_t image_id)
40{
41 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r');
42 const int img_group_id = img->group_id;
44 return img_group_id;
45}
46
48void dt_grouping_add_to_group(const int32_t group_id, const int32_t image_id)
49{
50 // remove from old group
52
54 img->group_id = group_id;
56}
57
59int dt_grouping_remove_from_group(const int32_t image_id)
60{
61 sqlite3_stmt *stmt;
62 int new_group_id = -1;
63 GList *imgs = NULL;
64
65 const dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r');
66 if(!img) return -1;
67 const int img_group_id = img->group_id;
69 if(img_group_id == image_id)
70 {
71 // get a new group_id for all the others in the group. also write it to the dt_image_t struct.
73 "SELECT id FROM main.images WHERE group_id = ?1 AND id != ?2", -1, &stmt, NULL);
74 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img_group_id);
75 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, image_id);
76 while(sqlite3_step(stmt) == SQLITE_ROW)
77 {
78 int other_id = sqlite3_column_int(stmt, 0);
79 if(new_group_id == -1) new_group_id = other_id;
80 dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
81 other_img->group_id = new_group_id;
83 imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id));
84 }
85 sqlite3_finalize(stmt);
86 if(new_group_id != -1)
87 {
89 "UPDATE main.images SET group_id = ?1 WHERE group_id = ?2 AND id != ?3", -1, &stmt,
90 NULL);
91 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, new_group_id);
92 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, img_group_id);
93 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, image_id);
94 sqlite3_step(stmt);
95 sqlite3_finalize(stmt);
96 }
97 else
98 {
99 // no change was made, no point in raising signal, bailing early
100 return -1;
101 }
102 }
103 else
104 {
105 // change the group_id for this image.
106 dt_image_t *wimg = dt_image_cache_get(darktable.image_cache, image_id, 'w');
107 new_group_id = wimg->group_id;
108 wimg->group_id = image_id;
110 imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id));
111 // refresh also the group leader which may be alone now
112 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img_group_id));
113 }
114
115 return new_group_id;
116}
117
119int dt_grouping_change_representative(const int32_t image_id)
120{
121 sqlite3_stmt *stmt;
122
123 dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r');
124 const int group_id = img->group_id;
126
127 GList *imgs = NULL;
128 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE group_id = ?1", -1,
129 &stmt, NULL);
130 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id);
131 while(sqlite3_step(stmt) == SQLITE_ROW)
132 {
133 const int other_id = sqlite3_column_int(stmt, 0);
134 dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
135 other_img->group_id = image_id;
137 imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id));
138 }
139 sqlite3_finalize(stmt);
140
141 return image_id;
142}
143
145GList *dt_grouping_get_group_images(const int32_t imgid)
146{
147 GList *imgs = NULL;
148 const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r');
149 if(image)
150 {
151 const int img_group_id = image->group_id;
153
154 sqlite3_stmt *stmt;
156 "SELECT id FROM main.images WHERE group_id = ?1", -1, &stmt, NULL);
157 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img_group_id);
158
159 while(sqlite3_step(stmt) == SQLITE_ROW)
160 {
161 const int32_t image_id = sqlite3_column_int(stmt, 0);
162 imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id));
163 }
164 sqlite3_finalize(stmt);
165
166 }
167 return g_list_reverse(imgs);
168}
169
172{
173 if(IS_NULL_PTR(*images)) return;
174 GList *gimgs = NULL;
175 for(GList *imgs = *images; imgs; imgs = g_list_next(imgs))
176 {
177 const dt_image_t *image = dt_image_cache_get(darktable.image_cache, GPOINTER_TO_INT(imgs->data), 'r');
178 if(image)
179 {
180 const int img_group_id = image->group_id;
183 {
184 sqlite3_stmt *stmt;
185 // clang-format off
186 gchar *query = g_strdup_printf(
187 "SELECT id"
188 " FROM main.images"
189 " WHERE group_id = %d AND id IN (%s)",
191 // clang-format on
193
194 while(sqlite3_step(stmt) == SQLITE_ROW)
195 {
196 const int32_t image_id = sqlite3_column_int(stmt, 0);
197 if(image_id != GPOINTER_TO_INT(imgs->data))
198 gimgs = g_list_prepend(gimgs, GINT_TO_POINTER(image_id));
199 }
200 sqlite3_finalize(stmt);
201 dt_free(query);
202 }
203 }
204 }
205
206 if(gimgs)
207 *images = g_list_concat(*images, g_list_reverse(gimgs));
208}
209
210// clang-format off
211// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
212// vim: shiftwidth=2 expandtab tabstop=2 cindent
213// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
214// clang-format on
const gchar * dt_collection_get_query(const dt_collection_t *collection)
Definition collection.c:552
darktable_t darktable
Definition darktable.c:183
#define dt_free(ptr)
Definition darktable.h:478
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3653
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
int dt_grouping_change_representative(const int32_t image_id)
Definition grouping.c:119
int dt_grouping_remove_from_group(const int32_t image_id)
Definition grouping.c:59
int32_t dt_grouping_get_image_group(const int32_t image_id)
Definition grouping.c:39
void dt_grouping_add_grouped_images(GList **images)
Definition grouping.c:171
void dt_grouping_add_to_group(const int32_t group_id, const int32_t image_id)
Definition grouping.c:48
GList * dt_grouping_get_group_images(const int32_t imgid)
Definition grouping.c:145
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:49
struct dt_collection_t * collection
Definition darktable.h:809
const struct dt_database_t * db
Definition darktable.h:807
struct dt_image_cache_t * image_cache
Definition darktable.h:805
int32_t group_id
Definition image.h:319