Line data Source code
1 : /* File: ctrl_classifier_controller.c; Copyright and License: see below */
2 :
3 : #include "ctrl_classifier_controller.h"
4 : #include "u8/u8_trace.h"
5 : #include "u8/u8_log.h"
6 :
7 47 : void ctrl_classifier_controller_init ( ctrl_classifier_controller_t *this_,
8 : ctrl_undo_redo_list_t *undo_redo_list,
9 : ctrl_classifier_trigger_t *policy_enforcer,
10 : data_database_t *database,
11 : data_database_reader_t *db_reader,
12 : data_database_writer_t *db_writer )
13 : {
14 47 : U8_TRACE_BEGIN();
15 :
16 47 : (*this_).undo_redo_list = undo_redo_list;
17 47 : (*this_).policy_enforcer = policy_enforcer;
18 47 : (*this_).database = database;
19 47 : (*this_).db_reader = db_reader;
20 47 : (*this_).db_writer = db_writer;
21 47 : consistency_checker_init ( &((*this_).consistency_checker), database, db_reader, db_writer );
22 :
23 47 : U8_TRACE_END();
24 47 : }
25 :
26 47 : void ctrl_classifier_controller_destroy ( ctrl_classifier_controller_t *this_ )
27 : {
28 47 : U8_TRACE_BEGIN();
29 :
30 47 : consistency_checker_destroy ( &((*this_).consistency_checker) );
31 47 : (*this_).undo_redo_list = NULL;
32 47 : (*this_).policy_enforcer = NULL;
33 47 : (*this_).database = NULL;
34 47 : (*this_).db_reader = NULL;
35 47 : (*this_).db_writer = NULL;
36 :
37 47 : U8_TRACE_END();
38 47 : }
39 :
40 : /* ================================ CLASSIFIER ================================ */
41 :
42 47 : u8_error_t ctrl_classifier_controller_create_classifier ( ctrl_classifier_controller_t *this_,
43 : const data_classifier_t *new_classifier,
44 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set,
45 : data_row_t* out_new_id )
46 : {
47 47 : U8_TRACE_BEGIN();
48 47 : assert( NULL != new_classifier );
49 : data_classifier_t to_be_created;
50 47 : u8_error_t result = U8_ERROR_NONE;
51 : data_row_t new_id;
52 :
53 47 : data_classifier_copy( &to_be_created, new_classifier );
54 :
55 47 : result = data_database_writer_create_classifier( (*this_).db_writer, &to_be_created, &new_id );
56 47 : if ( U8_ERROR_NONE == result )
57 : {
58 : /* store new id to data_classifier_t object */
59 40 : data_classifier_set_row( &to_be_created, new_id );
60 :
61 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
62 40 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
63 : {
64 : u8_error_t internal_err;
65 11 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
66 11 : if ( U8_ERROR_NONE != internal_err )
67 : {
68 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
69 : }
70 : }
71 :
72 : /* store the new diagram to the undo redo list */
73 40 : ctrl_undo_redo_list_add_create_classifier( (*this_).undo_redo_list, &to_be_created );
74 40 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
75 :
76 : /* copy new id to out parameter */
77 40 : if ( NULL != out_new_id )
78 : {
79 40 : *out_new_id = new_id;
80 : }
81 : }
82 :
83 47 : data_classifier_destroy( &to_be_created );
84 :
85 47 : U8_TRACE_END_ERR( result );
86 47 : return result;
87 : }
88 :
89 11 : u8_error_t ctrl_classifier_controller_delete_classifier( ctrl_classifier_controller_t *this_,
90 : data_row_t obj_id,
91 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set,
92 : consistency_stat_t *io_stat )
93 : {
94 11 : U8_TRACE_BEGIN();
95 11 : assert( io_stat != NULL );
96 11 : u8_error_t result = U8_ERROR_NONE;
97 : u8_error_t data_result;
98 :
99 : /* check if the classifier is still referenced by diagramelements */
100 11 : bool is_still_referenced = true;
101 : {
102 : data_diagram_iterator_t diagram_iterator;
103 11 : data_diagram_iterator_init_empty( &diagram_iterator );
104 11 : result |= data_database_reader_get_diagrams_by_classifier_id( (*this_).db_reader,
105 : obj_id,
106 : &diagram_iterator
107 : );
108 :
109 11 : if (( data_diagram_iterator_has_next( &diagram_iterator ) )||( result != U8_ERROR_NONE ))
110 : {
111 7 : is_still_referenced = true;
112 : }
113 : else
114 : {
115 4 : is_still_referenced = false;
116 : }
117 11 : result |= data_diagram_iterator_destroy( &diagram_iterator );
118 : }
119 :
120 : /* if the classifier is still referenced by diagramelements, do not do anything, report an error */
121 11 : if ( is_still_referenced )
122 : {
123 7 : result |= U8_ERROR_OBJECT_STILL_REFERENCED;
124 : }
125 : else
126 : {
127 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
128 4 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
129 : {
130 : u8_error_t internal_err;
131 4 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
132 4 : if ( U8_ERROR_NONE != internal_err )
133 : {
134 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
135 : }
136 : }
137 :
138 : /* delete all features */
139 : {
140 : data_feature_iterator_t feature_iterator;
141 4 : data_feature_iterator_init_empty( &feature_iterator );
142 4 : result |= data_database_reader_get_features_by_classifier_id( (*this_).db_reader,
143 : obj_id,
144 : &feature_iterator
145 : );
146 4 : while ( data_feature_iterator_has_next( &feature_iterator ) )
147 : {
148 0 : result |= data_feature_iterator_next( &feature_iterator, &((*this_).temp_feature) );
149 0 : const data_row_t feat_id = data_feature_get_row( &((*this_).temp_feature) );
150 0 : const bool is_lifeline
151 0 : = ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( &((*this_).temp_feature) ) );
152 0 : data_result = data_database_writer_delete_feature( (*this_).db_writer, feat_id, NULL );
153 0 : if ( data_result == U8_ERROR_NONE )
154 : {
155 0 : if ( is_lifeline )
156 : {
157 0 : consistency_stat_decrement_lifelines( io_stat );
158 : }
159 : else
160 : {
161 0 : consistency_stat_decrement_features( io_stat );
162 : }
163 :
164 : /* store the deleted feature to the undo redo list */
165 0 : ctrl_undo_redo_list_add_delete_feature( (*this_).undo_redo_list, &((*this_).temp_feature) );
166 : }
167 : else
168 : {
169 : /* report this unexpected error */
170 0 : result |= data_result;
171 : }
172 0 : data_feature_destroy( &((*this_).temp_feature) );
173 : }
174 4 : result |= data_feature_iterator_destroy( &feature_iterator );
175 : }
176 :
177 : /* delete all relationships */
178 : {
179 : data_relationship_iterator_t relationship_iterator;
180 4 : data_relationship_iterator_init_empty( &relationship_iterator );
181 4 : result |= data_database_reader_get_relationships_by_classifier_id( (*this_).db_reader,
182 : obj_id,
183 : &relationship_iterator
184 : );
185 4 : while ( data_relationship_iterator_has_next( &relationship_iterator ) )
186 : {
187 0 : result |= data_relationship_iterator_next( &relationship_iterator, &((*this_).temp_relationship) );
188 0 : const data_row_t rel_id = data_relationship_get_row( &((*this_).temp_relationship) );
189 0 : data_result = data_database_writer_delete_relationship( (*this_).db_writer, rel_id, NULL );
190 0 : if ( data_result == U8_ERROR_NONE )
191 : {
192 0 : consistency_stat_decrement_relationships( io_stat );
193 :
194 : /* store the deleted relationship to the undo redo list */
195 0 : ctrl_undo_redo_list_add_delete_relationship( (*this_).undo_redo_list, &((*this_).temp_relationship) );
196 : }
197 : else
198 : {
199 : /* report this unexpected error */
200 0 : result |= data_result;
201 : }
202 0 : data_relationship_destroy( &((*this_).temp_relationship) );
203 : }
204 4 : result |= data_relationship_iterator_destroy( &relationship_iterator );
205 : }
206 :
207 : /* delete the classifier */
208 : {
209 : data_classifier_t old_classifier;
210 4 : data_result = data_database_writer_delete_classifier( (*this_).db_writer,
211 : obj_id,
212 : &old_classifier
213 : );
214 :
215 4 : if ( U8_ERROR_NONE == data_result )
216 : {
217 3 : consistency_stat_decrement_classifiers( io_stat );
218 :
219 : /* store the deleted classifier to the undo redo list */
220 3 : ctrl_undo_redo_list_add_delete_classifier( (*this_).undo_redo_list, &old_classifier );
221 :
222 3 : data_classifier_destroy( &old_classifier );
223 : }
224 1 : else if ( u8_error_contains( data_result, U8_ERROR_OBJECT_STILL_REFERENCED ) )
225 : {
226 : /* report this unexpected error */
227 0 : U8_LOG_ERROR( "The classifier cannot be deleted because it is still referenced." );
228 0 : result |= data_result;
229 : }
230 : else
231 : {
232 : /* report this unexpected error */
233 1 : result |= data_result;
234 : }
235 : }
236 :
237 : /* add a boundary to the undo redo list */
238 4 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
239 : }
240 :
241 11 : U8_TRACE_END_ERR( result );
242 11 : return result;
243 : }
244 :
245 1 : u8_error_t ctrl_classifier_controller_update_classifier_main_type ( ctrl_classifier_controller_t *this_,
246 : data_row_t classifier_id,
247 : data_classifier_type_t new_classifier_main_type )
248 : {
249 1 : U8_TRACE_BEGIN();
250 1 : u8_error_t result = U8_ERROR_NONE;
251 : data_classifier_t old_classifier;
252 :
253 1 : result = data_database_writer_update_classifier_main_type( (*this_).db_writer, classifier_id, new_classifier_main_type, &old_classifier );
254 1 : if ( U8_ERROR_NONE == result )
255 : {
256 : /* prepare the new classifier */
257 : data_classifier_t new_classifier;
258 1 : data_classifier_copy( &new_classifier, &old_classifier );
259 1 : data_classifier_set_main_type( &new_classifier, new_classifier_main_type );
260 : /* store the change of the classifier to the undo redo list */
261 1 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
262 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
263 :
264 1 : data_classifier_destroy( &new_classifier );
265 1 : data_classifier_destroy( &old_classifier );
266 : }
267 :
268 1 : U8_TRACE_END_ERR( result );
269 1 : return result;
270 : }
271 :
272 2 : u8_error_t ctrl_classifier_controller_update_classifier_stereotype ( ctrl_classifier_controller_t *this_,
273 : data_row_t classifier_id,
274 : const char* new_classifier_stereotype )
275 : {
276 2 : U8_TRACE_BEGIN();
277 2 : u8_error_t result = U8_ERROR_NONE;
278 : data_classifier_t old_classifier;
279 :
280 2 : result = data_database_writer_update_classifier_stereotype( (*this_).db_writer, classifier_id, new_classifier_stereotype, &old_classifier );
281 2 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
282 : {
283 : /* prepare the new classifier */
284 : data_classifier_t new_classifier;
285 2 : data_classifier_copy( &new_classifier, &old_classifier );
286 2 : data_classifier_set_stereotype( &new_classifier, new_classifier_stereotype );
287 : /* store the change of the classifier to the undo redo list */
288 2 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
289 2 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
290 :
291 2 : data_classifier_destroy( &new_classifier );
292 2 : data_classifier_destroy( &old_classifier );
293 : }
294 :
295 2 : U8_TRACE_END_ERR( result );
296 2 : return result;
297 : }
298 :
299 1 : u8_error_t ctrl_classifier_controller_update_classifier_name ( ctrl_classifier_controller_t *this_,
300 : data_row_t classifier_id,
301 : const char* new_classifier_name )
302 : {
303 1 : U8_TRACE_BEGIN();
304 1 : u8_error_t result = U8_ERROR_NONE;
305 : data_classifier_t old_classifier;
306 :
307 1 : result = data_database_writer_update_classifier_name( (*this_).db_writer, classifier_id, new_classifier_name, &old_classifier );
308 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
309 : {
310 : /* prepare the new classifier */
311 : data_classifier_t new_classifier;
312 1 : data_classifier_copy( &new_classifier, &old_classifier );
313 1 : data_classifier_set_name( &new_classifier, new_classifier_name );
314 : /* store the change of the classifier to the undo redo list */
315 1 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
316 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
317 :
318 1 : data_classifier_destroy( &new_classifier );
319 1 : data_classifier_destroy( &old_classifier );
320 : }
321 :
322 1 : U8_TRACE_END_ERR( result );
323 1 : return result;
324 : }
325 :
326 1 : u8_error_t ctrl_classifier_controller_update_classifier_description ( ctrl_classifier_controller_t *this_,
327 : data_row_t classifier_id,
328 : const char* new_classifier_description )
329 : {
330 1 : U8_TRACE_BEGIN();
331 1 : u8_error_t result = U8_ERROR_NONE;
332 : data_classifier_t old_classifier;
333 :
334 1 : result = data_database_writer_update_classifier_description( (*this_).db_writer, classifier_id, new_classifier_description, &old_classifier );
335 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
336 : {
337 : /* prepare the new classifier */
338 : data_classifier_t new_classifier;
339 1 : data_classifier_copy( &new_classifier, &old_classifier );
340 1 : data_classifier_set_description( &new_classifier, new_classifier_description );
341 : /* store the change of the classifier to the undo redo list */
342 1 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
343 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
344 :
345 1 : data_classifier_destroy( &new_classifier );
346 1 : data_classifier_destroy( &old_classifier );
347 : }
348 :
349 1 : U8_TRACE_END_ERR( result );
350 1 : return result;
351 : }
352 :
353 1 : u8_error_t ctrl_classifier_controller_update_classifier_x_order ( ctrl_classifier_controller_t *this_,
354 : data_row_t classifier_id,
355 : int32_t new_classifier_x_order )
356 : {
357 1 : U8_TRACE_BEGIN();
358 1 : u8_error_t result = U8_ERROR_NONE;
359 : data_classifier_t old_classifier;
360 :
361 1 : result = data_database_writer_update_classifier_x_order( (*this_).db_writer, classifier_id, new_classifier_x_order, &old_classifier );
362 1 : if ( U8_ERROR_NONE == result )
363 : {
364 : /* prepare the new classifier */
365 : data_classifier_t new_classifier;
366 1 : data_classifier_copy( &new_classifier, &old_classifier );
367 1 : data_classifier_set_x_order( &new_classifier, new_classifier_x_order );
368 : /* store the change of the classifier to the undo redo list */
369 1 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
370 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
371 :
372 1 : data_classifier_destroy( &new_classifier );
373 1 : data_classifier_destroy( &old_classifier );
374 : }
375 :
376 1 : U8_TRACE_END_ERR( result );
377 1 : return result;
378 : }
379 :
380 1 : u8_error_t ctrl_classifier_controller_update_classifier_y_order ( ctrl_classifier_controller_t *this_,
381 : data_row_t classifier_id,
382 : int32_t new_classifier_y_order )
383 : {
384 1 : U8_TRACE_BEGIN();
385 1 : u8_error_t result = U8_ERROR_NONE;
386 : data_classifier_t old_classifier;
387 :
388 1 : result = data_database_writer_update_classifier_y_order( (*this_).db_writer, classifier_id, new_classifier_y_order, &old_classifier );
389 1 : if ( U8_ERROR_NONE == result )
390 : {
391 : /* prepare the new classifier */
392 : data_classifier_t new_classifier;
393 1 : data_classifier_copy( &new_classifier, &old_classifier );
394 1 : data_classifier_set_y_order( &new_classifier, new_classifier_y_order );
395 : /* store the change of the classifier to the undo redo list */
396 1 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
397 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
398 :
399 1 : data_classifier_destroy( &new_classifier );
400 1 : data_classifier_destroy( &old_classifier );
401 : }
402 :
403 1 : U8_TRACE_END_ERR( result );
404 1 : return result;
405 : }
406 :
407 0 : u8_error_t ctrl_classifier_controller_update_classifier_x_order_y_order ( ctrl_classifier_controller_t *this_,
408 : data_row_t classifier_id,
409 : int32_t new_classifier_x_order,
410 : int32_t new_classifier_y_order )
411 : {
412 0 : U8_TRACE_BEGIN();
413 0 : u8_error_t result = U8_ERROR_NONE;
414 : data_classifier_t old_classifier;
415 :
416 0 : result = data_database_writer_update_classifier_x_order( (*this_).db_writer, classifier_id, new_classifier_x_order, &old_classifier );
417 0 : if ( U8_ERROR_NONE == result )
418 : {
419 0 : result = data_database_writer_update_classifier_y_order( (*this_).db_writer, classifier_id, new_classifier_y_order, NULL );
420 0 : if ( U8_ERROR_NONE == result )
421 : {
422 : /* prepare the new classifier */
423 : data_classifier_t new_classifier;
424 0 : data_classifier_copy( &new_classifier, &old_classifier );
425 0 : data_classifier_set_x_order( &new_classifier, new_classifier_x_order );
426 0 : data_classifier_set_y_order( &new_classifier, new_classifier_y_order );
427 : /* store the change of the classifier to the undo redo list */
428 0 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
429 0 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
430 :
431 0 : data_classifier_destroy( &new_classifier );
432 : }
433 0 : data_classifier_destroy( &old_classifier );
434 : }
435 :
436 0 : U8_TRACE_END_ERR( result );
437 0 : return result;
438 : }
439 :
440 0 : u8_error_t ctrl_classifier_controller_update_classifier_list_order ( ctrl_classifier_controller_t *this_,
441 : data_row_t classifier_id,
442 : int32_t new_classifier_list_order )
443 : {
444 0 : U8_TRACE_BEGIN();
445 0 : u8_error_t result = U8_ERROR_NONE;
446 : data_classifier_t old_classifier;
447 :
448 0 : result = data_database_writer_update_classifier_list_order( (*this_).db_writer, classifier_id, new_classifier_list_order, &old_classifier );
449 0 : if ( U8_ERROR_NONE == result )
450 : {
451 : /* prepare the new classifier */
452 : data_classifier_t new_classifier;
453 0 : data_classifier_copy( &new_classifier, &old_classifier );
454 0 : data_classifier_set_list_order( &new_classifier, new_classifier_list_order );
455 : /* store the change of the classifier to the undo redo list */
456 0 : ctrl_undo_redo_list_add_update_classifier( (*this_).undo_redo_list, &old_classifier, &new_classifier );
457 0 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
458 :
459 0 : data_classifier_destroy( &new_classifier );
460 0 : data_classifier_destroy( &old_classifier );
461 : }
462 :
463 0 : U8_TRACE_END_ERR( result );
464 0 : return result;
465 : }
466 :
467 : /* ================================ FEATURE ================================ */
468 :
469 39 : u8_error_t ctrl_classifier_controller_create_feature ( ctrl_classifier_controller_t *this_,
470 : const data_feature_t *new_feature,
471 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set,
472 : data_row_t* out_new_id )
473 : {
474 39 : U8_TRACE_BEGIN();
475 39 : assert( NULL != new_feature );
476 : data_feature_t to_be_created;
477 39 : u8_error_t result = U8_ERROR_NONE;
478 : data_row_t new_id;
479 :
480 39 : data_feature_copy( &to_be_created, new_feature );
481 :
482 39 : result = data_database_writer_create_feature( (*this_).db_writer, &to_be_created, &new_id );
483 39 : if ( U8_ERROR_NONE == result )
484 : {
485 : /* store new id to data_feature_t object */
486 39 : data_feature_set_row( &to_be_created, new_id );
487 :
488 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
489 39 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
490 : {
491 : u8_error_t internal_err;
492 25 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
493 25 : if ( U8_ERROR_NONE != internal_err )
494 : {
495 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
496 : }
497 : }
498 :
499 : /* store the new feature to the undo redo list */
500 39 : ctrl_undo_redo_list_add_create_feature( (*this_).undo_redo_list, &to_be_created );
501 39 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
502 :
503 : /* copy new id to out parameter */
504 39 : if ( NULL != out_new_id )
505 : {
506 39 : *out_new_id = new_id;
507 : }
508 : }
509 :
510 : /* apply policy rules */
511 39 : if ( U8_ERROR_NONE == result )
512 : {
513 39 : result |= ctrl_classifier_trigger_post_create_feature ( (*this_).policy_enforcer, &to_be_created );
514 : }
515 :
516 39 : data_feature_destroy( &to_be_created );
517 :
518 39 : U8_TRACE_END_ERR( result );
519 39 : return result;
520 : }
521 :
522 16 : u8_error_t ctrl_classifier_controller_delete_feature ( ctrl_classifier_controller_t *this_,
523 : data_row_t obj_id,
524 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set,
525 : consistency_stat_t *io_stat )
526 : {
527 16 : U8_TRACE_BEGIN();
528 16 : assert( io_stat != NULL );
529 16 : u8_error_t result = U8_ERROR_NONE;
530 : u8_error_t data_result;
531 :
532 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
533 16 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
534 : {
535 : u8_error_t internal_err;
536 13 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
537 13 : if ( U8_ERROR_NONE != internal_err )
538 : {
539 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
540 : }
541 : }
542 :
543 : /* delete all relationships to and/or from this feature */
544 : {
545 : data_relationship_iterator_t relationship_iterator;
546 16 : data_relationship_iterator_init_empty( &relationship_iterator );
547 16 : result |= data_database_reader_get_relationships_by_feature_id( (*this_).db_reader,
548 : obj_id,
549 : &relationship_iterator
550 : );
551 18 : while ( data_relationship_iterator_has_next( &relationship_iterator ) )
552 : {
553 2 : result |= data_relationship_iterator_next( &relationship_iterator, &((*this_).temp_relationship) );
554 2 : const data_row_t rel_id = data_relationship_get_row( &((*this_).temp_relationship) );
555 2 : data_result = data_database_writer_delete_relationship( (*this_).db_writer, rel_id, NULL );
556 2 : if ( U8_ERROR_NONE == data_result )
557 : {
558 2 : consistency_stat_decrement_relationships( io_stat );
559 :
560 : /* store the deleted relationship to the undo redo list */
561 2 : ctrl_undo_redo_list_add_delete_relationship( (*this_).undo_redo_list, &((*this_).temp_relationship) );
562 : }
563 : else
564 : {
565 : /* report this unexpected error */
566 0 : result |= data_result;
567 : }
568 2 : data_relationship_destroy( &((*this_).temp_relationship) );
569 : }
570 16 : result |= data_relationship_iterator_destroy( &relationship_iterator );
571 : }
572 :
573 : /* delete the feature */
574 : data_feature_t old_feature;
575 : u8_error_t feature_result;
576 : {
577 : /* delete feature */
578 16 : feature_result = data_database_writer_delete_feature( (*this_).db_writer, obj_id, &old_feature );
579 :
580 16 : if ( U8_ERROR_NONE == feature_result )
581 : {
582 15 : const bool is_lifeline
583 15 : = ( DATA_FEATURE_TYPE_LIFELINE == data_feature_get_main_type( &old_feature ) );
584 15 : if ( is_lifeline )
585 : {
586 9 : consistency_stat_decrement_lifelines( io_stat );
587 : }
588 : else
589 : {
590 6 : consistency_stat_decrement_features( io_stat );
591 : }
592 :
593 : /* store the deleted feature to the undo redo list */
594 15 : ctrl_undo_redo_list_add_delete_feature( (*this_).undo_redo_list, &old_feature );
595 : }
596 :
597 16 : result |= feature_result;
598 : }
599 :
600 : /* add boundary to undo-redo-list */
601 16 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
602 :
603 : /* apply policy rules */
604 16 : if ( U8_ERROR_NONE == feature_result )
605 : {
606 15 : result |= ctrl_classifier_trigger_post_delete_feature ( (*this_).policy_enforcer, &old_feature );
607 15 : data_feature_destroy( &old_feature );
608 : }
609 :
610 16 : U8_TRACE_END_ERR( result );
611 16 : return result;
612 : }
613 :
614 2 : u8_error_t ctrl_classifier_controller_update_feature_main_type ( ctrl_classifier_controller_t *this_,
615 : data_row_t feature_id,
616 : data_feature_type_t new_feature_type )
617 : {
618 2 : U8_TRACE_BEGIN();
619 2 : u8_error_t result = U8_ERROR_NONE;
620 : data_feature_t old_feature;
621 :
622 2 : result = data_database_writer_update_feature_main_type( (*this_).db_writer, feature_id, new_feature_type, &old_feature );
623 2 : if ( U8_ERROR_NONE == result )
624 : {
625 : /* prepare the new feature */
626 : data_feature_t new_feature;
627 2 : data_feature_copy( &new_feature, &old_feature );
628 2 : data_feature_set_main_type( &new_feature, new_feature_type );
629 : /* store the change of the feature to the undo redo list */
630 2 : ctrl_undo_redo_list_add_update_feature( (*this_).undo_redo_list, &old_feature, &new_feature );
631 2 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
632 :
633 2 : data_feature_destroy( &new_feature );
634 2 : data_feature_destroy( &old_feature );
635 : }
636 :
637 2 : U8_TRACE_END_ERR( result );
638 2 : return result;
639 : }
640 :
641 1 : u8_error_t ctrl_classifier_controller_update_feature_key ( ctrl_classifier_controller_t *this_,
642 : data_row_t feature_id,
643 : const char* new_feature_key )
644 : {
645 1 : U8_TRACE_BEGIN();
646 1 : u8_error_t result = U8_ERROR_NONE;
647 : data_feature_t old_feature;
648 :
649 1 : result = data_database_writer_update_feature_key( (*this_).db_writer, feature_id, new_feature_key, &old_feature );
650 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
651 : {
652 : /* prepare the new feature */
653 : data_feature_t new_feature;
654 1 : data_feature_copy( &new_feature, &old_feature );
655 1 : data_feature_set_key( &new_feature, new_feature_key );
656 : /* store the change of the feature to the undo redo list */
657 1 : ctrl_undo_redo_list_add_update_feature( (*this_).undo_redo_list, &old_feature, &new_feature );
658 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
659 :
660 1 : data_feature_destroy( &new_feature );
661 1 : data_feature_destroy( &old_feature );
662 : }
663 :
664 1 : U8_TRACE_END_ERR( result );
665 1 : return result;
666 : }
667 :
668 2 : u8_error_t ctrl_classifier_controller_update_feature_value ( ctrl_classifier_controller_t *this_,
669 : data_row_t feature_id,
670 : const char* new_feature_value )
671 : {
672 2 : U8_TRACE_BEGIN();
673 2 : u8_error_t result = U8_ERROR_NONE;
674 : data_feature_t old_feature;
675 :
676 2 : result = data_database_writer_update_feature_value( (*this_).db_writer, feature_id, new_feature_value, &old_feature );
677 2 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
678 : {
679 : /* prepare the new feature */
680 : data_feature_t new_feature;
681 2 : data_feature_copy( &new_feature, &old_feature );
682 2 : data_feature_set_value( &new_feature, new_feature_value );
683 : /* store the change of the feature to the undo redo list */
684 2 : ctrl_undo_redo_list_add_update_feature( (*this_).undo_redo_list, &old_feature, &new_feature );
685 2 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
686 :
687 2 : data_feature_destroy( &new_feature );
688 2 : data_feature_destroy( &old_feature );
689 : }
690 :
691 2 : U8_TRACE_END_ERR( result );
692 2 : return result;
693 : }
694 :
695 1 : u8_error_t ctrl_classifier_controller_update_feature_description ( ctrl_classifier_controller_t *this_,
696 : data_row_t feature_id,
697 : const char* new_feature_description )
698 : {
699 1 : U8_TRACE_BEGIN();
700 1 : u8_error_t result = U8_ERROR_NONE;
701 : data_feature_t old_feature;
702 :
703 1 : result = data_database_writer_update_feature_description( (*this_).db_writer, feature_id, new_feature_description, &old_feature );
704 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
705 : {
706 : /* prepare the new feature */
707 : data_feature_t new_feature;
708 1 : data_feature_copy( &new_feature, &old_feature );
709 1 : data_feature_set_description( &new_feature, new_feature_description );
710 : /* store the change of the feature to the undo redo list */
711 1 : ctrl_undo_redo_list_add_update_feature( (*this_).undo_redo_list, &old_feature, &new_feature );
712 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
713 :
714 1 : data_feature_destroy( &new_feature );
715 1 : data_feature_destroy( &old_feature );
716 : }
717 :
718 1 : U8_TRACE_END_ERR( result );
719 1 : return result;
720 : }
721 :
722 1 : u8_error_t ctrl_classifier_controller_update_feature_list_order ( ctrl_classifier_controller_t *this_,
723 : data_row_t feature_id,
724 : int32_t new_feature_list_order )
725 : {
726 1 : U8_TRACE_BEGIN();
727 1 : u8_error_t result = U8_ERROR_NONE;
728 : data_feature_t old_feature;
729 :
730 1 : result = data_database_writer_update_feature_list_order( (*this_).db_writer, feature_id, new_feature_list_order, &old_feature );
731 1 : if ( U8_ERROR_NONE == result )
732 : {
733 : /* prepare the new feature */
734 : data_feature_t new_feature;
735 1 : data_feature_copy( &new_feature, &old_feature );
736 1 : data_feature_set_list_order( &new_feature, new_feature_list_order );
737 : /* store the change of the feature to the undo redo list */
738 1 : ctrl_undo_redo_list_add_update_feature( (*this_).undo_redo_list, &old_feature, &new_feature );
739 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
740 :
741 1 : data_feature_destroy( &new_feature );
742 1 : data_feature_destroy( &old_feature );
743 : }
744 :
745 1 : U8_TRACE_END_ERR( result );
746 1 : return result;
747 : }
748 :
749 : /* ================================ RELATIONSHIP ================================ */
750 :
751 21 : u8_error_t ctrl_classifier_controller_create_relationship ( ctrl_classifier_controller_t *this_,
752 : const data_relationship_t *new_relationship,
753 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set,
754 : data_row_t* out_new_id )
755 : {
756 21 : U8_TRACE_BEGIN();
757 21 : assert( NULL != new_relationship );
758 : data_relationship_t to_be_created;
759 21 : u8_error_t result = U8_ERROR_NONE;
760 : data_row_t new_id;
761 :
762 21 : data_relationship_copy( &to_be_created, new_relationship );
763 :
764 21 : result = data_database_writer_create_relationship( (*this_).db_writer, &to_be_created, &new_id );
765 21 : if ( U8_ERROR_NONE == result )
766 : {
767 : /* store new id to data_relationship_t object */
768 19 : data_relationship_set_row( &to_be_created, new_id );
769 :
770 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
771 19 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
772 : {
773 : u8_error_t internal_err;
774 8 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
775 8 : if ( U8_ERROR_NONE != internal_err )
776 : {
777 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
778 : }
779 : }
780 :
781 : /* store the new relationship to the undo redo list */
782 19 : ctrl_undo_redo_list_add_create_relationship( (*this_).undo_redo_list, &to_be_created );
783 19 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
784 :
785 : /* copy new id to out parameter */
786 19 : if ( NULL != out_new_id )
787 : {
788 19 : *out_new_id = new_id;
789 : }
790 : }
791 :
792 : /* apply policy rules */
793 21 : if ( U8_ERROR_NONE == result )
794 : {
795 19 : result |= ctrl_classifier_trigger_post_create_relationship ( (*this_).policy_enforcer, &to_be_created );
796 : }
797 :
798 21 : data_relationship_destroy( &to_be_created );
799 :
800 21 : U8_TRACE_END_ERR( result );
801 21 : return result;
802 : }
803 :
804 7 : u8_error_t ctrl_classifier_controller_delete_relationship ( ctrl_classifier_controller_t *this_,
805 : data_row_t obj_id,
806 : ctrl_undo_redo_action_boundary_t add_to_latest_undo_set )
807 : {
808 7 : U8_TRACE_BEGIN();
809 7 : u8_error_t result = U8_ERROR_NONE;
810 :
811 : /* delete relationship */
812 : data_relationship_t old_relation;
813 7 : result = data_database_writer_delete_relationship( (*this_).db_writer, obj_id, &old_relation );
814 :
815 7 : if ( U8_ERROR_NONE == result )
816 : {
817 : /* if this action shall be stored to the latest set of actions in the undo redo list, remove the boundary: */
818 6 : if ( add_to_latest_undo_set == CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
819 : {
820 : u8_error_t internal_err;
821 3 : internal_err = ctrl_undo_redo_list_remove_boundary_from_end( (*this_).undo_redo_list );
822 3 : if ( U8_ERROR_NONE != internal_err )
823 : {
824 0 : U8_LOG_ERROR_HEX( "unexpected internal error", internal_err );
825 : }
826 : }
827 :
828 : /* store the deleted relationship to the undo redo list */
829 6 : ctrl_undo_redo_list_add_delete_relationship( (*this_).undo_redo_list, &old_relation );
830 6 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
831 :
832 6 : data_relationship_destroy( &old_relation );
833 : }
834 :
835 7 : U8_TRACE_END_ERR( result );
836 7 : return result;
837 : }
838 :
839 1 : u8_error_t ctrl_classifier_controller_update_relationship_main_type ( ctrl_classifier_controller_t *this_,
840 : data_row_t relationship_id,
841 : data_relationship_type_t new_relationship_type )
842 : {
843 1 : U8_TRACE_BEGIN();
844 1 : u8_error_t result = U8_ERROR_NONE;
845 : data_relationship_t old_relation;
846 :
847 1 : result = data_database_writer_update_relationship_main_type( (*this_).db_writer, relationship_id, new_relationship_type, &old_relation );
848 1 : if ( U8_ERROR_NONE == result )
849 : {
850 : /* prepare the new relation */
851 : data_relationship_t new_relation;
852 1 : data_relationship_copy( &new_relation, &old_relation );
853 1 : data_relationship_set_main_type( &new_relation, new_relationship_type );
854 : /* store the change of the relation to the undo redo list */
855 1 : ctrl_undo_redo_list_add_update_relationship( (*this_).undo_redo_list, &old_relation, &new_relation );
856 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
857 :
858 1 : data_relationship_destroy( &new_relation );
859 1 : data_relationship_destroy( &old_relation );
860 : }
861 :
862 1 : U8_TRACE_END_ERR( result );
863 1 : return result;
864 : }
865 :
866 1 : u8_error_t ctrl_classifier_controller_update_relationship_stereotype ( ctrl_classifier_controller_t *this_,
867 : data_row_t relationship_id,
868 : const char* new_relationship_stereotype )
869 : {
870 1 : U8_TRACE_BEGIN();
871 1 : u8_error_t result = U8_ERROR_NONE;
872 : data_relationship_t old_relation;
873 :
874 1 : result = data_database_writer_update_relationship_stereotype( (*this_).db_writer, relationship_id, new_relationship_stereotype, &old_relation );
875 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
876 : {
877 : /* prepare the new relation */
878 : data_relationship_t new_relation;
879 1 : data_relationship_copy( &new_relation, &old_relation );
880 1 : data_relationship_set_stereotype( &new_relation, new_relationship_stereotype );
881 : /* store the change of the relation to the undo redo list */
882 1 : ctrl_undo_redo_list_add_update_relationship( (*this_).undo_redo_list, &old_relation, &new_relation );
883 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
884 :
885 1 : data_relationship_destroy( &new_relation );
886 1 : data_relationship_destroy( &old_relation );
887 : }
888 :
889 1 : U8_TRACE_END_ERR( result );
890 1 : return result;
891 : }
892 :
893 1 : u8_error_t ctrl_classifier_controller_update_relationship_name ( ctrl_classifier_controller_t *this_,
894 : data_row_t relationship_id,
895 : const char* new_relationship_name )
896 : {
897 1 : U8_TRACE_BEGIN();
898 1 : u8_error_t result = U8_ERROR_NONE;
899 : data_relationship_t old_relation;
900 :
901 1 : result = data_database_writer_update_relationship_name( (*this_).db_writer, relationship_id, new_relationship_name, &old_relation );
902 1 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
903 : {
904 : /* prepare the new relation */
905 : data_relationship_t new_relation;
906 1 : data_relationship_copy( &new_relation, &old_relation );
907 1 : data_relationship_set_name( &new_relation, new_relationship_name );
908 : /* store the change of the relation to the undo redo list */
909 1 : ctrl_undo_redo_list_add_update_relationship( (*this_).undo_redo_list, &old_relation, &new_relation );
910 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
911 :
912 1 : data_relationship_destroy( &new_relation );
913 1 : data_relationship_destroy( &old_relation );
914 : }
915 :
916 1 : U8_TRACE_END_ERR( result );
917 1 : return result;
918 : }
919 :
920 2 : u8_error_t ctrl_classifier_controller_update_relationship_description ( ctrl_classifier_controller_t *this_,
921 : data_row_t relationship_id,
922 : const char* new_relationship_description )
923 : {
924 2 : U8_TRACE_BEGIN();
925 2 : u8_error_t result = U8_ERROR_NONE;
926 : data_relationship_t old_relation;
927 :
928 2 : result = data_database_writer_update_relationship_description( (*this_).db_writer, relationship_id, new_relationship_description, &old_relation );
929 2 : if (( U8_ERROR_NONE == result ) || ( U8_ERROR_STRING_BUFFER_EXCEEDED == result ))
930 : {
931 : /* prepare the new relation */
932 : data_relationship_t new_relation;
933 2 : data_relationship_copy( &new_relation, &old_relation );
934 2 : data_relationship_set_description( &new_relation, new_relationship_description );
935 : /* store the change of the relation to the undo redo list */
936 2 : ctrl_undo_redo_list_add_update_relationship( (*this_).undo_redo_list, &old_relation, &new_relation );
937 2 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
938 :
939 2 : data_relationship_destroy( &new_relation );
940 2 : data_relationship_destroy( &old_relation );
941 : }
942 :
943 2 : U8_TRACE_END_ERR( result );
944 2 : return result;
945 : }
946 :
947 1 : u8_error_t ctrl_classifier_controller_update_relationship_list_order ( ctrl_classifier_controller_t *this_,
948 : data_row_t relationship_id,
949 : int32_t new_relationship_list_order )
950 : {
951 1 : U8_TRACE_BEGIN();
952 1 : u8_error_t result = U8_ERROR_NONE;
953 : data_relationship_t old_relation;
954 :
955 1 : result = data_database_writer_update_relationship_list_order( (*this_).db_writer, relationship_id, new_relationship_list_order, &old_relation );
956 1 : if ( U8_ERROR_NONE == result )
957 : {
958 : /* prepare the new relation */
959 : data_relationship_t new_relation;
960 1 : data_relationship_copy( &new_relation, &old_relation );
961 1 : data_relationship_set_list_order( &new_relation, new_relationship_list_order );
962 : /* store the change of the relation to the undo redo list */
963 1 : ctrl_undo_redo_list_add_update_relationship( (*this_).undo_redo_list, &old_relation, &new_relation );
964 1 : ctrl_undo_redo_list_add_boundary( (*this_).undo_redo_list );
965 :
966 1 : data_relationship_destroy( &new_relation );
967 1 : data_relationship_destroy( &old_relation );
968 : }
969 :
970 1 : U8_TRACE_END_ERR( result );
971 1 : return result;
972 : }
973 :
974 :
975 : /*
976 : Copyright 2016-2026 Andreas Warnke
977 :
978 : Licensed under the Apache License, Version 2.0 (the "License");
979 : you may not use this file except in compliance with the License.
980 : You may obtain a copy of the License at
981 :
982 : http://www.apache.org/licenses/LICENSE-2.0
983 :
984 : Unless required by applicable law or agreed to in writing, software
985 : distributed under the License is distributed on an "AS IS" BASIS,
986 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
987 : See the License for the specific language governing permissions and
988 : limitations under the License.
989 : */
|