feat(person): ajouter les relations factuelles contrôlées
This commit is contained in:
parent
4b2fb93076
commit
11cbc061ae
39 changed files with 1070 additions and 121 deletions
19
Makefile
19
Makefile
|
|
@ -196,6 +196,7 @@ TEST_EVIDENCE_METADATA_DIALOG_GTK := tests/test_evidence_metadata_dialog_gtk
|
||||||
TEST_EVIDENCE_IDENTITY_IMPORT_GTK := tests/test_evidence_identity_import_gtk
|
TEST_EVIDENCE_IDENTITY_IMPORT_GTK := tests/test_evidence_identity_import_gtk
|
||||||
TEST_WORKSPACE_IDENTITY_OCR_GTK := tests/test_workspace_identity_ocr_gtk
|
TEST_WORKSPACE_IDENTITY_OCR_GTK := tests/test_workspace_identity_ocr_gtk
|
||||||
TEST_DIALOG_GEOMETRY_GTK := tests/test_dialog_geometry_gtk
|
TEST_DIALOG_GEOMETRY_GTK := tests/test_dialog_geometry_gtk
|
||||||
|
TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK := tests/test_person_factual_relation_editor_gtk
|
||||||
FAKE_DOCUMENT_TOOL := tests/fake_document_tool
|
FAKE_DOCUMENT_TOOL := tests/fake_document_tool
|
||||||
|
|
||||||
DOCUMENT_ANALYSIS_TEST_SOURCES := \
|
DOCUMENT_ANALYSIS_TEST_SOURCES := \
|
||||||
|
|
@ -214,6 +215,16 @@ $(TEST_DIALOG_GEOMETRY_GTK): tests/test_dialog_geometry_gtk.c \
|
||||||
src/views/dialog_geometry.c
|
src/views/dialog_geometry.c
|
||||||
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK): \
|
||||||
|
tests/test_person_factual_relation_editor_gtk.c \
|
||||||
|
src/views/person_factual_relation_editor.c \
|
||||||
|
src/views/person_vocabulary_adapter.c src/models/identity_ocr.c \
|
||||||
|
src/models/identity_traceability.c src/models/person_role_assignment.c \
|
||||||
|
src/dao/identity_traceability_dao.c src/database/database.c \
|
||||||
|
src/database/schema.c src/database/statement.c src/database/transaction.c \
|
||||||
|
src/database/error.c src/core/relation_type_normalizer.c
|
||||||
|
$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
$(TEST_IDENTITY_OCR): tests/test_identity_ocr.c \
|
$(TEST_IDENTITY_OCR): tests/test_identity_ocr.c \
|
||||||
|
|
@ -234,6 +245,7 @@ $(TEST_IDENTITY_OCR_PREPROCESSOR): tests/test_identity_ocr_preprocessor.c \
|
||||||
$(TEST_IDENTITY_TRACEABILITY): tests/test_identity_traceability.c \
|
$(TEST_IDENTITY_TRACEABILITY): tests/test_identity_traceability.c \
|
||||||
src/models/identity_traceability.c src/dao/identity_traceability_dao.c \
|
src/models/identity_traceability.c src/dao/identity_traceability_dao.c \
|
||||||
src/views/person_vocabulary_adapter.c \
|
src/views/person_vocabulary_adapter.c \
|
||||||
|
src/views/person_factual_relation_editor.c \
|
||||||
src/models/person_role_assignment.c \
|
src/models/person_role_assignment.c \
|
||||||
src/models/identity_ocr.c src/dao/identity_ocr_dao.c \
|
src/models/identity_ocr.c src/dao/identity_ocr_dao.c \
|
||||||
src/core/relation_type_normalizer.c \
|
src/core/relation_type_normalizer.c \
|
||||||
|
|
@ -933,6 +945,7 @@ $(TEST_PERSON_DIALOG_LIFECYCLE): tests/test_person_dialog_lifecycle.c \
|
||||||
$(TEST_CREATE_PERSON_DIALOG_GTK): tests/test_create_person_dialog_gtk.c \
|
$(TEST_CREATE_PERSON_DIALOG_GTK): tests/test_create_person_dialog_gtk.c \
|
||||||
src/views/create_person_dialog.c src/views/dialog_geometry.c \
|
src/views/create_person_dialog.c src/views/dialog_geometry.c \
|
||||||
src/views/person_vocabulary_adapter.c \
|
src/views/person_vocabulary_adapter.c \
|
||||||
|
src/views/person_factual_relation_editor.c \
|
||||||
src/views/identity_ocr_option_adapter.c \
|
src/views/identity_ocr_option_adapter.c \
|
||||||
src/core/person_dialog_lifecycle.c \
|
src/core/person_dialog_lifecycle.c \
|
||||||
src/core/person_confirmation_summary.c \
|
src/core/person_confirmation_summary.c \
|
||||||
|
|
@ -963,6 +976,7 @@ $(TEST_CREATE_PERSON_DIALOG_OCR_GTK): \
|
||||||
tests/test_create_person_dialog_ocr_gtk.c \
|
tests/test_create_person_dialog_ocr_gtk.c \
|
||||||
src/views/create_person_dialog.c src/views/dialog_geometry.c \
|
src/views/create_person_dialog.c src/views/dialog_geometry.c \
|
||||||
src/views/person_vocabulary_adapter.c \
|
src/views/person_vocabulary_adapter.c \
|
||||||
|
src/views/person_factual_relation_editor.c \
|
||||||
src/views/identity_ocr_option_adapter.c \
|
src/views/identity_ocr_option_adapter.c \
|
||||||
src/core/person_dialog_lifecycle.c \
|
src/core/person_dialog_lifecycle.c \
|
||||||
src/core/person_confirmation_summary.c \
|
src/core/person_confirmation_summary.c \
|
||||||
|
|
@ -1184,7 +1198,8 @@ test: \
|
||||||
$(TEST_EVIDENCE_METADATA_DIALOG_GTK) \
|
$(TEST_EVIDENCE_METADATA_DIALOG_GTK) \
|
||||||
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
||||||
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
||||||
$(TEST_DIALOG_GEOMETRY_GTK)
|
$(TEST_DIALOG_GEOMETRY_GTK) \
|
||||||
|
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -1280,6 +1295,7 @@ test: \
|
||||||
@$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK)
|
@$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK)
|
||||||
@$(TEST_WORKSPACE_IDENTITY_OCR_GTK)
|
@$(TEST_WORKSPACE_IDENTITY_OCR_GTK)
|
||||||
@$(TEST_DIALOG_GEOMETRY_GTK)
|
@$(TEST_DIALOG_GEOMETRY_GTK)
|
||||||
|
@$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -1379,6 +1395,7 @@ clean:
|
||||||
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
$(TEST_EVIDENCE_IDENTITY_IMPORT_GTK) \
|
||||||
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
$(TEST_WORKSPACE_IDENTITY_OCR_GTK) \
|
||||||
$(TEST_DIALOG_GEOMETRY_GTK) \
|
$(TEST_DIALOG_GEOMETRY_GTK) \
|
||||||
|
$(TEST_PERSON_FACTUAL_RELATION_EDITOR_GTK) \
|
||||||
$(FAKE_DOCUMENT_TOOL)
|
$(FAKE_DOCUMENT_TOOL)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
20
diff_stat.txt
Normal file
20
diff_stat.txt
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
Makefile | 2 +
|
||||||
|
include/core/person_creation_task.h | 3 +-
|
||||||
|
include/dao/identity_traceability_dao.h | 2 +
|
||||||
|
include/views/create_person_dialog.h | 2 +
|
||||||
|
include/views/main_window.h | 7 ++++
|
||||||
|
include/views/person_vocabulary_adapter.h | 3 ++
|
||||||
|
include/widgets/entity_details_panel.h | 2 +
|
||||||
|
include/widgets/workspace.h | 4 +-
|
||||||
|
src/core/application.c | 20 ++++++++--
|
||||||
|
src/core/person_creation_task.c | 45 +++++++++++++++++++---
|
||||||
|
src/dao/identity_traceability_dao.c | 26 +++++++++++++
|
||||||
|
src/views/create_person_dialog.c | 63 +++++++++++++++++++++++++++----
|
||||||
|
src/views/evidence_metadata_dialog.c | 52 +++++++++++++++++++++++++
|
||||||
|
src/views/main_window.c | 8 +++-
|
||||||
|
src/views/person_vocabulary_adapter.c | 39 +++++++++++++++++++
|
||||||
|
src/widgets/entity_details_panel.c | 56 +++++++++++++++++++++++++++
|
||||||
|
src/widgets/workspace.c | 7 ++++
|
||||||
|
tests/test_create_person_dialog_gtk.c | 3 ++
|
||||||
|
tests/test_create_person_dialog_ocr_gtk.c | 2 +
|
||||||
|
19 files changed, 327 insertions(+), 19 deletions(-)
|
||||||
|
|
@ -45,6 +45,8 @@ typedef struct {
|
||||||
const char *relation_type;
|
const char *relation_type;
|
||||||
const char *factual_note;
|
const char *factual_note;
|
||||||
} PersonCreationFactualRelationInput;
|
} PersonCreationFactualRelationInput;
|
||||||
|
|
||||||
|
|
||||||
typedef gboolean (*PersonCreationSessionCheck)(gpointer user_data);
|
typedef gboolean (*PersonCreationSessionCheck)(gpointer user_data);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PersonCreationFailurePoint failure_point;
|
PersonCreationFailurePoint failure_point;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ typedef struct PersonCreationTaskRequest PersonCreationTaskRequest;
|
||||||
PersonCreationTaskRequest *person_creation_task_request_new(
|
PersonCreationTaskRequest *person_creation_task_request_new(
|
||||||
const char *database_path, const char *investigation_root_path,
|
const char *database_path, const char *investigation_root_path,
|
||||||
const PersonEntityInput *person,
|
const PersonEntityInput *person,
|
||||||
const PersonEvidenceSelection *selection, const GPtrArray *ocr_runs);
|
const PersonEvidenceSelection *selection, const GPtrArray *ocr_runs,
|
||||||
|
const GPtrArray *factual_relations);
|
||||||
void person_creation_task_request_free(PersonCreationTaskRequest *request);
|
void person_creation_task_request_free(PersonCreationTaskRequest *request);
|
||||||
BackgroundTask *person_creation_task_start(TaskManager *manager,
|
BackgroundTask *person_creation_task_start(TaskManager *manager,
|
||||||
const PersonCreationTaskRequest *request,
|
const PersonCreationTaskRequest *request,
|
||||||
|
|
|
||||||
10
include/core/person_details_provider.h
Normal file
10
include/core/person_details_provider.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef PERSON_DETAILS_PROVIDER_H
|
||||||
|
#define PERSON_DETAILS_PROVIDER_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include "database/database.h"
|
||||||
|
|
||||||
|
GPtrArray *person_details_provider_get_evidences(Database *database, const char *person_identifier, GError **error);
|
||||||
|
GPtrArray *person_details_provider_get_factual_relations(Database *database, const char *person_identifier, GError **error);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -21,6 +21,10 @@ gboolean identity_traceability_dao_insert_factual_relation(
|
||||||
GError **error);
|
GError **error);
|
||||||
GPtrArray *identity_traceability_dao_list_factual_relations(
|
GPtrArray *identity_traceability_dao_list_factual_relations(
|
||||||
IdentityTraceabilityDao *dao,const char *evidence_identifier,GError **error);
|
IdentityTraceabilityDao *dao,const char *evidence_identifier,GError **error);
|
||||||
|
GPtrArray *identity_traceability_dao_list_factual_relations_by_evidence(
|
||||||
|
IdentityTraceabilityDao *dao,const char *evidence_identifier,GError **error);
|
||||||
|
GPtrArray *identity_traceability_dao_list_factual_relations_by_person(
|
||||||
|
IdentityTraceabilityDao *dao,const char *person_identifier,GError **error);
|
||||||
GPtrArray *identity_traceability_dao_list_roles(
|
GPtrArray *identity_traceability_dao_list_roles(
|
||||||
IdentityTraceabilityDao *dao,gboolean include_inactive,GError **error);
|
IdentityTraceabilityDao *dao,gboolean include_inactive,GError **error);
|
||||||
GPtrArray *identity_traceability_dao_list_identification_statuses(
|
GPtrArray *identity_traceability_dao_list_identification_statuses(
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,15 @@ PersonEvidenceFactualRelation *person_evidence_factual_relation_copy(
|
||||||
const PersonEvidenceFactualRelation *relation);
|
const PersonEvidenceFactualRelation *relation);
|
||||||
void person_evidence_factual_relation_free(
|
void person_evidence_factual_relation_free(
|
||||||
PersonEvidenceFactualRelation *relation);
|
PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_identifier(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_person_identifier(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_evidence_identifier(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_ocr_run_identifier(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_relation_type(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_factual_note(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_observed_at(const PersonEvidenceFactualRelation *relation);
|
||||||
|
const char *person_evidence_factual_relation_get_origin(const PersonEvidenceFactualRelation *relation);
|
||||||
|
gboolean person_evidence_factual_relation_get_active(const PersonEvidenceFactualRelation *relation);
|
||||||
void person_role_vocabulary_entry_free(PersonRoleVocabularyEntry *entry);
|
void person_role_vocabulary_entry_free(PersonRoleVocabularyEntry *entry);
|
||||||
void identification_status_vocabulary_entry_free(
|
void identification_status_vocabulary_entry_free(
|
||||||
IdentificationStatusVocabularyEntry *entry);
|
IdentificationStatusVocabularyEntry *entry);
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ const char *person_evidence_selection_item_get_original_name(
|
||||||
const PersonEvidenceSelectionItem *item);
|
const PersonEvidenceSelectionItem *item);
|
||||||
const char *person_evidence_selection_item_get_mime_type(
|
const char *person_evidence_selection_item_get_mime_type(
|
||||||
const PersonEvidenceSelectionItem *item);
|
const PersonEvidenceSelectionItem *item);
|
||||||
|
const char *person_evidence_selection_item_get_effective_ocr_mime(
|
||||||
|
const PersonEvidenceSelectionItem *item);
|
||||||
const char *person_evidence_selection_item_get_type_identifier(
|
const char *person_evidence_selection_item_get_type_identifier(
|
||||||
const PersonEvidenceSelectionItem *item);
|
const PersonEvidenceSelectionItem *item);
|
||||||
const char *person_evidence_selection_item_get_sha256(
|
const char *person_evidence_selection_item_get_sha256(
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ EvidenceStaging *create_person_dialog_result_steal_staging(
|
||||||
CreatePersonDialogResult *result);
|
CreatePersonDialogResult *result);
|
||||||
const GPtrArray *create_person_dialog_result_get_ocr_runs(
|
const GPtrArray *create_person_dialog_result_get_ocr_runs(
|
||||||
const CreatePersonDialogResult *result);
|
const CreatePersonDialogResult *result);
|
||||||
|
const GPtrArray *create_person_dialog_result_get_factual_relations(
|
||||||
|
const CreatePersonDialogResult *result);
|
||||||
gboolean create_person_dialog_test_overlay_has_region(GtkWindow *window);
|
gboolean create_person_dialog_test_overlay_has_region(GtkWindow *window);
|
||||||
guint64 create_person_dialog_test_ocr_generation(GtkWindow *window);
|
guint64 create_person_dialog_test_ocr_generation(GtkWindow *window);
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
|
||||||
|
|
@ -26,5 +26,6 @@ void labfy_dialog_present(GtkWindow *window);
|
||||||
|
|
||||||
void labfy_paned_apply_initial_ratio(
|
void labfy_paned_apply_initial_ratio(
|
||||||
GtkPaned *paned, double ratio, int minimum_start, int minimum_end);
|
GtkPaned *paned, double ratio, int minimum_start, int minimum_end);
|
||||||
|
gboolean labfy_paned_initial_ratio_applied(GtkPaned *paned);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
8
include/views/identity_ocr_language_loader.h
Normal file
8
include/views/identity_ocr_language_loader.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef IDENTITY_OCR_LANGUAGE_LOADER_H
|
||||||
|
#define IDENTITY_OCR_LANGUAGE_LOADER_H
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
void identity_ocr_language_loader_start(GtkWindow *window, const char *tesseract_path, GtkDropDown *language_dropdown);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -322,6 +322,13 @@ void main_window_set_relation_evidences(
|
||||||
const GPtrArray *evidence_records
|
const GPtrArray *evidence_records
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** @brief Transmet les preuves associées à l'entité sélectionnée. */
|
||||||
|
void main_window_set_person_evidences(MainWindow *main_window,
|
||||||
|
const GPtrArray *records);
|
||||||
|
void main_window_set_person_factual_relations(MainWindow *main_window,
|
||||||
|
const GPtrArray *relations, const GPtrArray *evidence_records);
|
||||||
|
|
||||||
|
|
||||||
/** @brief Définit le callback de catégorisation d'une personne. */
|
/** @brief Définit le callback de catégorisation d'une personne. */
|
||||||
void main_window_set_person_role_callback(MainWindow *main_window,
|
void main_window_set_person_role_callback(MainWindow *main_window,
|
||||||
MainWindowPersonRoleCallback callback, gpointer user_data);
|
MainWindowPersonRoleCallback callback, gpointer user_data);
|
||||||
|
|
|
||||||
40
include/views/person_factual_relation_editor.h
Normal file
40
include/views/person_factual_relation_editor.h
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#ifndef LABFY_PERSON_FACTUAL_RELATION_EDITOR_H
|
||||||
|
#define LABFY_PERSON_FACTUAL_RELATION_EDITOR_H
|
||||||
|
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include "core/person_creation_coordinator.h"
|
||||||
|
#include "models/identity_ocr.h"
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
typedef struct PersonFactualRelationEditor PersonFactualRelationEditor;
|
||||||
|
|
||||||
|
PersonFactualRelationEditor *person_factual_relation_editor_new(void);
|
||||||
|
|
||||||
|
GtkWidget *person_factual_relation_editor_get_widget(
|
||||||
|
PersonFactualRelationEditor *editor);
|
||||||
|
|
||||||
|
void person_factual_relation_editor_set_available_evidence(
|
||||||
|
PersonFactualRelationEditor *editor,
|
||||||
|
GtkStringList *evidence_labels,
|
||||||
|
GPtrArray *evidence_identifiers);
|
||||||
|
|
||||||
|
void person_factual_relation_editor_set_available_ocr_runs(
|
||||||
|
PersonFactualRelationEditor *editor,
|
||||||
|
GPtrArray *ocr_runs);
|
||||||
|
|
||||||
|
gboolean person_factual_relation_editor_collect_relations(
|
||||||
|
PersonFactualRelationEditor *editor, GPtrArray **relations,
|
||||||
|
GError **error);
|
||||||
|
guint person_factual_relation_editor_get_count(
|
||||||
|
const PersonFactualRelationEditor *editor);
|
||||||
|
gboolean person_factual_relation_editor_validate(
|
||||||
|
PersonFactualRelationEditor *editor, GError **error);
|
||||||
|
void person_factual_relation_editor_append_summary(
|
||||||
|
PersonFactualRelationEditor *editor, GString *summary);
|
||||||
|
|
||||||
|
void person_factual_relation_editor_free(PersonFactualRelationEditor *editor);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -16,6 +16,10 @@ GtkStringList *person_vocabulary_adapter_create_role_labels(
|
||||||
const PersonVocabularyAdapter *adapter);
|
const PersonVocabularyAdapter *adapter);
|
||||||
GtkStringList *person_vocabulary_adapter_create_status_labels(
|
GtkStringList *person_vocabulary_adapter_create_status_labels(
|
||||||
const PersonVocabularyAdapter *adapter);
|
const PersonVocabularyAdapter *adapter);
|
||||||
|
GtkStringList *person_vocabulary_adapter_create_relation_labels(void);
|
||||||
|
const char *person_vocabulary_adapter_relation_code(guint index);
|
||||||
|
const char *person_vocabulary_adapter_relation_label(const char *code);
|
||||||
|
const char *person_vocabulary_adapter_relation_description(const char *code);
|
||||||
const char *person_vocabulary_adapter_status_code(
|
const char *person_vocabulary_adapter_status_code(
|
||||||
const PersonVocabularyAdapter *adapter, guint index);
|
const PersonVocabularyAdapter *adapter, guint index);
|
||||||
const char *person_vocabulary_adapter_status_label(
|
const char *person_vocabulary_adapter_status_label(
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,8 @@ void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel,
|
||||||
*/
|
*/
|
||||||
void entity_details_panel_set_person_evidences(
|
void entity_details_panel_set_person_evidences(
|
||||||
EntityDetailsPanel *details_panel, const GPtrArray *evidence_records);
|
EntityDetailsPanel *details_panel, const GPtrArray *evidence_records);
|
||||||
|
void entity_details_panel_set_person_factual_relations(
|
||||||
|
EntityDetailsPanel *details_panel, const GPtrArray *relations, const GPtrArray *evidence_records);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Indique si le volet est actuellement ouvert.
|
* @brief Indique si le volet est actuellement ouvert.
|
||||||
|
|
|
||||||
|
|
@ -472,7 +472,9 @@ void workspace_set_entity_selected_callback(Workspace *workspace,
|
||||||
WorkspaceEntitySelectedCallback callback, gpointer user_data);
|
WorkspaceEntitySelectedCallback callback, gpointer user_data);
|
||||||
/** @brief Affiche les preuves de la personne sélectionnée. */
|
/** @brief Affiche les preuves de la personne sélectionnée. */
|
||||||
void workspace_set_person_evidences(Workspace *workspace,
|
void workspace_set_person_evidences(Workspace *workspace,
|
||||||
const GPtrArray *evidence_records);
|
const GPtrArray *records);
|
||||||
|
void workspace_set_person_factual_relations(Workspace *workspace,
|
||||||
|
const GPtrArray *relations, const GPtrArray *evidence_records);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Affiche le graphe chargé avec sa disposition persistée.
|
* @brief Affiche le graphe chargé avec sa disposition persistée.
|
||||||
|
|
|
||||||
19
name_status.txt
Normal file
19
name_status.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
M Makefile
|
||||||
|
M include/core/person_creation_task.h
|
||||||
|
M include/dao/identity_traceability_dao.h
|
||||||
|
M include/views/create_person_dialog.h
|
||||||
|
M include/views/main_window.h
|
||||||
|
M include/views/person_vocabulary_adapter.h
|
||||||
|
M include/widgets/entity_details_panel.h
|
||||||
|
M include/widgets/workspace.h
|
||||||
|
M src/core/application.c
|
||||||
|
M src/core/person_creation_task.c
|
||||||
|
M src/dao/identity_traceability_dao.c
|
||||||
|
M src/views/create_person_dialog.c
|
||||||
|
M src/views/evidence_metadata_dialog.c
|
||||||
|
M src/views/main_window.c
|
||||||
|
M src/views/person_vocabulary_adapter.c
|
||||||
|
M src/widgets/entity_details_panel.c
|
||||||
|
M src/widgets/workspace.c
|
||||||
|
M tests/test_create_person_dialog_gtk.c
|
||||||
|
M tests/test_create_person_dialog_ocr_gtk.c
|
||||||
|
|
@ -47,6 +47,7 @@
|
||||||
#include "dao/evidence_dao.h"
|
#include "dao/evidence_dao.h"
|
||||||
#include "dao/identity_ocr_dao.h"
|
#include "dao/identity_ocr_dao.h"
|
||||||
#include "dao/evidence_entity_dao.h"
|
#include "dao/evidence_entity_dao.h"
|
||||||
|
#include "core/person_details_provider.h"
|
||||||
#include "dao/entity_dao.h"
|
#include "dao/entity_dao.h"
|
||||||
#include "dao/relation_dao.h"
|
#include "dao/relation_dao.h"
|
||||||
#include "dao/relation_evidence_dao.h"
|
#include "dao/relation_evidence_dao.h"
|
||||||
|
|
@ -6044,7 +6045,8 @@ static void application_on_person_completed(
|
||||||
goto changed_session;
|
goto changed_session;
|
||||||
request = person_creation_task_request_new(active_database, active_root,
|
request = person_creation_task_request_new(active_database, active_root,
|
||||||
input, create_person_dialog_result_get_evidence_selection(result),
|
input, create_person_dialog_result_get_evidence_selection(result),
|
||||||
create_person_dialog_result_get_ocr_runs(result));
|
create_person_dialog_result_get_ocr_runs(result),
|
||||||
|
create_person_dialog_result_get_factual_relations(result));
|
||||||
task_context = g_new0(ApplicationPersonCreationTaskContext, 1);
|
task_context = g_new0(ApplicationPersonCreationTaskContext, 1);
|
||||||
task_context->application = application;
|
task_context->application = application;
|
||||||
task_context->generation = application->session_generation;
|
task_context->generation = application->session_generation;
|
||||||
|
|
@ -7058,36 +7060,26 @@ static void application_on_person_name_changed(const char *entity_identifier,
|
||||||
static void application_on_entity_selected(const char *entity_identifier,
|
static void application_on_entity_selected(const char *entity_identifier,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
Application *application = user_data; Database *database = NULL;
|
Application *application = user_data;
|
||||||
EvidenceEntityDao *link_dao = NULL; EvidenceDao *evidence_dao = NULL;
|
|
||||||
GPtrArray *identifiers = NULL; GPtrArray *records = NULL;
|
|
||||||
GError *error = NULL;
|
|
||||||
if (application == NULL || application->session == NULL ||
|
if (application == NULL || application->session == NULL ||
|
||||||
entity_identifier == NULL) return;
|
entity_identifier == NULL) return;
|
||||||
database = investigation_session_get_database(application->session);
|
Database *database = investigation_session_get_database(application->session);
|
||||||
link_dao = evidence_entity_dao_new(database, &error);
|
GError *error = NULL;
|
||||||
if (link_dao == NULL) goto cleanup;
|
GPtrArray *records = person_details_provider_get_evidences(database, entity_identifier, &error);
|
||||||
evidence_dao = evidence_dao_new(database, &error);
|
GPtrArray *relations = NULL;
|
||||||
if (evidence_dao == NULL) goto cleanup;
|
if (records != NULL) {
|
||||||
identifiers = evidence_entity_dao_list_evidence_identifiers(link_dao,
|
relations = person_details_provider_get_factual_relations(database, entity_identifier, NULL);
|
||||||
entity_identifier, &error);
|
|
||||||
if (identifiers == NULL) goto cleanup;
|
|
||||||
records = g_ptr_array_new_with_free_func((GDestroyNotify)
|
|
||||||
evidence_record_free);
|
|
||||||
for (guint index = 0; index < identifiers->len; index++)
|
|
||||||
{
|
|
||||||
EvidenceRecord *record = evidence_dao_find_by_identifier(evidence_dao,
|
|
||||||
g_ptr_array_index(identifiers, index), &error);
|
|
||||||
if (record == NULL) goto cleanup;
|
|
||||||
g_ptr_array_add(records, record);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main_window_set_person_evidences(application->main_window, records);
|
main_window_set_person_evidences(application->main_window, records);
|
||||||
cleanup:
|
main_window_set_person_factual_relations(application->main_window, relations, records);
|
||||||
if (error != NULL)
|
|
||||||
main_window_set_person_evidences(application->main_window, NULL);
|
if (error != NULL) {
|
||||||
g_clear_error(&error); g_clear_pointer(&records, g_ptr_array_unref);
|
application_present_error(application, "Erreur de chargement", error->message);
|
||||||
g_clear_pointer(&identifiers, g_ptr_array_unref);
|
g_clear_error(&error);
|
||||||
evidence_dao_free(evidence_dao); evidence_entity_dao_free(link_dao);
|
}
|
||||||
|
if (records != NULL) g_ptr_array_unref(records);
|
||||||
|
if (relations != NULL) g_ptr_array_unref(relations);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Contexte possédé par la gestion des preuves d'une personne. */
|
/** @brief Contexte possédé par la gestion des preuves d'une personne. */
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
static GQuark coordinator_error(void)
|
static GQuark coordinator_error(void)
|
||||||
{
|
{
|
||||||
return g_quark_from_static_string("person-creation-coordinator-error");
|
return g_quark_from_static_string("person-creation-coordinator-error");
|
||||||
|
|
|
||||||
|
|
@ -12,11 +12,13 @@ struct PersonCreationTaskRequest {
|
||||||
GPtrArray *roles;
|
GPtrArray *roles;
|
||||||
PersonEvidenceSelection *selection;
|
PersonEvidenceSelection *selection;
|
||||||
GPtrArray *ocr_runs;
|
GPtrArray *ocr_runs;
|
||||||
|
GPtrArray *factual_relations;
|
||||||
};
|
};
|
||||||
PersonCreationTaskRequest *person_creation_task_request_new(
|
PersonCreationTaskRequest *person_creation_task_request_new(
|
||||||
const char *database_path, const char *root,
|
const char *database_path, const char *root,
|
||||||
const PersonEntityInput *person,
|
const PersonEntityInput *person,
|
||||||
const PersonEvidenceSelection *selection, const GPtrArray *ocr_runs)
|
const PersonEvidenceSelection *selection, const GPtrArray *ocr_runs,
|
||||||
|
const GPtrArray *factual_relations)
|
||||||
{
|
{
|
||||||
PersonCreationTaskRequest *request;
|
PersonCreationTaskRequest *request;
|
||||||
if (database_path == NULL || root == NULL || person == NULL) return NULL;
|
if (database_path == NULL || root == NULL || person == NULL) return NULL;
|
||||||
|
|
@ -49,6 +51,21 @@ PersonCreationTaskRequest *person_creation_task_request_new(
|
||||||
for (guint i = 0; ocr_runs != NULL && i < ocr_runs->len; i++)
|
for (guint i = 0; ocr_runs != NULL && i < ocr_runs->len; i++)
|
||||||
g_ptr_array_add(request->ocr_runs,
|
g_ptr_array_add(request->ocr_runs,
|
||||||
identity_ocr_run_copy(g_ptr_array_index((GPtrArray *) ocr_runs,i)));
|
identity_ocr_run_copy(g_ptr_array_index((GPtrArray *) ocr_runs,i)));
|
||||||
|
|
||||||
|
request->factual_relations = NULL;
|
||||||
|
if (factual_relations != NULL) {
|
||||||
|
request->factual_relations = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
for (guint i = 0; i < factual_relations->len; i++) {
|
||||||
|
PersonCreationFactualRelationInput *orig = g_ptr_array_index((GPtrArray *) factual_relations, i);
|
||||||
|
PersonCreationFactualRelationInput *copy_rel = g_new0(PersonCreationFactualRelationInput, 1);
|
||||||
|
copy_rel->evidence_selection_identifier = g_strdup(orig->evidence_selection_identifier);
|
||||||
|
copy_rel->ocr_run_identifier = g_strdup(orig->ocr_run_identifier);
|
||||||
|
copy_rel->relation_type = g_strdup(orig->relation_type);
|
||||||
|
copy_rel->factual_note = g_strdup(orig->factual_note);
|
||||||
|
g_ptr_array_add(request->factual_relations, copy_rel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
void person_creation_task_request_free(PersonCreationTaskRequest *request)
|
void person_creation_task_request_free(PersonCreationTaskRequest *request)
|
||||||
|
|
@ -60,6 +77,16 @@ void person_creation_task_request_free(PersonCreationTaskRequest *request)
|
||||||
g_free(request->notes); g_ptr_array_unref(request->roles);
|
g_free(request->notes); g_ptr_array_unref(request->roles);
|
||||||
person_evidence_selection_free(request->selection);
|
person_evidence_selection_free(request->selection);
|
||||||
g_ptr_array_unref(request->ocr_runs);
|
g_ptr_array_unref(request->ocr_runs);
|
||||||
|
if (request->factual_relations) {
|
||||||
|
for (guint i = 0; i < request->factual_relations->len; i++) {
|
||||||
|
PersonCreationFactualRelationInput *rel = g_ptr_array_index(request->factual_relations, i);
|
||||||
|
g_free((char*)rel->evidence_selection_identifier);
|
||||||
|
g_free((char*)rel->ocr_run_identifier);
|
||||||
|
g_free((char*)rel->relation_type);
|
||||||
|
g_free((char*)rel->factual_note);
|
||||||
|
}
|
||||||
|
g_ptr_array_unref(request->factual_relations);
|
||||||
|
}
|
||||||
g_free(request);
|
g_free(request);
|
||||||
}
|
}
|
||||||
static gboolean worker(BackgroundTask *task, GCancellable *cancellable,
|
static gboolean worker(BackgroundTask *task, GCancellable *cancellable,
|
||||||
|
|
@ -75,9 +102,17 @@ static gboolean worker(BackgroundTask *task, GCancellable *cancellable,
|
||||||
"Impossible d’ouvrir la base de l’enquête.");
|
"Impossible d’ouvrir la base de l’enquête.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
if (request->factual_relations != NULL && request->factual_relations->len > 0) {
|
||||||
|
PersonCreationCoordinatorOptions options = {0};
|
||||||
|
options.factual_relations = request->factual_relations;
|
||||||
|
*result = person_creation_coordinator_execute_with_options(database, request->root,
|
||||||
|
&request->person, request->selection, request->ocr_runs, &options,
|
||||||
|
cancellable, error);
|
||||||
|
} else {
|
||||||
*result = person_creation_coordinator_execute(database, request->root,
|
*result = person_creation_coordinator_execute(database, request->root,
|
||||||
&request->person, request->selection, request->ocr_runs,
|
&request->person, request->selection, request->ocr_runs,
|
||||||
cancellable, error);
|
cancellable, error);
|
||||||
|
}
|
||||||
database_close(database);
|
database_close(database);
|
||||||
return *result != NULL;
|
return *result != NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +127,7 @@ BackgroundTask *person_creation_task_start(TaskManager *manager,
|
||||||
task = background_task_new("Création de la personne et import des preuves");
|
task = background_task_new("Création de la personne et import des preuves");
|
||||||
copy = person_creation_task_request_new(request->database_path,
|
copy = person_creation_task_request_new(request->database_path,
|
||||||
request->root, &request->person, request->selection,
|
request->root, &request->person, request->selection,
|
||||||
request->ocr_runs);
|
request->ocr_runs, request->factual_relations);
|
||||||
if (task == NULL || copy == NULL ||
|
if (task == NULL || copy == NULL ||
|
||||||
!task_manager_add(manager, task, error) ||
|
!task_manager_add(manager, task, error) ||
|
||||||
!background_task_start(task, worker, copy,
|
!background_task_start(task, worker, copy,
|
||||||
|
|
|
||||||
45
src/core/person_details_provider.c
Normal file
45
src/core/person_details_provider.c
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "core/person_details_provider.h"
|
||||||
|
#include "dao/evidence_dao.h"
|
||||||
|
#include "dao/evidence_entity_dao.h"
|
||||||
|
#include "dao/identity_traceability_dao.h"
|
||||||
|
#include "models/evidence_record.h"
|
||||||
|
|
||||||
|
GPtrArray *person_details_provider_get_evidences(Database *database, const char *person_identifier, GError **error)
|
||||||
|
{
|
||||||
|
EvidenceEntityDao *link_dao = evidence_entity_dao_new(database, error);
|
||||||
|
if (link_dao == NULL) return NULL;
|
||||||
|
EvidenceDao *evidence_dao = evidence_dao_new(database, error);
|
||||||
|
if (evidence_dao == NULL) {
|
||||||
|
evidence_entity_dao_free(link_dao);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GPtrArray *identifiers = evidence_entity_dao_list_evidence_identifiers(link_dao, person_identifier, error);
|
||||||
|
if (identifiers == NULL) {
|
||||||
|
evidence_dao_free(evidence_dao);
|
||||||
|
evidence_entity_dao_free(link_dao);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
GPtrArray *records = g_ptr_array_new_with_free_func((GDestroyNotify)evidence_record_free);
|
||||||
|
for (guint index = 0; index < identifiers->len; index++) {
|
||||||
|
EvidenceRecord *record = evidence_dao_find_by_identifier(evidence_dao, g_ptr_array_index(identifiers, index), error);
|
||||||
|
if (record == NULL) {
|
||||||
|
g_ptr_array_unref(records);
|
||||||
|
records = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
g_ptr_array_add(records, record);
|
||||||
|
}
|
||||||
|
g_ptr_array_unref(identifiers);
|
||||||
|
evidence_dao_free(evidence_dao);
|
||||||
|
evidence_entity_dao_free(link_dao);
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPtrArray *person_details_provider_get_factual_relations(Database *database, const char *person_identifier, GError **error)
|
||||||
|
{
|
||||||
|
IdentityTraceabilityDao *trace_dao = identity_traceability_dao_new(database);
|
||||||
|
if (trace_dao == NULL) return NULL;
|
||||||
|
GPtrArray *relations = identity_traceability_dao_list_factual_relations_by_person(trace_dao, person_identifier, error);
|
||||||
|
identity_traceability_dao_free(trace_dao);
|
||||||
|
return relations;
|
||||||
|
}
|
||||||
|
|
@ -78,12 +78,27 @@ gboolean identity_traceability_dao_insert_factual_relation(
|
||||||
{
|
{
|
||||||
PersonEvidenceFactualRelation*valid=r?person_evidence_factual_relation_copy(r):NULL;
|
PersonEvidenceFactualRelation*valid=r?person_evidence_factual_relation_copy(r):NULL;
|
||||||
if(!d||!valid){fail(e,"Relation factuelle invalide.");return FALSE;}
|
if(!d||!valid){fail(e,"Relation factuelle invalide.");return FALSE;}
|
||||||
|
const char*run=person_evidence_factual_relation_get_ocr_run_identifier(valid);
|
||||||
|
if(run){
|
||||||
|
DatabaseStatement*check=database_statement_prepare(d->database,
|
||||||
|
"SELECT 1 FROM identity_ocr_runs WHERE id=? AND evidence_id=?;");
|
||||||
|
gboolean compatible=check&&bind(check,1,run)&&bind(check,2,
|
||||||
|
person_evidence_factual_relation_get_evidence_identifier(valid))&&
|
||||||
|
database_statement_step(check)==DATABASE_STATEMENT_STEP_ROW;
|
||||||
|
database_statement_finalize(check);
|
||||||
|
if(!compatible){person_evidence_factual_relation_free(valid);
|
||||||
|
fail(e,"L’exécution OCR ne correspond pas à la preuve choisie.");return FALSE;}
|
||||||
|
}
|
||||||
DatabaseStatement*s=database_statement_prepare(d->database,
|
DatabaseStatement*s=database_statement_prepare(d->database,
|
||||||
"INSERT INTO person_evidence_factual_relations VALUES(?,?,?,?,?,?,?,?,?);");
|
"INSERT INTO person_evidence_factual_relations VALUES(?,?,?,?,?,?,?,?,?);");
|
||||||
gboolean ok=s&&bind(s,1,r->identifier)&&bind(s,2,r->person_identifier)&&
|
gboolean ok=s&&bind(s,1,person_evidence_factual_relation_get_identifier(valid))&&
|
||||||
bind(s,3,r->evidence_identifier)&&bind(s,4,r->ocr_run_identifier)&&
|
bind(s,2,person_evidence_factual_relation_get_person_identifier(valid))&&
|
||||||
bind(s,5,r->relation_type)&&bind(s,6,r->factual_note)&&bind(s,7,r->observed_at)&&
|
bind(s,3,person_evidence_factual_relation_get_evidence_identifier(valid))&&
|
||||||
bind(s,8,"human")&&database_statement_bind_int64(s,9,r->active?1:0)&&
|
bind(s,4,run)&&bind(s,5,person_evidence_factual_relation_get_relation_type(valid))&&
|
||||||
|
bind(s,6,person_evidence_factual_relation_get_factual_note(valid))&&
|
||||||
|
bind(s,7,person_evidence_factual_relation_get_observed_at(valid))&&
|
||||||
|
bind(s,8,"human")&&database_statement_bind_int64(s,9,
|
||||||
|
person_evidence_factual_relation_get_active(valid)?1:0)&&
|
||||||
database_statement_step(s)==DATABASE_STATEMENT_STEP_DONE;
|
database_statement_step(s)==DATABASE_STATEMENT_STEP_DONE;
|
||||||
database_statement_finalize(s);person_evidence_factual_relation_free(valid);
|
database_statement_finalize(s);person_evidence_factual_relation_free(valid);
|
||||||
if(!ok)fail(e,"Impossible de conserver la relation factuelle.");
|
if(!ok)fail(e,"Impossible de conserver la relation factuelle.");
|
||||||
|
|
@ -115,6 +130,35 @@ GPtrArray *identity_traceability_dao_list_factual_relations(
|
||||||
bad:database_statement_finalize(s);g_ptr_array_unref(a);
|
bad:database_statement_finalize(s);g_ptr_array_unref(a);
|
||||||
fail(e,"Impossible de lire les relations factuelles.");return NULL;
|
fail(e,"Impossible de lire les relations factuelles.");return NULL;
|
||||||
}
|
}
|
||||||
|
GPtrArray *identity_traceability_dao_list_factual_relations_by_evidence(
|
||||||
|
IdentityTraceabilityDao*d,const char*id,GError**e)
|
||||||
|
{return identity_traceability_dao_list_factual_relations(d,id,e);}
|
||||||
|
GPtrArray *identity_traceability_dao_list_factual_relations_by_person(
|
||||||
|
IdentityTraceabilityDao*d,const char*id,GError**e)
|
||||||
|
{
|
||||||
|
if(!d||!id){fail(e,"Lecture des relations factuelles invalide.");return NULL;}
|
||||||
|
DatabaseStatement*s=database_statement_prepare(d->database,
|
||||||
|
"SELECT id,person_id,evidence_id,ocr_run_id,relation_type,factual_note,"
|
||||||
|
"observed_at,origin,active FROM person_evidence_factual_relations "
|
||||||
|
"WHERE person_id=? ORDER BY observed_at,id;");
|
||||||
|
GPtrArray*a=g_ptr_array_new_with_free_func(
|
||||||
|
(GDestroyNotify)person_evidence_factual_relation_free);
|
||||||
|
if(!s||!bind(s,1,id))goto bad2;
|
||||||
|
for(;;){DatabaseStatementStepResult step=database_statement_step(s);
|
||||||
|
if(step==DATABASE_STATEMENT_STEP_DONE)break;
|
||||||
|
if(step!=DATABASE_STATEMENT_STEP_ROW)goto bad2;
|
||||||
|
char*v[8]={0};gint64 active=0;gboolean ok=TRUE;
|
||||||
|
for(int i=0;i<8;i++)ok=ok&&database_statement_column_text(s,i,&v[i]);
|
||||||
|
ok=ok&&database_statement_column_int64(s,8,&active);
|
||||||
|
PersonEvidenceFactualRelation*r=ok?person_evidence_factual_relation_new(
|
||||||
|
v[0],v[1],v[2],v[3],v[4],v[5],v[6],active!=0):NULL;
|
||||||
|
for(int i=0;i<8;i++)g_free(v[i]);
|
||||||
|
if(!r)goto bad2;
|
||||||
|
g_ptr_array_add(a,r);}
|
||||||
|
database_statement_finalize(s);return a;
|
||||||
|
bad2:database_statement_finalize(s);g_ptr_array_unref(a);
|
||||||
|
fail(e,"Impossible de lire les relations factuelles.");return NULL;
|
||||||
|
}
|
||||||
GPtrArray *identity_traceability_dao_list_roles(
|
GPtrArray *identity_traceability_dao_list_roles(
|
||||||
IdentityTraceabilityDao*d,gboolean inactive,GError**e)
|
IdentityTraceabilityDao*d,gboolean inactive,GError**e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,19 @@ void person_evidence_factual_relation_free(PersonEvidenceFactualRelation*r)
|
||||||
g_free(r->evidence_identifier);g_free(r->ocr_run_identifier);
|
g_free(r->evidence_identifier);g_free(r->ocr_run_identifier);
|
||||||
g_free(r->relation_type);g_free(r->factual_note);g_free(r->observed_at);
|
g_free(r->relation_type);g_free(r->factual_note);g_free(r->observed_at);
|
||||||
g_free(r->origin);g_free(r);}
|
g_free(r->origin);g_free(r);}
|
||||||
|
#define FACTUAL_GETTER(name,field) \
|
||||||
|
const char *person_evidence_factual_relation_get_##name( \
|
||||||
|
const PersonEvidenceFactualRelation*r){return r?r->field:NULL;}
|
||||||
|
FACTUAL_GETTER(identifier,identifier)
|
||||||
|
FACTUAL_GETTER(person_identifier,person_identifier)
|
||||||
|
FACTUAL_GETTER(evidence_identifier,evidence_identifier)
|
||||||
|
FACTUAL_GETTER(ocr_run_identifier,ocr_run_identifier)
|
||||||
|
FACTUAL_GETTER(relation_type,relation_type)
|
||||||
|
FACTUAL_GETTER(factual_note,factual_note)
|
||||||
|
FACTUAL_GETTER(observed_at,observed_at)
|
||||||
|
FACTUAL_GETTER(origin,origin)
|
||||||
|
gboolean person_evidence_factual_relation_get_active(
|
||||||
|
const PersonEvidenceFactualRelation*r){return r?r->active:FALSE;}
|
||||||
void person_role_vocabulary_entry_free(PersonRoleVocabularyEntry*e)
|
void person_role_vocabulary_entry_free(PersonRoleVocabularyEntry*e)
|
||||||
{if(!e)return;g_free(e->code);g_free(e->label);g_free(e->description);g_free(e);}
|
{if(!e)return;g_free(e->code);g_free(e->label);g_free(e->description);g_free(e);}
|
||||||
void identification_status_vocabulary_entry_free(
|
void identification_status_vocabulary_entry_free(
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,25 @@ const char *person_evidence_selection_find_existing_by_sha256(
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *person_evidence_selection_item_get_effective_ocr_mime(
|
||||||
|
const PersonEvidenceSelectionItem *item)
|
||||||
|
{
|
||||||
|
const char *mime = person_evidence_selection_item_get_mime_type(item);
|
||||||
|
if (mime != NULL && mime[0] != '\0') return mime;
|
||||||
|
const char *name = person_evidence_selection_item_get_original_name(item);
|
||||||
|
const char *suffix = name != NULL ? strrchr(name, '.') : NULL;
|
||||||
|
if (suffix == NULL) return NULL;
|
||||||
|
if (g_ascii_strcasecmp(suffix, ".png") == 0) return "image/png";
|
||||||
|
if (g_ascii_strcasecmp(suffix, ".jpg") == 0 || g_ascii_strcasecmp(suffix, ".jpeg") == 0) return "image/jpeg";
|
||||||
|
if (g_ascii_strcasecmp(suffix, ".heic") == 0) return "image/heic";
|
||||||
|
if (g_ascii_strcasecmp(suffix, ".heif") == 0) return "image/heif";
|
||||||
|
if (g_ascii_strcasecmp(suffix, ".pdf") == 0) return "application/pdf";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#define ITEM_GETTER(name, type, field) \
|
#define ITEM_GETTER(name, type, field) \
|
||||||
type person_evidence_selection_item_get_##name( \
|
type person_evidence_selection_item_get_##name( \
|
||||||
const PersonEvidenceSelectionItem *item) { \
|
const PersonEvidenceSelectionItem *item) { \
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "views/dialog_geometry.h"
|
#include "views/dialog_geometry.h"
|
||||||
#include "views/person_vocabulary_adapter.h"
|
#include "views/person_vocabulary_adapter.h"
|
||||||
#include "views/identity_ocr_option_adapter.h"
|
#include "views/identity_ocr_option_adapter.h"
|
||||||
|
#include "views/person_factual_relation_editor.h"
|
||||||
#include "core/evidence_staging.h"
|
#include "core/evidence_staging.h"
|
||||||
#include "core/evidence_staging_task.h"
|
#include "core/evidence_staging_task.h"
|
||||||
#include "core/person_confirmation_summary.h"
|
#include "core/person_confirmation_summary.h"
|
||||||
|
|
@ -33,6 +34,7 @@ struct CreatePersonDialogResult
|
||||||
PersonEvidenceSelection *evidence_selection;
|
PersonEvidenceSelection *evidence_selection;
|
||||||
EvidenceStaging *staging;
|
EvidenceStaging *staging;
|
||||||
GPtrArray *ocr_runs;
|
GPtrArray *ocr_runs;
|
||||||
|
GPtrArray *factual_relations;
|
||||||
};
|
};
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
@ -107,6 +109,7 @@ typedef struct
|
||||||
gulong retained_selected_handler;
|
gulong retained_selected_handler;
|
||||||
gboolean updating_evidence;
|
gboolean updating_evidence;
|
||||||
gboolean updating_retained;
|
gboolean updating_retained;
|
||||||
|
PersonFactualRelationEditor *factual_relation_editor;
|
||||||
} CreatePersonDialogState;
|
} CreatePersonDialogState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -152,8 +155,7 @@ static void identity_languages_worker(GTask *task, gpointer source,
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
char *raw = ocr_analysis_list_languages(job->executable, cancellable,
|
char *raw = ocr_analysis_list_languages(job->executable, cancellable,
|
||||||
&error);
|
&error);
|
||||||
GPtrArray *parsed = raw != NULL
|
GPtrArray *parsed = raw != NULL ? ocr_analysis_parse_languages(raw) : NULL;
|
||||||
? ocr_analysis_parse_languages(raw) : NULL;
|
|
||||||
GPtrArray *choices = parsed != NULL
|
GPtrArray *choices = parsed != NULL
|
||||||
? ocr_analysis_build_language_choices(parsed) : NULL;
|
? ocr_analysis_build_language_choices(parsed) : NULL;
|
||||||
g_free(raw);
|
g_free(raw);
|
||||||
|
|
@ -163,35 +165,6 @@ static void identity_languages_worker(GTask *task, gpointer source,
|
||||||
(GDestroyNotify) g_ptr_array_unref);
|
(GDestroyNotify) g_ptr_array_unref);
|
||||||
else g_task_return_error(task, error);
|
else g_task_return_error(task, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *create_person_dialog_effective_ocr_mime(
|
|
||||||
const PersonEvidenceSelectionItem *item)
|
|
||||||
{
|
|
||||||
const char *mime =
|
|
||||||
person_evidence_selection_item_get_mime_type(item);
|
|
||||||
const char *name;
|
|
||||||
const char *suffix;
|
|
||||||
|
|
||||||
if (mime != NULL && mime[0] != '\0')
|
|
||||||
return mime;
|
|
||||||
name = person_evidence_selection_item_get_original_name(item);
|
|
||||||
suffix = name != NULL ? strrchr(name, '.') : NULL;
|
|
||||||
if (suffix == NULL)
|
|
||||||
return NULL;
|
|
||||||
if (g_ascii_strcasecmp(suffix, ".png") == 0)
|
|
||||||
return "image/png";
|
|
||||||
if (g_ascii_strcasecmp(suffix, ".jpg") == 0 ||
|
|
||||||
g_ascii_strcasecmp(suffix, ".jpeg") == 0)
|
|
||||||
return "image/jpeg";
|
|
||||||
if (g_ascii_strcasecmp(suffix, ".heic") == 0)
|
|
||||||
return "image/heic";
|
|
||||||
if (g_ascii_strcasecmp(suffix, ".heif") == 0)
|
|
||||||
return "image/heif";
|
|
||||||
if (g_ascii_strcasecmp(suffix, ".pdf") == 0)
|
|
||||||
return "application/pdf";
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void identity_languages_completed(GObject *source,
|
static void identity_languages_completed(GObject *source,
|
||||||
GAsyncResult *result, gpointer data)
|
GAsyncResult *result, gpointer data)
|
||||||
{
|
{
|
||||||
|
|
@ -231,15 +204,6 @@ static void identity_languages_completed(GObject *source,
|
||||||
g_clear_object(&window);
|
g_clear_object(&window);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Copie et nettoie un texte facultatif. */
|
|
||||||
static char *create_person_dialog_copy(const char *text)
|
|
||||||
{
|
|
||||||
char *copy = text != NULL ? g_strdup(text) : NULL;
|
|
||||||
if (copy == NULL) return NULL;
|
|
||||||
g_strstrip(copy);
|
|
||||||
if (copy[0] == '\0') { g_free(copy); return NULL; }
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
/** @brief Extrait les notes de la zone de texte. */
|
/** @brief Extrait les notes de la zone de texte. */
|
||||||
static char *create_person_dialog_get_notes(CreatePersonDialogState *state)
|
static char *create_person_dialog_get_notes(CreatePersonDialogState *state)
|
||||||
{
|
{
|
||||||
|
|
@ -611,6 +575,10 @@ static void create_person_dialog_ocr_completed(GObject *source,
|
||||||
g_ptr_array_index((GPtrArray *) fields, 0),
|
g_ptr_array_index((GPtrArray *) fields, 0),
|
||||||
state->ocr_generation);
|
state->ocr_generation);
|
||||||
g_ptr_array_add(state->ocr_runs, run);
|
g_ptr_array_add(state->ocr_runs, run);
|
||||||
|
if (state->factual_relation_editor != NULL) {
|
||||||
|
person_factual_relation_editor_set_available_ocr_runs(
|
||||||
|
state->factual_relation_editor, state->ocr_runs);
|
||||||
|
}
|
||||||
run = NULL;
|
run = NULL;
|
||||||
gtk_label_set_text(state->ocr_status,
|
gtk_label_set_text(state->ocr_status,
|
||||||
"OCR terminé. Chaque proposition reste À vérifier.");
|
"OCR terminé. Chaque proposition reste À vérifier.");
|
||||||
|
|
@ -660,7 +628,7 @@ static void create_person_dialog_on_ocr_start(GtkButton *button,
|
||||||
job->identifier = g_strdup(
|
job->identifier = g_strdup(
|
||||||
person_evidence_selection_item_get_identifier(item));
|
person_evidence_selection_item_get_identifier(item));
|
||||||
job->sha256 = g_strdup(person_evidence_selection_item_get_sha256(item));
|
job->sha256 = g_strdup(person_evidence_selection_item_get_sha256(item));
|
||||||
job->mime = g_strdup(create_person_dialog_effective_ocr_mime(item));
|
job->mime = g_strdup(person_evidence_selection_item_get_effective_ocr_mime(item));
|
||||||
if (person_evidence_selection_item_get_origin(item) ==
|
if (person_evidence_selection_item_get_origin(item) ==
|
||||||
PERSON_EVIDENCE_ORIGIN_EXISTING) {
|
PERSON_EVIDENCE_ORIGIN_EXISTING) {
|
||||||
record = person_evidence_selection_item_get_record(item);
|
record = person_evidence_selection_item_get_record(item);
|
||||||
|
|
@ -743,6 +711,7 @@ static void create_person_dialog_state_free(gpointer data)
|
||||||
g_free(state->investigation_root_path);
|
g_free(state->investigation_root_path);
|
||||||
g_free(state->tesseract_path);
|
g_free(state->tesseract_path);
|
||||||
g_free(state->tesseract_version);
|
g_free(state->tesseract_version);
|
||||||
|
person_factual_relation_editor_free(state->factual_relation_editor);
|
||||||
if (state->user_data_destroy != NULL)
|
if (state->user_data_destroy != NULL)
|
||||||
state->user_data_destroy(state->user_data);
|
state->user_data_destroy(state->user_data);
|
||||||
g_free(state);
|
g_free(state);
|
||||||
|
|
@ -1298,15 +1267,15 @@ static void create_person_dialog_on_create(GtkButton *button, gpointer data)
|
||||||
}
|
}
|
||||||
notes = create_person_dialog_get_notes(state);
|
notes = create_person_dialog_get_notes(state);
|
||||||
result = g_new0(CreatePersonDialogResult, 1);
|
result = g_new0(CreatePersonDialogResult, 1);
|
||||||
result->designation = create_person_dialog_copy(
|
result->designation = g_strdup(gtk_editable_get_text(GTK_EDITABLE(state->designation)));
|
||||||
gtk_editable_get_text(GTK_EDITABLE(state->designation)));
|
result->declared_name = g_strdup(gtk_editable_get_text(GTK_EDITABLE(state->name)));
|
||||||
result->declared_name = create_person_dialog_copy(
|
result->pseudonym = g_strdup(gtk_editable_get_text(GTK_EDITABLE(state->pseudonym)));
|
||||||
gtk_editable_get_text(GTK_EDITABLE(state->name)));
|
result->status = g_strdup(person_vocabulary_adapter_status_code(state->vocabularies, status));
|
||||||
result->pseudonym = create_person_dialog_copy(
|
result->notes = g_strdup(notes);
|
||||||
gtk_editable_get_text(GTK_EDITABLE(state->pseudonym)));
|
if (result->designation) { g_strstrip(result->designation); if (result->designation[0] == '\0') { g_free(result->designation); result->designation = NULL; } }
|
||||||
result->status = g_strdup(person_vocabulary_adapter_status_code(
|
if (result->declared_name) { g_strstrip(result->declared_name); if (result->declared_name[0] == '\0') { g_free(result->declared_name); result->declared_name = NULL; } }
|
||||||
state->vocabularies, status));
|
if (result->pseudonym) { g_strstrip(result->pseudonym); if (result->pseudonym[0] == '\0') { g_free(result->pseudonym); result->pseudonym = NULL; } }
|
||||||
result->notes = create_person_dialog_copy(notes);
|
if (result->notes) { g_strstrip(result->notes); if (result->notes[0] == '\0') { g_free(result->notes); result->notes = NULL; } }
|
||||||
if (person_evidence_selection_get_count(
|
if (person_evidence_selection_get_count(
|
||||||
state->person_evidence_selection) > 0) {
|
state->person_evidence_selection) > 0) {
|
||||||
const PersonEvidenceSelectionItem *first =
|
const PersonEvidenceSelectionItem *first =
|
||||||
|
|
@ -1327,6 +1296,14 @@ static void create_person_dialog_on_create(GtkButton *button, gpointer data)
|
||||||
state->vocabularies, state->role_buttons,
|
state->vocabularies, state->role_buttons,
|
||||||
result->evidence_identifier);
|
result->evidence_identifier);
|
||||||
result->input.role_assignments = result->role_assignments;
|
result->input.role_assignments = result->role_assignments;
|
||||||
|
GError *relation_error = NULL;
|
||||||
|
if (!person_factual_relation_editor_collect_relations(state->factual_relation_editor,
|
||||||
|
&result->factual_relations, &relation_error)) {
|
||||||
|
gtk_label_set_text(state->error, relation_error->message);
|
||||||
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
|
g_clear_error(&relation_error); create_person_dialog_result_free(result);
|
||||||
|
g_free(notes); return;
|
||||||
|
}
|
||||||
result->evidence_selection = state->person_evidence_selection;
|
result->evidence_selection = state->person_evidence_selection;
|
||||||
state->person_evidence_selection = NULL;
|
state->person_evidence_selection = NULL;
|
||||||
result->staging = state->staging;
|
result->staging = state->staging;
|
||||||
|
|
@ -1346,10 +1323,10 @@ static void create_person_dialog_on_create(GtkButton *button, gpointer data)
|
||||||
static void create_person_dialog_update_navigation(CreatePersonDialogState *state)
|
static void create_person_dialog_update_navigation(CreatePersonDialogState *state)
|
||||||
{
|
{
|
||||||
static const char *const pages[] = {
|
static const char *const pages[] = {
|
||||||
"person", "roles", "evidence", "identity-ocr", "summary"};
|
"person", "roles", "evidence", "identity-ocr", "factual-relations", "summary"};
|
||||||
static const char *const steps[] = {
|
static const char *const steps[] = {
|
||||||
"1 Personne", "2 Rôles", "3 Preuves", "4 OCR identité",
|
"1 Personne", "2 Rôles", "3 Preuves", "4 OCR identité",
|
||||||
"5 Confirmation"};
|
"5 Relations factuelles", "6 Confirmation"};
|
||||||
GString *progress = g_string_new(NULL);
|
GString *progress = g_string_new(NULL);
|
||||||
gtk_stack_set_visible_child_name(state->stack, pages[state->step]);
|
gtk_stack_set_visible_child_name(state->stack, pages[state->step]);
|
||||||
for (guint i = 0; i < G_N_ELEMENTS(steps); i++) {
|
for (guint i = 0; i < G_N_ELEMENTS(steps); i++) {
|
||||||
|
|
@ -1363,7 +1340,7 @@ static void create_person_dialog_update_navigation(CreatePersonDialogState *stat
|
||||||
}
|
}
|
||||||
gtk_label_set_markup(state->progress, progress->str);
|
gtk_label_set_markup(state->progress, progress->str);
|
||||||
g_string_free(progress, TRUE);
|
g_string_free(progress, TRUE);
|
||||||
if (state->step == 4) {
|
if (state->step == 5) {
|
||||||
GPtrArray *role_labels =
|
GPtrArray *role_labels =
|
||||||
person_vocabulary_adapter_selected_role_labels(
|
person_vocabulary_adapter_selected_role_labels(
|
||||||
state->role_buttons);
|
state->role_buttons);
|
||||||
|
|
@ -1381,6 +1358,8 @@ static void create_person_dialog_update_navigation(CreatePersonDialogState *stat
|
||||||
gtk_spin_button_get_value_as_int(state->confidence), notes,
|
gtk_spin_button_get_value_as_int(state->confidence), notes,
|
||||||
role_labels, state->person_evidence_selection);
|
role_labels, state->person_evidence_selection);
|
||||||
GString *confirmation = g_string_new(text);
|
GString *confirmation = g_string_new(text);
|
||||||
|
person_factual_relation_editor_append_summary(state->factual_relation_editor,
|
||||||
|
confirmation);
|
||||||
g_string_append(confirmation,
|
g_string_append(confirmation,
|
||||||
"\n\nOCR identité\nL’OCR peut contenir des erreurs. Ces "
|
"\n\nOCR identité\nL’OCR peut contenir des erreurs. Ces "
|
||||||
"informations sont seulement présentées sur le document ; "
|
"informations sont seulement présentées sur le document ; "
|
||||||
|
|
@ -1436,10 +1415,11 @@ static void create_person_dialog_update_navigation(CreatePersonDialogState *stat
|
||||||
g_ptr_array_unref(role_labels);
|
g_ptr_array_unref(role_labels);
|
||||||
}
|
}
|
||||||
gtk_widget_set_sensitive(GTK_WIDGET(state->previous), state->step > 0);
|
gtk_widget_set_sensitive(GTK_WIDGET(state->previous), state->step > 0);
|
||||||
gtk_widget_set_visible(GTK_WIDGET(state->next), state->step < 4);
|
gtk_widget_set_visible(GTK_WIDGET(state->next), state->step < 5);
|
||||||
gtk_widget_set_visible(GTK_WIDGET(state->create), state->step == 4);
|
gtk_widget_set_visible(GTK_WIDGET(state->create), state->step == 5);
|
||||||
gtk_widget_set_sensitive(GTK_WIDGET(state->create),
|
gtk_widget_set_sensitive(GTK_WIDGET(state->create),
|
||||||
state->step == 4 &&
|
state->step == 5 &&
|
||||||
|
gtk_editable_get_text(GTK_EDITABLE(state->designation))[0] != '\0' &&
|
||||||
person_evidence_selection_is_confirmable(
|
person_evidence_selection_is_confirmable(
|
||||||
state->person_evidence_selection));
|
state->person_evidence_selection));
|
||||||
}
|
}
|
||||||
|
|
@ -1463,8 +1443,17 @@ static void create_person_dialog_on_next(GtkButton *button, gpointer data)
|
||||||
create_person_dialog_capture_corrected_transcription(state);
|
create_person_dialog_capture_corrected_transcription(state);
|
||||||
if (state->step == 3)
|
if (state->step == 3)
|
||||||
create_person_dialog_capture_factual_notes(state);
|
create_person_dialog_capture_factual_notes(state);
|
||||||
|
if (state->step == 4) {
|
||||||
|
GError *error = NULL;
|
||||||
|
if (!person_factual_relation_editor_validate(state->factual_relation_editor,
|
||||||
|
&error)) {
|
||||||
|
gtk_label_set_text(state->error, error->message);
|
||||||
|
gtk_widget_set_visible(GTK_WIDGET(state->error), TRUE);
|
||||||
|
g_clear_error(&error); return;
|
||||||
|
}
|
||||||
|
}
|
||||||
gtk_widget_set_visible(GTK_WIDGET(state->error), FALSE);
|
gtk_widget_set_visible(GTK_WIDGET(state->error), FALSE);
|
||||||
if (state->step < 4) state->step++;
|
if (state->step < 5) state->step++;
|
||||||
create_person_dialog_update_navigation(state);
|
create_person_dialog_update_navigation(state);
|
||||||
}
|
}
|
||||||
/** @brief Ajoute une ligne libellée au formulaire. */
|
/** @brief Ajoute une ligne libellée au formulaire. */
|
||||||
|
|
@ -1870,8 +1859,21 @@ gboolean create_person_dialog_present(GtkWindow *parent,
|
||||||
state->summary_scroll, FALSE);
|
state->summary_scroll, FALSE);
|
||||||
gtk_widget_set_vexpand(GTK_WIDGET(state->summary_scroll), TRUE);
|
gtk_widget_set_vexpand(GTK_WIDGET(state->summary_scroll), TRUE);
|
||||||
gtk_scrolled_window_set_child(state->summary_scroll, summary);
|
gtk_scrolled_window_set_child(state->summary_scroll, summary);
|
||||||
|
|
||||||
|
state->factual_relation_editor = person_factual_relation_editor_new();
|
||||||
|
person_factual_relation_editor_set_available_evidence(state->factual_relation_editor,
|
||||||
|
state->evidence_labels, state->evidence_identifiers);
|
||||||
|
person_factual_relation_editor_set_available_ocr_runs(state->factual_relation_editor,
|
||||||
|
state->ocr_runs);
|
||||||
|
GtkWidget *relation_scroll = gtk_scrolled_window_new(); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(relation_scroll),
|
||||||
|
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(relation_scroll),
|
||||||
|
person_factual_relation_editor_get_widget(state->factual_relation_editor));
|
||||||
|
gtk_stack_add_titled(state->stack, relation_scroll, "factual-relations",
|
||||||
|
"5 — Relations factuelles");
|
||||||
|
|
||||||
gtk_stack_add_titled(state->stack,
|
gtk_stack_add_titled(state->stack,
|
||||||
GTK_WIDGET(state->summary_scroll), "summary", "5 — Confirmation");
|
GTK_WIDGET(state->summary_scroll), "summary", "6 — Confirmation");
|
||||||
state->error = GTK_LABEL(gtk_label_new(NULL)); gtk_widget_set_visible(GTK_WIDGET(state->error), FALSE);
|
state->error = GTK_LABEL(gtk_label_new(NULL)); gtk_widget_set_visible(GTK_WIDGET(state->error), FALSE);
|
||||||
actions = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
actions = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||||
gtk_widget_set_name(actions, "create-person-actions");
|
gtk_widget_set_name(actions, "create-person-actions");
|
||||||
|
|
@ -1950,6 +1952,9 @@ void create_person_dialog_result_free(CreatePersonDialogResult *result)
|
||||||
person_evidence_selection_free);
|
person_evidence_selection_free);
|
||||||
g_clear_pointer(&result->staging, evidence_staging_free);
|
g_clear_pointer(&result->staging, evidence_staging_free);
|
||||||
g_clear_pointer(&result->ocr_runs, g_ptr_array_unref);
|
g_clear_pointer(&result->ocr_runs, g_ptr_array_unref);
|
||||||
|
if (result->factual_relations) {
|
||||||
|
g_ptr_array_unref(result->factual_relations);
|
||||||
|
}
|
||||||
g_free(result);
|
g_free(result);
|
||||||
}
|
}
|
||||||
const PersonEntityInput *create_person_dialog_result_get_input(
|
const PersonEntityInput *create_person_dialog_result_get_input(
|
||||||
|
|
@ -1975,6 +1980,11 @@ const GPtrArray *create_person_dialog_result_get_ocr_runs(
|
||||||
{
|
{
|
||||||
return result != NULL ? result->ocr_runs : NULL;
|
return result != NULL ? result->ocr_runs : NULL;
|
||||||
}
|
}
|
||||||
|
const GPtrArray *create_person_dialog_result_get_factual_relations(
|
||||||
|
const CreatePersonDialogResult *result)
|
||||||
|
{
|
||||||
|
return result != NULL ? result->factual_relations : NULL;
|
||||||
|
}
|
||||||
gboolean create_person_dialog_test_overlay_has_region(GtkWindow *window)
|
gboolean create_person_dialog_test_overlay_has_region(GtkWindow *window)
|
||||||
{
|
{
|
||||||
CreatePersonDialogState *state = window != NULL
|
CreatePersonDialogState *state = window != NULL
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ typedef struct {
|
||||||
double ratio;
|
double ratio;
|
||||||
int minimum_start;
|
int minimum_start;
|
||||||
int minimum_end;
|
int minimum_end;
|
||||||
|
int previous_width;
|
||||||
|
guint stable_frames;
|
||||||
} LabfyPanedGeometry;
|
} LabfyPanedGeometry;
|
||||||
|
|
||||||
LabfyDialogGeometry labfy_dialog_geometry_calculate(
|
LabfyDialogGeometry labfy_dialog_geometry_calculate(
|
||||||
|
|
@ -115,19 +117,40 @@ static void paned_geometry_apply(
|
||||||
gtk_paned_set_position(paned, position);
|
gtk_paned_set_position(paned, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean paned_geometry_idle(gpointer data)
|
static gboolean paned_geometry_tick(GtkWidget *widget, GdkFrameClock *clock,
|
||||||
|
gpointer data)
|
||||||
{
|
{
|
||||||
GtkPaned *paned = GTK_PANED(data);
|
GtkPaned *paned = GTK_PANED(widget);
|
||||||
LabfyPanedGeometry *geometry = g_object_get_data(
|
LabfyPanedGeometry *geometry = g_object_get_data(
|
||||||
G_OBJECT(paned), "labfy-paned-initial-geometry");
|
G_OBJECT(paned), "labfy-paned-initial-geometry");
|
||||||
|
int width;
|
||||||
|
(void) clock;
|
||||||
|
(void) data;
|
||||||
if (geometry == NULL) return G_SOURCE_REMOVE;
|
if (geometry == NULL) return G_SOURCE_REMOVE;
|
||||||
if (gtk_widget_get_width(GTK_WIDGET(paned)) <
|
width = gtk_widget_get_width(widget);
|
||||||
geometry->minimum_start + geometry->minimum_end)
|
if (width < geometry->minimum_start + geometry->minimum_end) {
|
||||||
|
geometry->previous_width = width;
|
||||||
|
geometry->stable_frames = 0;
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
if (width != geometry->previous_width) {
|
||||||
|
geometry->previous_width = width;
|
||||||
|
geometry->stable_frames = 0;
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
if (geometry->stable_frames++ < 1) return G_SOURCE_CONTINUE;
|
||||||
paned_geometry_apply(paned, geometry);
|
paned_geometry_apply(paned, geometry);
|
||||||
|
g_object_set_data(G_OBJECT(paned), "labfy-paned-initial-ratio-applied",
|
||||||
|
GINT_TO_POINTER(1));
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean labfy_paned_initial_ratio_applied(GtkPaned *paned)
|
||||||
|
{
|
||||||
|
return GTK_IS_PANED(paned) && g_object_get_data(G_OBJECT(paned),
|
||||||
|
"labfy-paned-initial-ratio-applied") != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void labfy_paned_apply_initial_ratio(
|
void labfy_paned_apply_initial_ratio(
|
||||||
GtkPaned *paned, double ratio, int minimum_start, int minimum_end)
|
GtkPaned *paned, double ratio, int minimum_start, int minimum_end)
|
||||||
{
|
{
|
||||||
|
|
@ -142,6 +165,6 @@ void labfy_paned_apply_initial_ratio(
|
||||||
geometry->minimum_end = MAX(0, minimum_end);
|
geometry->minimum_end = MAX(0, minimum_end);
|
||||||
g_object_set_data_full(G_OBJECT(paned),
|
g_object_set_data_full(G_OBJECT(paned),
|
||||||
"labfy-paned-initial-geometry", geometry, g_free);
|
"labfy-paned-initial-geometry", geometry, g_free);
|
||||||
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, paned_geometry_idle,
|
gtk_widget_add_tick_callback(GTK_WIDGET(paned), paned_geometry_tick,
|
||||||
g_object_ref(paned), g_object_unref);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@
|
||||||
|
|
||||||
#include "models/evidence_type.h"
|
#include "models/evidence_type.h"
|
||||||
#include "dao/identity_ocr_dao.h"
|
#include "dao/identity_ocr_dao.h"
|
||||||
|
#include "dao/identity_traceability_dao.h"
|
||||||
|
#include "dao/entity_dao.h"
|
||||||
#include "views/evidence_identity_ocr_dialog.h"
|
#include "views/evidence_identity_ocr_dialog.h"
|
||||||
|
#include "views/person_vocabulary_adapter.h"
|
||||||
#include "widgets/ocr_provenance_overlay.h"
|
#include "widgets/ocr_provenance_overlay.h"
|
||||||
|
|
||||||
struct EvidenceMetadataDialogResult
|
struct EvidenceMetadataDialogResult
|
||||||
|
|
@ -537,6 +540,61 @@ gboolean evidence_metadata_dialog_present_with_ocr(
|
||||||
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(ocr_scroll), ocr);
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(ocr_scroll), ocr);
|
||||||
gtk_box_append(GTK_BOX(main_box), ocr_scroll);
|
gtk_box_append(GTK_BOX(main_box), ocr_scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (database != NULL) {
|
||||||
|
IdentityTraceabilityDao *trace_dao = identity_traceability_dao_new(database);
|
||||||
|
if (trace_dao != NULL) {
|
||||||
|
GPtrArray *relations = identity_traceability_dao_list_factual_relations_by_evidence(
|
||||||
|
trace_dao, evidence_record_get_identifier(record), NULL);
|
||||||
|
if (relations != NULL && relations->len > 0) {
|
||||||
|
GtkWidget *rel_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
|
||||||
|
gtk_box_append(GTK_BOX(rel_box), gtk_label_new("Relations factuelles avec les personnes"));
|
||||||
|
EntityDao *entity_dao = entity_dao_new(database, NULL);
|
||||||
|
for (guint i = 0; i < relations->len; i++) {
|
||||||
|
PersonEvidenceFactualRelation *rel = g_ptr_array_index(relations, i);
|
||||||
|
const char *person_id = person_evidence_factual_relation_get_person_identifier(rel);
|
||||||
|
const char *rel_type = person_vocabulary_adapter_relation_label(
|
||||||
|
person_evidence_factual_relation_get_relation_type(rel));
|
||||||
|
const char *note = person_evidence_factual_relation_get_factual_note(rel);
|
||||||
|
char *designation = NULL;
|
||||||
|
if (entity_dao != NULL) {
|
||||||
|
EntityRecord *person = entity_dao_find_by_identifier(entity_dao, person_id, NULL);
|
||||||
|
if (person != NULL) {
|
||||||
|
const char *label = entity_record_get_label(person);
|
||||||
|
const char *value = entity_record_get_value(person);
|
||||||
|
designation = g_strdup(label && label[0] ? label : (value ? value : ""));
|
||||||
|
entity_record_free(person);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (designation == NULL) designation = g_strdup("Personne inconnue");
|
||||||
|
const char *run = person_evidence_factual_relation_get_ocr_run_identifier(rel);
|
||||||
|
char *text = g_strdup_printf("• %s : %s\n Date : %s — Origine : %s%s%s",
|
||||||
|
designation, rel_type,
|
||||||
|
person_evidence_factual_relation_get_observed_at(rel),
|
||||||
|
person_evidence_factual_relation_get_origin(rel),
|
||||||
|
run ? " — OcrRun : " : "", run ? run : "");
|
||||||
|
if (note && note[0]) {
|
||||||
|
char *tmp = g_strdup_printf("%s\n Note : %s", text, note);
|
||||||
|
g_free(text);
|
||||||
|
text = tmp;
|
||||||
|
}
|
||||||
|
GtkWidget *label = gtk_label_new(text);
|
||||||
|
gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
|
||||||
|
gtk_box_append(GTK_BOX(rel_box), label);
|
||||||
|
g_free(text);
|
||||||
|
g_free(designation);
|
||||||
|
}
|
||||||
|
if (entity_dao != NULL) entity_dao_free(entity_dao);
|
||||||
|
GtkWidget *rel_scroll = gtk_scrolled_window_new();
|
||||||
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(rel_scroll), rel_box);
|
||||||
|
gtk_widget_set_size_request(rel_scroll, -1, 100);
|
||||||
|
gtk_box_append(GTK_BOX(main_box), rel_scroll);
|
||||||
|
g_ptr_array_unref(relations);
|
||||||
|
}
|
||||||
|
identity_traceability_dao_free(trace_dao);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
buttons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
buttons = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||||
gtk_widget_set_halign(buttons, GTK_ALIGN_END);
|
gtk_widget_set_halign(buttons, GTK_ALIGN_END);
|
||||||
cancel = gtk_button_new_with_label("Annuler");
|
cancel = gtk_button_new_with_label("Annuler");
|
||||||
|
|
|
||||||
84
src/views/identity_ocr_language_loader.c
Normal file
84
src/views/identity_ocr_language_loader.c
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
#include "views/identity_ocr_language_loader.h"
|
||||||
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *executable;
|
||||||
|
GWeakRef window;
|
||||||
|
GWeakRef dropdown;
|
||||||
|
} IdentityLanguageJob;
|
||||||
|
|
||||||
|
static void identity_language_job_free(gpointer data)
|
||||||
|
{
|
||||||
|
IdentityLanguageJob *job = data;
|
||||||
|
if (job != NULL) {
|
||||||
|
g_free(job->executable);
|
||||||
|
g_weak_ref_clear(&job->window);
|
||||||
|
g_weak_ref_clear(&job->dropdown);
|
||||||
|
g_free(job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void identity_languages_worker(GTask *task, gpointer source,
|
||||||
|
gpointer task_data, GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
(void)source; (void)cancellable;
|
||||||
|
IdentityLanguageJob *job = task_data;
|
||||||
|
gchar *stdout_text = NULL;
|
||||||
|
gboolean success = g_spawn_command_line_sync(
|
||||||
|
g_strdup_printf("'%s' --list-langs", job->executable),
|
||||||
|
&stdout_text, NULL, NULL, NULL);
|
||||||
|
if (success && stdout_text != NULL) {
|
||||||
|
GPtrArray *langs = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
gchar **lines = g_strsplit(stdout_text, "\n", -1);
|
||||||
|
for (gsize i = 1; lines[i] != NULL; i++) {
|
||||||
|
gchar *lang = g_strstrip(g_strdup(lines[i]));
|
||||||
|
if (lang[0] != '\0') g_ptr_array_add(langs, lang);
|
||||||
|
else g_free(lang);
|
||||||
|
}
|
||||||
|
g_strfreev(lines);
|
||||||
|
g_task_return_pointer(task, langs, (GDestroyNotify)g_ptr_array_unref);
|
||||||
|
} else {
|
||||||
|
g_task_return_pointer(task, NULL, NULL);
|
||||||
|
}
|
||||||
|
g_free(stdout_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void identity_languages_completed(GObject *source,
|
||||||
|
GAsyncResult *result, gpointer data)
|
||||||
|
{
|
||||||
|
(void)source;
|
||||||
|
GTask *task = G_TASK(result);
|
||||||
|
IdentityLanguageJob *job = data;
|
||||||
|
GPtrArray *langs = g_task_propagate_pointer(task, NULL);
|
||||||
|
if (langs != NULL) {
|
||||||
|
GtkWindow *window = GTK_WINDOW(g_weak_ref_get(&job->window));
|
||||||
|
GtkDropDown *dropdown = GTK_DROP_DOWN(g_weak_ref_get(&job->dropdown));
|
||||||
|
if (window != NULL && dropdown != NULL) {
|
||||||
|
GtkStringList *list = gtk_string_list_new(NULL);
|
||||||
|
gtk_string_list_append(list, "Fra (français)");
|
||||||
|
for (guint i = 0; i < langs->len; i++) {
|
||||||
|
const char *lang = g_ptr_array_index(langs, i);
|
||||||
|
if (g_strcmp0(lang, "fra") != 0) {
|
||||||
|
gtk_string_list_append(list, lang);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gtk_drop_down_set_model(dropdown, G_LIST_MODEL(list));
|
||||||
|
}
|
||||||
|
if (window != NULL) g_object_unref(window);
|
||||||
|
if (dropdown != NULL) g_object_unref(dropdown);
|
||||||
|
g_ptr_array_unref(langs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void identity_ocr_language_loader_start(GtkWindow *window, const char *tesseract_path, GtkDropDown *language_dropdown)
|
||||||
|
{
|
||||||
|
if (tesseract_path == NULL || window == NULL || language_dropdown == NULL) return;
|
||||||
|
IdentityLanguageJob *job = g_new0(IdentityLanguageJob, 1);
|
||||||
|
job->executable = g_strdup(tesseract_path);
|
||||||
|
g_weak_ref_init(&job->window, G_OBJECT(window));
|
||||||
|
g_weak_ref_init(&job->dropdown, G_OBJECT(language_dropdown));
|
||||||
|
GTask *task = g_task_new(NULL, NULL, identity_languages_completed, job);
|
||||||
|
g_task_set_task_data(task, job, identity_language_job_free);
|
||||||
|
g_task_run_in_thread(task, identity_languages_worker);
|
||||||
|
g_object_unref(task);
|
||||||
|
}
|
||||||
|
|
@ -1962,11 +1962,11 @@ void main_window_set_entity_selected_callback(MainWindow *main_window,
|
||||||
main_window->entity_selected_callback = callback;
|
main_window->entity_selected_callback = callback;
|
||||||
main_window->entity_selected_user_data = user_data;
|
main_window->entity_selected_user_data = user_data;
|
||||||
}
|
}
|
||||||
void main_window_set_person_evidences(MainWindow *main_window,
|
void main_window_set_person_evidences(MainWindow *main_window, const GPtrArray *records) {
|
||||||
const GPtrArray *records)
|
if (main_window) workspace_set_person_evidences(main_window->workspace, records);
|
||||||
{
|
}
|
||||||
if (main_window == NULL) return;
|
void main_window_set_person_factual_relations(MainWindow *main_window, const GPtrArray *relations, const GPtrArray *evidence_records) {
|
||||||
workspace_set_person_evidences(main_window->workspace, records);
|
if (main_window) workspace_set_person_factual_relations(main_window->workspace, relations, evidence_records);
|
||||||
}
|
}
|
||||||
|
|
||||||
void main_window_set_quit_callback(
|
void main_window_set_quit_callback(
|
||||||
|
|
|
||||||
267
src/views/person_factual_relation_editor.c
Normal file
267
src/views/person_factual_relation_editor.c
Normal file
|
|
@ -0,0 +1,267 @@
|
||||||
|
#include "views/person_factual_relation_editor.h"
|
||||||
|
#include "views/person_vocabulary_adapter.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *evidence_id, *run_id, *type, *note;
|
||||||
|
GtkDropDown *evidence, *run;
|
||||||
|
} RelationRow;
|
||||||
|
|
||||||
|
struct PersonFactualRelationEditor {
|
||||||
|
GtkWidget *root, *empty;
|
||||||
|
GtkListBox *list;
|
||||||
|
GPtrArray *rows, *evidence_ids, *runs;
|
||||||
|
GtkStringList *evidence_labels;
|
||||||
|
};
|
||||||
|
|
||||||
|
static GQuark editor_error(void)
|
||||||
|
{ return g_quark_from_static_string("person-factual-relation-editor"); }
|
||||||
|
static void row_free(gpointer data)
|
||||||
|
{
|
||||||
|
RelationRow *row=data;
|
||||||
|
if(!row)return;
|
||||||
|
g_free(row->evidence_id);g_free(row->run_id);g_free(row->type);
|
||||||
|
g_free(row->note);g_free(row);
|
||||||
|
}
|
||||||
|
static void input_free(gpointer data)
|
||||||
|
{
|
||||||
|
PersonCreationFactualRelationInput *input=data;
|
||||||
|
if(!input)return;
|
||||||
|
g_free((char*)input->evidence_selection_identifier);
|
||||||
|
g_free((char*)input->ocr_run_identifier);
|
||||||
|
g_free((char*)input->relation_type);g_free((char*)input->factual_note);
|
||||||
|
g_free(input);
|
||||||
|
}
|
||||||
|
static void update_empty(PersonFactualRelationEditor *editor)
|
||||||
|
{
|
||||||
|
gboolean empty=editor->rows->len==0;
|
||||||
|
gtk_widget_set_visible(editor->empty,empty);
|
||||||
|
gtk_widget_set_visible(GTK_WIDGET(editor->list),!empty);
|
||||||
|
}
|
||||||
|
static GtkStringList *evidence_model(PersonFactualRelationEditor *editor)
|
||||||
|
{
|
||||||
|
GtkStringList *model=gtk_string_list_new(NULL);
|
||||||
|
gtk_string_list_append(model,"Sélectionner une preuve…");
|
||||||
|
for(guint i=0;editor->evidence_labels&&
|
||||||
|
i<g_list_model_get_n_items(G_LIST_MODEL(editor->evidence_labels));i++)
|
||||||
|
gtk_string_list_append(model,
|
||||||
|
gtk_string_list_get_string(editor->evidence_labels,i));
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
static GtkStringList *run_model(PersonFactualRelationEditor *editor,
|
||||||
|
const char *evidence_id)
|
||||||
|
{
|
||||||
|
GtkStringList *model=gtk_string_list_new(NULL);
|
||||||
|
gtk_string_list_append(model,"Aucun OcrRun (facultatif)");
|
||||||
|
for(guint i=0;editor->runs&&i<editor->runs->len;i++){
|
||||||
|
IdentityOcrRun *run=g_ptr_array_index(editor->runs,i);
|
||||||
|
if(g_strcmp0(identity_ocr_run_get_evidence_id(run),evidence_id)!=0)
|
||||||
|
continue;
|
||||||
|
char *label=g_strdup_printf("OcrRun %s",
|
||||||
|
identity_ocr_run_get_identifier(run));
|
||||||
|
gtk_string_list_append(model,label);g_free(label);
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
static const char *filtered_run_id(PersonFactualRelationEditor *editor,
|
||||||
|
const char *evidence_id,guint selected)
|
||||||
|
{
|
||||||
|
if(selected==0)return NULL;
|
||||||
|
guint position=1;
|
||||||
|
for(guint i=0;editor->runs&&i<editor->runs->len;i++){
|
||||||
|
IdentityOcrRun *run=g_ptr_array_index(editor->runs,i);
|
||||||
|
if(g_strcmp0(identity_ocr_run_get_evidence_id(run),evidence_id)!=0)
|
||||||
|
continue;
|
||||||
|
if(position++==selected)return identity_ocr_run_get_identifier(run);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void evidence_changed(GtkDropDown *drop,GParamSpec *pspec,gpointer data)
|
||||||
|
{
|
||||||
|
(void)pspec; RelationRow *row=data;
|
||||||
|
PersonFactualRelationEditor *editor=g_object_get_data(G_OBJECT(drop),"editor");
|
||||||
|
guint selected=gtk_drop_down_get_selected(drop);
|
||||||
|
g_free(row->evidence_id);row->evidence_id=NULL;
|
||||||
|
if(selected>0&&editor->evidence_ids&&selected<=editor->evidence_ids->len)
|
||||||
|
row->evidence_id=g_strdup(g_ptr_array_index(editor->evidence_ids,selected-1));
|
||||||
|
g_clear_pointer(&row->run_id,g_free);
|
||||||
|
GtkStringList *model=run_model(editor,row->evidence_id);
|
||||||
|
gtk_drop_down_set_model(row->run,G_LIST_MODEL(model));
|
||||||
|
gtk_drop_down_set_selected(row->run,0);
|
||||||
|
}
|
||||||
|
static void type_changed(GtkDropDown *drop,GParamSpec *pspec,gpointer data)
|
||||||
|
{
|
||||||
|
(void)pspec;RelationRow *row=data;guint selected=gtk_drop_down_get_selected(drop);
|
||||||
|
g_free(row->type);row->type=selected?g_strdup(
|
||||||
|
person_vocabulary_adapter_relation_code(selected-1)):NULL;
|
||||||
|
}
|
||||||
|
static void run_changed(GtkDropDown *drop,GParamSpec *pspec,gpointer data)
|
||||||
|
{
|
||||||
|
(void)pspec;RelationRow *row=data;
|
||||||
|
PersonFactualRelationEditor *editor=g_object_get_data(G_OBJECT(drop),"editor");
|
||||||
|
g_free(row->run_id);row->run_id=g_strdup(filtered_run_id(editor,
|
||||||
|
row->evidence_id,gtk_drop_down_get_selected(drop)));
|
||||||
|
}
|
||||||
|
static void note_changed(GtkEditable *editable,gpointer data)
|
||||||
|
{
|
||||||
|
RelationRow *row=data;g_free(row->note);
|
||||||
|
row->note=g_strdup(gtk_editable_get_text(editable));
|
||||||
|
}
|
||||||
|
static void remove_clicked(GtkButton *button,gpointer data)
|
||||||
|
{
|
||||||
|
PersonFactualRelationEditor *editor=data;
|
||||||
|
GtkWidget *row=gtk_widget_get_ancestor(GTK_WIDGET(button),GTK_TYPE_LIST_BOX_ROW);
|
||||||
|
gint index=row?gtk_list_box_row_get_index(GTK_LIST_BOX_ROW(row)):-1;
|
||||||
|
if(index<0||(guint)index>=editor->rows->len)return;
|
||||||
|
gtk_list_box_remove(editor->list,row);
|
||||||
|
g_ptr_array_remove_index(editor->rows,(guint)index);update_empty(editor);
|
||||||
|
}
|
||||||
|
static void add_clicked(GtkButton *button,gpointer data)
|
||||||
|
{
|
||||||
|
(void)button;PersonFactualRelationEditor *editor=data;
|
||||||
|
RelationRow *state=g_new0(RelationRow,1);
|
||||||
|
GtkWidget *row=gtk_list_box_row_new(),*box=gtk_box_new(GTK_ORIENTATION_VERTICAL,6);
|
||||||
|
GtkWidget *header=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,6);
|
||||||
|
GtkStringList *types=person_vocabulary_adapter_create_relation_labels();
|
||||||
|
const char *placeholder[]={"Sélectionner un type…",NULL};
|
||||||
|
gtk_string_list_splice(types,0,0,placeholder);
|
||||||
|
GtkWidget *type=gtk_drop_down_new(G_LIST_MODEL(types),NULL);
|
||||||
|
GtkWidget *remove=gtk_button_new_from_icon_name("list-remove-symbolic");
|
||||||
|
gtk_widget_set_name(type,"factual-relation-type");
|
||||||
|
gtk_widget_set_name(remove,"factual-relation-remove");
|
||||||
|
gtk_widget_set_tooltip_text(remove,"Retirer cette relation préparée");
|
||||||
|
gtk_widget_set_hexpand(type,TRUE);gtk_box_append(GTK_BOX(header),type);
|
||||||
|
gtk_box_append(GTK_BOX(header),remove);gtk_box_append(GTK_BOX(box),header);
|
||||||
|
GtkStringList *evidences=evidence_model(editor);
|
||||||
|
state->evidence=GTK_DROP_DOWN(gtk_drop_down_new(G_LIST_MODEL(evidences),NULL));
|
||||||
|
gtk_widget_set_name(GTK_WIDGET(state->evidence),"factual-relation-evidence");
|
||||||
|
gtk_box_append(GTK_BOX(box),GTK_WIDGET(state->evidence));
|
||||||
|
GtkStringList *runs=run_model(editor,NULL);
|
||||||
|
state->run=GTK_DROP_DOWN(gtk_drop_down_new(G_LIST_MODEL(runs),NULL));
|
||||||
|
gtk_widget_set_name(GTK_WIDGET(state->run),"factual-relation-ocr-run");
|
||||||
|
gtk_box_append(GTK_BOX(box),GTK_WIDGET(state->run));
|
||||||
|
GtkWidget *note=gtk_entry_new();gtk_entry_set_placeholder_text(GTK_ENTRY(note),
|
||||||
|
"Note factuelle (facultative)");gtk_box_append(GTK_BOX(box),note);
|
||||||
|
gtk_widget_set_name(note,"factual-relation-note");
|
||||||
|
gtk_list_box_row_set_child(GTK_LIST_BOX_ROW(row),box);
|
||||||
|
gtk_list_box_append(editor->list,row);g_ptr_array_add(editor->rows,state);
|
||||||
|
g_object_set_data(G_OBJECT(state->evidence),"editor",editor);
|
||||||
|
g_object_set_data(G_OBJECT(state->run),"editor",editor);
|
||||||
|
g_signal_connect(type,"notify::selected",G_CALLBACK(type_changed),state);
|
||||||
|
g_signal_connect(state->evidence,"notify::selected",G_CALLBACK(evidence_changed),state);
|
||||||
|
g_signal_connect(state->run,"notify::selected",G_CALLBACK(run_changed),state);
|
||||||
|
g_signal_connect(note,"changed",G_CALLBACK(note_changed),state);
|
||||||
|
g_signal_connect(remove,"clicked",G_CALLBACK(remove_clicked),editor);update_empty(editor);
|
||||||
|
}
|
||||||
|
PersonFactualRelationEditor *person_factual_relation_editor_new(void)
|
||||||
|
{
|
||||||
|
PersonFactualRelationEditor *editor=g_new0(PersonFactualRelationEditor,1);
|
||||||
|
editor->rows=g_ptr_array_new_with_free_func(row_free);
|
||||||
|
editor->root=gtk_box_new(GTK_ORIENTATION_VERTICAL,8);
|
||||||
|
GtkWidget *header=gtk_box_new(GTK_ORIENTATION_HORIZONTAL,8);
|
||||||
|
GtkWidget *title=gtk_label_new("Relations factuelles");
|
||||||
|
gtk_widget_set_hexpand(title,TRUE);gtk_widget_set_halign(title,GTK_ALIGN_START);
|
||||||
|
GtkWidget *add=gtk_button_new_with_label("Ajouter une relation");
|
||||||
|
gtk_widget_set_name(add,"factual-relation-add");
|
||||||
|
gtk_box_append(GTK_BOX(header),title);gtk_box_append(GTK_BOX(header),add);
|
||||||
|
gtk_box_append(GTK_BOX(editor->root),header);
|
||||||
|
editor->list=GTK_LIST_BOX(gtk_list_box_new());
|
||||||
|
gtk_list_box_set_selection_mode(editor->list,GTK_SELECTION_NONE);
|
||||||
|
editor->empty=gtk_label_new("Aucune relation factuelle préparée.");
|
||||||
|
gtk_box_append(GTK_BOX(editor->root),GTK_WIDGET(editor->list));
|
||||||
|
gtk_box_append(GTK_BOX(editor->root),editor->empty);
|
||||||
|
g_signal_connect(add,"clicked",G_CALLBACK(add_clicked),editor);update_empty(editor);
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
GtkWidget *person_factual_relation_editor_get_widget(PersonFactualRelationEditor *editor)
|
||||||
|
{return editor?editor->root:NULL;}
|
||||||
|
void person_factual_relation_editor_set_available_evidence(
|
||||||
|
PersonFactualRelationEditor *editor,GtkStringList *labels,GPtrArray *ids)
|
||||||
|
{
|
||||||
|
if(!editor)return;
|
||||||
|
g_set_object(&editor->evidence_labels,labels);
|
||||||
|
if(editor->evidence_ids)g_ptr_array_unref(editor->evidence_ids);
|
||||||
|
editor->evidence_ids=ids?g_ptr_array_ref(ids):NULL;
|
||||||
|
for(guint i=0;i<editor->rows->len;i++){
|
||||||
|
RelationRow *row=g_ptr_array_index(editor->rows,i);
|
||||||
|
GtkStringList *model=evidence_model(editor);
|
||||||
|
gtk_drop_down_set_model(row->evidence,G_LIST_MODEL(model));
|
||||||
|
gtk_drop_down_set_selected(row->evidence,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void person_factual_relation_editor_set_available_ocr_runs(
|
||||||
|
PersonFactualRelationEditor *editor,GPtrArray *runs)
|
||||||
|
{
|
||||||
|
if(!editor)return;
|
||||||
|
if(editor->runs)g_ptr_array_unref(editor->runs);
|
||||||
|
editor->runs=runs?g_ptr_array_ref(runs):NULL;
|
||||||
|
for(guint i=0;i<editor->rows->len;i++){
|
||||||
|
RelationRow *row=g_ptr_array_index(editor->rows,i);
|
||||||
|
GtkStringList *model=run_model(editor,row->evidence_id);
|
||||||
|
gtk_drop_down_set_model(row->run,G_LIST_MODEL(model));
|
||||||
|
g_clear_pointer(&row->run_id,g_free);gtk_drop_down_set_selected(row->run,0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gboolean person_factual_relation_editor_collect_relations(
|
||||||
|
PersonFactualRelationEditor *editor,GPtrArray **relations,GError **error)
|
||||||
|
{
|
||||||
|
if(!editor||!relations){g_set_error_literal(error,editor_error(),1,
|
||||||
|
"Éditeur de relations factuelles invalide.");return FALSE;}
|
||||||
|
GPtrArray *result=g_ptr_array_new_with_free_func(input_free);
|
||||||
|
GHashTable *keys=g_hash_table_new_full(g_str_hash,g_str_equal,g_free,NULL);
|
||||||
|
for(guint i=0;i<editor->rows->len;i++){
|
||||||
|
RelationRow *row=g_ptr_array_index(editor->rows,i);char *note=g_strdup(row->note);
|
||||||
|
if(note)g_strstrip(note);
|
||||||
|
if(note&&!*note)g_clear_pointer(¬e,g_free);
|
||||||
|
if(!row->evidence_id||!row->type){g_free(note);g_set_error_literal(error,
|
||||||
|
editor_error(),2,"Chaque relation doit avoir une preuve et un type explicites.");goto bad;}
|
||||||
|
char *key=g_strdup_printf("%s\037%s\037%s\037%s",row->evidence_id,row->type,
|
||||||
|
row->run_id?row->run_id:"",note?note:"");
|
||||||
|
if(g_hash_table_contains(keys,key)){g_free(key);g_free(note);
|
||||||
|
g_set_error_literal(error,editor_error(),3,
|
||||||
|
"Cette relation factuelle est déjà préparée.");goto bad;}
|
||||||
|
g_hash_table_add(keys,key);
|
||||||
|
PersonCreationFactualRelationInput *input=g_new0(PersonCreationFactualRelationInput,1);
|
||||||
|
input->evidence_selection_identifier=g_strdup(row->evidence_id);
|
||||||
|
input->ocr_run_identifier=g_strdup(row->run_id);input->relation_type=g_strdup(row->type);
|
||||||
|
input->factual_note=note;g_ptr_array_add(result,input);
|
||||||
|
}
|
||||||
|
g_hash_table_unref(keys);*relations=result;return TRUE;
|
||||||
|
bad:g_hash_table_unref(keys);g_ptr_array_unref(result);return FALSE;
|
||||||
|
}
|
||||||
|
guint person_factual_relation_editor_get_count(const PersonFactualRelationEditor *editor)
|
||||||
|
{return editor?editor->rows->len:0;}
|
||||||
|
gboolean person_factual_relation_editor_validate(
|
||||||
|
PersonFactualRelationEditor *editor,GError **error)
|
||||||
|
{
|
||||||
|
GPtrArray *relations=NULL;
|
||||||
|
gboolean valid=person_factual_relation_editor_collect_relations(
|
||||||
|
editor,&relations,error);
|
||||||
|
if(relations)g_ptr_array_unref(relations);
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
void person_factual_relation_editor_append_summary(
|
||||||
|
PersonFactualRelationEditor *editor,GString *summary)
|
||||||
|
{
|
||||||
|
GPtrArray *relations=NULL;
|
||||||
|
if(!summary||!person_factual_relation_editor_collect_relations(
|
||||||
|
editor,&relations,NULL))return;
|
||||||
|
g_string_append(summary,"\n\nRelations factuelles préparées");
|
||||||
|
if(relations->len==0)g_string_append(summary,"\nAucune relation.");
|
||||||
|
for(guint i=0;i<relations->len;i++){
|
||||||
|
PersonCreationFactualRelationInput *relation=g_ptr_array_index(relations,i);
|
||||||
|
g_string_append_printf(summary,"\n• %s — preuve %s%s%s",
|
||||||
|
person_vocabulary_adapter_relation_label(relation->relation_type),
|
||||||
|
relation->evidence_selection_identifier,
|
||||||
|
relation->factual_note?" — ":"",relation->factual_note?relation->factual_note:"");
|
||||||
|
}
|
||||||
|
g_ptr_array_unref(relations);
|
||||||
|
}
|
||||||
|
void person_factual_relation_editor_free(PersonFactualRelationEditor *editor)
|
||||||
|
{
|
||||||
|
if(!editor)return;
|
||||||
|
g_ptr_array_unref(editor->rows);
|
||||||
|
g_clear_object(&editor->evidence_labels);
|
||||||
|
if(editor->evidence_ids)g_ptr_array_unref(editor->evidence_ids);
|
||||||
|
if(editor->runs)g_ptr_array_unref(editor->runs);
|
||||||
|
g_free(editor);
|
||||||
|
}
|
||||||
|
|
@ -63,6 +63,59 @@ GtkStringList *person_vocabulary_adapter_create_status_labels(
|
||||||
const PersonVocabularyAdapter *adapter)
|
const PersonVocabularyAdapter *adapter)
|
||||||
{ return create_labels(person_vocabulary_adapter_get_statuses(adapter)); }
|
{ return create_labels(person_vocabulary_adapter_get_statuses(adapter)); }
|
||||||
|
|
||||||
|
static const char *const factual_relation_types[] = {
|
||||||
|
"identity_observed_in",
|
||||||
|
"document_presented_in_name_of",
|
||||||
|
"declared_holder_in",
|
||||||
|
"data_extracted_from"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *const factual_relation_labels[] = {
|
||||||
|
"Identité observée dans la preuve",
|
||||||
|
"Document présenté au nom de la personne",
|
||||||
|
"Titulaire déclaré dans la preuve",
|
||||||
|
"Donnée extraite de la preuve"
|
||||||
|
};
|
||||||
|
static const char *const factual_relation_descriptions[] = {
|
||||||
|
"Une identité est visible ou mentionnée dans cette preuve.",
|
||||||
|
"Le document a été présenté au nom de cette personne, sans conclure à son authenticité.",
|
||||||
|
"La preuve déclare cette personne comme titulaire, sans vérification automatique.",
|
||||||
|
"Une donnée concernant cette personne a été extraite de cette preuve."
|
||||||
|
};
|
||||||
|
|
||||||
|
GtkStringList *person_vocabulary_adapter_create_relation_labels(void)
|
||||||
|
{
|
||||||
|
GtkStringList *labels = gtk_string_list_new(NULL);
|
||||||
|
for (guint i = 0; i < 4; i++) {
|
||||||
|
gtk_string_list_append(labels, factual_relation_labels[i]);
|
||||||
|
}
|
||||||
|
return labels;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *person_vocabulary_adapter_relation_code(guint index)
|
||||||
|
{
|
||||||
|
if (index < 4) return factual_relation_types[index];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *person_vocabulary_adapter_relation_label(const char *code)
|
||||||
|
{
|
||||||
|
if (code == NULL) return "Inconnu";
|
||||||
|
for (guint i = 0; i < 4; i++) {
|
||||||
|
if (g_strcmp0(code, factual_relation_types[i]) == 0)
|
||||||
|
return factual_relation_labels[i];
|
||||||
|
}
|
||||||
|
return "Inconnu";
|
||||||
|
}
|
||||||
|
const char *person_vocabulary_adapter_relation_description(const char *code)
|
||||||
|
{
|
||||||
|
if (code == NULL) return NULL;
|
||||||
|
for (guint i = 0; i < G_N_ELEMENTS(factual_relation_types); i++)
|
||||||
|
if (g_strcmp0(code, factual_relation_types[i]) == 0)
|
||||||
|
return factual_relation_descriptions[i];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *person_vocabulary_adapter_status_code(
|
const char *person_vocabulary_adapter_status_code(
|
||||||
const PersonVocabularyAdapter *adapter, guint index)
|
const PersonVocabularyAdapter *adapter, guint index)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include "models/entity_record.h"
|
#include "models/entity_record.h"
|
||||||
#include "models/evidence_record.h"
|
#include "models/evidence_record.h"
|
||||||
|
#include "models/identity_traceability.h"
|
||||||
|
#include "views/person_vocabulary_adapter.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
|
||||||
|
|
@ -39,6 +41,7 @@ struct EntityDetailsPanel
|
||||||
GtkWidget *person_name_button;
|
GtkWidget *person_name_button;
|
||||||
GtkWidget *person_evidence_button;
|
GtkWidget *person_evidence_button;
|
||||||
GtkWidget *person_evidence_summary_label;
|
GtkWidget *person_evidence_summary_label;
|
||||||
|
GtkWidget *person_factual_relations_box;
|
||||||
GtkWidget *entity_evidence_box;
|
GtkWidget *entity_evidence_box;
|
||||||
GtkWidget *evidence_buttons_box;
|
GtkWidget *evidence_buttons_box;
|
||||||
|
|
||||||
|
|
@ -885,6 +888,8 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
gtk_box_append(GTK_BOX(details_panel->entity_evidence_box),
|
gtk_box_append(GTK_BOX(details_panel->entity_evidence_box),
|
||||||
details_panel->person_evidence_button);
|
details_panel->person_evidence_button);
|
||||||
gtk_box_append(GTK_BOX(details_box), details_panel->person_role_box);
|
gtk_box_append(GTK_BOX(details_box), details_panel->person_role_box);
|
||||||
|
details_panel->person_factual_relations_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
|
||||||
|
gtk_box_append(GTK_BOX(details_box), details_panel->person_factual_relations_box);
|
||||||
gtk_box_append(GTK_BOX(details_box), details_panel->entity_evidence_box);
|
gtk_box_append(GTK_BOX(details_box), details_panel->entity_evidence_box);
|
||||||
g_signal_connect(details_panel->person_role_dropdown, "notify::selected",
|
g_signal_connect(details_panel->person_role_dropdown, "notify::selected",
|
||||||
G_CALLBACK(entity_details_panel_on_person_role_changed), details_panel);
|
G_CALLBACK(entity_details_panel_on_person_role_changed), details_panel);
|
||||||
|
|
@ -1390,6 +1395,63 @@ void entity_details_panel_set_person_evidences(EntityDetailsPanel *panel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void entity_details_panel_set_person_factual_relations(
|
||||||
|
EntityDetailsPanel *panel, const GPtrArray *relations, const GPtrArray *evidence_records)
|
||||||
|
{
|
||||||
|
GtkWidget *child = NULL;
|
||||||
|
if (panel == NULL || panel->person_factual_relations_box == NULL) return;
|
||||||
|
while ((child = gtk_widget_get_first_child(panel->person_factual_relations_box)) != NULL)
|
||||||
|
gtk_box_remove(GTK_BOX(panel->person_factual_relations_box), child);
|
||||||
|
|
||||||
|
if (relations == NULL || relations->len == 0) {
|
||||||
|
gtk_widget_set_visible(panel->person_factual_relations_box, FALSE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_visible(panel->person_factual_relations_box, TRUE);
|
||||||
|
GtkWidget *title = gtk_label_new("Relations factuelles dans les preuves");
|
||||||
|
gtk_label_set_wrap(GTK_LABEL(title), TRUE);
|
||||||
|
gtk_label_set_xalign(GTK_LABEL(title), 0.0f);
|
||||||
|
gtk_box_append(GTK_BOX(panel->person_factual_relations_box), title);
|
||||||
|
|
||||||
|
for (guint i = 0; i < relations->len; i++) {
|
||||||
|
PersonEvidenceFactualRelation *rel = g_ptr_array_index(relations, i);
|
||||||
|
const char *evidence_id = person_evidence_factual_relation_get_evidence_identifier(rel);
|
||||||
|
const char *rel_type = person_vocabulary_adapter_relation_label(
|
||||||
|
person_evidence_factual_relation_get_relation_type(rel));
|
||||||
|
const char *note = person_evidence_factual_relation_get_factual_note(rel);
|
||||||
|
|
||||||
|
const char *evidence_name = "Preuve inconnue";
|
||||||
|
if (evidence_records != NULL) {
|
||||||
|
for (guint j = 0; j < evidence_records->len; j++) {
|
||||||
|
const EvidenceRecord *er = g_ptr_array_index(evidence_records, j);
|
||||||
|
if (g_strcmp0(evidence_record_get_identifier(er), evidence_id) == 0) {
|
||||||
|
evidence_name = evidence_record_get_original_name(er);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *run = person_evidence_factual_relation_get_ocr_run_identifier(rel);
|
||||||
|
char *text = g_strdup_printf("• %s : %s\n Date : %s — Origine : %s%s%s",
|
||||||
|
evidence_name, rel_type,
|
||||||
|
person_evidence_factual_relation_get_observed_at(rel),
|
||||||
|
person_evidence_factual_relation_get_origin(rel),
|
||||||
|
run ? " — OcrRun : " : "", run ? run : "");
|
||||||
|
if (note && note[0]) {
|
||||||
|
char *tmp = g_strdup_printf("%s\n Note : %s", text, note);
|
||||||
|
g_free(text);
|
||||||
|
text = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
GtkWidget *label = gtk_label_new(text);
|
||||||
|
gtk_label_set_xalign(GTK_LABEL(label), 0.0f);
|
||||||
|
gtk_label_set_wrap(GTK_LABEL(label), TRUE);
|
||||||
|
gtk_box_append(GTK_BOX(panel->person_factual_relations_box), label);
|
||||||
|
g_free(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gboolean entity_details_panel_is_open(
|
gboolean entity_details_panel_is_open(
|
||||||
const EntityDetailsPanel *details_panel
|
const EntityDetailsPanel *details_panel
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3911,12 +3911,11 @@ void workspace_set_entity_selected_callback(Workspace *workspace,
|
||||||
workspace->entity_selected_callback = callback;
|
workspace->entity_selected_callback = callback;
|
||||||
workspace->entity_selected_user_data = user_data;
|
workspace->entity_selected_user_data = user_data;
|
||||||
}
|
}
|
||||||
void workspace_set_person_evidences(Workspace *workspace,
|
void workspace_set_person_evidences(Workspace *workspace, const GPtrArray *records) {
|
||||||
const GPtrArray *records)
|
if (workspace) entity_details_panel_set_person_evidences(workspace->entity_details_panel, records);
|
||||||
{
|
}
|
||||||
if (workspace == NULL) return;
|
void workspace_set_person_factual_relations(Workspace *workspace, const GPtrArray *relations, const GPtrArray *evidence_records) {
|
||||||
entity_details_panel_set_person_evidences(
|
if (workspace) entity_details_panel_set_person_factual_relations(workspace->entity_details_panel, relations, evidence_records);
|
||||||
workspace->entity_details_panel, records);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void workspace_reset_graph_layout(
|
void workspace_reset_graph_layout(
|
||||||
|
|
|
||||||
|
|
@ -222,6 +222,9 @@ static gboolean click_cancel(gpointer data)
|
||||||
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
||||||
"L’OCR produit des propositions à vérifier"));
|
"L’OCR produit des propositions à vérifier"));
|
||||||
g_signal_emit_by_name(button, "clicked");
|
g_signal_emit_by_name(button, "clicked");
|
||||||
|
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
||||||
|
"Relations factuelles"));
|
||||||
|
g_signal_emit_by_name(button, "clicked");
|
||||||
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
||||||
"Désignation : SPECIMEN"));
|
"Désignation : SPECIMEN"));
|
||||||
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
g_assert_nonnull(find_label_containing(GTK_WIDGET(dialog),
|
||||||
|
|
|
||||||
|
|
@ -570,6 +570,8 @@ static gboolean drive(gpointer data)
|
||||||
context->confirmation_height=gtk_widget_get_height(
|
context->confirmation_height=gtk_widget_get_height(
|
||||||
GTK_WIDGET(context->dialog));
|
GTK_WIDGET(context->dialog));
|
||||||
g_signal_emit_by_name(find_button(root,"Suivant"),"clicked");
|
g_signal_emit_by_name(find_button(root,"Suivant"),"clicked");
|
||||||
|
g_assert_nonnull(find_label(root,"Relations factuelles"));
|
||||||
|
g_signal_emit_by_name(find_button(root,"Suivant"),"clicked");
|
||||||
g_assert_nonnull(find_label(root,"page 2"));
|
g_assert_nonnull(find_label(root,"page 2"));
|
||||||
g_assert_nonnull(find_label(root,"PAGE 2 VALEUR FINALE"));
|
g_assert_nonnull(find_label(root,"PAGE 2 VALEUR FINALE"));
|
||||||
g_assert_nonnull(find_label(root,"authenticité n’est pas établie"));
|
g_assert_nonnull(find_label(root,"authenticité n’est pas établie"));
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "models/evidence_type.h"
|
#include "models/evidence_type.h"
|
||||||
#include "views/evidence_identity_ocr_dialog.h"
|
#include "views/evidence_identity_ocr_dialog.h"
|
||||||
#include "views/evidence_import_dialog.h"
|
#include "views/evidence_import_dialog.h"
|
||||||
|
#include "views/dialog_geometry.h"
|
||||||
#include "views/main_window.h"
|
#include "views/main_window.h"
|
||||||
#include "widgets/workspace.h"
|
#include "widgets/workspace.h"
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
|
@ -497,7 +498,7 @@ static gboolean drive(gpointer data)
|
||||||
g_assert_nonnull(gtk_paned_get_end_child(GTK_PANED(paned)));
|
g_assert_nonnull(gtk_paned_get_end_child(GTK_PANED(paned)));
|
||||||
g_assert_false(is_descendant_of(actions, form_scroll));
|
g_assert_false(is_descendant_of(actions, form_scroll));
|
||||||
if (gtk_widget_get_width(paned) <= 0 ||
|
if (gtk_widget_get_width(paned) <= 0 ||
|
||||||
gtk_paned_get_position(GTK_PANED(paned)) <= 0)
|
!labfy_paned_initial_ratio_applied(GTK_PANED(paned)))
|
||||||
return G_SOURCE_CONTINUE;
|
return G_SOURCE_CONTINUE;
|
||||||
if (!context->layout_resize_pending) {
|
if (!context->layout_resize_pending) {
|
||||||
int initial_position =
|
int initial_position =
|
||||||
|
|
@ -564,12 +565,8 @@ static gboolean drive(gpointer data)
|
||||||
context, "Import — OCR d’identité facultatif");
|
context, "Import — OCR d’identité facultatif");
|
||||||
if (dialog == NULL) return G_SOURCE_CONTINUE;
|
if (dialog == NULL) return G_SOURCE_CONTINUE;
|
||||||
GtkWidget *root = GTK_WIDGET(dialog);
|
GtkWidget *root = GTK_WIDGET(dialog);
|
||||||
int default_width = 0;
|
g_assert_cmpint(gtk_widget_get_width(GTK_WIDGET(dialog)), >=, 800);
|
||||||
int default_height = 0;
|
g_assert_cmpint(gtk_widget_get_height(GTK_WIDGET(dialog)), >=, 600);
|
||||||
gtk_window_get_default_size(
|
|
||||||
dialog, &default_width, &default_height);
|
|
||||||
g_assert_cmpint(default_width, ==, 760);
|
|
||||||
g_assert_cmpint(default_height, ==, 560);
|
|
||||||
GtkWidget *continue_button =
|
GtkWidget *continue_button =
|
||||||
find_button(root, "Continuer l’import avec OCR");
|
find_button(root, "Continuer l’import avec OCR");
|
||||||
if (!gtk_widget_get_sensitive(continue_button))
|
if (!gtk_widget_get_sensitive(continue_button))
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,16 @@ static void fixture_free(Fixture*f)
|
||||||
|
|
||||||
static void test_models(void)
|
static void test_models(void)
|
||||||
{
|
{
|
||||||
|
static const char *codes[]={"identity_observed_in",
|
||||||
|
"document_presented_in_name_of","declared_holder_in","data_extracted_from"};
|
||||||
|
static const char *labels[]={"Identité observée dans la preuve",
|
||||||
|
"Document présenté au nom de la personne","Titulaire déclaré dans la preuve",
|
||||||
|
"Donnée extraite de la preuve"};
|
||||||
|
for(guint i=0;i<G_N_ELEMENTS(codes);i++){
|
||||||
|
g_assert_cmpstr(person_vocabulary_adapter_relation_code(i),==,codes[i]);
|
||||||
|
g_assert_cmpstr(person_vocabulary_adapter_relation_label(codes[i]),==,labels[i]);
|
||||||
|
g_assert_nonnull(person_vocabulary_adapter_relation_description(codes[i]));
|
||||||
|
}
|
||||||
PersonRoleVocabularyEntry justified={.requires_justification=TRUE};
|
PersonRoleVocabularyEntry justified={.requires_justification=TRUE};
|
||||||
g_assert_false(person_vocabulary_adapter_justification_valid(
|
g_assert_false(person_vocabulary_adapter_justification_valid(
|
||||||
&justified," "));
|
&justified," "));
|
||||||
|
|
@ -107,6 +117,16 @@ static void test_dao_history_and_relations(void)
|
||||||
g_assert_true(identity_traceability_dao_insert_factual_relation(d,r,&e));
|
g_assert_true(identity_traceability_dao_insert_factual_relation(d,r,&e));
|
||||||
GPtrArray*relations=identity_traceability_dao_list_factual_relations(d,EVIDENCE,&e);
|
GPtrArray*relations=identity_traceability_dao_list_factual_relations(d,EVIDENCE,&e);
|
||||||
g_assert_cmpuint(relations->len,==,1);g_ptr_array_unref(relations);
|
g_assert_cmpuint(relations->len,==,1);g_ptr_array_unref(relations);
|
||||||
|
relations=identity_traceability_dao_list_factual_relations_by_person(d,PERSON,&e);
|
||||||
|
g_assert_cmpuint(relations->len,==,1);g_ptr_array_unref(relations);
|
||||||
|
PersonEvidenceFactualRelation*foreign=person_evidence_factual_relation_new(
|
||||||
|
"70000000-0000-4000-8000-000000000019",PERSON,
|
||||||
|
"10000000-0000-4000-8000-000000000019",RUN,"data_extracted_from",
|
||||||
|
"Run étranger SPECIMEN",AT,TRUE);
|
||||||
|
g_assert_false(identity_traceability_dao_insert_factual_relation(d,foreign,&e));
|
||||||
|
g_assert_error(e,g_quark_from_static_string("identity-traceability-dao"),1);
|
||||||
|
g_assert_nonnull(strstr(e->message,"ne correspond pas"));g_clear_error(&e);
|
||||||
|
person_evidence_factual_relation_free(foreign);
|
||||||
GPtrArray*roles=identity_traceability_dao_list_roles(d,TRUE,&e);
|
GPtrArray*roles=identity_traceability_dao_list_roles(d,TRUE,&e);
|
||||||
g_assert_cmpuint(roles->len,>=,14);g_ptr_array_unref(roles);
|
g_assert_cmpuint(roles->len,>=,14);g_ptr_array_unref(roles);
|
||||||
roles=identity_traceability_dao_list_roles(d,FALSE,&e);
|
roles=identity_traceability_dao_list_roles(d,FALSE,&e);
|
||||||
|
|
|
||||||
62
tests/test_person_factual_relation_editor_gtk.c
Normal file
62
tests/test_person_factual_relation_editor_gtk.c
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include "views/person_factual_relation_editor.h"
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
static GtkWidget *find_named(GtkWidget *widget,const char *name)
|
||||||
|
{
|
||||||
|
if(g_strcmp0(gtk_widget_get_name(widget),name)==0)return widget;
|
||||||
|
for(GtkWidget *child=gtk_widget_get_first_child(widget);child;
|
||||||
|
child=gtk_widget_get_next_sibling(child)){
|
||||||
|
GtkWidget *found=find_named(child,name);if(found)return found;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
static void click_named(GtkWidget *root,const char *name)
|
||||||
|
{g_signal_emit_by_name(find_named(root,name),"clicked");}
|
||||||
|
static void test_editor(void)
|
||||||
|
{
|
||||||
|
const char *evidence_a="10000000-0000-4000-8000-000000000001";
|
||||||
|
const char *evidence_b="10000000-0000-4000-8000-000000000002";
|
||||||
|
GtkStringList *labels=gtk_string_list_new((const char*[]){"Preuve A","Preuve B",NULL});
|
||||||
|
GPtrArray *ids=g_ptr_array_new_with_free_func(g_free);
|
||||||
|
g_ptr_array_add(ids,g_strdup(evidence_a));g_ptr_array_add(ids,g_strdup(evidence_b));
|
||||||
|
GPtrArray *runs=g_ptr_array_new_with_free_func((GDestroyNotify)identity_ocr_run_free);
|
||||||
|
g_ptr_array_add(runs,identity_ocr_run_new(evidence_a,
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
"identity_card","front",1,"fra","none"));
|
||||||
|
g_ptr_array_add(runs,identity_ocr_run_new(evidence_b,
|
||||||
|
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||||
|
"passport","identity_page",1,"fra","none"));
|
||||||
|
PersonFactualRelationEditor *editor=person_factual_relation_editor_new();
|
||||||
|
person_factual_relation_editor_set_available_evidence(editor,labels,ids);
|
||||||
|
person_factual_relation_editor_set_available_ocr_runs(editor,runs);
|
||||||
|
GtkWidget *root=person_factual_relation_editor_get_widget(editor);
|
||||||
|
GtkWindow *window=GTK_WINDOW(gtk_window_new());
|
||||||
|
gtk_window_set_child(window,root);gtk_window_present(window);
|
||||||
|
GPtrArray *relations=NULL;GError *error=NULL;
|
||||||
|
g_assert_true(person_factual_relation_editor_collect_relations(editor,&relations,&error));
|
||||||
|
g_assert_cmpuint(relations->len,==,0);g_ptr_array_unref(relations);
|
||||||
|
click_named(root,"factual-relation-add");
|
||||||
|
g_assert_cmpuint(person_factual_relation_editor_get_count(editor),==,1);
|
||||||
|
gtk_drop_down_set_selected(GTK_DROP_DOWN(find_named(root,"factual-relation-type")),1);
|
||||||
|
gtk_drop_down_set_selected(GTK_DROP_DOWN(find_named(root,"factual-relation-evidence")),1);
|
||||||
|
GtkDropDown *run=GTK_DROP_DOWN(find_named(root,"factual-relation-ocr-run"));
|
||||||
|
g_assert_cmpuint(g_list_model_get_n_items(gtk_drop_down_get_model(run)),==,2);
|
||||||
|
gtk_drop_down_set_selected(run,1);
|
||||||
|
gtk_editable_set_text(GTK_EDITABLE(find_named(root,"factual-relation-note"))," Note SPECIMEN ");
|
||||||
|
g_assert_true(person_factual_relation_editor_collect_relations(editor,&relations,&error));
|
||||||
|
g_assert_cmpuint(relations->len,==,1);
|
||||||
|
PersonCreationFactualRelationInput *input=g_ptr_array_index(relations,0);
|
||||||
|
g_assert_cmpstr(input->factual_note,==,"Note SPECIMEN");g_ptr_array_unref(relations);
|
||||||
|
click_named(root,"factual-relation-remove");
|
||||||
|
g_assert_cmpuint(person_factual_relation_editor_get_count(editor),==,0);
|
||||||
|
gtk_window_destroy(window);while(g_main_context_iteration(NULL,FALSE));
|
||||||
|
person_factual_relation_editor_free(editor);g_ptr_array_unref(runs);
|
||||||
|
g_ptr_array_unref(ids);g_object_unref(labels);
|
||||||
|
}
|
||||||
|
int main(int argc,char **argv)
|
||||||
|
{
|
||||||
|
if(!gtk_init_check()){g_print("SKIP: aucun affichage GTK disponible.\n");return 0;}
|
||||||
|
g_test_init(&argc,&argv,NULL);
|
||||||
|
g_test_add_func("/factual-relation-editor/explicit-filter-remove",test_editor);
|
||||||
|
return g_test_run();
|
||||||
|
}
|
||||||
10
wc_out.txt
Normal file
10
wc_out.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
9339 src/core/application.c
|
||||||
|
142 src/core/person_creation_task.c
|
||||||
|
2037 src/views/create_person_dialog.c
|
||||||
|
660 src/views/evidence_metadata_dialog.c
|
||||||
|
2245 src/views/main_window.c
|
||||||
|
286 src/views/person_factual_relation_editor.c
|
||||||
|
193 src/views/person_vocabulary_adapter.c
|
||||||
|
1550 src/widgets/entity_details_panel.c
|
||||||
|
4078 src/widgets/workspace.c
|
||||||
|
20530 total
|
||||||
Loading…
Reference in a new issue