fix(graph): restore viewport when reopening
This commit is contained in:
parent
f54af89e3e
commit
6b43379e75
14 changed files with 330 additions and 6 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Labfy Investigation
|
* Labfy Investigation
|
||||||
*
|
*
|
||||||
* Extensions idempotentes du schéma SQLite courant V6
|
* Extensions idempotentes du schéma SQLite courant V8
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -93,6 +93,15 @@ CREATE TABLE IF NOT EXISTS graph_layout_positions
|
||||||
CHECK (length(updated_at) = 20)
|
CHECK (length(updated_at) = 20)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS graph_viewport
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
|
zoom REAL NOT NULL CHECK (zoom = zoom AND zoom > 0),
|
||||||
|
offset_x REAL NOT NULL CHECK (offset_x = offset_x),
|
||||||
|
offset_y REAL NOT NULL CHECK (offset_y = offset_y),
|
||||||
|
updated_at TEXT NOT NULL CHECK (length(updated_at) = 20)
|
||||||
|
);
|
||||||
|
|
||||||
/* Migration idempotente des positions d'entités déjà enregistrées. */
|
/* Migration idempotente des positions d'entités déjà enregistrées. */
|
||||||
INSERT OR IGNORE INTO graph_layout_positions(node_id, x, y, updated_at)
|
INSERT OR IGNORE INTO graph_layout_positions(node_id, x, y, updated_at)
|
||||||
SELECT entity_id, x, y, updated_at
|
SELECT entity_id, x, y, updated_at
|
||||||
|
|
|
||||||
8
database/schema_v8.sql
Normal file
8
database/schema_v8.sql
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS graph_viewport
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY CHECK (id = 1),
|
||||||
|
zoom REAL NOT NULL CHECK (zoom = zoom AND zoom > 0),
|
||||||
|
offset_x REAL NOT NULL CHECK (offset_x = offset_x),
|
||||||
|
offset_y REAL NOT NULL CHECK (offset_y = offset_y),
|
||||||
|
updated_at TEXT NOT NULL CHECK (length(updated_at) = 20)
|
||||||
|
);
|
||||||
|
|
@ -2269,6 +2269,12 @@ Cette stratégie préserve les positions existantes tout en permettant aux
|
||||||
nœuds de relation de suivre exactement le même cycle de chargement,
|
nœuds de relation de suivre exactement le même cycle de chargement,
|
||||||
d'enregistrement et de réinitialisation que les nœuds d'entité.
|
d'enregistrement et de réinitialisation que les nœuds d'entité.
|
||||||
|
|
||||||
|
Le cadrage global est stocké séparément dans la ligne unique de
|
||||||
|
`graph_viewport`. Elle conserve le niveau de zoom et les décalages horizontal
|
||||||
|
et vertical du canevas. Ces valeurs sont enregistrées à la fermeture de
|
||||||
|
l'enquête et restaurées lors de son premier chargement, afin que la vue
|
||||||
|
réapparaisse exactement à l'endroit où l'utilisateur l'avait laissée.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# 12. Conclusion
|
# 12. Conclusion
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,23 @@ gboolean graph_node_position_dao_delete_all(
|
||||||
GError **error
|
GError **error
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gboolean graph_node_position_dao_load_viewport(
|
||||||
|
GraphNodePositionDao *position_dao,
|
||||||
|
double *zoom,
|
||||||
|
double *offset_x,
|
||||||
|
double *offset_y,
|
||||||
|
gboolean *found,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
gboolean graph_node_position_dao_upsert_viewport(
|
||||||
|
GraphNodePositionDao *position_dao,
|
||||||
|
double zoom,
|
||||||
|
double offset_x,
|
||||||
|
double offset_y,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,7 @@ bool schema_install_v5(Database *database);
|
||||||
bool schema_install_v6(Database *database);
|
bool schema_install_v6(Database *database);
|
||||||
|
|
||||||
bool schema_install_v7(Database *database);
|
bool schema_install_v7(Database *database);
|
||||||
|
bool schema_install_v8(Database *database);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Garantit la présence des extensions du schéma courant V2.
|
* @brief Garantit la présence des extensions du schéma courant V2.
|
||||||
|
|
|
||||||
|
|
@ -526,6 +526,11 @@ void main_window_set_graph(
|
||||||
const InvestigationGraphLayout *graph_layout
|
const InvestigationGraphLayout *graph_layout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gboolean main_window_get_graph_view_transform(
|
||||||
|
MainWindow *main_window, double *zoom, double *offset_x, double *offset_y);
|
||||||
|
void main_window_set_graph_view_transform(
|
||||||
|
MainWindow *main_window, double zoom, double offset_x, double offset_y);
|
||||||
|
|
||||||
/** @brief Sélectionne une relation dans le graphe affiché. */
|
/** @brief Sélectionne une relation dans le graphe affiché. */
|
||||||
gboolean main_window_select_graph_relation(
|
gboolean main_window_select_graph_relation(
|
||||||
MainWindow *main_window,
|
MainWindow *main_window,
|
||||||
|
|
|
||||||
|
|
@ -447,6 +447,11 @@ void workspace_set_graph(
|
||||||
const InvestigationGraphLayout *graph_layout
|
const InvestigationGraphLayout *graph_layout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gboolean workspace_get_graph_view_transform(
|
||||||
|
Workspace *workspace, double *zoom, double *offset_x, double *offset_y);
|
||||||
|
void workspace_set_graph_view_transform(
|
||||||
|
Workspace *workspace, double zoom, double offset_x, double offset_y);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Affiche une erreur de chargement du graphe.
|
* @brief Affiche une erreur de chargement du graphe.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ struct Application
|
||||||
InvestigationGraphModel *graph_model;
|
InvestigationGraphModel *graph_model;
|
||||||
InvestigationGraphLayout *graph_layout;
|
InvestigationGraphLayout *graph_layout;
|
||||||
guint64 graph_load_generation;
|
guint64 graph_load_generation;
|
||||||
|
gboolean graph_viewport_restored;
|
||||||
|
|
||||||
char *selected_evidence_identifier;
|
char *selected_evidence_identifier;
|
||||||
char *pending_relation_selection_identifier;
|
char *pending_relation_selection_identifier;
|
||||||
|
|
@ -252,6 +253,59 @@ static void application_start_graph_loading(
|
||||||
const char *database_path
|
const char *database_path
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static void application_save_graph_viewport(Application *application)
|
||||||
|
{
|
||||||
|
GraphNodePositionDao *dao = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
double zoom = 0.0;
|
||||||
|
double offset_x = 0.0;
|
||||||
|
double offset_y = 0.0;
|
||||||
|
|
||||||
|
if (application == NULL || application->session == NULL ||
|
||||||
|
application->main_window == NULL ||
|
||||||
|
!main_window_get_graph_view_transform(application->main_window,
|
||||||
|
&zoom, &offset_x, &offset_y))
|
||||||
|
return;
|
||||||
|
|
||||||
|
dao = graph_node_position_dao_new(
|
||||||
|
investigation_session_get_database(application->session), &error);
|
||||||
|
if (dao == NULL || !graph_node_position_dao_upsert_viewport(
|
||||||
|
dao, zoom, offset_x, offset_y, &error))
|
||||||
|
g_warning("Impossible d'enregistrer le cadrage du graphe : %s",
|
||||||
|
error != NULL ? error->message : "erreur inconnue");
|
||||||
|
|
||||||
|
graph_node_position_dao_free(dao);
|
||||||
|
g_clear_error(&error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void application_restore_graph_viewport(Application *application)
|
||||||
|
{
|
||||||
|
GraphNodePositionDao *dao = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean found = FALSE;
|
||||||
|
double zoom = 0.0;
|
||||||
|
double offset_x = 0.0;
|
||||||
|
double offset_y = 0.0;
|
||||||
|
|
||||||
|
if (application == NULL || application->graph_viewport_restored ||
|
||||||
|
application->session == NULL || application->main_window == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
dao = graph_node_position_dao_new(
|
||||||
|
investigation_session_get_database(application->session), &error);
|
||||||
|
if (dao != NULL && graph_node_position_dao_load_viewport(
|
||||||
|
dao, &zoom, &offset_x, &offset_y, &found, &error) && found)
|
||||||
|
main_window_set_graph_view_transform(
|
||||||
|
application->main_window, zoom, offset_x, offset_y);
|
||||||
|
else if (error != NULL)
|
||||||
|
g_warning("Impossible de restaurer le cadrage du graphe : %s",
|
||||||
|
error->message);
|
||||||
|
|
||||||
|
application->graph_viewport_restored = TRUE;
|
||||||
|
graph_node_position_dao_free(dao);
|
||||||
|
g_clear_error(&error);
|
||||||
|
}
|
||||||
|
|
||||||
static void application_present_error(
|
static void application_present_error(
|
||||||
Application *application,
|
Application *application,
|
||||||
const char *title,
|
const char *title,
|
||||||
|
|
@ -1068,6 +1122,8 @@ static void application_on_graph_loaded(
|
||||||
application->graph_layout
|
application->graph_layout
|
||||||
);
|
);
|
||||||
|
|
||||||
|
application_restore_graph_viewport(application);
|
||||||
|
|
||||||
if (application->pending_relation_selection_identifier != NULL)
|
if (application->pending_relation_selection_identifier != NULL)
|
||||||
{
|
{
|
||||||
main_window_select_graph_relation(application->main_window,
|
main_window_select_graph_relation(application->main_window,
|
||||||
|
|
@ -2609,12 +2665,14 @@ static gboolean application_install_session(
|
||||||
application->tree_model
|
application->tree_model
|
||||||
);
|
);
|
||||||
|
|
||||||
|
application_save_graph_viewport(application);
|
||||||
investigation_session_close(
|
investigation_session_close(
|
||||||
application->session
|
application->session
|
||||||
);
|
);
|
||||||
|
|
||||||
application->tree_model = new_tree_model;
|
application->tree_model = new_tree_model;
|
||||||
application->session = new_session;
|
application->session = new_session;
|
||||||
|
application->graph_viewport_restored = FALSE;
|
||||||
|
|
||||||
main_window_set_tree_model(
|
main_window_set_tree_model(
|
||||||
application->main_window,
|
application->main_window,
|
||||||
|
|
@ -8068,6 +8126,8 @@ void application_free(
|
||||||
application
|
application
|
||||||
);
|
);
|
||||||
|
|
||||||
|
application_save_graph_viewport(application);
|
||||||
|
|
||||||
application_clear_graph(
|
application_clear_graph(
|
||||||
application
|
application
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,16 @@ static const char *const graph_node_position_dao_delete_sql =
|
||||||
static const char *const graph_node_position_dao_delete_all_sql =
|
static const char *const graph_node_position_dao_delete_all_sql =
|
||||||
"DELETE FROM graph_layout_positions;";
|
"DELETE FROM graph_layout_positions;";
|
||||||
|
|
||||||
|
static const char *const graph_node_position_dao_load_viewport_sql =
|
||||||
|
"SELECT zoom, offset_x, offset_y FROM graph_viewport WHERE id = 1;";
|
||||||
|
|
||||||
|
static const char *const graph_node_position_dao_upsert_viewport_sql =
|
||||||
|
"INSERT INTO graph_viewport(id, zoom, offset_x, offset_y, updated_at) "
|
||||||
|
"VALUES(1, ?, ?, ?, ?) "
|
||||||
|
"ON CONFLICT(id) DO UPDATE SET zoom = excluded.zoom, "
|
||||||
|
"offset_x = excluded.offset_x, offset_y = excluded.offset_y, "
|
||||||
|
"updated_at = excluded.updated_at;";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enregistre une erreur littérale.
|
* @brief Enregistre une erreur littérale.
|
||||||
*/
|
*/
|
||||||
|
|
@ -869,3 +879,125 @@ cleanup:
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean graph_node_position_dao_load_viewport(
|
||||||
|
GraphNodePositionDao *position_dao,
|
||||||
|
double *zoom,
|
||||||
|
double *offset_x,
|
||||||
|
double *offset_y,
|
||||||
|
gboolean *found,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DatabaseStatement *statement = NULL;
|
||||||
|
DatabaseStatementStepResult step_result;
|
||||||
|
gboolean success = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
|
||||||
|
if (position_dao == NULL || position_dao->database == NULL ||
|
||||||
|
zoom == NULL || offset_x == NULL || offset_y == NULL || found == NULL)
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_error_literal(error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Les paramètres de chargement du cadrage sont invalides.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*found = FALSE;
|
||||||
|
statement = database_statement_prepare(position_dao->database,
|
||||||
|
graph_node_position_dao_load_viewport_sql);
|
||||||
|
if (statement == NULL)
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_database_error(position_dao, error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_PREPARE,
|
||||||
|
"Impossible de préparer le chargement du cadrage");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
step_result = database_statement_step(statement);
|
||||||
|
if (step_result == DATABASE_STATEMENT_STEP_ROW)
|
||||||
|
{
|
||||||
|
if (!database_statement_column_double(statement, 0, zoom) ||
|
||||||
|
!database_statement_column_double(statement, 1, offset_x) ||
|
||||||
|
!database_statement_column_double(statement, 2, offset_y) ||
|
||||||
|
!isfinite(*zoom) || *zoom <= 0.0 ||
|
||||||
|
!isfinite(*offset_x) || !isfinite(*offset_y))
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_error_literal(error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_READ,
|
||||||
|
"Le cadrage enregistré est invalide.");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
*found = TRUE;
|
||||||
|
}
|
||||||
|
else if (step_result == DATABASE_STATEMENT_STEP_ERROR)
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_database_error(position_dao, error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_EXECUTE,
|
||||||
|
"Impossible de charger le cadrage");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
database_statement_finalize(statement);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean graph_node_position_dao_upsert_viewport(
|
||||||
|
GraphNodePositionDao *position_dao,
|
||||||
|
double zoom,
|
||||||
|
double offset_x,
|
||||||
|
double offset_y,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DatabaseStatement *statement = NULL;
|
||||||
|
char *updated_at = NULL;
|
||||||
|
gboolean success = FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
|
||||||
|
if (position_dao == NULL || position_dao->database == NULL ||
|
||||||
|
!isfinite(zoom) || zoom <= 0.0 ||
|
||||||
|
!isfinite(offset_x) || !isfinite(offset_y))
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_error_literal(error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le cadrage du graphe est invalide.");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated_at = graph_node_position_dao_create_utc_timestamp();
|
||||||
|
statement = database_statement_prepare(position_dao->database,
|
||||||
|
graph_node_position_dao_upsert_viewport_sql);
|
||||||
|
if (updated_at == NULL || statement == NULL)
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_database_error(position_dao, error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_PREPARE,
|
||||||
|
"Impossible de préparer l'enregistrement du cadrage");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!database_statement_bind_double(statement, 1, zoom) ||
|
||||||
|
!database_statement_bind_double(statement, 2, offset_x) ||
|
||||||
|
!database_statement_bind_double(statement, 3, offset_y) ||
|
||||||
|
!database_statement_bind_text(statement, 4, updated_at))
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_database_error(position_dao, error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_BIND,
|
||||||
|
"Impossible de lier les données du cadrage");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (database_statement_step(statement) != DATABASE_STATEMENT_STEP_DONE)
|
||||||
|
{
|
||||||
|
graph_node_position_dao_set_database_error(position_dao, error,
|
||||||
|
GRAPH_NODE_POSITION_DAO_ERROR_EXECUTE,
|
||||||
|
"Impossible d'enregistrer le cadrage");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
success = TRUE;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
database_statement_finalize(statement);
|
||||||
|
g_free(updated_at);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@
|
||||||
/**
|
/**
|
||||||
* @brief Version actuelle du schéma SQLite.
|
* @brief Version actuelle du schéma SQLite.
|
||||||
*/
|
*/
|
||||||
#define DATABASE_SCHEMA_VERSION_CURRENT 7
|
#define DATABASE_SCHEMA_VERSION_CURRENT 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Version actuelle sous forme textuelle pour metadata.
|
* @brief Version actuelle sous forme textuelle pour metadata.
|
||||||
*/
|
*/
|
||||||
#define DATABASE_SCHEMA_VERSION_CURRENT_TEXT "7"
|
#define DATABASE_SCHEMA_VERSION_CURRENT_TEXT "8"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Nom de l'application enregistré dans les métadonnées.
|
* @brief Nom de l'application enregistré dans les métadonnées.
|
||||||
|
|
@ -748,6 +748,40 @@ rollback:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool database_migrate_v6_to_v7(Database *database)
|
||||||
|
{
|
||||||
|
bool transaction_started = false;
|
||||||
|
if (database == NULL || !database_transaction_begin(database))
|
||||||
|
return false;
|
||||||
|
transaction_started = true;
|
||||||
|
if (!schema_install_v7(database) ||
|
||||||
|
!database_update_schema_version(database, "7") ||
|
||||||
|
!database_transaction_commit(database))
|
||||||
|
goto rollback;
|
||||||
|
return true;
|
||||||
|
rollback:
|
||||||
|
if (transaction_started && !database_transaction_rollback(database))
|
||||||
|
g_warning("Impossible d’annuler la migration SQLite V6 vers V7.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool database_migrate_v7_to_v8(Database *database)
|
||||||
|
{
|
||||||
|
bool transaction_started = false;
|
||||||
|
if (database == NULL || !database_transaction_begin(database))
|
||||||
|
return false;
|
||||||
|
transaction_started = true;
|
||||||
|
if (!schema_install_v8(database) ||
|
||||||
|
!database_update_schema_version(database, "8") ||
|
||||||
|
!database_transaction_commit(database))
|
||||||
|
goto rollback;
|
||||||
|
return true;
|
||||||
|
rollback:
|
||||||
|
if (transaction_started && !database_transaction_rollback(database))
|
||||||
|
g_warning("Impossible d’annuler la migration SQLite V7 vers V8.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Garantit atomiquement la présence des extensions du schéma courant.
|
* @brief Garantit atomiquement la présence des extensions du schéma courant.
|
||||||
*/
|
*/
|
||||||
|
|
@ -959,11 +993,17 @@ bool database_migrate_to_latest(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
if (!schema_install_v7(database))
|
if (!database_migrate_v6_to_v7(database))
|
||||||
return false;
|
return false;
|
||||||
schema_version = 7;
|
schema_version = 7;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
if (!database_migrate_v7_to_v8(database))
|
||||||
|
return false;
|
||||||
|
schema_version = 8;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
database_set_error(
|
database_set_error(
|
||||||
database,
|
database,
|
||||||
|
|
|
||||||
|
|
@ -233,6 +233,12 @@ bool schema_install_v7(Database *database)
|
||||||
"la migration SQLite V7");
|
"la migration SQLite V7");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool schema_install_v8(Database *database)
|
||||||
|
{
|
||||||
|
return schema_execute_file(database, "database/schema_v8.sql",
|
||||||
|
"la migration SQLite V8");
|
||||||
|
}
|
||||||
|
|
||||||
bool schema_ensure_current(
|
bool schema_ensure_current(
|
||||||
Database *database
|
Database *database
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1421,6 +1421,22 @@ void main_window_set_graph(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean main_window_get_graph_view_transform(
|
||||||
|
MainWindow *main_window, double *zoom, double *offset_x, double *offset_y)
|
||||||
|
{
|
||||||
|
return main_window != NULL &&
|
||||||
|
workspace_get_graph_view_transform(
|
||||||
|
main_window->workspace, zoom, offset_x, offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main_window_set_graph_view_transform(
|
||||||
|
MainWindow *main_window, double zoom, double offset_x, double offset_y)
|
||||||
|
{
|
||||||
|
if (main_window != NULL)
|
||||||
|
workspace_set_graph_view_transform(
|
||||||
|
main_window->workspace, zoom, offset_x, offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
gboolean main_window_select_graph_relation(MainWindow *main_window,
|
gboolean main_window_select_graph_relation(MainWindow *main_window,
|
||||||
const char *relation_identifier)
|
const char *relation_identifier)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3229,6 +3229,24 @@ void workspace_set_graph(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean workspace_get_graph_view_transform(
|
||||||
|
Workspace *workspace, double *zoom, double *offset_x, double *offset_y)
|
||||||
|
{
|
||||||
|
if (workspace == NULL || workspace->graph_state != WORKSPACE_GRAPH_STATE_READY)
|
||||||
|
return FALSE;
|
||||||
|
return investigation_graph_view_get_view_transform(
|
||||||
|
workspace->graph_view, zoom, offset_x, offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void workspace_set_graph_view_transform(
|
||||||
|
Workspace *workspace, double zoom, double offset_x, double offset_y)
|
||||||
|
{
|
||||||
|
if (workspace == NULL || workspace->graph_state != WORKSPACE_GRAPH_STATE_READY)
|
||||||
|
return;
|
||||||
|
investigation_graph_view_set_view_transform(
|
||||||
|
workspace->graph_view, zoom, offset_x, offset_y);
|
||||||
|
}
|
||||||
|
|
||||||
void workspace_set_graph_error(
|
void workspace_set_graph_error(
|
||||||
Workspace *workspace,
|
Workspace *workspace,
|
||||||
const char *message
|
const char *message
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,8 @@ static void test_database_initialize_valid_database(void)
|
||||||
"FROM investigation;"
|
"FROM investigation;"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert(strcmp(schema_version, "7") == 0);
|
assert(strcmp(schema_version, "8") == 0);
|
||||||
|
test_database_assert_table_exists(database, "graph_viewport");
|
||||||
test_database_assert_table_exists(database, "osint_executions");
|
test_database_assert_table_exists(database, "osint_executions");
|
||||||
test_database_assert_table_exists(database, "osint_execution_entities");
|
test_database_assert_table_exists(database, "osint_execution_entities");
|
||||||
test_database_assert_table_exists(database, "osint_execution_relations");
|
test_database_assert_table_exists(database, "osint_execution_relations");
|
||||||
|
|
@ -989,7 +990,7 @@ static void test_database_migrate_v1_to_v2(void)
|
||||||
assert(
|
assert(
|
||||||
strcmp(
|
strcmp(
|
||||||
schema_version,
|
schema_version,
|
||||||
"6"
|
"8"
|
||||||
) == 0
|
) == 0
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue