film.c 18.8 KB
Newer Older
1
/*
2 3
   This file is part of darktable,
   copyright (c) 2009--2010 johannes hanika.
4
   copyright (c) 2011-2012 henrik andersson.
5

6 7 8 9
   darktable is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
10

11 12 13 14
   darktable is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
15

16 17
   You should have received a copy of the GNU General Public License
   along with darktable.  If not, see <http://www.gnu.org/licenses/>.
18
*/
19
#include "common/film.h"
20
#include "common/collection.h"
21
#include "common/darktable.h"
22
#include "common/debug.h"
23 24
#include "common/dtpthread.h"
#include "common/image_cache.h"
25
#include "common/tags.h"
26 27 28
#include "control/conf.h"
#include "control/control.h"
#include "control/jobs.h"
johannes hanika's avatar
johannes hanika committed
29
#include "views/view.h"
30

31 32
#include <assert.h>
#include <errno.h>
33
#include <limits.h>
34
#include <math.h>
35 36
#include <stdio.h>
#include <stdlib.h>
37 38
#include <string.h>
#include <strings.h>
39 40 41
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
42 43
#ifdef USE_LUA
#include "lua/glist.h"
44
#include "lua/lua.h"
45
#endif
46

47
void dt_film_init(dt_film_t *film)
48
{
49 50 51 52 53 54
  dt_pthread_mutex_init(&film->images_mutex, NULL);
  film->last_loaded = film->num_images = 0;
  film->dirname[0] = '\0';
  film->dir = NULL;
  film->id = -1;
  film->ref = 0;
55 56
}

57
void dt_film_cleanup(dt_film_t *film)
58
{
59 60 61 62 63 64
  dt_pthread_mutex_destroy(&film->images_mutex);
  if(film->dir)
  {
    g_dir_close(film->dir);
    film->dir = NULL;
  }
65 66
}

67 68
void dt_film_set_query(const int32_t id)
{
69
  /* enable film id filter and set film id */
70 71
  dt_conf_set_int("plugins/lighttable/collect/num_rules", 1);
  dt_conf_set_int("plugins/lighttable/collect/item0", 0);
72
  sqlite3_stmt *stmt;
73
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
74
                              "SELECT id, folder FROM main.film_rolls WHERE id = ?1", -1, &stmt, NULL);
75 76 77
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  if(sqlite3_step(stmt) == SQLITE_ROW)
  {
78
    dt_conf_set_string("plugins/lighttable/collect/string0", (gchar *)sqlite3_column_text(stmt, 1));
79
  }
80
  sqlite3_finalize(stmt);
81
  dt_collection_update_query(darktable.collection);
82 83 84
}

/** open film with given id. */
85
int dt_film_open2(dt_film_t *film)
86
{
87
  /* check if we got a decent film id */
88
  if(film->id < 0) return 1;
89

90 91
  /* query database for id and folder */
  sqlite3_stmt *stmt;
92
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
93
                              "SELECT id, folder FROM main.film_rolls WHERE id = ?1", -1, &stmt, NULL);
94 95 96 97
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film->id);
  if(sqlite3_step(stmt) == SQLITE_ROW)
  {
    /* fill out the film dirname */
98 99
    snprintf(film->dirname, sizeof(film->dirname), "%s", (gchar *)sqlite3_column_text(stmt, 1));
    sqlite3_finalize(stmt);
100
    char datetime[20];
101
    dt_gettime(datetime, sizeof(datetime));
102

103
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
104
                                "UPDATE main.film_rolls SET datetime_accessed = ?1 WHERE id = ?2", -1, &stmt,
105
                                NULL);
106
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, -1, SQLITE_STATIC);
107
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, film->id);
108
    sqlite3_step(stmt);
109

110 111 112 113
    sqlite3_finalize(stmt);
    dt_film_set_query(film->id);
    dt_control_queue_redraw_center();
    dt_view_manager_reset(darktable.view_manager);
114 115
    return 0;
  }
116 117
  else
    sqlite3_finalize(stmt);
118 119 120

  /* failure */
  return 1;
121 122
}

123
int dt_film_open(const int32_t id)
124
{
125
  sqlite3_stmt *stmt;
126
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
127
                              "SELECT id, folder FROM main.film_rolls WHERE id = ?1", -1, &stmt, NULL);
128 129 130 131 132
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  if(sqlite3_step(stmt) == SQLITE_ROW)
  {
    sqlite3_finalize(stmt);
    char datetime[20];
133
    dt_gettime(datetime, sizeof(datetime));
134

135
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
136
                                "UPDATE main.film_rolls SET datetime_accessed = ?1 WHERE id = ?2", -1, &stmt,
137
                                NULL);
