125 const char *src_prev,
const char *src_next,
126 const char *dst_prev,
const char *dst_next)
146 GHashTable *src_last_by_id, GHashTable *dst_last_before_by_id,
147 const GHashTable *orig_ids,
const GHashTable *mod_list_ids,
151 return _merge_report_handler(dev_dest, dev_src, merge_iop_order, used_source_order, strategy, src_last_by_id,
152 dst_last_before_by_id, orig_ids, mod_list_ids, source_label, batch);
175 return g_strdup_printf(
"%s|%s", op, multi_name);
181 g_list_free(
n->previous);
223 const char *sep = strchr(
id,
'|');
231 memcpy(op,
id, op_len);
253 const char *prev_id = NULL;
255 for(
const GList *l = ids; l; l = g_list_next(l))
257 const char *
id = (
const char *)l->data;
259 if(prev_id) g_hash_table_replace(prev, g_strdup(
id), g_strdup(prev_id));
281 const char *prev_id = NULL;
283 for(
const GList *l = ids; l; l = g_list_next(l))
285 const char *
id = (
const char *)l->data;
287 if(prev_id) g_hash_table_replace(next, g_strdup(prev_id), g_strdup(
id));
306 for(
const GList *
p = g_list_first(
n->previous);
p;
p = g_list_next(
p))
307 if(
p->data == pred)
return TRUE;
319 GList *link = g_list_find(
n->previous, pred);
320 if(link)
n->previous = g_list_delete_link(
n->previous, link);
360 GHashTable *map = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
364 for(GList *l = g_list_first(history); l && idx < history_end; l = g_list_next(l), idx++)
372 "[_hm_build_last_history_by_id_from_history] history_end=%d scanned=%d entries=%d\n",
373 history_end, idx, g_hash_table_size(map));
385 GHashTable *last_by_id = NULL;
389 "[_hm_backup_dest] imgid=%d history_end=%d history_len=%d iop_order=%d modules=%u selected=%d\n",
392 mod_list_ids ? g_hash_table_size((GHashTable *)mod_list_ids) : 0);
399 "[_hm_restore_dest_from_backup] imgid=%d history_end=%d history_len=%d iop_order=%d\n",
443 GHashTable *map = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
447 for(GList *modules = g_list_first(dev->
iop); modules; modules = g_list_next(modules))
456 "[_hm_build_last_history_by_id] imgid=%d history_end=%d iop=%d entries=%d\n",
464 GHashTable *ids = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
466 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
473 g_list_length((GList *)mod_list), g_hash_table_size(ids));
506 "[_hm_id_info_upsert] %s input node \n",
509 g_hash_table_insert(id_ht,
id, info);
516 info->
flags |= origin;
517 if(mod_list) info->
mod_list = mod_list;
536 for(
const GList *l = iop; l; l = g_list_next(l))
542 if(info && (info->
flags & keep_mask))
543 ids = g_list_append(ids,
id);
568 for(
const GList *l = ids; l; l = g_list_next(l))
570 const char *
id = (
const char *)l->data;
580 n->tag = g_strdup(tag);
589 if(prev)
n->previous = g_list_append(
n->previous, prev);
591 nodes = g_list_append(nodes,
n);
615 for(
const GList *l = ids; l; l = g_list_next(l))
617 const char *
id = (
const char *)l->data;
627 n->tag = g_strdup(tag);
638 const gboolean keep_edge = !focus || g_hash_table_contains((GHashTable *)focus, prev->
id)
639 || g_hash_table_contains((GHashTable *)focus,
n->id);
640 if(keep_edge)
n->previous = g_list_append(
n->previous, prev);
643 nodes = g_list_append(nodes,
n);
654 for(
const GList *l = g_list_first((GList *)modules); l; l = g_list_next(l))
668 n->tag = g_strdup(tag);
677 nodes = g_list_append(nodes,
n);
686 const char *tag, GList **out_nodes)
690 for(
const GList *l = g_list_first((GList *)modules); l; l = g_list_next(l))
701 if(!(user_info && (user_info->
flags & keep_mask) && prod_info && (prod_info->
flags & keep_mask)))
719 prod->
tag = g_strdup(tag);
720 user->
tag = g_strdup(tag);
731 nodes = g_list_append(nodes, prod);
732 nodes = g_list_append(nodes, user);
751 GList *iop_rules = NULL;
758 char next_id[256], prev_id[256];
759 snprintf(next_id,
sizeof(next_id),
"%s|", rule->op_next);
760 snprintf(prev_id,
sizeof(prev_id),
"%s|", rule->op_prev);
771 next->
tag = g_strdup(
"rule");
772 prev->
tag = g_strdup(
"rule");
781 iop_rules = g_list_append(iop_rules, next);
782 iop_rules = g_list_append(iop_rules, prev);
784 *out_nodes = iop_rules;
847 if(ctx->
id_ht) g_hash_table_destroy(ctx->
id_ht);
859 const GList *mod_list)
875 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
882 for(
const GList *l = g_list_first(dev_src->
iop); l; l = g_list_next(l))
889 for(
const GList *l = g_list_first(dev_dest->
iop); l; l = g_list_next(l))
908 const GList *mod_list,
const gboolean merge_iop_order)
926 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
934 if(merge_iop_order || !exists_in_dest) g_hash_table_add(ctx->
src_focus_ids, g_strdup(
id));
949 "[dt_history_merge_module_list_into_image_topological] iop-order solve: merge_iop_order=%d mod_list=%d "
951 "dst_iop=%d keep(dst+mod+rules) dest_constraints=%d src_constraints=%d focus=%d\n",
952 merge_iop_order, g_list_length((GList *)mod_list), g_list_length(dev_src->
iop),
953 g_list_length(dev_dest->
iop), g_list_length(ctx->
dest_ids), g_list_length(ctx->
src_ids),
961 const GList *dest_ids);
976 GList *dest_nodes = NULL;
977 GList *src_nodes = NULL;
978 GList *mod_nodes = NULL;
979 GList *dst_raster_nodes = NULL;
980 GList *src_raster_nodes = NULL;
981 GList *rule_nodes = NULL;
982 GHashTable *dest_rank = NULL;
1002 dest_rank = g_hash_table_new(g_str_hash, g_str_equal);
1006 for(
const GList *
d = g_list_first(ctx->
dest_ids);
d;
d = g_list_next(
d), rank++)
1007 g_hash_table_insert(dest_rank,
d->data, GINT_TO_POINTER(rank));
1009 for(
const GList *l = g_list_first(ctx->
src_ids); l; l = g_list_next(l))
1011 const char *
id = (
const char *)l->data;
1012 if(!g_hash_table_contains(ctx->
src_focus_ids,
id))
continue;
1016 const char *lower_id = NULL;
1017 const char *upper_id = NULL;
1018 const char *prev_focus_id = NULL;
1019 const char *next_focus_id = NULL;
1021 const GList *prev_link = g_list_previous((GList *)l);
1022 if(prev_link && g_hash_table_contains(ctx->
src_focus_ids, prev_link->data))
1023 prev_focus_id = (
const char *)prev_link->data;
1024 const GList *next_link = g_list_next(l);
1025 if(next_link && g_hash_table_contains(ctx->
src_focus_ids, next_link->data))
1026 next_focus_id = (
const char *)next_link->data;
1029 for(
const GList *
p = g_list_first(ctx->
src_ids);
p &&
p != l;
p = g_list_next(
p))
1031 const char *candidate_id = (
const char *)
p->data;
1032 const int candidate_rank = GPOINTER_TO_INT(g_hash_table_lookup(dest_rank, candidate_id));
1033 if(candidate_rank > lower_rank)
1035 lower_rank = candidate_rank;
1036 lower_id = candidate_id;
1041 for(
const GList *
n = g_list_next(l);
n;
n = g_list_next(
n))
1043 const char *candidate_id = (
const char *)
n->data;
1044 const int candidate_rank = GPOINTER_TO_INT(g_hash_table_lookup(dest_rank, candidate_id));
1045 if(candidate_rank <= lower_rank)
continue;
1046 if(upper_rank == 0 || candidate_rank < upper_rank)
1048 upper_rank = candidate_rank;
1049 upper_id = candidate_id;
1055 src_nodes = g_list_append(src_nodes, cur);
1062 src_nodes = g_list_append(src_nodes, lower);
1069 src_nodes = g_list_append(src_nodes, prev_focus);
1082 next_focus->
previous = g_list_append(next_focus->
previous, next_focus_prev);
1083 src_nodes = g_list_append(src_nodes, next_focus_prev);
1084 src_nodes = g_list_append(src_nodes, next_focus);
1097 src_nodes = g_list_append(src_nodes, upper_prev);
1098 src_nodes = g_list_append(src_nodes, upper);
1102 "[_hm_topo_flatten_constraints] destination slot: %s after %s%s%s before %s%s%s\n",
1103 id, lower_id ? lower_id :
"(none)", (lower_id && prev_focus_id) ?
", " :
"",
1104 prev_focus_id ? prev_focus_id :
"", upper_id ? upper_id :
"(end)",
1105 (upper_id && next_focus_id) ?
", " :
"", next_focus_id ? next_focus_id :
"");
1107 g_hash_table_destroy(dest_rank);
1121 const int dest_nodes_len = g_list_length(dest_nodes);
1122 const int src_nodes_len = g_list_length(src_nodes);
1123 const int mod_nodes_len = g_list_length(mod_nodes);
1124 const int dst_raster_nodes_len = g_list_length(dst_raster_nodes);
1125 const int src_raster_nodes_len = g_list_length(src_raster_nodes);
1126 const int rule_nodes_len = g_list_length(rule_nodes);
1129 g_list_concat(g_list_concat(dest_nodes, src_nodes),
1130 g_list_concat(mod_nodes, g_list_concat(dst_raster_nodes, src_raster_nodes))),
1133 "[_hm_topo_flatten_constraints] input nodes: dst=%d src=%d mod=%d dst-raster=%d src-raster=%d "
1134 "rules=%d total=%d\n",
1135 dest_nodes_len, src_nodes_len, mod_nodes_len, dst_raster_nodes_len, src_raster_nodes_len,
1141 "[dt_history_merge_module_list_into_image_topological] iop-order merge: flatten failed\n");
1151 if(dest_rank) g_hash_table_destroy(dest_rank);
1153 "[_hm_topo_flatten_constraints] failed while building input nodes: dst=%d src=%d mod=%d "
1154 "dst-raster=%d src-raster=%d rules=%d\n",
1155 g_list_length(dest_nodes), g_list_length(src_nodes), g_list_length(mod_nodes),
1156 g_list_length(dst_raster_nodes), g_list_length(src_raster_nodes), g_list_length(rule_nodes));
1167 const GList *dest_ids)
1181 GList *_hm_cycles = NULL;
1182 GHashTable *seen_cycles = NULL;
1184 GHashTable *src_prev = NULL;
1185 GHashTable *src_next = NULL;
1186 GHashTable *dst_prev = NULL;
1187 GHashTable *dst_next = NULL;
1188 const char *cleanup_reason = NULL;
1189 int cleanup_line = 0;
1192 cleanup_reason =
"_hm_build_prev_map_from_ids(src_ids)";
1193 cleanup_line = __LINE__;
1198 cleanup_reason =
"_hm_build_next_map_from_ids(src_ids)";
1199 cleanup_line = __LINE__;
1204 cleanup_reason =
"_hm_build_prev_map_from_ids(dest_ids)";
1205 cleanup_line = __LINE__;
1210 cleanup_reason =
"_hm_build_next_map_from_ids(dest_ids)";
1211 cleanup_line = __LINE__;
1225 seen_cycles = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
1228 cleanup_reason =
"g_hash_table_new_full(seen_cycles)";
1229 cleanup_line = __LINE__;
1234 for(GList *it = g_list_first(flat); it; it = g_list_next(it))
1239 for(GList *
p = g_list_first(a->previous);
p;
p = g_list_next(
p))
1246 const char *id1 = a->id;
1247 const char *id2 = b->id;
1248 if(strcmp(id1, id2) > 0)
1254 gchar *
key = g_strdup_printf(
"%s<->%s", id1, id2);
1257 cleanup_reason =
"g_strdup_printf(cycle key)";
1258 cleanup_line = __LINE__;
1261 if(g_hash_table_contains(seen_cycles,
key))
1266 g_hash_table_add(seen_cycles,
key);
1268 _hm_cycle_t *c = g_new0(_hm_cycle_t, 1);
1271 cleanup_reason =
"g_new0(_hm_cycle_t)";
1272 cleanup_line = __LINE__;
1284 _hm_cycles = g_list_append(_hm_cycles, c);
1291 const _hm_cycle_t *first = (
const _hm_cycle_t *)_hm_cycles->data;
1294 const char *sp = (faulty && src_prev) ? (
const char *)g_hash_table_lookup(src_prev, faulty->
id) : NULL;
1295 const char *sn = (faulty && src_next) ? (
const char *)g_hash_table_lookup(src_next, faulty->
id) : NULL;
1296 const char *dp = (faulty && dst_prev) ? (
const char *)g_hash_table_lookup(dst_prev, faulty->
id) : NULL;
1297 const char *dn = (faulty && dst_next) ? (
const char *)g_hash_table_lookup(dst_next, faulty->
id) : NULL;
1301 "[dt_history_merge_module_list_into_image_topological] incompatible constraints: found %d 2-cycle(s)\n",
1302 g_list_length(_hm_cycles));
1308 "[dt_history_merge_module_list_into_image_topological] incompatible constraints choice: %s\n",
1311 for(GList *l = _hm_cycles; l; l = g_list_next(l))
1313 _hm_cycle_t *c = (_hm_cycle_t *)l->data;
1319 const char *want_prev_a = NULL;
1320 const char *want_prev_b = NULL;
1324 want_prev_a = src_prev ? (
const char *)g_hash_table_lookup(src_prev, a->id) : NULL;
1325 want_prev_b = src_prev ? (
const char *)g_hash_table_lookup(src_prev, b->id) : NULL;
1330 want_prev_a = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, a->id) : NULL;
1331 want_prev_b = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, b->id) : NULL;
1334 if(want_prev_a && !strcmp(want_prev_a, b->id))
1339 else if(want_prev_b && !strcmp(want_prev_b, a->id))
1347 const char *dpa = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, a->id) : NULL;
1348 const char *dpb = dst_prev ? (
const char *)g_hash_table_lookup(dst_prev, b->id) : NULL;
1349 if(dpa && !strcmp(dpa, b->id))
1351 else if(dpb && !strcmp(dpb, a->id))
1361 g_hash_table_destroy(seen_cycles);
1362 g_hash_table_destroy(src_prev);
1363 g_hash_table_destroy(src_next);
1364 g_hash_table_destroy(dst_prev);
1365 g_hash_table_destroy(dst_next);
1370 "[_hm_topo_resolve_incompatible_constraints] cleanup from line %d: %s\n",
1371 cleanup_line, cleanup_reason ? cleanup_reason :
"unknown");
1372 if(seen_cycles) g_hash_table_destroy(seen_cycles);
1373 if(src_prev) g_hash_table_destroy(src_prev);
1374 if(src_next) g_hash_table_destroy(src_next);
1375 if(dst_prev) g_hash_table_destroy(dst_prev);
1376 if(dst_next) g_hash_table_destroy(dst_next);
1394 GList *cycle_nodes = NULL;
1399 "unsatisfiable constraints (cycle)\n");
1403 g_list_free(cycle_nodes);
1411 g_list_free(cycle_nodes);
1434 GList *ordered_modules = NULL;
1439 for(
const GList *l = g_list_first(ctx->
sorted); l; l = g_list_next(l))
1469 ordered_modules = g_list_append(ordered_modules, mod_dest);
1476 g_list_free(ordered_modules);
1477 ordered_modules = NULL;
1482 "[dt_history_merge_module_list_into_image_topological] iop-order solve: created=%d copied=%d\n",
1488 const GList *mod_list,
const gboolean merge_iop_order)
1504 "[_hm_try_merge_iop_order_topologically] start merge_iop_order=%d modules=%d dst_iop=%d src_iop=%d\n",
1505 merge_iop_order, g_list_length((GList *)mod_list), g_list_length(dev_dest->
iop),
1506 g_list_length(dev_src->
iop));
1544 "[_hm_try_merge_iop_order_topologically] success merge_iop_order=%d dst_iop=%d order=%d\n",
1545 merge_iop_order, g_list_length(dev_dest->
iop), g_list_length(dev_dest->
iop_order_list));
1560 for(GList *it = g_list_first(history); it; it = g_list_next(it), idx++)
1579 const int history_len = g_list_length(dev_dest->
history);
1581 if(history_end >= history_len)
1584 "[_hm_truncate_dest_redo_tail] no redo tail: imgid=%d end=%d len=%d\n",
1590 "[dt_history_merge_module_list_into_image_advanced] truncating destination redo tail: end=%d len=%d\n",
1591 history_end, history_len);
1596 GList *link = g_list_nth(dev_dest->
history, history_end);
1600 GList *next = g_list_next(link);
1636 for(GList *l = g_list_first(dev_dest->
iop); l; l = g_list_next(l))
1653 GHashTable *cached = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
1654 for(GList *l = g_list_first(order_ids); l; l = g_list_next(l))
1655 g_hash_table_add(cached, g_strdup((
const char *)l->data));
1657 gboolean applicable =
TRUE;
1658 GHashTable *present = g_hash_table_new_full(g_str_hash, g_str_equal,
dt_free_gpointer, NULL);
1659 for(GList *l = g_list_first(dev_dest->
iop); l; l = g_list_next(l))
1664 g_hash_table_add(present,
id);
1665 if(!g_hash_table_contains(cached,
id)) applicable =
FALSE;
1670 for(GList *l = g_list_first(order_ids); l; l = g_list_next(l))
1671 if(!g_hash_table_contains(present, (
const char *)l->data))
1678 g_hash_table_destroy(cached);
1679 g_hash_table_destroy(present);
1690 GHashTable *placed = g_hash_table_new(g_direct_hash, g_direct_equal);
1691 GList *ordered = NULL;
1693 for(GList *l = g_list_first(order_ids); l; l = g_list_next(l))
1696 if(mod && !g_hash_table_contains(placed, mod))
1698 ordered = g_list_append(ordered, mod);
1699 g_hash_table_add(placed, mod);
1703 for(GList *l = g_list_first(dev_dest->
iop); l; l = g_list_next(l))
1706 if(mod && !g_hash_table_contains(placed, mod))
1708 ordered = g_list_append(ordered, mod);
1709 g_hash_table_add(placed, mod);
1714 g_list_free(ordered);
1715 g_hash_table_destroy(placed);
1725 if(!g_strcmp0(cleanup_reason,
"merge report revert"))
1728 if(!g_strcmp0(cleanup_reason,
"_hm_try_merge_iop_order_topologically()"))
1729 return _(
"Could not paste: the pasted modules require a pipeline order that conflicts "
1730 "with this image's current module order.");
1732 if(!g_strcmp0(cleanup_reason,
"dt_dev_history_item_from_source_history_item()"))
1733 return _(
"Could not paste: one of the pasted modules could not be recreated on the "
1734 "destination image.");
1736 return _(
"Could not paste: an internal error occurred while preparing the merge.");
1740 const GList *mod_list,
const gboolean merge_iop_order,
1764 if(dest_imgid <= 0)
return 1;
1770 gboolean used_source_order = merge_iop_order;
1771 gboolean revert =
FALSE;
1772 GHashTable *mod_list_ids = NULL;
1773 GHashTable *src_last_by_id = NULL;
1774 GHashTable *dst_last_before_by_id = NULL;
1776 const char *cleanup_reason = NULL;
1777 int cleanup_line = 0;
1782 cleanup_reason =
"_hm_build_id_set_from_mod_list(mod_list)";
1783 cleanup_line = __LINE__;
1788 cleanup_reason =
"_hm_backup_dest(dev_dest)";
1789 cleanup_line = __LINE__;
1794 cleanup_reason =
"_hm_build_last_history_by_id(dev_src)";
1795 cleanup_line = __LINE__;
1800 cleanup_reason =
"_hm_build_last_history_by_id(dev_dest)";
1801 cleanup_line = __LINE__;
1805 if(force_new_modules)
1807 "temporarily unsupported, ignoring\n");
1810 "[dt_history_merge] imgid=%d merge_iop_order=%d strategy=%d "
1811 "force_new=%d modules=%d\n",
1812 dest_imgid, merge_iop_order, strategy, force_new_modules, g_list_length((GList *)mod_list));
1830 gboolean recovered =
FALSE;
1833 used_source_order =
FALSE;
1838 cleanup_reason =
"_hm_try_merge_iop_order_topologically()";
1839 cleanup_line = __LINE__;
1848 gboolean use_cached_order =
FALSE;
1852 if(use_cached_order)
1856 "[dt_history_merge] imgid=%d cached batch order not applicable (topology mismatch); "
1857 "showing merge report for manual control\n",
1864 GList *temp_history = NULL;
1866 for(
const GList *l = g_list_first((GList *)mod_list); l; l = g_list_next(l))
1885 "[dt_history_merge] build temp history: src=%s multi='%s' priority=%d hist=%s dest=%s dest_priority=%d\n",
1887 hist_src ?
"yes" :
"no", mod_dest ?
"yes" :
"no",
1891 cleanup_reason =
"dt_dev_history_item_from_source_history_item()";
1892 cleanup_line = __LINE__;
1896 temp_history = g_list_append(temp_history, hist);
1901 dev_dest->
history = g_list_concat(dev_dest->
history, temp_history);
1903 dev_dest->
history = g_list_concat(temp_history, dev_dest->
history);
1916 const gboolean silent = batch
1922 revert =
_hm_report_merge(dev_dest, dev_src, merge_iop_order, used_source_order, strategy,
1923 src_last_by_id, dst_last_before_by_id, backup.
orig_ids,
1924 mod_list_ids, source_label, batch);
1934 cleanup_reason =
"merge report revert";
1935 cleanup_line = __LINE__;
1947 cleanup_line, cleanup_reason);
1953 if(src_last_by_id) g_hash_table_destroy(src_last_by_id);
1954 if(dst_last_before_by_id) g_hash_table_destroy(dst_last_before_by_id);
1955 if(mod_list_ids) g_hash_table_destroy(mod_list_ids);
static void error(char *msg)
void cleanup(dt_imageio_module_format_t *self)
GList * dt_ioppr_get_iop_order_rules_global(void)
void dt_dev_pop_history_items_ext(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Apply history items to module params up to dev->history_end.
dt_iop_module_t * dt_dev_get_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority)
Find a module instance by op name and instance metadata.
void dt_dev_free_history_item(gpointer data)
Release a reference to a history item (used as GList free callback).
dt_iop_module_t * dt_dev_create_module_instance(dt_develop_t *dev, const char *op, const char *multi_name, const int multi_priority, gboolean use_next_priority)
Create a new module instance from an existing base .so.
GList * dt_history_duplicate(GList *hist)
Deep-copy a history list.
int dt_dev_copy_module_contents(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_dest, const dt_iop_module_t *mod_src)
void dt_dev_history_free_history(dt_develop_t *dev) REQUIRES(dev -> history_mutex)
Free the whole history list attached to dev->history.
int dt_dev_history_item_from_source_history_item(dt_develop_t *dev_dest, dt_develop_t *dev_src, const dt_dev_history_item_t *hist_src, dt_iop_module_t *mod_dest, dt_dev_history_item_t **out_hist)
dt_dev_history_item_t * dt_dev_history_get_last_item_by_module(GList *history_list, dt_iop_module_t *module, int history_end)
Find the last history item referencing a module up to history_end.
void dt_dev_write_history_ext(dt_develop_t *dev, const int32_t imgid) REQUIRES_SHARED(dev -> history_mutex)
Write dev->history to DB and XMP for a given image id.
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
void dt_history_message(const char *format,...)
Everything the history, styles and presets code says to the outside world: messages for the user,...
void dt_hm_set_merge_report_handler(dt_hm_merge_report_handler_t handler)
static int _hm_build_last_history_by_id_from_history(GList *history, const int history_end, GHashTable **out_map)
static void _hm_free_input_nodes(GList *input_nodes)
static int _hm_topo_resolve_incompatible_constraints(GList *flat, GHashTable *id_ht, const GList *src_ids, const GList *dest_ids)
static dt_hm_merge_report_handler_t _merge_report_handler
void dt_hm_set_constraints_choice_handler(dt_hm_constraints_choice_handler_t handler)
static void _hm_truncate_dest_redo_tail(dt_develop_t *dev_dest)
void _hm_id_to_op_name(const char *id, char *op, char *name)
static dt_iop_module_t * _hm_dest_module_from_id(dt_develop_t *dev, const char *id)
static void _hm_backup_cleanup(_hm_dest_backup_t *backup)
int dt_history_merge(dt_develop_t *dev_dest, dt_develop_t *dev_src, const int32_t dest_imgid, const GList *mod_list, const gboolean merge_iop_order, const dt_history_merge_strategy_t strategy, const gboolean force_new_modules, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image, solving pipeline topologies for proper insertion of...
int _hm_build_last_history_by_id(const dt_develop_t *dev, GHashTable **out_map)
static GList * _hm_capture_order_ids(dt_develop_t *dev_dest)
static int _hm_topo_build_id_info_table(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list)
char * _hm_make_node_id(const char *op, const char *multi_name)
static int _hm_topo_build_constraint_ids(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list, const gboolean merge_iop_order)
static gboolean _hm_node_has_predecessor(const dt_digraph_node_t *n, const dt_digraph_node_t *pred)
static dt_hm_missing_raster_handler_t _missing_raster_handler
static int _hm_build_input_nodes_from_ids(const GList *ids, const char *tag, GList **out_nodes)
static void _hm_remove_predecessor(dt_digraph_node_t *n, const dt_digraph_node_t *pred)
static gboolean _hm_report_merge(dt_develop_t *dev_dest, dt_develop_t *dev_src, const gboolean merge_iop_order, const gboolean used_source_order, const dt_history_merge_strategy_t strategy, GHashTable *src_last_by_id, GHashTable *dst_last_before_by_id, const GHashTable *orig_ids, const GHashTable *mod_list_ids, const char *source_label, dt_hm_batch_state_t *batch)
static _hm_id_info_t * _hm_id_info_upsert(GHashTable *id_ht, const char *op, const char *multi_name, const _hm_id_origin_t origin, const dt_iop_module_t *mod_list, const dt_iop_module_t *src_iop, dt_iop_module_t *dst_iop)
static void _hm_topo_merge_cleanup(_hm_topo_merge_ctx_t *ctx)
static int _hm_build_raster_mask_nodes_from_modules(const GList *modules, GHashTable *id_ht, const guint keep_mask, const char *tag, GList **out_nodes)
static int _hm_topo_apply_solution(_hm_topo_merge_ctx_t *ctx, dt_develop_t *dev_dest, dt_develop_t *dev_src)
static void _hm_free_input_node(dt_digraph_node_t *n)
static int _hm_topo_flatten_constraints(_hm_topo_merge_ctx_t *ctx)
static void _hm_report_toposort_cycle(GList *cycle_nodes, GHashTable *id_ht)
void dt_hm_batch_state_cleanup(dt_hm_batch_state_t *batch)
Release resources held by a batch state (the cached order). Safe to call on a zeroed state.
static int _hm_try_merge_iop_order_topologically(dt_develop_t *dev_dest, dt_develop_t *dev_src, const GList *mod_list, const gboolean merge_iop_order)
static const char * _hm_failure_message(const char *cleanup_reason)
void dt_hm_set_missing_raster_handler(dt_hm_missing_raster_handler_t handler)
void dt_hm_set_toposort_cycle_handler(dt_hm_toposort_cycle_handler_t handler)
static dt_hm_constraint_choice_t _hm_constraints_choice(GHashTable *id_ht, const char *faulty_id, const char *src_prev, const char *src_next, const char *dst_prev, const char *dst_next)
static int _hm_build_input_nodes_from_ids_filtered(const GList *ids, const char *tag, const GHashTable *focus, GList **out_nodes)
static void _hm_apply_cached_order(dt_develop_t *dev_dest, GList *order_ids)
static int _hm_ids_from_iop_list(GList *iop, GHashTable *id_ht, const guint keep_mask, GList **out_ids)
static int _hm_backup_dest(const dt_develop_t *dev_dest, const GHashTable *mod_list_ids, _hm_dest_backup_t *backup)
static dt_hm_toposort_cycle_handler_t _toposort_cycle_handler
static int _hm_build_prev_map_from_ids(const GList *ids, GHashTable **out_prev)
static int _hm_build_next_map_from_ids(const GList *ids, GHashTable **out_next)
static int _hm_build_isolated_nodes_from_modules(const GList *modules, const char *tag, GList **out_nodes)
static int _hm_topo_sort_constraints(_hm_topo_merge_ctx_t *ctx)
static int _hm_build_id_set_from_mod_list(const GList *mod_list, GHashTable **out_ids)
static void _hm_renumber_history(GList *history)
static gboolean _hm_cached_order_applicable(dt_develop_t *dev_dest, GList *order_ids)
static int _iop_rules(GHashTable *keep, GList **out_nodes)
static void _hm_restore_dest_from_backup(dt_develop_t *dev_dest, _hm_dest_backup_t *backup)
static dt_hm_constraints_choice_handler_t _constraints_choice_handler
static gboolean _hm_confirm_missing_raster(const GList *mod_list)
dt_hm_constraint_choice_t(* dt_hm_constraints_choice_handler_t)(GHashTable *id_ht, const char *faulty_id, const char *src_prev, const char *src_next, const char *dst_prev, const char *dst_next)
void(* dt_hm_toposort_cycle_handler_t)(GList *cycle_nodes, GHashTable *id_ht)
dt_hm_constraint_choice_t
@ DT_HM_CONSTRAINTS_PREFER_DEST
@ DT_HM_CONSTRAINTS_PREFER_SRC
gboolean(* dt_hm_merge_report_handler_t)(struct dt_develop_t *dev_dest, struct dt_develop_t *dev_src, const gboolean merge_iop_order, const gboolean used_source_order, const dt_history_merge_strategy_t strategy, GHashTable *src_last_by_id, GHashTable *dst_last_before_by_id, const GHashTable *orig_ids, const GHashTable *mod_list_ids, const char *source_label, dt_hm_batch_state_t *batch)
dt_history_merge_strategy_t
@ DT_HISTORY_MERGE_APPEND
gboolean(* dt_hm_missing_raster_handler_t)(const GList *mod_list)
dt_iop_module_t * dt_iop_get_module_by_instance_name(GList *modules, const char *operation, const char *multi_name)
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
void dt_ioppr_rebuild_iop_order_from_modules(struct dt_develop_t *dev, GList *ordered_modules)
Rebuild dev->iop_order_list from a list of ordered modules.
GList * dt_ioppr_iop_order_copy_deep(GList *iop_order_list)
Deep-copy an order list.
void dt_ioppr_resync_pipeline(dt_develop_t *dev, const int32_t imgid, const char *msg, gboolean check_duplicates)
Resynchronize pipeline order and related structures.
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
const dt_iop_module_t * src_iop
dt_iop_module_t * dst_iop
const dt_iop_module_t * mod_list
gboolean copy_module_contents
GHashTable * src_focus_ids
gboolean source_iop_order
dt_hm_batch_decision_t decision
struct dt_iop_module_t::@23::@24 source
struct dt_iop_module_t::@23::@25 sink
struct dt_iop_module_t::@23 raster_mask
void dt_digraph_cleanup_full(GList *nodes, GHashTable *node_ht, dt_node_user_data_destroy_t user_destroy)
Free a canonical graph (nodes, constraints, ids) in one call.
int flatten_nodes(GList *input_nodes, GList **out_nodes)
Canonicalize / merge duplicated nodes by id.
dt_digraph_node_t * dt_digraph_node_new(const char *id)
Allocate and initialize a new digraph node with the given id.
int topological_sort(GList *nodes, GList **sorted, GList **cycle_out)
Perform a topological sort using depth-first search (DFS).
Small directed-graph helper for constraint aggregation and topological sorting.