Esempio n. 1
0
void dt_selection_select_unaltered(dt_selection_t *selection)
{
  char *fullq = NULL;

  if (!selection->collection)
    return;

  /* set unaltered collection filter and update query */
  uint32_t old_filter_flags = dt_collection_get_filter_flags(selection->collection);
  dt_collection_set_filter_flags (selection->collection,
                                  (dt_collection_get_filter_flags(selection->collection) |
                                   COLLECTION_FILTER_UNALTERED));
  dt_collection_update(selection->collection);


  fullq = dt_util_dstrcat(fullq, "%s", "insert or ignore into selected_images ");
  fullq = dt_util_dstrcat(fullq, "%s", dt_collection_get_query(selection->collection));


  /* clean current selection and select unaltered images */
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        "delete from selected_images", NULL, NULL, NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        fullq, NULL, NULL, NULL);

  /* restore collection filter and update query */
  dt_collection_set_filter_flags(selection->collection, old_filter_flags);
  dt_collection_update(selection->collection);

  g_free(fullq);

  selection->last_single_id = -1;
}
Esempio n. 2
0
void dt_selection_select_range(dt_selection_t *selection, uint32_t imgid)
{
  gchar *fullq = NULL;

  if(!selection->collection || selection->last_single_id == -1) return;

  /* get start and end rows for range selection */
  sqlite3_stmt *stmt;
  int rc = 0;
  uint32_t sr = -1, er = -1;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), dt_collection_get_query_no_group(selection->collection),
                              -1, &stmt, NULL);

  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    const int id = sqlite3_column_int(stmt, 0);
    if(id == selection->last_single_id) sr = rc;

    if(id == imgid) er = rc;

    if(sr != -1 && er != -1) break;

    rc++;
  }

  sqlite3_finalize(stmt);

  /* select the images in range from start to end */
  const uint32_t old_flags = dt_collection_get_query_flags(selection->collection);

  /* use the limit to select range of images */
  dt_collection_set_query_flags(selection->collection, (old_flags | COLLECTION_QUERY_USE_LIMIT));

  dt_collection_update(selection->collection);

  fullq = dt_util_dstrcat(fullq, "%s", "INSERT OR IGNORE INTO main.selected_images ");
  fullq = dt_util_dstrcat(fullq, "%s", dt_collection_get_query_no_group(selection->collection));

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), fullq, -1, &stmt, NULL);

  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, MIN(sr, er));
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, (MAX(sr, er) - MIN(sr, er)) + 1);

  sqlite3_step(stmt);
  sqlite3_finalize(stmt);

  /* reset filter */
  dt_collection_set_query_flags(selection->collection, old_flags);
  dt_collection_update(selection->collection);

  // The logic above doesn't handle groups, so explicitly select the beginning and end to make sure those are selected properly
  dt_selection_select(selection, selection->last_single_id);
  dt_selection_select(selection, imgid);

  g_free(fullq);
}
Esempio n. 3
0
void dt_selection_select_range(dt_selection_t *selection, uint32_t imgid)
{
  gchar *fullq = NULL;
  sqlite3_stmt *stmt;
  if (!selection->collection || selection->last_single_id == -1)
    return;

  /* get start and end rows for range selection */
  int rc=0;
  uint32_t sr=-1,er=-1;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                              dt_collection_get_query(selection->collection), -1, &stmt, NULL);

  while(sqlite3_step(stmt)==SQLITE_ROW)
  {
    int id = sqlite3_column_int(stmt, 0);
    if (id == selection->last_single_id)
      sr = rc;

    if (id == imgid)
      er = rc;

    if (sr != -1 && er != -1 )
      break;

    rc++;
  }

  sqlite3_finalize(stmt);

  /* selece the images in range from start to end */
  uint32_t old_flags = dt_collection_get_query_flags(selection->collection);

  /* use the limit to select range of images */
  dt_collection_set_query_flags(selection->collection,
                                (old_flags |COLLECTION_QUERY_USE_LIMIT));

  dt_collection_update(selection->collection);

  fullq = dt_util_dstrcat(fullq, "%s", "insert or ignore into selected_images ");
  fullq = dt_util_dstrcat(fullq, "%s", dt_collection_get_query(selection->collection));

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),
                              fullq, -1, &stmt, NULL);

  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, MIN(sr,er));
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, (MAX(sr,er)-MIN(sr,er))+1);

  sqlite3_step(stmt);

  /* reset filter */
  dt_collection_set_query_flags(selection->collection,
                                old_flags);
  dt_collection_update(selection->collection);
  selection->last_single_id = -1;
}
Esempio n. 4
0
const gchar *dt_collection_get_query(const dt_collection_t *collection)
{
  /* ensure there is a query string for collection */
  if(!collection->query) dt_collection_update(collection);

  return collection->query;
}
Esempio n. 5
0
int32_t dt_control_remove_images_job_run(dt_job_t *job)
{
  long int imgid = -1;
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction=0;
  snprintf(message, 512, ngettext ("removing %d image", "removing %d images", total), total );
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);

  char query[1024];
  sprintf(query, "update images set flags = (flags | %d) where id in (select imgid from selected_images)",DT_IMAGE_REMOVE);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);

  dt_collection_update(darktable.collection);

  // We need a list of files to regenerate .xmp files if there are duplicates
  GList *list = NULL;
  sqlite3_stmt *stmt = NULL;

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select distinct folder || '/' || filename from images, film_rolls where images.film_id = film_rolls.id and images.id in (select imgid from selected_images)", -1, &stmt, NULL);
  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    list = g_list_append(list, g_strdup((const gchar *)sqlite3_column_text(stmt, 0)));
  }
  sqlite3_finalize(stmt);

  while(t)
  {
    imgid = (long int)t->data;
    dt_image_remove(imgid);
    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }

  char *imgname;
  while(list)
  {
    imgname = (char *)list->data;
    dt_image_synch_all_xmp(imgname);
    list = g_list_delete_link(list, list);
  }
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  dt_control_queue_redraw_center();
  return 0;
}
Esempio n. 6
0
void _selection_update_collection(gpointer instance, gpointer user_data)
{
  dt_selection_t *selection = (dt_selection_t *)user_data;

  /* free previous collection copy if any */
  if(selection->collection) dt_collection_free(selection->collection);

  /* create a new fresh copy of darktable collection */
  selection->collection = dt_collection_new(darktable.collection);

  /* remove limit part of local collection */
  dt_collection_set_query_flags(selection->collection, (dt_collection_get_query_flags(selection->collection)
                                                        & (~(COLLECTION_QUERY_USE_LIMIT))));
  dt_collection_update(selection->collection);
}
Esempio n. 7
0
void dt_selection_select_filmroll(dt_selection_t *selection)
{
  // clear at start, too, just to be sure:
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.tmp_selection", NULL, NULL, NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        "INSERT INTO memory.tmp_selection SELECT imgid FROM main.selected_images", NULL, NULL,
                        NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM main.selected_images", NULL, NULL, NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db),
                        "INSERT OR IGNORE INTO main.selected_images SELECT id FROM main.images WHERE film_id IN "
                        "(SELECT film_id FROM main.images AS a JOIN memory.tmp_selection AS "
                        "b ON a.id = b.imgid)",
                        NULL, NULL, NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.tmp_selection", NULL, NULL, NULL);

  dt_collection_update(selection->collection);

  selection->last_single_id = -1;
}
Esempio n. 8
0
static int32_t _generic_dt_control_fileop_images_job_run(dt_job_t *job,
    int32_t (*fileop_callback)(const int32_t, const int32_t),
    const char *desc, const char *desc_pl)
{
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction = 0;
  gchar *newdir = (gchar *)job->user_data;

  /* create a cancellable bgjob ui template */
  g_snprintf(message, 512, ngettext(desc, desc_pl, total), total);
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);
  dt_control_backgroundjobs_set_cancellable(darktable.control, jid, job);

  // create new film roll for the destination directory
  dt_film_t new_film;
  const int32_t film_id = dt_film_new(&new_film, newdir);
  g_free(newdir);

  if (film_id <= 0)
  {
    dt_control_log(_("failed to create film roll for destination directory, aborting move.."));
    dt_control_backgroundjobs_destroy(darktable.control, jid);
    return -1;
  }

  while(t && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED)
  {
    fileop_callback(GPOINTER_TO_INT(t->data), film_id);
    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }

  dt_collection_update(darktable.collection);
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  return 0;
}
Esempio n. 9
0
int32_t dt_control_delete_images_job_run(dt_job_t *job)
{
  long int imgid = -1;
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction=0;
  snprintf(message, 512, ngettext ("deleting %d image", "deleting %d images", total), total );
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);

  sqlite3_stmt *stmt;

  char query[1024];
  sprintf(query, "update images set flags = (flags | %d) where id in (select imgid from selected_images)",DT_IMAGE_REMOVE);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);

  dt_collection_update(darktable.collection);

  // We need a list of files to regenerate .xmp files if there are duplicates
  GList *list = NULL;

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select distinct folder || '/' || filename from images, film_rolls where images.film_id = film_rolls.id and images.id in (select imgid from selected_images)", -1, &stmt, NULL);

  if(sqlite3_step(stmt) == SQLITE_ROW)
  {
    list = g_list_append(list, g_strdup((const gchar *)sqlite3_column_text(stmt, 0)));
  }
  sqlite3_finalize(stmt);

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images where filename in (select filename from images where id = ?1) and film_id in (select film_id from images where id = ?1)", -1, &stmt, NULL);
  while(t)
  {
    imgid = (long int)t->data;
    char filename[DT_MAX_PATH_LEN];
    dt_image_full_path(imgid, filename, DT_MAX_PATH_LEN);

    int duplicates = 0;
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
    if(sqlite3_step(stmt) == SQLITE_ROW)
      duplicates = sqlite3_column_int(stmt, 0);
    sqlite3_reset(stmt);
    sqlite3_clear_bindings(stmt);

    // remove from disk:
    if(duplicates == 1) // don't remove the actual data if there are (other) duplicates using it
      (void)g_unlink(filename);
    dt_image_path_append_version(imgid, filename, DT_MAX_PATH_LEN);
    char *c = filename + strlen(filename);
    sprintf(c, ".xmp");
    (void)g_unlink(filename);

    dt_image_remove(imgid);

    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }
  sqlite3_finalize(stmt);

  char *imgname;
  while(list)
  {
    imgname = (char *)list->data;
    dt_image_synch_all_xmp(imgname);
    list = g_list_delete_link(list, list);
  }
  g_list_free(list);
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  dt_control_queue_redraw_center();
  return 0;
}
Esempio n. 10
0
void dt_similarity_match_image(uint32_t imgid,dt_similarity_t *data)
{
  sqlite3_stmt *stmt;
  gboolean all_ok_for_match = TRUE;
  dt_similarity_histogram_t orginal_histogram,test_histogram;
  dt_similarity_lightmap_t orginal_lightmap,test_lightmap;
 
  /* create temporary mem table for matches */
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "create temporary table if not exists similar_images (id integer,score real)", NULL, NULL, NULL);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "delete from similar_images", NULL, NULL, NULL);
  
  /* 
   * get the histogram and lightmap data for image to match against 
   */
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select histogram,lightmap from images where id = ?1", -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
  if (sqlite3_step(stmt) == SQLITE_ROW)
  {
    /* get the histogram data */
    uint32_t size = sqlite3_column_bytes(stmt,0);
    if (size!=sizeof(dt_similarity_histogram_t)) 
    {
      all_ok_for_match = FALSE;
      dt_control_log(_("this image has not been indexed yet."));
    } 
    else 
      memcpy(&orginal_histogram, sqlite3_column_blob(stmt, 0), sizeof(dt_similarity_histogram_t));

    /* get the lightmap data */
    size = sqlite3_column_bytes(stmt,1);
    if (size!=sizeof(dt_similarity_lightmap_t)) 
    {
      all_ok_for_match = FALSE;
      dt_control_log(_("this image has not been indexed yet."));
    } 
    else 
      memcpy(&orginal_lightmap, sqlite3_column_blob(stmt, 1), sizeof(dt_similarity_lightmap_t));
    
  }
  else
  {
    all_ok_for_match = FALSE;
    dt_control_log(_("this image has not been indexed yet."));
  }
  sqlite3_reset(stmt);
  sqlite3_clear_bindings(stmt);
  
  
  /*
   * if all ok lets begin matching
   */
  if (all_ok_for_match) 
  {
    char query[4096]={0};

    /* add target image with 100.0 in score into result to ensure it always shown in top */
    sprintf(query,"insert into similar_images(id,score) values(%d,%f)",imgid,100.0);
    DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);
    

    /* set an extended collection query for viewing the result of match */
    dt_collection_set_extended_where(darktable.collection, ", similar_images where images.id = similar_images.id order by similar_images.score desc");
    dt_collection_set_query_flags( darktable.collection, 
            dt_collection_get_query_flags(darktable.collection) | COLLECTION_QUERY_USE_ONLY_WHERE_EXT);
    dt_collection_update(darktable.collection);
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED);  

        
    /* loop thru images and generate score table */
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id,histogram,lightmap from images", -1, &stmt, NULL);
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
      float score_histogram=0, score_lightmap=0, score_colormap=0;
      
      /* verify size of histogram and lightmap blob of test image */
      if ( 
                  (sqlite3_column_bytes(stmt,1) == sizeof(dt_similarity_histogram_t)) && 
                  (sqlite3_column_bytes(stmt,2) == sizeof(dt_similarity_lightmap_t))
      )
      {
        /*
         * Get the histogram blob and calculate the similarity score
         */
        memcpy(&test_histogram, sqlite3_column_blob(stmt, 1), sizeof(dt_similarity_histogram_t));
        score_histogram = _similarity_match_histogram_rgb(data, &orginal_histogram, &test_histogram);
         
        /*
         * Get the lightmap blob and calculate the similarity score
         *  1.08 is a tuned constant that works well with threshold
         */
        memcpy(&test_lightmap, sqlite3_column_blob(stmt, 2), sizeof(dt_similarity_lightmap_t));
        score_lightmap = _similarity_match_lightmap(data, &orginal_lightmap, &test_lightmap);
        
        /*
         * then calculate the colormap similarity score
         */
        score_colormap = _similarity_match_colormap(data, &orginal_lightmap, &test_lightmap);
       
        
        /* 
         * calculate the similarity score
         */
	float score =  (pow(score_histogram, data->histogram_weight) *
			     pow(score_lightmap, data->lightmap_weight) *
			     pow(score_colormap, data->redmap_weight));
       
        // fprintf(stderr,"score: %f, histo: %f, light: %f, color: %f\n",score,score_histogram,score_lightmap,score_colormap);

        
        /* 
         * If current images scored, lets add it to similar_images table 
         */
        if(score >= 0.92)
        {
          sprintf(query,"insert into similar_images(id,score) values(%d,%f)",sqlite3_column_int(stmt, 0),score);
          DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);
                    
          /* lets redraw the view */
          dt_control_queue_redraw_center();
        }
      } else
        fprintf(stderr,"Image has inconsisten similarity matching data..\n");
    }
  }
  sqlite3_finalize (stmt);  

}
Esempio n. 11
0
void
dt_collection_update_query(const dt_collection_t *collection)
{
  char query[1024], confname[200];
  gchar *complete_query = NULL;

  const int _n_r = dt_conf_get_int("plugins/lighttable/collect/num_rules");
  const int num_rules = CLAMP(_n_r, 1, 10);
  char *conj[] = {"and", "or", "and not"};

  complete_query = dt_util_dstrcat(complete_query, "(");

  for(int i=0; i<num_rules; i++)
  {
    snprintf(confname, sizeof(confname), "plugins/lighttable/collect/item%1d", i);
    const int property = dt_conf_get_int(confname);
    snprintf(confname, sizeof(confname), "plugins/lighttable/collect/string%1d", i);
    gchar *text = dt_conf_get_string(confname);
    if(!text) break;
    snprintf(confname, sizeof(confname), "plugins/lighttable/collect/mode%1d", i);
    const int mode = dt_conf_get_int(confname);
    gchar *escaped_text = dt_util_str_replace(text, "'", "''");

    get_query_string(property, escaped_text, query, sizeof(query));

    if(i > 0)
      complete_query = dt_util_dstrcat(complete_query, " %s %s", conj[mode], query);
    else
      complete_query = dt_util_dstrcat(complete_query, "%s", query);

    g_free(escaped_text);
    g_free(text);
  }

  complete_query = dt_util_dstrcat(complete_query, ")");

  // printf("complete query: `%s'\n", complete_query);

  /* set the extended where and the use of it in the query */
  dt_collection_set_extended_where (collection, complete_query);
  dt_collection_set_query_flags (collection, (dt_collection_get_query_flags (collection) | COLLECTION_QUERY_USE_WHERE_EXT));

  /* remove film id from default filter */
  dt_collection_set_filter_flags (collection, (dt_collection_get_filter_flags (collection) & ~COLLECTION_FILTER_FILM_ID));

  /* update query and at last the visual */
  dt_collection_update (collection);

  /* free string */
  g_free(complete_query);

  // remove from selected images where not in this query.
  sqlite3_stmt *stmt = NULL;
  const gchar *cquery = dt_collection_get_query(collection);
  complete_query = NULL;
  if(cquery && cquery[0] != '\0')
  {
    complete_query = dt_util_dstrcat(complete_query, "delete from selected_images where imgid not in (%s)", cquery);
    DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), complete_query, -1, &stmt, NULL);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, 0);
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, -1);
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);

    /* free allocated strings */
    g_free(complete_query);
  }


  /* raise signal of collection change, only if this is an original */
  if (!collection->clone)
    dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED);

}
Esempio n. 12
0
int32_t dt_control_remove_images_job_run(dt_job_t *job)
{
  long int imgid = -1;
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction=0;
  snprintf(message, 512, ngettext ("removing %d image", "removing %d images", total), total );
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);
  sqlite3_stmt *stmt = NULL;

  // check that we can safely remove the image
  char query[1024];
  gboolean remove_ok = TRUE;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM images WHERE id IN (SELECT imgid FROM selected_images) AND flags&?1=?1", -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, DT_IMAGE_LOCAL_COPY);

  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int imgid = sqlite3_column_int(stmt, 0);
    if (!dt_image_safe_remove(imgid))
    {
      remove_ok = FALSE;
      break;
    }
  }
  sqlite3_finalize(stmt);

  if (!remove_ok)
  {
    dt_control_log(_("cannot remove local copy when the original file is not accessible."));
    dt_control_backgroundjobs_destroy(darktable.control, jid);
    return 0;
  }

  // update remove status
  sprintf(query, "update images set flags = (flags | %d) where id in (select imgid from selected_images)",DT_IMAGE_REMOVE);
  DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);

  dt_collection_update(darktable.collection);

  // We need a list of files to regenerate .xmp files if there are duplicates
  GList *list = NULL;

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select distinct folder || '/' || filename from images, film_rolls where images.film_id = film_rolls.id and images.id in (select imgid from selected_images)", -1, &stmt, NULL);
  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    list = g_list_append(list, g_strdup((const gchar *)sqlite3_column_text(stmt, 0)));
  }
  sqlite3_finalize(stmt);

  while(t)
  {
    imgid = (long int)t->data;
    dt_image_remove(imgid);
    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }

  char *imgname;
  while(list)
  {
    imgname = (char *)list->data;
    dt_image_synch_all_xmp(imgname);
    list = g_list_delete_link(list, list);
  }
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  dt_control_queue_redraw_center();
  return 0;
}
Esempio n. 13
0
int32_t dt_control_delete_images_job_run(dt_job_t *job)
{
  int imgid = -1;
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  char *imgs = _get_image_list(t);
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction=0;
  snprintf(message, 512, ngettext ("deleting %d image", "deleting %d images", total), total );
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);

  sqlite3_stmt *stmt;

  _set_remove_flag(imgs);

  dt_collection_update(darktable.collection);

  // We need a list of files to regenerate .xmp files if there are duplicates
  GList *list = _get_full_pathname(imgs);

  free(imgs);

  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images where filename in (select filename from images where id = ?1) and film_id in (select film_id from images where id = ?1)", -1, &stmt, NULL);
  while(t)
  {
    imgid = GPOINTER_TO_INT(t->data);
    char filename[DT_MAX_PATH_LEN];
    gboolean from_cache = FALSE;
    dt_image_full_path(imgid, filename, DT_MAX_PATH_LEN, &from_cache);

    int duplicates = 0;
    DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
    if(sqlite3_step(stmt) == SQLITE_ROW)
      duplicates = sqlite3_column_int(stmt, 0);
    sqlite3_reset(stmt);
    sqlite3_clear_bindings(stmt);

    // remove from disk:
    if(duplicates == 1)
    {
      // there are no further duplicates so we can remove the source data file
      (void)g_unlink(filename);
      dt_image_remove(imgid);

      // all sidecar files - including left-overs - can be deleted;
      // left-overs can result when previously duplicates have been REMOVED;
      // no need to keep them as the source data file is gone.
      const int len = DT_MAX_PATH_LEN + 30;
      gchar pattern[len];

      // NULL terminated list of glob patterns; should include "" and can be extended if needed
      static const gchar *glob_patterns[] = { "", "_[0-9][0-9]", "_[0-9][0-9][0-9]", "_[0-9][0-9][0-9][0-9]", NULL };

      const gchar **glob_pattern = glob_patterns;
      GList *files = NULL;
      while(*glob_pattern)
      {
        snprintf(pattern, len, "%s", filename);
        gchar *c1 = pattern + strlen(pattern);
        while(*c1 != '.' && c1 > pattern) c1--;
        snprintf(c1, pattern + len - c1, "%s", *glob_pattern);
        const gchar *c2 = filename + strlen(filename);
        while(*c2 != '.' && c2 > filename) c2--;
        snprintf(c1+strlen(*glob_pattern), pattern + len - c1 - strlen(*glob_pattern), "%s.xmp", c2);

#ifdef __WIN32__
        WIN32_FIND_DATA data;
        HANDLE handle = FindFirstFile(pattern, &data);
        if(handle != INVALID_HANDLE_VALUE)
        {
          do
            files = g_list_append(files, g_strdup(data.cFileName));
          while(FindNextFile(handle, &data));
        }
#else
        glob_t globbuf;
        if(!glob(pattern, 0, NULL, &globbuf))
        {
          for(size_t i=0; i < globbuf.gl_pathc; i++)
            files = g_list_append(files, g_strdup(globbuf.gl_pathv[i]));
          globfree(&globbuf);
        }
#endif

        glob_pattern++;
      }

      GList *file_iter = g_list_first(files);
      while(file_iter != NULL)
      {
        (void)g_unlink(file_iter->data);
        file_iter = g_list_next(file_iter);
      }

      g_list_free_full(files, g_free);
    }
    else
    {
      // don't remove the actual source data if there are further duplicates using it;
      // just delete the xmp file of the duplicate selected.

      dt_image_path_append_version(imgid, filename, DT_MAX_PATH_LEN);
      char *c = filename + strlen(filename);
      sprintf(c, ".xmp");

      dt_image_remove(imgid);
      (void)g_unlink(filename);
    }

    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }
  sqlite3_finalize(stmt);

  char *imgname;
  while(list)
  {
    imgname = (char *)list->data;
    dt_image_synch_all_xmp(imgname);
    list = g_list_delete_link(list, list);
  }
  g_list_free(list);
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED);
  dt_control_queue_redraw_center();
  return 0;
}
Esempio n. 14
0
int32_t dt_control_remove_images_job_run(dt_job_t *job)
{
  int imgid = -1;
  dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param;
  GList *t = t1->index;
  char *imgs = _get_image_list(t);
  int total = g_list_length(t);
  char message[512]= {0};
  double fraction=0;
  snprintf(message, 512, ngettext ("removing %d image", "removing %d images", total), total );
  const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message);
  sqlite3_stmt *stmt = NULL;

  // check that we can safely remove the image
  gboolean remove_ok = TRUE;
  DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM images WHERE id IN (?2) AND flags&?1=?1", -1, &stmt, NULL);
  DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, DT_IMAGE_LOCAL_COPY);
  DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgs, -1, SQLITE_STATIC);

  while(sqlite3_step(stmt) == SQLITE_ROW)
  {
    int imgid = sqlite3_column_int(stmt, 0);
    if (!dt_image_safe_remove(imgid))
    {
      remove_ok = FALSE;
      break;
    }
  }
  sqlite3_finalize(stmt);

  if (!remove_ok)
  {
    dt_control_log(_("cannot remove local copy when the original file is not accessible."));
    dt_control_backgroundjobs_destroy(darktable.control, jid);
    free(imgs);
    return 0;
  }

  // update remove status
  _set_remove_flag(imgs);

  dt_collection_update(darktable.collection);

  // We need a list of files to regenerate .xmp files if there are duplicates
  GList *list = _get_full_pathname(imgs);

  free(imgs);

  while(t)
  {
    imgid = GPOINTER_TO_INT(t->data);
    dt_image_remove(imgid);
    t = g_list_delete_link(t, t);
    fraction=1.0/total;
    dt_control_backgroundjobs_progress(darktable.control, jid, fraction);
  }

  char *imgname;
  while(list)
  {
    imgname = (char *)list->data;
    dt_image_synch_all_xmp(imgname);
    list = g_list_delete_link(list, list);
  }
  dt_control_backgroundjobs_destroy(darktable.control, jid);
  dt_film_remove_empty();
  dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED);
  dt_control_queue_redraw_center();
  return 0;
}