138
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, -1, SQLITE_STATIC);
139 140 141 142 143 144
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id);
    sqlite3_step(stmt);
  }
  sqlite3_finalize(stmt);
  // TODO: prefetch to cache using image_open
  dt_film_set_query(id);
145
  dt_control_queue_redraw_center();
146 147
  dt_view_manager_reset(darktable.view_manager);
  return 0;
148
}
149

150
// FIXME: needs a rewrite
151
int dt_film_open_recent(const int num)
jhanika's avatar
jhanika committed
152
{
153
  sqlite3_stmt *stmt;
154
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
155
                              "SELECT id FROM main.film_rolls ORDER BY datetime_accessed DESC LIMIT ?1,1", -1,
156
                              &stmt, NULL);
157 158 159 160 161 162 163
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, num);
  if(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int id = sqlite3_column_int(stmt, 0);
    sqlite3_finalize(stmt);
    if(dt_film_open(id)) return 1;
    char datetime[20];
164
    dt_gettime(datetime, sizeof(datetime));
165
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
166
                                "UPDATE main.film_rolls SET datetime_accessed = ?1 WHERE id = ?2", -1, &stmt,
167
                                NULL);
168
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, -1, SQLITE_STATIC);
169 170 171 172 173 174
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id);
    sqlite3_step(stmt);
  }
  sqlite3_finalize(stmt);
  // dt_control_update_recent_films();
  return 0;
175 176
}

177
int dt_film_new(dt_film_t *film, const char *directory)
178
{
179 180 181 182
  // Try open filmroll for folder if exists
  film->id = -1;
  int rc;
  sqlite3_stmt *stmt;
183
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.film_rolls WHERE folder = ?1",
184
                              -1, &stmt, NULL);
185
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, directory, -1, SQLITE_STATIC);
186
  if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0);
187 188 189 190 191 192
  sqlite3_finalize(stmt);

  if(film->id <= 0)
  {
    // create a new filmroll
    char datetime[20];
193
    dt_gettime(datetime, sizeof(datetime));
194
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
195 196
                                "INSERT INTO main.film_rolls (id, datetime_accessed, folder) "
                                "VALUES (NULL, ?1, ?2)",
197
                                -1, &stmt, NULL);
198 199
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, -1, SQLITE_STATIC);
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, directory, -1, SQLITE_STATIC);
200
    dt_pthread_mutex_lock(&darktable.db_insert);
201
    rc = sqlite3_step(stmt);
202 203
    if(rc != SQLITE_DONE)
      fprintf(stderr, "[film_new] failed to insert film roll! %s\n",
204
              sqlite3_errmsg(dt_database_get(darktable.db)));
205
    sqlite3_finalize(stmt);
206
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.film_rolls WHERE folder=?1",
207
                                -1, &stmt, NULL);
208
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, directory, -1, SQLITE_STATIC);
209
    if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0);
210
    sqlite3_finalize(stmt);
211
    dt_pthread_mutex_unlock(&darktable.db_insert);
212 213
  }

214 215
  if(film->id <= 0) return 0;
  g_strlcpy(film->dirname, directory, sizeof(film->dirname));
216 217
  film->last_loaded = 0;
  return film->id;
218 219
}

Boucman's avatar
Boucman committed
220
int dt_film_import(const char *dirname)
221
{
222 223
  int rc;
  sqlite3_stmt *stmt;
224
  GError *error = NULL;
225

226
  /* initialize a film object*/
227 228 229
  dt_film_t *film = (dt_film_t *)malloc(sizeof(dt_film_t));
  dt_film_init(film);
  film->id = -1;
230

231
  /* lookup if film exists and reuse id */
232
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.film_rolls WHERE folder = ?1",
233
                              -1, &stmt, NULL);
234
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, dirname, -1, SQLITE_STATIC);
235
  if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0);
236
  sqlite3_finalize(stmt);
237

Unknown's avatar
Unknown committed
238
  /* if we didn't find an id, lets instantiate a new filmroll */
239 240 241
  if(film->id <= 0)
  {
    char datetime[20];
242
    dt_gettime(datetime, sizeof(datetime));
243
    /* insert a new film roll into database */
244
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
245 246
                                "INSERT INTO main.film_rolls (id, datetime_accessed, folder) VALUES "
                                "(NULL, ?1, ?2)",
247
                                -1, &stmt, NULL);
248 249
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, -1, SQLITE_STATIC);
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, dirname, -1, SQLITE_STATIC);
250

251
    rc = sqlite3_step(stmt);
252 253
    if(rc != SQLITE_DONE)
      fprintf(stderr, "[film_import] failed to insert film roll! %s\n",
254
              sqlite3_errmsg(dt_database_get(darktable.db)));
