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 const int img_group_id = img->group_id;
68 if(img_group_id == image_id)
69 {
70 // get a new group_id for all the others in the group. also write it to the dt_image_t struct.
72 "SELECT id FROM main.images WHERE group_id = ?1 AND id != ?2", -1, &stmt, NULL);
73 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img_group_id);
74 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, image_id);
75 while(sqlite3_step(stmt) == SQLITE_ROW)
76 {
77 int other_id = sqlite3_column_int(stmt, 0);
78 if(new_group_id == -1) new_group_id = other_id;
79 dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
80 other_img->group_id = new_group_id;
82 imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id));
83 }
84 sqlite3_finalize(stmt);
85 if(new_group_id != -1)
86 {
88 "UPDATE main.images SET group_id = ?1 WHERE group_id = ?2 AND id != ?3", -1, &stmt,
89 NULL);
90 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, new_group_id);
91 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, img_group_id);
92 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, image_id);
93 sqlite3_step(stmt);
94 sqlite3_finalize(stmt);
95 }
96 else
97 {
98 // no change was made, no point in raising signal, bailing early
99 return -1;
100 }
101 }
102 else
103 {
104 // change the group_id for this image.
105 dt_image_t *wimg = dt_image_cache_get(darktable.image_cache, image_id, 'w');
106 new_group_id = wimg->group_id;
107 wimg->group_id = image_id;
109 imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id));
110 // refresh also the group leader which may be alone now
111 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img_group_id));
112 }
113
114 return new_group_id;
115}
116
118int dt_grouping_change_representative(const int32_t image_id)
119{
120 sqlite3_stmt *stmt;
121
122 dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r');
123 const int group_id = img->group_id;
125
126 GList *imgs = NULL;
127 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE group_id = ?1", -1,
128 &stmt, NULL);
129 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id);
130 while(sqlite3_step(stmt) == SQLITE_ROW)
131 {
132 const int other_id = sqlite3_column_int(stmt, 0);
133 dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w');
134 other_img->group_id = image_id;
136 imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id));
137 }
138 sqlite3_finalize(stmt);
139
140 return image_id;
141}
142
144GList *dt_grouping_get_group_images(const int32_t imgid)
145{
146 GList *imgs = NULL;
147 const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r');
148 if(image)
149 {
150 const int img_group_id = image->group_id;
152
153 sqlite3_stmt *stmt;
155 "SELECT id FROM main.images WHERE group_id = ?1", -1, &stmt, NULL);
156 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img_group_id);
157
158 while(sqlite3_step(stmt) == SQLITE_ROW)
159 {
160 const int32_t image_id = sqlite3_column_int(stmt, 0);
161 imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id));
162 }
163 sqlite3_finalize(stmt);
164
165 }
166 return g_list_reverse(imgs);
167}
168
171{
172 if(IS_NULL_PTR(*images)) return;
173 GList *gimgs = NULL;
174 for(GList *imgs = *images; imgs; imgs = g_list_next(imgs))
175 {
176 const dt_image_t *image = dt_image_cache_get(darktable.image_cache, GPOINTER_TO_INT(imgs->data), 'r');
177 if(image)
178 {
179 const int img_group_id = image->group_id;
182 {
183 sqlite3_stmt *stmt;
184 // clang-format off
185 gchar *query = g_strdup_printf(
186 "SELECT id"
187 " FROM main.images"
188 " WHERE group_id = %d AND id IN (%s)",
190 // clang-format on
192
193 while(sqlite3_step(stmt) == SQLITE_ROW)
194 {
195 const int32_t image_id = sqlite3_column_int(stmt, 0);
196 if(image_id != GPOINTER_TO_INT(imgs->data))
197 gimgs = g_list_prepend(gimgs, GINT_TO_POINTER(image_id));
198 }
199 sqlite3_finalize(stmt);
200 dt_free(query);
201 }
202 }
203 }
204
205 if(gimgs)
206 *images = g_list_concat(*images, g_list_reverse(gimgs));
207}
208
209// clang-format off
210// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
211// vim: shiftwidth=2 expandtab tabstop=2 cindent
212// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
213// clang-format on
const gchar * dt_collection_get_query(const dt_collection_t *collection)
Definition collection.c:552
darktable_t darktable
Definition darktable.c:181
#define dt_free(ptr)
Definition darktable.h:456
#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:281
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
#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:118
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:170
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:144
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:781
const struct dt_database_t * db
Definition darktable.h:779
struct dt_image_cache_t * image_cache
Definition darktable.h:777
int32_t group_id
Definition image.h:319