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; }
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; }