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

Generated by: LCOV version 2.0-1