LCOV - code coverage report
Current view: top level - ctrl/source - ctrl_multi_step_changer.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 217 270 80.4 %
Date: 2024-10-26 21:44:38 Functions: 9 10 90.0 %

          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          21 : 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          21 :     U8_TRACE_BEGIN();
      13          21 :     assert( NULL != controller );
      14          21 :     assert( NULL != db_reader );
      15             : 
      16             :     /* init member attributes */
      17          21 :     (*this_).controller = controller;
      18          21 :     (*this_).db_reader = db_reader;
      19             : 
      20          21 :     (*this_).is_first_step = CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW;
      21             : 
      22          21 :     U8_TRACE_END();
      23          21 : }
      24             : 
      25          21 : void ctrl_multi_step_changer_destroy ( ctrl_multi_step_changer_t *this_ )
      26             : {
      27          21 :     U8_TRACE_BEGIN();
      28          21 :     assert( NULL != (*this_).controller );
      29          21 :     assert( NULL != (*this_).db_reader );
      30             : 
      31             :     /* destroy member attributes */
      32          21 :     (*this_).controller = NULL;
      33          21 :     (*this_).db_reader = NULL;
      34             : 
      35          21 :     U8_TRACE_END();
      36          21 : }
      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_id_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_ID_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_id_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_ID_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_id_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_ID_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_id_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_ID_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_id_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_ID_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_id_t diagram_id,
     638             :                                                               data_row_id_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_init( utf8stringbuf_get_size(out_name)-RESERVED_FOR_NUMBER, utf8stringbuf_get_string(out_name) );
     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-2024 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 1.16