void dt_image_set_flip(const int32_t imgid, const int32_t orientation) { sqlite3_stmt *stmt; // push new orientation to sql via additional history entry: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select MAX(num) from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); int num = 0; if(sqlite3_step(stmt) == SQLITE_ROW) { num = 1 + sqlite3_column_int(stmt, 0); } sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into history (imgid, num, module, operation, op_params, enabled, " "blendop_params, blendop_version) values" " (?1, ?2, 1, 'flip', ?3, 1, null, 0) ", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, num); DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 3, &orientation, sizeof(int32_t), SQLITE_TRANSIENT); sqlite3_step (stmt); sqlite3_finalize(stmt); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); // write that through to xmp: dt_image_write_sidecar_file(imgid); }
static int drop_cache(lua_State *L) { dt_lua_image_t imgid = -1; luaA_to(L, dt_lua_image_t, &imgid, -1); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); return 0; }
void dt_styles_remove_from_image(const char *name, int32_t imgid) { int id=0; sqlite3_stmt *stmt; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* copy history items from styles onto image */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid=?1 and operation in (select operation from style_items where styleid=?2)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id); sqlite3_step (stmt); sqlite3_finalize (stmt); /* update xmp file dt_image_synch_xmp(imgid); */ /* remove old obsolete thumbnails */ dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); /* redraw center view to update visible mipmaps */ dt_control_queue_redraw_center(); } }
void dt_history_delete_on_image(int32_t imgid) { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from mask where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); remove_preset_flag(imgid); /* if current image in develop reload history */ if (dt_dev_is_current_image (darktable.develop, imgid)) dt_dev_reload_history_items (darktable.develop); /* make sure mipmaps are recomputed */ dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); /* remove darktable|style|* tags */ dt_tag_detach_by_string("darktable|style%", imgid); }
int dt_history_load_and_apply_on_selection (gchar *filename) { int res=0; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select * from selected_images", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { int imgid = sqlite3_column_int(stmt, 0); const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, (int32_t)imgid); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); if(img) { if (dt_exif_xmp_read(img, filename, 1)) { res=1; break; } /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, imgid)) dt_dev_reload_history_items (darktable.develop); dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); } } sqlite3_finalize(stmt); return res; }
void dt_styles_apply_to_image(const char *name,gboolean duplicate, int32_t imgid) { int id=0; sqlite3_stmt *stmt; int32_t newimgid; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* check if we should make a duplicate before applying style */ if (duplicate) { newimgid = dt_image_duplicate (imgid); if(newimgid != -1) dt_history_copy_and_paste_on_image(imgid, newimgid, FALSE, NULL); } else newimgid = imgid; /* merge onto history stack, let's find history offest in destination image */ int32_t offs = 0; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT MAX(num)+1 FROM history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); if (sqlite3_step (stmt) == SQLITE_ROW) offs = sqlite3_column_int (stmt, 0); sqlite3_finalize (stmt); /* copy history items from styles onto image */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into history (imgid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num+?2,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from style_items where styleid=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); sqlite3_step (stmt); sqlite3_finalize (stmt); /* add tag */ guint tagid=0; gchar ntag[512]= {0}; g_snprintf(ntag,512,"darktable|style|%s",name); if (dt_tag_new(ntag,&tagid)) dt_tag_attach(tagid,newimgid); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, newimgid)) { dt_dev_reload_history_items (darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(newimgid); /* remove old obsolete thumbnails */ dt_mipmap_cache_remove(darktable.mipmap_cache, newimgid); /* redraw center view to update visible mipmaps */ dt_control_queue_redraw_center(); } }
void dt_image_remove(const int32_t imgid) { sqlite3_stmt *stmt; const dt_image_t *img = dt_image_cache_read_get(darktable.image_cache, imgid); int old_group_id = img->group_id; dt_image_cache_read_release(darktable.image_cache, img); // make sure we remove from the cache first, or else the cache will look for imgid in sql dt_image_cache_remove(darktable.image_cache, imgid); int new_group_id = dt_grouping_remove_from_group(imgid); if(darktable.gui && darktable.gui->expanded_group_id == old_group_id) darktable.gui->expanded_group_id = new_group_id; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update tagxtag set count = count - 1 where " "(id2 in (select tagid from tagged_images where imgid = ?1)) or " "(id1 in (select tagid from tagged_images where imgid = ?1))", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from tagged_images where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from color_labels where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from meta_data where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from selected_images where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); // also clear all thumbnails in mipmap_cache. dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); }
int dt_history_copy_and_paste_on_image (int32_t imgid, int32_t dest_imgid, gboolean merge) { sqlite3_stmt *stmt; if(imgid==dest_imgid) return 1; if(imgid==-1) { dt_control_log(_("you need to copy history from an image before you paste it onto another")); return 1; } /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; if (merge) { /* apply on top of history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(num) from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); if (sqlite3_step (stmt) == SQLITE_ROW) offs = sqlite3_column_int (stmt, 0); } else { /* replace history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step (stmt); } sqlite3_finalize (stmt); /* add the history items to stack offest */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into history (imgid, num, module, operation, op_params, enabled, blendop_params, blendop_version) select ?1, num+?2, module, operation, op_params, enabled, blendop_params, blendop_version from history where imgid = ?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, dest_imgid)) { dt_dev_reload_history_items (darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(dest_imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); return 0; }
int dt_history_load_and_apply(int imgid, gchar *filename, int history_only) { int res = 0; dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); if(img) { if(dt_exif_xmp_read(img, filename, history_only)) return 1; /* if current image in develop reload history */ if(dt_dev_is_current_image(darktable.develop, imgid)) dt_dev_reload_history_items(darktable.develop); dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_SAFE); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); } return res; }
void dt_styles_apply_to_image(const char *name,gboolean duplicate, int32_t imgid) { int id=0; sqlite3_stmt *stmt; int32_t newimgid; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* check if we should make a duplicate before applying style */ if (duplicate) { newimgid = dt_image_duplicate (imgid); if(newimgid != -1) dt_history_copy_and_paste_on_image(imgid, newimgid, FALSE, NULL); } else newimgid = imgid; /* merge onto history stack, let's find history offest in destination image */ int32_t offs = 0; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT MAX(num)+1 FROM history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); if (sqlite3_step (stmt) == SQLITE_ROW) offs = sqlite3_column_int (stmt, 0); sqlite3_finalize (stmt); /* delete all items from the temp styles_items, this table is used only to get a ROWNUM of the results */ DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.style_items",NULL,NULL,NULL); /* copy history items from styles onto temp table */ DT_DEBUG_SQLITE3_PREPARE_V2 (dt_database_get(darktable.db), "INSERT INTO MEMORY.style_items SELECT * FROM style_items WHERE styleid=?1 ORDER BY multi_priority DESC;", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step (stmt); sqlite3_finalize (stmt); /* copy the style items into the history */ DT_DEBUG_SQLITE3_PREPARE_V2 (dt_database_get(darktable.db), "INSERT INTO history (imgid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) SELECT ?1,?2+rowid,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name FROM MEMORY.style_items", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); sqlite3_step (stmt); sqlite3_finalize (stmt); /* add tag */ guint tagid=0; gchar ntag[512]= {0}; g_snprintf(ntag,512,"darktable|style|%s",name); if (dt_tag_new(ntag,&tagid)) dt_tag_attach(tagid,newimgid); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, newimgid)) { dt_dev_reload_history_items (darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(newimgid); /* remove old obsolete thumbnails */ dt_mipmap_cache_remove(darktable.mipmap_cache, newimgid); /* if we have created a duplicate, reset collected images */ if (duplicate) dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED); /* redraw center view to update visible mipmaps */ dt_control_queue_redraw_center(); } }
int dt_history_copy_and_paste_on_image (int32_t imgid, int32_t dest_imgid, gboolean merge, GList *ops) { sqlite3_stmt *stmt; if(imgid==dest_imgid) return 1; if(imgid==-1) { dt_control_log(_("you need to copy history from an image before you paste it onto another")); return 1; } /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; if (merge) { /* apply on top of history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT MAX(num)+1 FROM history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); if (sqlite3_step (stmt) == SQLITE_ROW) offs = sqlite3_column_int (stmt, 0); } else { /* replace history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step (stmt); } sqlite3_finalize (stmt); // prepare SQL request char req[2048]; strcpy (req, "insert into history (imgid, num, module, operation, op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority) select ?1, num+?2, module, operation, op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority from history where imgid = ?3"); // Add ops selection if any format: ... and num in (val1, val2) if (ops) { GList *l = ops; int first = 1; strcat (req, " and num in ("); while (l) { unsigned int value = GPOINTER_TO_UINT(l->data); char v[30]; if (!first) strcat (req, ","); snprintf (v, 30, "%u", value); strcat (req, v); first=0; l = g_list_next(l); } strcat (req, ")"); } /* add the history items to stack offest */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); if (merge && ops) _dt_history_cleanup_multi_instance(dest_imgid, offs); //we have to copy masks too //what to do with existing masks ? if (merge) { //there's very little chance that we will have same shapes id. //but we may want to handle this case anyway //and it's not trivial at all ! } else { //let's remove all existing shapes DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from mask where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); } //let's copy now strcpy (req, "insert into mask (imgid, formid, form, name, version, points, points_count, source) select ?1, formid, form, name, version, points, points_count, source from mask where imgid = ?2"); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, dest_imgid)) { dt_dev_reload_history_items (darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(dest_imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); return 0; }
// 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 void dt_film_remove(const int id) { // only allowed if local copies have their original accessible sqlite3_stmt *stmt; gboolean remove_ok = TRUE; 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, id); 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 film roll having local copies with non accessible originals")); return; } 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.masks_history WHERE imgid IN " "(SELECT id FROM main.images WHERE film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(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, id); while(sqlite3_step(stmt) == SQLITE_ROW) { const uint32_t imgid = sqlite3_column_int(stmt, 0); dt_image_local_copy_reset(imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); dt_image_cache_remove(darktable.image_cache, imgid); } sqlite3_finalize(stmt); 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)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.film_rolls WHERE id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); // dt_control_update_recent_films(); dt_tag_update_used_tags(); dt_control_signal_raise(darktable.signals, DT_SIGNAL_FILMROLLS_CHANGED); }
int dt_history_copy_and_paste_on_image(int32_t imgid, int32_t dest_imgid, gboolean merge, GList *ops) { sqlite3_stmt *stmt; if(imgid == dest_imgid) return 1; if(imgid == -1) { dt_control_log(_("you need to copy history from an image before you paste it onto another")); return 1; } // be sure the current history is written before pasting some other history data const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t *)cv) == DT_VIEW_DARKROOM) dt_dev_write_history(darktable.develop); /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; if(merge) { /* apply on top of history stack */ // first trim the stack to get rid of whatever is above the selected entry DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1 AND num >= (SELECT history_end " "FROM main.images WHERE id = imgid)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT IFNULL(MAX(num), -1)+1 FROM main.history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); if(sqlite3_step(stmt) == SQLITE_ROW) offs = sqlite3_column_int(stmt, 0); } else { /* replace history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); } sqlite3_finalize(stmt); /* delete all items from the temp styles_items, this table is used only to get a ROWNUM of the results */ DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.style_items", NULL, NULL, NULL); /* copy history items from styles onto temp table */ // prepare SQL request char req[2048]; g_strlcpy(req, "INSERT INTO memory.style_items (num, module, operation, op_params, enabled, blendop_params, " "blendop_version, multi_name, multi_priority) SELECT num, module, operation, " "op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority FROM " "main.history WHERE imgid = ?1", sizeof(req)); // Add ops selection if any format: ... and num in (val1, val2) if(ops) { GList *l = ops; int first = 1; g_strlcat(req, " AND num IN (", sizeof(req)); while(l) { unsigned int value = GPOINTER_TO_UINT(l->data); char v[30]; if(!first) g_strlcat(req, ",", sizeof(req)); snprintf(v, sizeof(v), "%u", value); g_strlcat(req, v, sizeof(req)); first = 0; l = g_list_next(l); } g_strlcat(req, ")", sizeof(req)); } DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* copy the history items into the history of the dest image */ /* note: rowid starts at 1 while num has to start at 0! */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO main.history " "(imgid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) SELECT " "?1,?2+rowid-1,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name FROM memory.style_items", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); sqlite3_step(stmt); sqlite3_finalize(stmt); if(merge && ops) _dt_history_cleanup_multi_instance(dest_imgid, offs); // we have to copy masks too // what to do with existing masks ? if(merge) { // there's very little chance that we will have same shapes id. // but we may want to handle this case anyway // and it's not trivial at all ! } else { // let's remove all existing shapes DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.mask WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); } // let's copy now g_strlcpy(req, "INSERT INTO main.mask (imgid, formid, form, name, version, points, points_count, source) SELECT " "?1, formid, form, name, version, points, points_count, source FROM main.mask WHERE imgid = ?2", sizeof(req)); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); // always make the whole stack active DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "UPDATE main.images SET history_end = (SELECT MAX(num) + 1 FROM main.history " "WHERE imgid = ?1) WHERE id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* if current image in develop reload history */ if(dt_dev_is_current_image(darktable.develop, dest_imgid)) { dt_dev_reload_history_items(darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(dest_imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); return 0; }
// 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 void dt_film_remove(const int id) { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update tagxtag set count = count - 1 where " "(id2 in (select tagid from tagged_images where imgid in " "(select id from images where film_id = ?1))) or (id1 in " "(select tagid from tagged_images where imgid in " "(select id from images where film_id = ?1)))", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from tagged_images where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from color_labels where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from meta_data where id in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from selected_images where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while(sqlite3_step(stmt) == SQLITE_ROW) { const uint32_t imgid = sqlite3_column_int(stmt, 0); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); dt_image_cache_remove (darktable.image_cache, imgid); } sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from images where id in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from film_rolls where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); // dt_control_update_recent_films(); dt_control_signal_raise(darktable.signals , DT_SIGNAL_FILMROLLS_CHANGED); }
static void dt_dev_change_image(dt_develop_t *dev, const uint32_t imgid) { // stop crazy users from sleeping on key-repeat spacebar: if(dev->image_loading) return; // get last active plugin, make sure focus out is called: gchar *active_plugin = dt_conf_get_string("plugins/darkroom/active"); dt_iop_request_focus(NULL); // store last active group dt_conf_set_int("plugins/darkroom/groups", dt_dev_modulegroups_get(dev)); // store last active plugin: if(darktable.develop->gui_module) dt_conf_set_string("plugins/darkroom/active", darktable.develop->gui_module->op); else dt_conf_set_string("plugins/darkroom/active", ""); g_assert(dev->gui_attached); // commit image ops to db dt_dev_write_history(dev); // be sure light table will update the thumbnail // TODO: only if image changed! // if() { dt_mipmap_cache_remove(darktable.mipmap_cache, dev->image_storage.id); dt_image_synch_xmp(dev->image_storage.id); } select_this_image(imgid); while(dev->history) { // clear history of old image free(((dt_dev_history_item_t *)dev->history->data)->params); free( (dt_dev_history_item_t *)dev->history->data); dev->history = g_list_delete_link(dev->history, dev->history); } // get new image: dt_dev_reload_image(dev, imgid); // make sure no signals propagate here: darktable.gui->reset = 1; GList *modules = g_list_last(dev->iop); int nb_iop = g_list_length(dev->iop); dt_dev_pixelpipe_cleanup_nodes(dev->pipe); dt_dev_pixelpipe_cleanup_nodes(dev->preview_pipe); for (int i=nb_iop-1; i>0; i--) { dt_iop_module_t *module = (dt_iop_module_t *)(g_list_nth_data(dev->iop,i)); if (module->multi_priority == 0) //if the module is the "base" instance, we keep it { dt_iop_reload_defaults(module); dt_iop_gui_update(module); } else //else we delete it and remove it from the panel { if (!dt_iop_is_hidden(module)) { gtk_container_remove (GTK_CONTAINER(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER)),module->expander); dt_iop_gui_cleanup_module(module); } //we remove the module from the list dev->iop = g_list_remove_link(dev->iop,g_list_nth(dev->iop,i)); //we cleanup the module dt_accel_disconnect_list(module->accel_closures); dt_accel_cleanup_locals_iop(module); module->accel_closures = NULL; dt_iop_cleanup_module(module); free(module); } } dt_dev_pixelpipe_create_nodes(dev->pipe, dev); dt_dev_pixelpipe_create_nodes(dev->preview_pipe, dev); dt_dev_read_history(dev); //we have to init all module instances other than "base" instance modules = dev->iop; while(modules) { dt_iop_module_t *module = (dt_iop_module_t *)(modules->data); if(module->multi_priority > 0) { if (!dt_iop_is_hidden(module)) { module->gui_init(module); dt_iop_reload_defaults(module); //we search the base iop corresponding GList *mods = g_list_first(dev->iop); dt_iop_module_t *base = NULL; int pos_module = 0; int pos_base = 0; int pos = 0; while (mods) { dt_iop_module_t *mod = (dt_iop_module_t *)(mods->data); if (mod->multi_priority == 0 && mod->instance == module->instance) { base = mod; pos_base = pos; } else if (mod == module) pos_module = pos; mods = g_list_next(mods); pos++; } if (!base) continue; /* add module to right panel */ GtkWidget *expander = dt_iop_gui_get_expander(module); dt_ui_container_add_widget(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER, expander); GValue gv = { 0, { { 0 } } }; g_value_init(&gv,G_TYPE_INT); gtk_container_child_get_property(GTK_CONTAINER(dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER)),base->expander,"position",&gv); gtk_box_reorder_child (dt_ui_get_container(darktable.gui->ui, DT_UI_CONTAINER_PANEL_RIGHT_CENTER),expander,g_value_get_int(&gv)+pos_base-pos_module); dt_iop_gui_set_expanded(module, TRUE); dt_iop_gui_update_blending(module); } /* setup key accelerators */ module->accel_closures = NULL; if(module->connect_key_accels) module->connect_key_accels(module); dt_iop_connect_common_accels(module); //we update show params for multi-instances for each other instances dt_dev_modules_update_multishow(module->dev); } modules = g_list_next(modules); } dt_dev_pop_history_items(dev, dev->history_end); if(active_plugin) { modules = dev->iop; while(modules) { dt_iop_module_t *module = (dt_iop_module_t *)(modules->data); if(!strcmp(module->op, active_plugin)) dt_iop_request_focus(module); modules = g_list_next(modules); } g_free(active_plugin); } /* last set the group to update visibility of iop modules for new pipe */ dt_dev_modulegroups_set(dev,dt_conf_get_int("plugins/darkroom/groups")); // make signals work again, but only after focus event, // to avoid crop/rotate for example to add another history item. darktable.gui->reset = 0; // Signal develop initialize dt_control_signal_raise(darktable.signals, DT_SIGNAL_DEVELOP_IMAGE_CHANGED); // prefetch next few from first selected image on. dt_view_filmstrip_prefetch(); }
void leave(dt_view_t *self) { /* disconnect from filmstrip image activate */ dt_control_signal_disconnect(darktable.signals, G_CALLBACK(_view_darkroom_filmstrip_activate_callback), (gpointer)self); /* disconnect from pipe finish signal */ dt_control_signal_disconnect(darktable.signals, G_CALLBACK(_darkroom_ui_pipe_finish_signal_callback), (gpointer)self); // store groups for next time: dt_conf_set_int("plugins/darkroom/groups", dt_dev_modulegroups_get(darktable.develop)); // store last active plugin: if(darktable.develop->gui_module) dt_conf_set_string("plugins/darkroom/active", darktable.develop->gui_module->op); else dt_conf_set_string("plugins/darkroom/active", ""); dt_develop_t *dev = (dt_develop_t *)self->data; // tag image as changed // TODO: only tag the image when there was a real change. guint tagid = 0; dt_tag_new("darktable|changed",&tagid); dt_tag_attach(tagid, dev->image_storage.id); // commit image ops to db dt_dev_write_history(dev); // be sure light table will regenerate the thumbnail: // TODO: only if changed! // if() { dt_mipmap_cache_remove(darktable.mipmap_cache, dev->image_storage.id); // dump new xmp data dt_image_synch_xmp(dev->image_storage.id); } // clear gui. dev->gui_leaving = 1; dt_pthread_mutex_lock(&dev->history_mutex); dt_dev_pixelpipe_cleanup_nodes(dev->pipe); dt_dev_pixelpipe_cleanup_nodes(dev->preview_pipe); while(dev->history) { dt_dev_history_item_t *hist = (dt_dev_history_item_t *)(dev->history->data); // printf("removing history item %d - %s, data %f %f\n", hist->module->instance, hist->module->op, *(float *)hist->params, *((float *)hist->params+1)); free(hist->params); hist->params = NULL; free(hist); dev->history = g_list_delete_link(dev->history, dev->history); } while(dev->iop) { dt_iop_module_t *module = (dt_iop_module_t *)(dev->iop->data); if (!dt_iop_is_hidden(module)) dt_iop_gui_cleanup_module(module); dt_dev_cleanup_module_accels(module); module->accel_closures = NULL; dt_iop_cleanup_module(module) ; free(module); dev->iop = g_list_delete_link(dev->iop, dev->iop); } dt_pthread_mutex_unlock(&dev->history_mutex); dt_print(DT_DEBUG_CONTROL, "[run_job-] 11 %f in darkroom mode\n", dt_get_wtime()); }