Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
history_snapshot.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2019 Hanno Schwalm.
4 Copyright (C) 2019 Heiko Bauke.
5 Copyright (C) 2019-2020, 2022 Pascal Obry.
6 Copyright (C) 2019 Philippe Weyland.
7 Copyright (C) 2020 Aldric Renaudin.
8 Copyright (C) 2020 Hubert Kowalski.
9 Copyright (C) 2022-2023 Aurélien PIERRE.
10 Copyright (C) 2022 Martin Bařinka.
11
12 darktable is free software: you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation, either version 3 of the License, or
15 (at your option) any later version.
16
17 darktable is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with darktable. If not, see <http://www.gnu.org/licenses/>.
24*/
25
27#include "common/darktable.h"
28#include "common/debug.h"
29#include "common/history.h"
30#include "common/image_cache.h"
31#include "control/signal.h"
32
37
38void dt_history_snapshot_undo_create(const int32_t imgid, int *snap_id, int *history_end)
39{
40 // create history & mask snapshots for imgid, return the snapshot id
41 sqlite3_stmt *stmt;
42 gboolean all_ok = TRUE;
43
44 // get current history end
45 *history_end = dt_history_get_end(imgid);
46
47 // get max snapshot
48
49 *snap_id = 0;
51 "SELECT MAX(id) FROM memory.undo_history WHERE imgid=?1", -1, &stmt, NULL);
52 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
53
54 if (sqlite3_step(stmt) == SQLITE_ROW)
55 *snap_id = sqlite3_column_int(stmt, 0) + 1;
56 sqlite3_finalize(stmt);
57
59
60 if(*history_end == 0)
61 {
62 // insert a dummy undo_histroy to ensure proper snap_id later
63 // clang-format off
65 "INSERT INTO memory.undo_history"
66 " VALUES (?1, ?2, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL)"
67 , -1, &stmt, NULL);
68 // clang-format on
69 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, *snap_id);
70 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
71 all_ok = all_ok && (sqlite3_step(stmt) == SQLITE_DONE);
72
73 goto end_create;
74 }
75
76 // copy current state into undo_history
77
78 // clang-format off
80 "INSERT INTO memory.undo_history"
81 " SELECT ?1, imgid, num, module, operation, op_params, enabled, "
82 " blendop_params, blendop_version, multi_priority, multi_name "
83 " FROM main.history"
84 " WHERE imgid=?2", -1, &stmt, NULL);
85 // clang-format on
86 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, *snap_id);
87 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
88 all_ok = all_ok && (sqlite3_step(stmt) == SQLITE_DONE);
89 sqlite3_finalize(stmt);
90
91 // copy current state into undo_masks_history
92
93 // clang-format off
95 "INSERT INTO memory.undo_masks_history"
96 " SELECT ?1, imgid, num, formid, form, name, version,"
97 " points, points_count, source"
98 " FROM main.masks_history"
99 " WHERE imgid=?2", -1, &stmt, NULL);
100 // clang-format on
101 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, *snap_id);
102 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
103 all_ok = all_ok && (sqlite3_step(stmt) == SQLITE_DONE);
104 sqlite3_finalize(stmt);
105
106 // copy the module order
107
108 // clang-format off
110 "INSERT INTO memory.undo_module_order"
111 " SELECT ?1, imgid, version, iop_list"
112 " FROM main.module_order"
113 " WHERE imgid=?2", -1, &stmt, NULL);
114 // clang-format on
115 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, *snap_id);
116 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
117 all_ok = all_ok && (sqlite3_step(stmt) == SQLITE_DONE);
118
119 end_create:
120
121 sqlite3_finalize(stmt);
122
123 if(all_ok)
125 else
126 {
128 fprintf(stderr, "[dt_history_snapshot_undo_create] fails to create a snapshot for %d\n", imgid);
129 }
130}
131
132static void _history_snapshot_undo_restore(const int32_t imgid, const int snap_id, const int history_end)
133{
134 // restore the given snapshot for imgid
135 sqlite3_stmt *stmt;
136 gboolean all_ok = TRUE;
137
139
142
143 // if no history end it means the image history was discarded, nothing more to restore
144 if(history_end == 0)
145 {
146 goto end_restore;
147 }
148
149 // copy undo_history snapshot back as current history state
150
151 // clang-format off
153 "INSERT INTO main.history"
154 " SELECT imgid, num, module, operation, op_params, enabled, "
155 " blendop_params, blendop_version, multi_priority, multi_name "
156 " FROM memory.undo_history"
157 " WHERE imgid=?2 AND id=?1", -1, &stmt, NULL);
158 // clang-format on
159 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
160 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
161 all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
162 sqlite3_finalize(stmt);
163
164 // copy undo_masks_history snapshot back as current masks_history state
165
166 // clang-format off
168 "INSERT INTO main.masks_history"
169 " SELECT imgid, num, formid, form, name, version, "
170 " points, points_count, source"
171 " FROM memory.undo_masks_history"
172 " WHERE imgid=?2 AND id=?1",
173 -1, &stmt, NULL);
174 // clang-format on
175 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
176 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
177 all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
178 sqlite3_finalize(stmt);
179
180 // restore module order
181
182 // clang-format off
184 "INSERT INTO main.module_order"
185 " SELECT imgid, version, iop_list"
186 " FROM memory.undo_module_order"
187 " WHERE imgid=?2 AND id=?1", -1, &stmt, NULL);
188 // clang-format on
189 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
190 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
191 all_ok &= (sqlite3_step(stmt) == SQLITE_DONE);
192 sqlite3_finalize(stmt);
193
194 end_restore:
195
196 // set history end
197 all_ok &= dt_history_set_end(imgid, history_end);
198
199 if(all_ok)
201 else
202 {
204 fprintf(stderr, "[_history_snapshot_undo_restore] fails to restore a snapshot for %d\n", imgid);
205 }
206
208 if(image)
209 {
210 // FIXME: this might be wrong or need more accurate handling
211 image->history_hash = UINT64_MAX;
213 }
214}
215
216static void _clear_undo_snapshot(const int32_t imgid, const int snap_id)
217{
218 sqlite3_stmt *stmt;
219
221 "DELETE FROM memory.undo_history WHERE id=?1 AND imgid=?2", -1, &stmt, NULL);
222 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
223 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
224 sqlite3_step(stmt);
225 sqlite3_finalize(stmt);
226
228 "DELETE FROM memory.undo_masks_history WHERE id=?1 AND imgid=?2", -1, &stmt, NULL);
229 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
230 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
231 sqlite3_step(stmt);
232 sqlite3_finalize(stmt);
233
235 "DELETE FROM memory.undo_module_order WHERE id=?1 AND imgid=?2", -1, &stmt, NULL);
236 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, snap_id);
237 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
238 sqlite3_step(stmt);
239 sqlite3_finalize(stmt);
240}
241
243{
245
246 _clear_undo_snapshot(hist->imgid, hist->after);
247
248 // this is the first element in for this image, it corresponds to the initial status, we can safely remove it now
249 if(hist->before == 0)
250 _clear_undo_snapshot(hist->imgid, hist->before);
251
252 dt_free(hist);
253}
254
255void dt_history_snapshot_undo_pop(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs)
256{
258 {
260
261 if(action == DT_ACTION_UNDO)
262 {
264 }
265 else
266 {
268 }
269
270 *imgs = g_list_append(*imgs, GINT_TO_POINTER(hist->imgid));
271 }
272}
273// clang-format off
274// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
275// vim: shiftwidth=2 expandtab tabstop=2 cindent
276// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
277// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
gboolean dt_history_set_end(const int32_t imgid, const int32_t history_end)
int32_t dt_history_get_end(const int32_t imgid)
void dt_history_delete_on_image_ext(int32_t imgid, gboolean undo)
int type
darktable_t darktable
Definition darktable.c:181
#define dt_free(ptr)
Definition darktable.h:456
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
void dt_database_rollback_transaction(const struct dt_database_t *db)
Definition database.c:4711
#define dt_database_start_transaction(db)
Definition database.h:77
#define dt_database_release_transaction(db)
Definition database.h:78
#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
void dt_history_snapshot_undo_create(const int32_t imgid, int *snap_id, int *history_end)
void dt_history_snapshot_undo_lt_history_data_free(gpointer data)
static void _clear_undo_snapshot(const int32_t imgid, const int snap_id)
dt_undo_lt_history_t * dt_history_snapshot_item_init(void)
void dt_history_snapshot_undo_pop(gpointer user_data, dt_undo_type_t type, dt_undo_data_t data, dt_undo_action_t action, GList **imgs)
static void _history_snapshot_undo_restore(const int32_t imgid, const int snap_id, const int history_end)
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_RELAXED
Definition image_cache.h:51
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:130
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_image_cache_t * image_cache
Definition darktable.h:777
uint64_t history_hash
Definition image.h:322
dt_undo_type_t
Definition undo.h:39
@ DT_UNDO_LT_HISTORY
Definition undo.h:48
void * dt_undo_data_t
Definition undo.h:67
dt_undo_action_t
Definition undo.h:62
@ DT_ACTION_UNDO
Definition undo.h:63