255
    sqlite3_finalize(stmt);
256

257
    /* requery for filmroll and fetch new id */
258
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.film_rolls WHERE folder=?1",
259
                                -1, &stmt, NULL);
260
    DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, dirname, -1, SQLITE_STATIC);
261
    if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0);
262 263
    sqlite3_finalize(stmt);
  }
264 265

  /* bail out if we got troubles */
266 267
  if(film->id <= 0)
  {
268 269 270 271 272
    // if the film is empty => remove it again.
    if(dt_film_is_empty(film->id))
    {
      dt_film_remove(film->id);
    }
273 274 275 276
    dt_film_cleanup(film);
    free(film);
    return 0;
  }
277

278 279 280
  // when called without job system running the import will be done synchronously and destroy the film object
  int filmid = film->id;

281
  /* at last put import film job on queue */
282
  film->last_loaded = 0;
283 284 285
  g_strlcpy(film->dirname, dirname, sizeof(film->dirname));
  char *last = &film->dirname[strlen(film->dirname) - 1];
  if(*last == '/' && last != film->dirname) *last = '\0'; // remove the closing /, unless it's also the start
286 287 288 289 290 291 292 293 294
  film->dir = g_dir_open(film->dirname, 0, &error);
  if(error)
  {
    fprintf(stderr, "[film_import] failed to open directory %s: %s\n", film->dirname, error->message);
    g_error_free(error);
    dt_film_cleanup(film);
    free(film);
    return 0;
  }
295
  dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, dt_film_import1_create(film));
296

297
  return filmid;
298 299
}

300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
static gboolean ask_and_delete(gpointer user_data)
{
  GList *empty_dirs = (GList *)user_data;
  const int n_empty_dirs = g_list_length(empty_dirs);

  GtkWidget *dialog;
  GtkWidget *win = dt_ui_main_window(darktable.gui->ui);

  dialog = gtk_message_dialog_new(GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
                                  GTK_BUTTONS_YES_NO,
                                  ngettext("do you want to remove this empty directory?",
                                           "do you want to remove these empty directories?", n_empty_dirs));

  gtk_window_set_title(GTK_WINDOW(dialog),
                       ngettext("remove empty directory?", "remove empty directories?", n_empty_dirs));

  GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));

  GtkWidget *scroll = gtk_scrolled_window_new(NULL, NULL);
  gtk_widget_set_vexpand(scroll, TRUE);
  gtk_widget_set_margin_start(scroll, DT_PIXEL_APPLY_DPI(10));
  gtk_widget_set_margin_end(scroll, DT_PIXEL_APPLY_DPI(10));
  gtk_widget_set_margin_top(scroll, DT_PIXEL_APPLY_DPI(0));
  gtk_widget_set_margin_bottom(scroll, DT_PIXEL_APPLY_DPI(0));

  GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);

  for(GList *list_iter = empty_dirs; list_iter; list_iter = g_list_next(list_iter))
  {
    GtkTreeIter iter;
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, 0, list_iter->data, -1);
  }

  GtkWidget *tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);

  GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(_("name"), gtk_cell_renderer_text_new(),
                                                                       "text", 0, NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);

  gtk_container_add(GTK_CONTAINER(scroll), tree);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);

  gtk_container_add(GTK_CONTAINER(content_area), scroll);

  gtk_widget_show_all(dialog); // needed for the content area!

  gint res = gtk_dialog_run(GTK_DIALOG(dialog));
  gtk_widget_destroy(dialog);
  if(res == GTK_RESPONSE_YES)
    for(GList *iter = empty_dirs; iter; iter = g_list_next(iter))
      rmdir((char *)iter->data);

  g_list_free_full(empty_dirs, g_free);
  g_object_unref(store);

  return FALSE;
}

360 361 362
void dt_film_remove_empty()
{
  // remove all empty film rolls from db:
363 364
  GList *empty_dirs = NULL;
  gboolean ask_before_rmdir = dt_conf_get_bool("ask_before_rmdir");
365
  gboolean raise_signal = FALSE;
366
  sqlite3_stmt *stmt;
367 368
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id,folder FROM main.film_rolls AS B WHERE "
                                                             "(SELECT COUNT(*) FROM main.images AS A WHERE "
369 370 371
                                                             "A.film_id=B.id)=0",
                              -1, &stmt, NULL);
  while(sqlite3_step(stmt) == SQLITE_ROW)
372
  {
373 374
    sqlite3_stmt *inner_stmt;
    raise_signal = TRUE;
Pascal Obry's avatar
Pascal Obry committed
375
    const gint id = sqlite3_column_int(stmt, 0);
376
    const gchar *folder = (const gchar *)sqlite3_column_text(stmt, 1);
377
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.film_rolls WHERE id=?1", -1,
378
                                &inner_stmt, NULL);
