Line data Source code
1 : /* File: ctrl_multi_step_changer.c; Copyright and License: see below */
2 :
3 : #include "ctrl_multi_step_changer.h"
4 : #include "u8/u8_trace.h"
5 : #include "u8/u8_log.h"
6 : #include <assert.h>
7 :
8 23 : void ctrl_multi_step_changer_init ( ctrl_multi_step_changer_t *this_,
9 : ctrl_controller_t *controller,
10 : data_database_reader_t *db_reader )
11 : {
12 23 : U8_TRACE_BEGIN();
13 23 : assert( NULL != controller );
14 23 : assert( NULL != db_reader );
15 :
16 : /* init member attributes */
17 23 : (*this_).controller = controller;
18 23 : (*this_).db_reader = db_reader;
19 :
20 23 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW;
21 :
22 23 : U8_TRACE_END();
23 23 : }
24 :
25 23 : void ctrl_multi_step_changer_destroy ( ctrl_multi_step_changer_t *this_ )
26 : {
27 23 : U8_TRACE_BEGIN();
28 23 : assert( NULL != (*this_).controller );
29 23 : assert( NULL != (*this_).db_reader );
30 :
31 : /* destroy member attributes */
32 23 : (*this_).controller = NULL;
33 23 : (*this_).db_reader = NULL;
34 :
35 23 : U8_TRACE_END();
36 23 : }
37 :
38 : /* ================================ delete sets of elements ================================ */
39 :
40 3 : u8_error_t ctrl_multi_step_changer_delete_set ( ctrl_multi_step_changer_t *this_,
41 : const data_small_set_t *objects,
42 : data_stat_t *io_stat )
43 : {
44 3 : U8_TRACE_BEGIN();
45 3 : assert ( NULL != io_stat );
46 3 : u8_error_t result = U8_ERROR_NONE;
47 :
48 3 : if ( data_small_set_is_empty( objects ) )
49 : {
50 0 : result = U8_ERROR_INPUT_EMPTY;
51 : }
52 : else
53 : {
54 3 : ctrl_classifier_controller_t *const classifier_ctrl = ctrl_controller_get_classifier_control_ptr( (*this_).controller);
55 3 : ctrl_diagram_controller_t *const diagram_ctrl = ctrl_controller_get_diagram_control_ptr( (*this_).controller );
56 :
57 : /* STEP ONE: Delete all objects that can be immediately deleted */
58 :
59 15 : for ( int index1 = 0; index1 < data_small_set_get_count( objects ); index1 ++ )
60 : {
61 : data_id_t current_id;
62 12 : current_id = data_small_set_get_id( objects, index1 );
63 12 : switch ( data_id_get_table( ¤t_id ) )
64 : {
65 2 : case DATA_TABLE_CLASSIFIER:
66 : {
67 : /* see step FOUR */
68 : }
69 2 : break;
70 :
71 3 : case DATA_TABLE_FEATURE:
72 : {
73 : /* see step TWO */
74 : }
75 3 : break;
76 :
77 3 : case DATA_TABLE_RELATIONSHIP:
78 : {
79 3 : result |= ctrl_classifier_controller_delete_relationship( classifier_ctrl,
80 : data_id_get_row( ¤t_id ),
81 : (*this_).is_first_step
82 : );
83 3 : if ( result == U8_ERROR_NONE )
84 : {
85 2 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_DELETED );
86 2 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
87 : }
88 : else
89 : {
90 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_RELATIONSHIP, DATA_STAT_SERIES_ERROR );
91 : }
92 : }
93 3 : break;
94 :
95 2 : case DATA_TABLE_DIAGRAMELEMENT:
96 : {
97 : /* see step THREE */
98 : }
99 2 : break;
100 :
101 2 : case DATA_TABLE_DIAGRAM:
102 : {
103 : /* see step FOUR */
104 : }
105 2 : break;
106 :
107 0 : default:
108 : {
109 0 : result |= U8_ERROR_VALUE_OUT_OF_RANGE;
110 : }
111 0 : break;
112 : }
113 : }
114 :
115 : /* STEP TWO: Delete all objects that can be deleted after relationships are gone */
116 :
117 15 : for ( int index2 = 0; index2 < data_small_set_get_count( objects ); index2 ++ )
118 : {
119 : data_id_t current_id;
120 12 : current_id = data_small_set_get_id( objects, index2 );
121 12 : switch ( data_id_get_table( ¤t_id ) )
122 : {
123 2 : case DATA_TABLE_CLASSIFIER:
124 : {
125 : /* see step FOUR */
126 : }
127 2 : break;
128 :
129 3 : case DATA_TABLE_FEATURE:
130 : {
131 3 : consistency_stat_t stat_feat = CONSISTENCY_STAT_ZERO;
132 3 : result |= ctrl_classifier_controller_delete_feature( classifier_ctrl,
133 : data_id_get_row( ¤t_id ),
134 : (*this_).is_first_step,
135 : &stat_feat
136 : );
137 3 : if ( result == U8_ERROR_NONE )
138 : {
139 : /* no need to increase the io_stat here, the feature is already contained in stat_feat */
140 2 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
141 : }
142 : else
143 : {
144 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_FEATURE, DATA_STAT_SERIES_ERROR );
145 : }
146 3 : consistency_stat_transfer_to( &stat_feat, io_stat );
147 : }
148 3 : break;
149 :
150 3 : case DATA_TABLE_RELATIONSHIP:
151 : {
152 : /* see step ONE */
153 : }
154 3 : break;
155 :
156 2 : case DATA_TABLE_DIAGRAMELEMENT:
157 : {
158 : /* see step THREE */
159 : }
160 2 : break;
161 :
162 2 : case DATA_TABLE_DIAGRAM:
163 : {
164 : /* see step FOUR */
165 : }
166 2 : break;
167 :
168 0 : default:
169 : {
170 0 : result |= U8_ERROR_VALUE_OUT_OF_RANGE;
171 : }
172 0 : break;
173 : }
174 : }
175 :
176 : /* STEP THREE: Delete all objects that can be deleted after relationships and features are gone */
177 :
178 15 : for ( int index3 = 0; index3 < data_small_set_get_count( objects ); index3 ++ )
179 : {
180 : data_id_t current_id;
181 12 : current_id = data_small_set_get_id( objects, index3 );
182 12 : switch ( data_id_get_table( ¤t_id ) )
183 : {
184 2 : case DATA_TABLE_CLASSIFIER:
185 : {
186 : /* see step FOUR */
187 : }
188 2 : break;
189 :
190 3 : case DATA_TABLE_FEATURE:
191 : {
192 : /* see step TWO */
193 : }
194 3 : break;
195 :
196 3 : case DATA_TABLE_RELATIONSHIP:
197 : {
198 : /* see step ONE */
199 : }
200 3 : break;
201 :
202 2 : case DATA_TABLE_DIAGRAMELEMENT:
203 : {
204 2 : consistency_stat_t stat_ele = CONSISTENCY_STAT_ZERO;
205 2 : result |= ctrl_diagram_controller_delete_diagramelement( diagram_ctrl,
206 : data_id_get_row( ¤t_id ),
207 : (*this_).is_first_step,
208 : &stat_ele
209 : );
210 2 : if ( result == U8_ERROR_NONE )
211 : {
212 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_DELETED );
213 1 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
214 : }
215 : else
216 : {
217 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_DIAGRAMELEMENT, DATA_STAT_SERIES_ERROR );
218 : }
219 2 : consistency_stat_transfer_to( &stat_ele, io_stat );
220 : }
221 2 : break;
222 :
223 2 : case DATA_TABLE_DIAGRAM:
224 : {
225 : /* see step FOUR */
226 : }
227 2 : break;
228 :
229 0 : default:
230 : {
231 : /* see step zero */
232 : }
233 0 : break;
234 : }
235 : }
236 :
237 : /* STEP FOUR: Delete all objects that can be deleted after step THREE */
238 :
239 15 : for ( int index4 = 0; index4 < data_small_set_get_count( objects ); index4 ++ )
240 : {
241 : data_id_t current_id;
242 12 : current_id = data_small_set_get_id( objects, index4 );
243 12 : switch ( data_id_get_table( ¤t_id ) )
244 : {
245 2 : case DATA_TABLE_CLASSIFIER:
246 : {
247 2 : consistency_stat_t stat_clas = CONSISTENCY_STAT_ZERO;
248 2 : result |= ctrl_classifier_controller_delete_classifier( classifier_ctrl,
249 : data_id_get_row( ¤t_id ),
250 : (*this_).is_first_step,
251 : &stat_clas
252 : );
253 2 : if ( result == U8_ERROR_NONE )
254 : {
255 : /* no need to increase the io_stat here, the classifier is already contained in stat_clas */
256 1 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
257 : }
258 : else
259 : {
260 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_CLASSIFIER, DATA_STAT_SERIES_ERROR );
261 : }
262 2 : consistency_stat_transfer_to( &stat_clas, io_stat );
263 : }
264 2 : break;
265 :
266 3 : case DATA_TABLE_FEATURE:
267 : {
268 : /* see step TWO */
269 : }
270 3 : break;
271 :
272 3 : case DATA_TABLE_RELATIONSHIP:
273 : {
274 : /* see step ONE */
275 : }
276 3 : break;
277 :
278 2 : case DATA_TABLE_DIAGRAMELEMENT:
279 : {
280 : /* see step THREE */
281 : }
282 2 : break;
283 :
284 2 : case DATA_TABLE_DIAGRAM:
285 : {
286 2 : result |= ctrl_diagram_controller_delete_diagram( diagram_ctrl,
287 : data_id_get_row( ¤t_id ),
288 : (*this_).is_first_step
289 : );
290 2 : if ( result == U8_ERROR_NONE )
291 : {
292 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_DELETED );
293 1 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
294 : }
295 : else
296 : {
297 1 : data_stat_inc_count( io_stat, DATA_STAT_TABLE_DIAGRAM, DATA_STAT_SERIES_ERROR );
298 : }
299 : }
300 2 : break;
301 :
302 0 : default:
303 : {
304 : /* see step zero */
305 : }
306 0 : break;
307 : }
308 : }
309 : }
310 :
311 3 : U8_TRACE_END_ERR( result );
312 3 : return result;
313 : }
314 :
315 : /* ================================ create elements without duplicate ids ================================ */
316 :
317 12 : u8_error_t ctrl_multi_step_changer_create_diagram ( ctrl_multi_step_changer_t *this_,
318 : data_diagram_t *new_diagram,
319 : u8_error_t* out_info )
320 : {
321 12 : U8_TRACE_BEGIN();
322 12 : assert( NULL != new_diagram );
323 12 : assert( NULL != out_info );
324 12 : u8_error_t result = U8_ERROR_NONE;
325 :
326 : /* ensure that a uuid exists */
327 12 : if ( 0 == utf8string_get_length( data_diagram_get_uuid_const( new_diagram ) ) )
328 : {
329 : data_uuid_t new_uuid;
330 0 : data_uuid_init_new( &new_uuid );
331 0 : data_diagram_set_uuid( new_diagram, data_uuid_get_string( &new_uuid ) );
332 0 : data_uuid_destroy( &new_uuid );
333 : }
334 :
335 : ctrl_diagram_controller_t *const diagram_ctrl
336 12 : = ctrl_controller_get_diagram_control_ptr( (*this_).controller );
337 :
338 : data_row_t new_diagram_id;
339 : const u8_error_t create_err
340 12 : = ctrl_diagram_controller_create_diagram( diagram_ctrl,
341 : new_diagram,
342 : (*this_).is_first_step,
343 : &new_diagram_id
344 : );
345 12 : *out_info = create_err;
346 12 : if ( create_err == U8_ERROR_NONE )
347 : {
348 10 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
349 10 : data_diagram_set_row( new_diagram, new_diagram_id );
350 : }
351 2 : else if ( u8_error_contains( create_err, U8_ERROR_DUPLICATE ) )
352 : {
353 2 : data_diagram_set_row( new_diagram, DATA_ROW_VOID );
354 : const u8_error_t alt_create_err
355 2 : = ctrl_diagram_controller_create_diagram( diagram_ctrl,
356 : new_diagram,
357 : (*this_).is_first_step,
358 : &new_diagram_id
359 : );
360 2 : if ( alt_create_err == U8_ERROR_NONE )
361 : {
362 2 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
363 2 : data_diagram_set_row( new_diagram, new_diagram_id );
364 2 : *out_info |= U8_ERROR_DUPLICATE_ID;
365 : }
366 : else
367 : {
368 0 : result = alt_create_err;
369 : }
370 : }
371 : else
372 : {
373 0 : result = create_err;
374 : }
375 :
376 12 : U8_TRACE_END_ERR( result );
377 12 : return result;
378 : }
379 :
380 19 : u8_error_t ctrl_multi_step_changer_create_diagramelement ( ctrl_multi_step_changer_t *this_,
381 : data_diagramelement_t *new_diagramelement,
382 : u8_error_t* out_info,
383 : data_id_t *out_created_lifeline )
384 : {
385 19 : U8_TRACE_BEGIN();
386 19 : assert( NULL != new_diagramelement );
387 19 : assert( NULL != out_info );
388 19 : assert( NULL != out_created_lifeline );
389 19 : u8_error_t result = U8_ERROR_NONE;
390 :
391 : /* ensure that a uuid exists */
392 19 : if ( 0 == utf8string_get_length( data_diagramelement_get_uuid_const( new_diagramelement ) ) )
393 : {
394 : data_uuid_t new_uuid;
395 0 : data_uuid_init_new( &new_uuid );
396 0 : data_diagramelement_set_uuid( new_diagramelement, data_uuid_get_string( &new_uuid ) );
397 0 : data_uuid_destroy( &new_uuid );
398 : }
399 :
400 : ctrl_diagram_controller_t *const diagram_ctrl
401 19 : = ctrl_controller_get_diagram_control_ptr( (*this_).controller );
402 :
403 : data_row_t new_diagramelement_id;
404 : const u8_error_t create_err
405 19 : = ctrl_diagram_controller_create_diagramelement( diagram_ctrl,
406 : new_diagramelement,
407 : (*this_).is_first_step,
408 : &new_diagramelement_id,
409 : out_created_lifeline
410 : );
411 19 : *out_info = create_err;
412 19 : if ( create_err == U8_ERROR_NONE )
413 : {
414 19 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
415 19 : data_diagramelement_set_row( new_diagramelement, new_diagramelement_id );
416 : }
417 0 : else if ( u8_error_contains( create_err, U8_ERROR_DUPLICATE ) )
418 : {
419 : /* retry without pre-defined id now; overwrite out_created_lifeline */
420 0 : data_diagramelement_set_row( new_diagramelement, DATA_ROW_VOID );
421 : const u8_error_t alt_create_err
422 0 : = ctrl_diagram_controller_create_diagramelement( diagram_ctrl,
423 : new_diagramelement,
424 : (*this_).is_first_step,
425 : &new_diagramelement_id,
426 : out_created_lifeline
427 : );
428 0 : if ( alt_create_err == U8_ERROR_NONE )
429 : {
430 0 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
431 0 : data_diagramelement_set_row( new_diagramelement, new_diagramelement_id );
432 0 : *out_info |= U8_ERROR_DUPLICATE_ID;
433 : }
434 : else
435 : {
436 0 : result = alt_create_err;
437 : }
438 : }
439 : else
440 : {
441 0 : result = create_err;
442 : }
443 :
444 19 : U8_TRACE_END_ERR( result );
445 19 : return result;
446 : }
447 :
448 14 : u8_error_t ctrl_multi_step_changer_create_classifier ( ctrl_multi_step_changer_t *this_,
449 : data_classifier_t *new_classifier,
450 : u8_error_t* out_info )
451 : {
452 14 : U8_TRACE_BEGIN();
453 14 : assert( NULL != new_classifier );
454 14 : assert( NULL != out_info );
455 14 : u8_error_t result = U8_ERROR_NONE;
456 :
457 : /* ensure that a uuid exists */
458 14 : if ( 0 == utf8string_get_length( data_classifier_get_uuid_const( new_classifier ) ) )
459 : {
460 : data_uuid_t new_uuid;
461 0 : data_uuid_init_new( &new_uuid );
462 0 : data_classifier_set_uuid( new_classifier, data_uuid_get_string( &new_uuid ) );
463 0 : data_uuid_destroy( &new_uuid );
464 : }
465 :
466 : ctrl_classifier_controller_t *const classifier_ctrl
467 14 : = ctrl_controller_get_classifier_control_ptr( (*this_).controller);
468 :
469 : data_row_t new_classifier_id;
470 : const u8_error_t create_err
471 14 : = ctrl_classifier_controller_create_classifier( classifier_ctrl,
472 : new_classifier,
473 : (*this_).is_first_step,
474 : &new_classifier_id
475 : );
476 14 : *out_info = create_err;
477 14 : if ( create_err == U8_ERROR_NONE )
478 : {
479 11 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
480 11 : data_classifier_set_row( new_classifier, new_classifier_id );
481 : }
482 3 : else if ( u8_error_contains( create_err, U8_ERROR_DUPLICATE ) )
483 : {
484 3 : data_classifier_set_row( new_classifier, DATA_ROW_VOID );
485 : const u8_error_t alt_create_err
486 3 : = ctrl_classifier_controller_create_classifier( classifier_ctrl,
487 : new_classifier,
488 : (*this_).is_first_step,
489 : &new_classifier_id
490 : );
491 3 : if ( alt_create_err == U8_ERROR_NONE )
492 : {
493 0 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
494 0 : data_classifier_set_row( new_classifier, new_classifier_id );
495 0 : *out_info |= U8_ERROR_DUPLICATE_ID;
496 : }
497 : else
498 : {
499 3 : result = alt_create_err;
500 : }
501 : }
502 : else
503 : {
504 0 : result = create_err;
505 : }
506 :
507 14 : if ( u8_error_contains( result, U8_ERROR_DUPLICATE ) )
508 : {
509 3 : *out_info |= result;
510 3 : result = U8_ERROR_NONE;
511 :
512 : /* find an alternative, unused name */
513 : char wish_name_buf[DATA_CLASSIFIER_MAX_NAME_SIZE];
514 3 : utf8stringbuf_t wish_name = UTF8STRINGBUF( wish_name_buf );
515 3 : result |= utf8stringbuf_copy_str( &wish_name, data_classifier_get_name_const( new_classifier ) ); /* error to be reported to caller */
516 : {
517 3 : bool name_ok = false;
518 : static const uint_fast16_t MAX_SEARCH_STEP = 10000;
519 : static const uint_fast16_t FIRST_STEP = 2;
520 7 : for ( uint_fast16_t search_step = FIRST_STEP; ( search_step < MAX_SEARCH_STEP )&&( ! name_ok )&&( result == U8_ERROR_NONE ); search_step ++ )
521 : {
522 : char new_name_buf[DATA_CLASSIFIER_MAX_NAME_SIZE];
523 4 : utf8stringbuf_t new_name = UTF8STRINGBUF( new_name_buf );
524 : const u8_error_t trunc_err
525 4 : = ctrl_multi_step_changer_private_propose_classifier_name( this_,
526 4 : utf8stringbuf_get_string( &wish_name ),
527 : search_step,
528 : new_name
529 : );
530 4 : if ( trunc_err != U8_ERROR_NONE )
531 : {
532 0 : U8_TRACE_INFO_STR("Name truncated at search for alternative:", utf8stringbuf_get_string( &new_name ) );
533 : }
534 4 : data_classifier_set_name( new_classifier, utf8stringbuf_get_string( &new_name ) );
535 : const u8_error_t retry_err
536 4 : = ctrl_classifier_controller_create_classifier( classifier_ctrl,
537 : new_classifier,
538 : (*this_).is_first_step,
539 : &new_classifier_id
540 : );
541 4 : if ( u8_error_contains( retry_err, U8_ERROR_DUPLICATE ) )
542 : {
543 1 : *out_info |= retry_err;
544 : }
545 3 : else if ( retry_err == U8_ERROR_NONE )
546 : {
547 3 : name_ok = true; /* name unused */
548 3 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
549 3 : data_classifier_set_row( new_classifier, new_classifier_id );
550 3 : *out_info |= U8_ERROR_DUPLICATE_NAME;
551 : }
552 : else
553 : {
554 0 : result |= retry_err;
555 : }
556 : }
557 : }
558 : }
559 :
560 14 : U8_TRACE_END_ERR( result );
561 14 : return result;
562 : }
563 :
564 8 : u8_error_t ctrl_multi_step_changer_create_feature ( ctrl_multi_step_changer_t *this_,
565 : data_feature_t *new_feature,
566 : u8_error_t* out_info )
567 : {
568 8 : U8_TRACE_BEGIN();
569 8 : assert( NULL != new_feature );
570 8 : assert( NULL != out_info );
571 8 : u8_error_t result = U8_ERROR_NONE;
572 :
573 : /* ensure that a uuid exists */
574 8 : if ( 0 == utf8string_get_length( data_feature_get_uuid_const( new_feature ) ) )
575 : {
576 : data_uuid_t new_uuid;
577 0 : data_uuid_init_new( &new_uuid );
578 0 : data_feature_set_uuid( new_feature, data_uuid_get_string( &new_uuid ) );
579 0 : data_uuid_destroy( &new_uuid );
580 : }
581 :
582 : ctrl_classifier_controller_t *const classifier_ctrl
583 8 : = ctrl_controller_get_classifier_control_ptr( (*this_).controller);
584 :
585 : data_row_t new_feature_id;
586 : const u8_error_t create_err
587 8 : = ctrl_classifier_controller_create_feature( classifier_ctrl,
588 : new_feature,
589 : (*this_).is_first_step,
590 : &new_feature_id
591 : );
592 8 : *out_info = create_err;
593 8 : if ( create_err == U8_ERROR_NONE )
594 : {
595 8 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
596 8 : data_feature_set_row( new_feature, new_feature_id );
597 : }
598 0 : else if ( u8_error_contains( create_err, U8_ERROR_DUPLICATE) )
599 : {
600 0 : data_feature_set_row( new_feature, DATA_ROW_VOID );
601 : const u8_error_t alt_create_err
602 0 : = ctrl_classifier_controller_create_feature( classifier_ctrl,
603 : new_feature,
604 : (*this_).is_first_step,
605 : &new_feature_id
606 : );
607 0 : if ( alt_create_err == U8_ERROR_NONE )
608 : {
609 0 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
610 0 : data_feature_set_row( new_feature, new_feature_id );
611 0 : *out_info |= U8_ERROR_DUPLICATE_ID;
612 : }
613 : else
614 : {
615 0 : result = alt_create_err;
616 : }
617 : }
618 : else
619 : {
620 0 : result = create_err;
621 : }
622 :
623 8 : U8_TRACE_END_ERR( result );
624 8 : return result;
625 : }
626 :
627 8 : u8_error_t ctrl_multi_step_changer_create_relationship ( ctrl_multi_step_changer_t *this_,
628 : data_relationship_t *new_relationship,
629 : u8_error_t* out_info )
630 : {
631 8 : U8_TRACE_BEGIN();
632 8 : assert( NULL != new_relationship );
633 8 : assert( NULL != out_info );
634 8 : u8_error_t result = U8_ERROR_NONE;
635 :
636 : /* ensure that a uuid exists */
637 8 : if ( 0 == utf8string_get_length( data_relationship_get_uuid_const( new_relationship ) ) )
638 : {
639 : data_uuid_t new_uuid;
640 0 : data_uuid_init_new( &new_uuid );
641 0 : data_relationship_set_uuid( new_relationship, data_uuid_get_string( &new_uuid ) );
642 0 : data_uuid_destroy( &new_uuid );
643 : }
644 :
645 : ctrl_classifier_controller_t *const classifier_ctrl
646 8 : = ctrl_controller_get_classifier_control_ptr( (*this_).controller);
647 :
648 : data_row_t new_relationship_id;
649 : const u8_error_t create_err
650 8 : = ctrl_classifier_controller_create_relationship( classifier_ctrl,
651 : new_relationship,
652 : (*this_).is_first_step,
653 : &new_relationship_id
654 : );
655 8 : *out_info = create_err;
656 8 : if ( create_err == U8_ERROR_NONE )
657 : {
658 6 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
659 6 : data_relationship_set_row( new_relationship, new_relationship_id );
660 : }
661 2 : else if ( u8_error_contains( create_err, U8_ERROR_DUPLICATE) )
662 : {
663 2 : data_relationship_set_row( new_relationship, DATA_ROW_VOID );
664 : const u8_error_t alt_create_err
665 2 : = ctrl_classifier_controller_create_relationship( classifier_ctrl,
666 : new_relationship,
667 : (*this_).is_first_step,
668 : &new_relationship_id
669 : );
670 2 : if ( alt_create_err == U8_ERROR_NONE )
671 : {
672 2 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
673 2 : data_relationship_set_row( new_relationship, new_relationship_id );
674 2 : *out_info |= U8_ERROR_DUPLICATE_ID;
675 : }
676 : else
677 : {
678 0 : result = alt_create_err;
679 : }
680 : }
681 : else
682 : {
683 0 : result = create_err;
684 : }
685 :
686 8 : U8_TRACE_END_ERR( result );
687 8 : return result;
688 : }
689 :
690 : /* ================================ update links of existing elements ================================ */
691 :
692 0 : u8_error_t ctrl_multi_step_changer_update_diagram_parent_id ( ctrl_multi_step_changer_t *this_,
693 : data_row_t diagram_id,
694 : data_row_t new_diagram_parent_id )
695 : {
696 0 : U8_TRACE_BEGIN();
697 0 : u8_error_t result = U8_ERROR_NONE;
698 :
699 : ctrl_diagram_controller_t *const diagram_ctrl
700 0 : = ctrl_controller_get_diagram_control_ptr( (*this_).controller );
701 :
702 0 : result = ctrl_diagram_controller_update_diagram_parent_id( diagram_ctrl,
703 : diagram_id,
704 : new_diagram_parent_id,
705 : (*this_).is_first_step
706 : );
707 0 : if ( result == U8_ERROR_NONE )
708 : {
709 0 : (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND;
710 : }
711 :
712 0 : U8_TRACE_END_ERR( result );
713 0 : return result;
714 : }
715 :
716 : /* ================================ propose names of classifiers ================================ */
717 :
718 4 : u8_error_t ctrl_multi_step_changer_private_propose_classifier_name ( ctrl_multi_step_changer_t *this_,
719 : const char* base_classifier_name,
720 : uint_fast16_t iteration,
721 : utf8stringbuf_t out_name )
722 : {
723 4 : U8_TRACE_BEGIN();
724 4 : const size_t RESERVED_FOR_NUMBER = 5;
725 4 : assert( NULL != base_classifier_name );
726 4 : assert( utf8stringbuf_get_size( &out_name ) > RESERVED_FOR_NUMBER );
727 4 : u8_error_t result = U8_ERROR_NONE;
728 :
729 : /* find an alternative, unused name */
730 : /* copy the base_classifier_name to newname_buf */
731 : {
732 : utf8stringbuf_t shortened_new_name
733 4 : = utf8stringbuf_new( utf8stringbuf_get_string( &out_name ), utf8stringbuf_get_size( &out_name ) - RESERVED_FOR_NUMBER );
734 4 : result |= utf8stringbuf_copy_str( &shortened_new_name, base_classifier_name );
735 : /* null termination is guaranteed, also this function does not cut an utf8 code point in the middle. */
736 : }
737 : /* append a separator and the iteration number */
738 4 : result |= utf8stringbuf_append_str( &out_name, "-" );
739 4 : result |= utf8stringbuf_append_int( &out_name, iteration );
740 :
741 4 : U8_TRACE_END_ERR( result );
742 4 : return result;
743 : }
744 :
745 :
746 : /*
747 : Copyright 2016-2026 Andreas Warnke
748 :
749 : Licensed under the Apache License, Version 2.0 (the "License");
750 : you may not use this file except in compliance with the License.
751 : You may obtain a copy of the License at
752 :
753 : http://www.apache.org/licenses/LICENSE-2.0
754 :
755 : Unless required by applicable law or agreed to in writing, software
756 : distributed under the License is distributed on an "AS IS" BASIS,
757 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
758 : See the License for the specific language governing permissions and
759 : limitations under the License.
760 : */
|