LCOV - code coverage report
Current view: top level - ctrl/source - ctrl_multi_step_changer.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.70.2_covts Lines: 78.4 % 292 229
Test Date: 2026-05-03 11:56:31 Functions: 90.0 % 10 9

            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( &current_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( &current_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( &current_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( &current_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( &current_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( &current_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( &current_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( &current_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( &current_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              : */
        

Generated by: LCOV version 2.0-1