379 380 381
    DT_DEBUG_SQLITE3_BIND_INT(inner_stmt, 1, id);
    sqlite3_step(inner_stmt);
    sqlite3_finalize(inner_stmt);
382

383 384 385 386 387
    if(dt_util_is_dir_empty(folder))
    {
      if(ask_before_rmdir) empty_dirs = g_list_append(empty_dirs, g_strdup(folder));
      else rmdir(folder);
    }
388 389
  }
  sqlite3_finalize(stmt);
390
  if(raise_signal) dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_REMOVED);
391 392 393 394

  // dispatch asking for deletion (and subsequent deletion) to the gui thread
  if(empty_dirs)
    g_idle_add(ask_and_delete, empty_dirs);
395 396
}

397 398
int dt_film_is_empty(const int id)
{
399
  int empty = 0;
400
  sqlite3_stmt *stmt;
401
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE film_id = ?1", -1,
402
                              &stmt, NULL);
403
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
404
  if(sqlite3_step(stmt) != SQLITE_ROW) empty = 1;
405 406
  sqlite3_finalize(stmt);
  return empty;
407 408
}

409 410
// This is basically the same as dt_image_remove() from common/image.c.
// It just does the iteration over all images in the SQL statement
johannes hanika's avatar
johannes hanika committed
411 412
void dt_film_remove(const int id)
{
413 414
  // only allowed if local copies have their original accessible

415
  sqlite3_stmt *stmt;
416 417

  gboolean remove_ok = TRUE;
418
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE film_id = ?1", -1,
419
                              &stmt, NULL);
420 421 422 423 424
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);

  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int imgid = sqlite3_column_int(stmt, 0);
425
    if(!dt_image_safe_remove(imgid))
426 427 428 429 430 431 432
    {
      remove_ok = FALSE;
      break;
    }
  }
  sqlite3_finalize(stmt);

433
  if(!remove_ok)
434
  {
Pascal Obry's avatar
Pascal Obry committed
435
    dt_control_log(_("cannot remove film roll having local copies with non accessible originals"));
436 437 438
    return;
  }

439 440
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.tagged_images WHERE imgid IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
441
                              -1, &stmt, NULL);
442 443
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
444
  sqlite3_finalize(stmt);
445 446
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
447
                              -1, &stmt, NULL);
448 449
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
450
  sqlite3_finalize(stmt);
451 452
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.color_labels WHERE imgid IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
453
                              -1, &stmt, NULL);
454 455
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
456
  sqlite3_finalize(stmt);
457 458
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.meta_data WHERE id IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
459
                              -1, &stmt, NULL);
460 461
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
462
  sqlite3_finalize(stmt);
463 464
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.selected_images WHERE imgid IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
465
                              -1, &stmt, NULL);
466 467
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
468
  sqlite3_finalize(stmt);
johannes hanika's avatar
johannes hanika committed
469

470
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE film_id = ?1", -1,
471
                              &stmt, NULL);
472
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
473
  while(sqlite3_step(stmt) == SQLITE_ROW)
474 475
  {
    const uint32_t imgid = sqlite3_column_int(stmt, 0);
476
    dt_image_local_copy_reset(imgid);
477
    dt_mipmap_cache_remove(darktable.mipmap_cache, imgid);
478
    dt_image_cache_remove(darktable.image_cache, imgid);
479
  }
480
  sqlite3_finalize(stmt);
johannes hanika's avatar
johannes hanika committed
481

482 483
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.images WHERE id IN "
                                                             "(SELECT id FROM main.images WHERE film_id = ?1)",
484
                              -1, &stmt, NULL);
485 486
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
487 488
  sqlite3_finalize(stmt);

489
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.film_rolls WHERE id = ?1", -1,
490
                              &stmt, NULL);
491 492 493
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
  sqlite3_step(stmt);
  sqlite3_finalize(stmt);
494
  // dt_control_update_recent_films();
495 496 497

  dt_tag_update_used_tags();

498
  dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED);
499
}
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515

GList *dt_film_get_image_ids(const int filmid)
{
  GList *result = NULL;
  sqlite3_stmt *stmt;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE film_id = ?1",
                              -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, filmid);
  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int id = sqlite3_column_int(stmt, 0);
    result = g_list_append(result, GINT_TO_POINTER(id));
  }
  return result;
}

Richard Wonka's avatar
Richard Wonka committed
516
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
517
// vim: shiftwidth=2 expandtab tabstop=2 cindent
Tobias Ellinghaus's avatar
Tobias Ellinghaus committed
518
// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;