LCOV - code coverage report
Current view: top level - gui/source - gui_toolbox.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 0.0 % 451 0
Test Date: 2025-05-01 10:10:14 Functions: 0.0 % 28 0

            Line data    Source code
       1              : /* File: gui_toolbox.c; Copyright and License: see below */
       2              : 
       3              : #include "gui_toolbox.h"
       4              : #include "ctrl_multi_step_changer.h"
       5              : #include "u8/u8_trace.h"
       6              : #include "u8/u8_error.h"
       7              : #include "utf8stringbuf/utf8string.h"
       8              : #include <assert.h>
       9              : #include "gui_gtk.h"
      10              : #include <stdbool.h>
      11              : 
      12              : static bool gui_toolbox_glib_signal_initialized = false;
      13              : static guint gui_toolbox_glib_signal_id = 0;
      14              : const char *GUI_TOOLBOX_GLIB_SIGNAL_NAME = "cfu_tool_changed";
      15              : 
      16            0 : void gui_toolbox_init( gui_toolbox_t *this_,
      17              :                        GtkWidget *toolbar,
      18              :                        GtkWidget *tool_navigate,
      19              :                        GtkWidget *tool_edit,
      20              :                        GtkWidget *tool_create,
      21              :                        GtkWidget *tool_search,
      22              :                        GdkClipboard *gtk_clipboard,
      23              :                        gui_marked_set_t *marker,
      24              :                        gui_simple_message_to_user_t *message_to_user,
      25              :                        data_database_reader_t *db_reader,
      26              :                        ctrl_controller_t *controller )
      27              : {
      28            0 :     U8_TRACE_BEGIN();
      29            0 :     assert( NULL != tool_navigate );
      30            0 :     assert( NULL != tool_edit );
      31            0 :     assert( NULL != tool_create );
      32            0 :     assert( NULL != tool_search );
      33            0 :     assert( NULL != gtk_clipboard );
      34            0 :     assert( NULL != marker );
      35            0 :     assert( NULL != message_to_user );
      36            0 :     assert( NULL != db_reader );
      37            0 :     assert( NULL != controller );
      38              : 
      39            0 :     (*this_).selected_tool = GUI_TOOL_NAVIGATE;
      40            0 :     (*this_).marker = marker;
      41            0 :     (*this_).message_to_user = message_to_user;
      42            0 :     (*this_).db_reader = db_reader;
      43            0 :     (*this_).controller = controller;
      44            0 :     (*this_).toolbar = toolbar;
      45            0 :     (*this_).tool_navigate = tool_navigate;
      46            0 :     (*this_).tool_edit = tool_edit;
      47            0 :     (*this_).tool_create = tool_create;
      48            0 :     (*this_).tool_search = tool_search;
      49              : 
      50            0 :     gui_clipboard_init( &((*this_).clipboard),
      51              :                         gtk_clipboard,
      52              :                         this_,
      53              :                         message_to_user,
      54              :                         db_reader,
      55              :                         controller
      56              :                       );
      57              : 
      58              :     /* define a new signal */
      59            0 :     if ( ! gui_toolbox_glib_signal_initialized )
      60              :     {
      61            0 :         gui_toolbox_glib_signal_id = g_signal_new(
      62              :             GUI_TOOLBOX_GLIB_SIGNAL_NAME,
      63              :             G_TYPE_OBJECT,
      64              :             G_SIGNAL_RUN_FIRST,
      65              :             0,
      66              :             NULL,
      67              :             NULL,
      68              :             g_cclosure_marshal_VOID__INT,
      69              :             G_TYPE_NONE,
      70              :             1,
      71              :             G_TYPE_INT /* gui_tool_t */
      72              :         );
      73            0 :         gui_toolbox_glib_signal_initialized = true;
      74            0 :         U8_TRACE_INFO_INT( "g_signal_new(\"cfu_tool_changed\") returned new signal id", gui_toolbox_glib_signal_id );
      75              :     }
      76              : 
      77            0 :     U8_TRACE_END();
      78            0 : }
      79              : 
      80            0 : void gui_toolbox_destroy( gui_toolbox_t *this_ )
      81              : {
      82            0 :     U8_TRACE_BEGIN();
      83              : 
      84            0 :     gui_clipboard_destroy( &((*this_).clipboard) );
      85              : 
      86            0 :     (*this_).db_reader = NULL;
      87            0 :     (*this_).controller = NULL;
      88            0 :     (*this_).marker = NULL;
      89            0 :     (*this_).message_to_user = NULL;
      90            0 :     (*this_).toolbar = NULL;
      91            0 :     (*this_).tool_navigate = NULL;
      92            0 :     (*this_).tool_edit = NULL;
      93            0 :     (*this_).tool_create = NULL;
      94            0 :     (*this_).tool_search = NULL;
      95              : 
      96            0 :     U8_TRACE_END();
      97            0 : }
      98              : 
      99            0 : void gui_toolbox_set_selected_tool( gui_toolbox_t *this_, gui_tool_t tool )
     100              : {
     101            0 :     U8_TRACE_BEGIN();
     102              : 
     103            0 :     switch ( tool )
     104              :     {
     105            0 :         case GUI_TOOL_NAVIGATE:
     106              :         {
     107            0 :             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( (*this_).tool_navigate ), true );
     108            0 :             gui_simple_message_to_user_hide( (*this_).message_to_user );
     109            0 :             (*this_).selected_tool = GUI_TOOL_NAVIGATE;
     110            0 :             gui_toolbox_private_notify_listeners( this_ );
     111              :         }
     112            0 :         break;
     113              : 
     114            0 :         case GUI_TOOL_EDIT:
     115              :         {
     116            0 :             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( (*this_).tool_edit ), true );
     117            0 :             gui_simple_message_to_user_hide( (*this_).message_to_user );
     118            0 :             (*this_).selected_tool = GUI_TOOL_EDIT;
     119            0 :             gui_toolbox_private_notify_listeners( this_ );
     120              :         }
     121            0 :         break;
     122              : 
     123            0 :         case GUI_TOOL_SEARCH:
     124              :         {
     125            0 :             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( (*this_).tool_search ), true );
     126            0 :             gui_simple_message_to_user_hide( (*this_).message_to_user );
     127            0 :             (*this_).selected_tool = GUI_TOOL_SEARCH;
     128            0 :             gui_toolbox_private_notify_listeners( this_ );
     129              :         }
     130            0 :         break;
     131              : 
     132            0 :         case GUI_TOOL_CREATE:
     133              :         {
     134            0 :             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( (*this_).tool_create ), true );
     135            0 :             gui_simple_message_to_user_hide( (*this_).message_to_user );
     136            0 :             (*this_).selected_tool = GUI_TOOL_CREATE;
     137            0 :             gui_toolbox_private_notify_listeners( this_ );
     138              :         }
     139            0 :         break;
     140              : 
     141            0 :         default:
     142              :         {
     143            0 :             U8_LOG_ERROR( "invalid enum value" );
     144              :         }
     145            0 :         break;
     146              :     }
     147              : 
     148            0 :     U8_TRACE_END();
     149            0 : }
     150              : 
     151            0 : void gui_toolbox_set_selected_tool_and_focus ( gui_toolbox_t *this_, gui_tool_t tool, data_id_t focused_diagram )
     152              : {
     153            0 :     U8_TRACE_BEGIN();
     154              : 
     155              :     /* switch tool */
     156            0 :     gui_toolbox_set_selected_tool( this_, tool );
     157              : 
     158            0 :     const data_id_t current_focus = gui_marked_set_get_focused_diagram( (*this_).marker );
     159            0 :     if ( ! data_id_equals_or_both_void( &focused_diagram, &current_focus ) )
     160              :     {
     161              :         /* clear selected set (no notification) */
     162            0 :         gui_marked_set_clear_selected_set( (*this_).marker );
     163              : 
     164              :         /* request to load the diagram to focus on */
     165            0 :         gui_marked_set_request_focused_diagram( (*this_).marker, focused_diagram );
     166              :     }
     167              : 
     168            0 :     U8_TRACE_END();
     169            0 : }
     170              : 
     171            0 : void gui_toolbox_navigate_btn_callback( GtkWidget* button, gpointer data )
     172              : {
     173            0 :     U8_TRACE_BEGIN();
     174            0 :     gui_toolbox_t *this_ = data;
     175            0 :     assert( NULL != this_ );
     176              : 
     177            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     178              : 
     179            0 :     (*this_).selected_tool = GUI_TOOL_NAVIGATE;
     180              : 
     181            0 :     gui_toolbox_private_notify_listeners( this_ );
     182              : 
     183            0 :     U8_TRACE_TIMESTAMP();
     184            0 :     U8_TRACE_END();
     185            0 : }
     186              : 
     187            0 : void gui_toolbox_edit_btn_callback( GtkWidget* button, gpointer data )
     188              : {
     189            0 :     U8_TRACE_BEGIN();
     190            0 :     gui_toolbox_t *this_ = data;
     191            0 :     assert( NULL != this_ );
     192              : 
     193            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     194              : 
     195            0 :     (*this_).selected_tool = GUI_TOOL_EDIT;
     196              : 
     197            0 :     gui_toolbox_private_notify_listeners( this_ );
     198              : 
     199            0 :     U8_TRACE_TIMESTAMP();
     200            0 :     U8_TRACE_END();
     201            0 : }
     202              : 
     203            0 : void gui_toolbox_create_btn_callback( GtkWidget* button, gpointer data )
     204              : {
     205            0 :     U8_TRACE_BEGIN();
     206            0 :     gui_toolbox_t *this_ = data;
     207            0 :     assert( NULL != this_ );
     208              : 
     209            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     210              : 
     211            0 :     (*this_).selected_tool = GUI_TOOL_CREATE;
     212              : 
     213            0 :     gui_toolbox_private_notify_listeners( this_ );
     214              : 
     215            0 :     U8_TRACE_TIMESTAMP();
     216            0 :     U8_TRACE_END();
     217            0 : }
     218              : 
     219            0 : void gui_toolbox_search_btn_callback( GtkWidget* button, gpointer data )
     220              : {
     221            0 :     U8_TRACE_BEGIN();
     222            0 :     gui_toolbox_t *this_ = data;
     223            0 :     assert( NULL != this_ );
     224              : 
     225            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     226              : 
     227            0 :     (*this_).selected_tool = GUI_TOOL_SEARCH;
     228              : 
     229            0 :     gui_toolbox_private_notify_listeners( this_ );
     230              : 
     231            0 :     U8_TRACE_TIMESTAMP();
     232            0 :     U8_TRACE_END();
     233            0 : }
     234              : 
     235            0 : void gui_toolbox_search_id_btn_callback( GtkWidget* button, gpointer data )
     236              : {
     237            0 :     U8_TRACE_BEGIN();
     238            0 :     gui_toolbox_t *this_ = data;
     239            0 :     assert( NULL != this_ );
     240              : 
     241            0 :     gui_toolbox_set_selected_tool( this_, GUI_TOOL_SEARCH );
     242              : 
     243            0 :     U8_TRACE_TIMESTAMP();
     244            0 :     U8_TRACE_END();
     245            0 : }
     246              : 
     247            0 : void gui_toolbox_cut_btn_callback( GtkWidget* button, gpointer data )
     248              : {
     249            0 :     U8_TRACE_BEGIN();
     250            0 :     gui_toolbox_t *this_ = data;
     251            0 :     assert( NULL != this_ );
     252              : 
     253            0 :     gui_toolbox_cut( this_ );
     254              : 
     255            0 :     U8_TRACE_TIMESTAMP();
     256            0 :     U8_TRACE_END();
     257            0 : }
     258              : 
     259            0 : void gui_toolbox_cut( gui_toolbox_t *this_ )
     260              : {
     261            0 :     U8_TRACE_BEGIN();
     262              :     u8_error_t ctrl_err;
     263              : 
     264            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     265              : 
     266              :     data_stat_t stat;
     267            0 :     data_stat_init(&stat);
     268              : 
     269            0 :     const data_small_set_t *const set_to_be_cut = gui_marked_set_get_selected_set_const( (*this_).marker );
     270              : 
     271              :     /* do not check if set is empty; gui_clipboard_copy_set_to_clipboard will do this */
     272              : 
     273            0 :     gui_clipboard_copy_set_to_clipboard( &((*this_).clipboard), set_to_be_cut, &stat );
     274              : 
     275            0 :     ctrl_err = gui_toolbox_private_delete_set( this_, set_to_be_cut, &stat );
     276              : 
     277            0 :     gui_marked_set_clear_selected_set( (*this_).marker );
     278              : 
     279            0 :     if ( U8_ERROR_INPUT_EMPTY == ctrl_err )
     280              :     {
     281            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     282              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     283              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_SELECTION
     284              :                                                );
     285              :     }
     286            0 :     else if ( u8_error_contains( ctrl_err, U8_ERROR_OBJECT_STILL_REFERENCED ) )
     287              :     {
     288            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     289              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ERROR,
     290              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_DELETING_NOT_POSSIBLE
     291              :                                                );
     292              :     }
     293            0 :     else if ( U8_ERROR_NONE != ctrl_err )
     294              :     {
     295            0 :         U8_LOG_ERROR_HEX( "Error in ctrl_classifier_controller_delete_set_from_diagram", ctrl_err );
     296              :     }
     297              :     else
     298              :     {
     299            0 :         gui_simple_message_to_user_show_message_with_stat ( (*this_).message_to_user,
     300              :                                                             GUI_SIMPLE_MESSAGE_TYPE_INFO,
     301              :                                                             GUI_SIMPLE_MESSAGE_CONTENT_CUT_TO_CLIPBOARD,
     302              :                                                             &stat
     303              :                                                           );
     304              :     }
     305              : 
     306            0 :     data_stat_destroy(&stat);
     307              : 
     308            0 :     U8_TRACE_END();
     309            0 : }
     310              : 
     311            0 : void gui_toolbox_copy_btn_callback( GtkWidget* button, gpointer data )
     312              : {
     313            0 :     U8_TRACE_BEGIN();
     314            0 :     gui_toolbox_t *this_ = data;
     315            0 :     assert( NULL != this_ );
     316              : 
     317            0 :     gui_toolbox_copy( this_ );
     318              : 
     319            0 :     U8_TRACE_TIMESTAMP();
     320            0 :     U8_TRACE_END();
     321            0 : }
     322              : 
     323            0 : void gui_toolbox_copy( gui_toolbox_t *this_ )
     324              : {
     325            0 :     U8_TRACE_BEGIN();
     326              :     int out_err;
     327              : 
     328            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     329              : 
     330              :     data_stat_t stat;
     331            0 :     data_stat_init(&stat);
     332              : 
     333            0 :     const data_small_set_t *const set_to_be_copied = gui_marked_set_get_selected_set_const( (*this_).marker );
     334              : 
     335              :     /* even in case data_small_set_is_empty( set_to_be_copied ),
     336              :      * it is possible to copy an empty set to the clipboard
     337              :      * --> therefore simply continue... */
     338            0 :     out_err = gui_clipboard_copy_set_to_clipboard( &((*this_).clipboard), set_to_be_copied, &stat );
     339              : 
     340            0 :     if ( out_err == 0 )
     341              :     {
     342            0 :         if ( 0 == data_stat_get_total_count( &stat ) )
     343              :         {
     344            0 :             gui_simple_message_to_user_show_message( (*this_).message_to_user,
     345              :                                                      GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     346              :                                                      GUI_SIMPLE_MESSAGE_CONTENT_NO_SELECTION
     347              :                                                    );
     348              :         }
     349              :         else
     350              :         {
     351            0 :             gui_simple_message_to_user_show_message_with_stat( (*this_).message_to_user,
     352              :                                                                GUI_SIMPLE_MESSAGE_TYPE_INFO,
     353              :                                                                GUI_SIMPLE_MESSAGE_CONTENT_COPY_TO_CLIPBOARD,
     354              :                                                                &stat
     355              :                                                              );
     356              :         }
     357              :     }
     358              :     else
     359              :     {
     360              :         /* error to be shown to the user */
     361            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     362              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ERROR,
     363              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_STRING_TRUNCATED
     364              :                                                );
     365              :     }
     366              : 
     367            0 :     data_stat_destroy(&stat);
     368              : 
     369            0 :     U8_TRACE_END();
     370            0 : }
     371              : 
     372            0 : void gui_toolbox_paste_btn_callback( GtkWidget* button, gpointer data )
     373              : {
     374            0 :     U8_TRACE_BEGIN();
     375            0 :     gui_toolbox_t *this_ = data;
     376            0 :     assert( NULL != this_ );
     377              : 
     378            0 :     gui_toolbox_paste( this_ );
     379              : 
     380            0 :     U8_TRACE_TIMESTAMP();
     381            0 :     U8_TRACE_END();
     382            0 : }
     383              : 
     384            0 : void gui_toolbox_paste( gui_toolbox_t *this_ )
     385              : {
     386            0 :     U8_TRACE_BEGIN();
     387            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     388              : 
     389            0 :     const data_id_t destination_diagram_id = gui_marked_set_get_focused_diagram( (*this_).marker );
     390            0 :     if ( data_id_is_valid( &destination_diagram_id ) )
     391              :     {
     392            0 :         const data_row_t dest_diagram_row_id = data_id_get_row_id( &destination_diagram_id );
     393            0 :         gui_clipboard_request_clipboard_text( &((*this_).clipboard), dest_diagram_row_id );
     394              : 
     395              :         /* this call triggers a callback later to gui_clipboard_clipboard_text_received_callback */
     396              : 
     397              :         /* Note: (*this_).message_to_user is updated by (*this_).clipboard already - nothing to do here */
     398              :     }
     399              :     else
     400              :     {
     401              :         /* error to be shown to the user */
     402            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     403              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ERROR,
     404              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_FOCUS
     405              :                                                );
     406              :     }
     407              : 
     408            0 :     U8_TRACE_END();
     409            0 : }
     410              : 
     411            0 : void gui_toolbox_delete_btn_callback( GtkWidget* button, gpointer data )
     412              : {
     413            0 :     U8_TRACE_BEGIN();
     414            0 :     gui_toolbox_t *this_ = data;
     415            0 :     assert( NULL != this_ );
     416              : 
     417            0 :     gui_toolbox_delete( this_ );
     418              : 
     419            0 :     U8_TRACE_TIMESTAMP();
     420            0 :     U8_TRACE_END();
     421            0 : }
     422              : 
     423            0 : void gui_toolbox_delete( gui_toolbox_t *this_ )
     424              : {
     425            0 :     U8_TRACE_BEGIN();
     426              :     u8_error_t ctrl_err;
     427              : 
     428            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     429              : 
     430              :     data_stat_t stat;
     431            0 :     data_stat_init(&stat);
     432              : 
     433            0 :     const data_small_set_t *const set_to_be_deleted = gui_marked_set_get_selected_set_const( (*this_).marker );
     434              : 
     435              :     /* do not check if set is empty; gui_toolbox_private_delete_set will do this */
     436              : 
     437            0 :     ctrl_err = gui_toolbox_private_delete_set( this_, set_to_be_deleted, &stat );
     438              : 
     439            0 :     gui_marked_set_clear_selected_set( (*this_).marker );
     440              : 
     441            0 :     if ( U8_ERROR_INPUT_EMPTY == ctrl_err )
     442              :     {
     443            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     444              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     445              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_SELECTION
     446              :                                                );
     447              :     }
     448            0 :     else if ( u8_error_contains( ctrl_err, U8_ERROR_OBJECT_STILL_REFERENCED ) )
     449              :     {
     450            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     451              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ERROR,
     452              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_DELETING_NOT_POSSIBLE
     453              :                                                );
     454              :     }
     455            0 :     else if ( U8_ERROR_NONE != ctrl_err )
     456              :     {
     457            0 :         U8_LOG_ERROR_HEX( "Error in ctrl_classifier_controller_delete_set_from_diagram", ctrl_err );
     458              :     }
     459              :     else
     460              :     {
     461            0 :         gui_simple_message_to_user_show_message_with_stat ( (*this_).message_to_user,
     462              :                                                             GUI_SIMPLE_MESSAGE_TYPE_INFO,
     463              :                                                             GUI_SIMPLE_MESSAGE_CONTENT_DELETE,
     464              :                                                             &stat
     465              :                                                           );
     466              :     }
     467              : 
     468            0 :     data_stat_destroy(&stat);
     469              : 
     470            0 :     U8_TRACE_END();
     471            0 : }
     472              : 
     473            0 : u8_error_t gui_toolbox_private_delete_set( gui_toolbox_t *this_,
     474              :                                            const data_small_set_t *set_to_be_deleted,
     475              :                                            data_stat_t *io_stat )
     476              : {
     477            0 :     U8_TRACE_BEGIN();
     478            0 :     assert( NULL != set_to_be_deleted );
     479            0 :     assert( NULL != io_stat );
     480              :     u8_error_t ctrl_err;
     481              : 
     482              :     ctrl_multi_step_changer_t multi_stepper;
     483            0 :     ctrl_multi_step_changer_init( &multi_stepper, (*this_).controller, (*this_).db_reader );
     484              : 
     485            0 :     ctrl_err = ctrl_multi_step_changer_delete_set ( &multi_stepper, set_to_be_deleted, io_stat );
     486              : 
     487            0 :     ctrl_multi_step_changer_destroy( &multi_stepper );
     488              : 
     489            0 :     U8_TRACE_END_ERR( ctrl_err );
     490            0 :     return ctrl_err;
     491              : }
     492              : 
     493            0 : void gui_toolbox_highlight_btn_callback( GtkWidget* button, gpointer data )
     494              : {
     495            0 :     U8_TRACE_BEGIN();
     496            0 :     gui_toolbox_t *this_ = data;
     497            0 :     assert( NULL != this_ );
     498              : 
     499            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     500              : 
     501            0 :     const data_small_set_t *const set_to_be_highlighted = gui_marked_set_get_selected_set_const( (*this_).marker );
     502              : 
     503              :     /* do not check if set is empty; gui_toolbox_private_toggle_display_flag_in_set will do this */
     504              : 
     505            0 :     gui_toolbox_private_toggle_display_flag_in_set( this_,
     506              :                                                     set_to_be_highlighted,
     507              :                                                     DATA_DIAGRAMELEMENT_FLAG_EMPHASIS | DATA_DIAGRAMELEMENT_FLAG_GRAY_OUT
     508              :                                                   );
     509              : 
     510            0 :     U8_TRACE_TIMESTAMP();
     511            0 :     U8_TRACE_END();
     512            0 : }
     513              : 
     514            0 : void gui_toolbox_instantiate_btn_callback( GtkWidget* button, gpointer data )
     515              : {
     516            0 :     U8_TRACE_BEGIN();
     517            0 :     gui_toolbox_t *this_ = data;
     518            0 :     assert( NULL != this_ );
     519              : 
     520            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     521              : 
     522            0 :     const data_small_set_t *const set_to_be_instantiated = gui_marked_set_get_selected_set_const( (*this_).marker );
     523              : 
     524              :     /* do not check if set is empty; gui_toolbox_private_toggle_display_flag_in_set will do this */
     525              : 
     526            0 :     gui_toolbox_private_toggle_display_flag_in_set( this_,
     527              :                                                     set_to_be_instantiated,
     528              :                                                     DATA_DIAGRAMELEMENT_FLAG_NAMED_INSTANCE | DATA_DIAGRAMELEMENT_FLAG_ANONYMOUS_INSTANCE
     529              :                                                   );
     530              : 
     531            0 :     U8_TRACE_TIMESTAMP();
     532            0 :     U8_TRACE_END();
     533            0 : }
     534              : 
     535            0 : void gui_toolbox_reset_btn_callback( GtkWidget* button, gpointer data )
     536              : {
     537            0 :     U8_TRACE_BEGIN();
     538            0 :     gui_toolbox_t *this_ = data;
     539            0 :     assert( NULL != this_ );
     540              : 
     541            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     542              : 
     543            0 :     gui_marked_set_clear_selected_set( (*this_).marker );
     544              :     //gui_marked_set_clear_focused( (*this_).marker );
     545              : 
     546              :     /* trigger redraw */
     547            0 :     gui_toolbox_private_notify_listeners( this_ );
     548              : 
     549            0 :     U8_TRACE_TIMESTAMP();
     550            0 :     U8_TRACE_END();
     551            0 : }
     552              : 
     553            0 : void gui_toolbox_private_toggle_display_flag_in_set( gui_toolbox_t *this_,
     554              :                                                      const data_small_set_t *set_to_be_toggled,
     555              :                                                      data_diagramelement_flag_t flag_bits_to_toggle )
     556              : {
     557            0 :     U8_TRACE_BEGIN();
     558            0 :     u8_error_t error = U8_ERROR_NONE;
     559            0 :     bool new_pattern_initialized = false;
     560            0 :     data_diagramelement_flag_t new_pattern = DATA_DIAGRAMELEMENT_FLAG_NONE;
     561            0 :     bool is_first = true;
     562              : 
     563            0 :     for ( int index = 0; index < data_small_set_get_count( set_to_be_toggled ); index ++ )
     564              :     {
     565              :         data_id_t current_id;
     566            0 :         current_id = data_small_set_get_id( set_to_be_toggled, index );
     567            0 :         switch ( data_id_get_table( &current_id ) )
     568              :         {
     569            0 :             case DATA_TABLE_CLASSIFIER:
     570              :             {
     571              :                 /* program internal error */
     572            0 :                 U8_LOG_WARNING( "gui_toolbox_private_toggle_display_flag_in_set cannot toggle display flags in non-diagramelements." );
     573            0 :                 error |= U8_ERROR_INVALID_REQUEST;
     574              :             }
     575            0 :             break;
     576              : 
     577            0 :             case DATA_TABLE_FEATURE:
     578              :             {
     579              :                 /* program internal error */
     580            0 :                 U8_LOG_WARNING( "gui_toolbox_private_toggle_display_flag_in_set cannot toggle display flags in non-diagramelements." );
     581            0 :                 error |= U8_ERROR_INVALID_REQUEST;
     582              :             }
     583            0 :             break;
     584              : 
     585            0 :             case DATA_TABLE_RELATIONSHIP:
     586              :             {
     587              :                 /* program internal error */
     588            0 :                 U8_LOG_WARNING( "gui_toolbox_private_toggle_display_flag_in_set cannot toggle display flags in non-diagramelements." );
     589            0 :                 error |= U8_ERROR_INVALID_REQUEST;
     590              :             }
     591            0 :             break;
     592              : 
     593            0 :             case DATA_TABLE_DIAGRAMELEMENT:
     594              :             {
     595              :                 data_diagramelement_t out_diagramelement;
     596            0 :                 data_row_t diag_elem_id = data_id_get_row_id( &current_id );
     597              :                 ctrl_diagram_controller_t *diag_ctrl;
     598            0 :                 diag_ctrl = ctrl_controller_get_diagram_control_ptr( (*this_).controller );
     599              : 
     600            0 :                 error |= (u8_error_t) data_database_reader_get_diagramelement_by_id ( (*this_).db_reader,
     601              :                                                                                         diag_elem_id,
     602              :                                                                                         &out_diagramelement
     603              :                                                                                       );
     604              :                 data_diagramelement_flag_t current_flags;
     605            0 :                 current_flags = data_diagramelement_get_display_flags( &out_diagramelement );
     606              : 
     607            0 :                 if ( ! new_pattern_initialized )
     608              :                 {
     609              :                     /* select zero or one bit to set. alg: select the next highest bit */
     610            0 :                     bool last_was_set = true;
     611            0 :                     new_pattern = DATA_DIAGRAMELEMENT_FLAG_NONE;
     612            0 :                     for ( int bit = 0; bit < 8*sizeof(data_diagramelement_flag_t); bit ++ )
     613              :                     {
     614            0 :                         data_diagramelement_flag_t probe = (1 << bit);
     615            0 :                         if ( 0 != ( probe & flag_bits_to_toggle ) )
     616              :                         {
     617              :                             /* this is a relevant bit */
     618            0 :                             if ( 0 != ( probe & current_flags ) )
     619              :                             {
     620            0 :                                 new_pattern = DATA_DIAGRAMELEMENT_FLAG_NONE;
     621            0 :                                 last_was_set = true;
     622              :                             }
     623              :                             else
     624              :                             {
     625            0 :                                 if ( last_was_set )
     626              :                                 {
     627            0 :                                     new_pattern = probe;
     628              :                                 }
     629            0 :                                 last_was_set = false;
     630              :                             }
     631              :                         }
     632              :                     }
     633            0 :                     new_pattern_initialized = true;
     634              :                 }
     635              : 
     636            0 :                 current_flags = (current_flags & (~flag_bits_to_toggle)) | new_pattern;
     637              : 
     638            0 :                 error |= ctrl_diagram_controller_update_diagramelement_display_flags( diag_ctrl,
     639              :                                                                                       diag_elem_id,
     640              :                                                                                       current_flags,
     641              :                                                                                       ( is_first
     642              :                                                                                       ? CTRL_UNDO_REDO_ACTION_BOUNDARY_START_NEW
     643            0 :                                                                                       : CTRL_UNDO_REDO_ACTION_BOUNDARY_APPEND )
     644              :                                                                                     );
     645            0 :                 is_first = false;
     646              :             }
     647            0 :             break;
     648              : 
     649            0 :             case DATA_TABLE_DIAGRAM:
     650              :             {
     651              :                 /* program internal error */
     652            0 :                 U8_LOG_WARNING( "gui_toolbox_private_toggle_display_flag_in_set cannot toggle display flags in non-diagramelements." );
     653            0 :                 error |= U8_ERROR_INVALID_REQUEST;
     654              :             }
     655            0 :             break;
     656              : 
     657            0 :             default:
     658              :             {
     659              :                 /* program internal error */
     660            0 :                 U8_LOG_ERROR( "gui_toolbox_private_toggle_display_flag_in_set fould illegal data_table_t enum value." );
     661              :             }
     662            0 :             break;
     663              :         }
     664              :     }
     665              : 
     666            0 :     if ( error != U8_ERROR_NONE )
     667              :     {
     668              :         /* error to be shown to the user */
     669            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     670              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     671              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_SET_PARTLY_UNSUITABLE
     672              :                                                );
     673              :     }
     674            0 :     else if ( 0 == data_small_set_get_count( set_to_be_toggled ) )
     675              :     {
     676              :         /* error to be shown to the user */
     677            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     678              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     679              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_SELECTION
     680              :                                                );
     681              :     }
     682              : 
     683            0 :     U8_TRACE_END();
     684            0 : }
     685              : 
     686            0 : void gui_toolbox_undo_btn_callback( GtkWidget* button, gpointer data )
     687              : {
     688            0 :     U8_TRACE_BEGIN();
     689            0 :     gui_toolbox_t *this_ = data;
     690            0 :     assert( this_ != NULL );
     691              :     u8_error_t ctrl_err;
     692              : 
     693            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     694              : 
     695              :     data_stat_t stat;
     696            0 :     data_stat_init( &stat );
     697              : 
     698            0 :     ctrl_err = ctrl_controller_undo( (*this_).controller, &stat );
     699              : 
     700              :     /* find a diagram that can show the changes */
     701            0 :     if ( U8_ERROR_NONE == ctrl_err )
     702              :     {
     703              :         ctrl_undo_redo_iterator_t iter;
     704            0 :         ctrl_undo_redo_iterator_init_empty( &iter );
     705            0 :         ctrl_err |= ctrl_controller_get_redo_iterator( (*this_).controller, &iter );
     706            0 :         gui_toolbox_private_show_changes( this_, &iter );
     707            0 :         ctrl_undo_redo_iterator_destroy( &iter );
     708              :     }
     709              : 
     710              :     /* show error/success message to the user */
     711            0 :     if ( U8_ERROR_INVALID_REQUEST == ctrl_err )
     712              :     {
     713            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     714              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     715              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_MORE_UNDO
     716              :                                                );
     717              :     }
     718            0 :     else if ( U8_ERROR_ARRAY_BUFFER_EXCEEDED == ctrl_err )
     719              :     {
     720            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     721              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ERROR,
     722              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_UNDO_NOT_POSSIBLE
     723              :                                                );
     724              :     }
     725              :     else
     726              :     {
     727              :         /* success */
     728            0 :         gui_simple_message_to_user_show_message_with_stat( (*this_).message_to_user,
     729              :                                                            GUI_SIMPLE_MESSAGE_TYPE_INFO,
     730              :                                                            GUI_SIMPLE_MESSAGE_CONTENT_UNDO,
     731              :                                                            &stat
     732              :                                                          );
     733              :     }
     734              : 
     735            0 :     data_stat_destroy( &stat );
     736              : 
     737            0 :     U8_TRACE_TIMESTAMP();
     738            0 :     U8_TRACE_END();
     739            0 : }
     740              : 
     741            0 : gboolean gui_toolbox_undo_shortcut_callback( GtkWidget* widget, GVariant* args, gpointer user_data )
     742              : {
     743            0 :     gui_toolbox_undo_btn_callback( widget, user_data );
     744            0 :     return TRUE;
     745              : }
     746              : 
     747            0 : void gui_toolbox_redo_btn_callback( GtkWidget* button, gpointer data )
     748              : {
     749            0 :     U8_TRACE_BEGIN();
     750            0 :     gui_toolbox_t *this_ = data;
     751            0 :     assert( this_ != NULL );
     752              :     u8_error_t ctrl_err;
     753              : 
     754            0 :     gui_simple_message_to_user_hide( (*this_).message_to_user );
     755              : 
     756              :     data_stat_t stat;
     757            0 :     data_stat_init( &stat );
     758              : 
     759            0 :     ctrl_err = ctrl_controller_redo( (*this_).controller, &stat );
     760              : 
     761              :     /* find a diagram that can show the changes */
     762            0 :     if ( U8_ERROR_NONE == ctrl_err )
     763              :     {
     764              :         ctrl_undo_redo_iterator_t iter;
     765            0 :         ctrl_undo_redo_iterator_init_empty( &iter );
     766            0 :         ctrl_err |= ctrl_controller_get_undo_iterator( (*this_).controller, &iter );
     767            0 :         gui_toolbox_private_show_changes( this_, &iter );
     768            0 :         ctrl_undo_redo_iterator_destroy( &iter );
     769              :     }
     770              : 
     771              :     /* show error/success message to the user */
     772            0 :     if ( U8_ERROR_INVALID_REQUEST == ctrl_err )
     773              :     {
     774            0 :         gui_simple_message_to_user_show_message( (*this_).message_to_user,
     775              :                                                  GUI_SIMPLE_MESSAGE_TYPE_WARNING,
     776              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_NO_MORE_REDO
     777              :                                                );
     778              :     }
     779              :     else
     780              :     {
     781              :         /* success */
     782            0 :         gui_simple_message_to_user_show_message_with_stat( (*this_).message_to_user,
     783              :                                                            GUI_SIMPLE_MESSAGE_TYPE_INFO,
     784              :                                                            GUI_SIMPLE_MESSAGE_CONTENT_REDO,
     785              :                                                            &stat
     786              :                                                          );
     787              :     }
     788              : 
     789            0 :     data_stat_destroy( &stat );
     790              : 
     791            0 :     U8_TRACE_TIMESTAMP();
     792            0 :     U8_TRACE_END();
     793            0 : }
     794              : 
     795              : /*!
     796              :  *  \brief callback that informs that the redo shortcut was activated
     797              :  */
     798            0 : gboolean gui_toolbox_redo_shortcut_callback( GtkWidget* widget, GVariant* args, gpointer user_data )
     799              : {
     800            0 :     gui_toolbox_redo_btn_callback( widget, user_data );
     801            0 :     return TRUE;
     802              : }
     803              : 
     804            0 : void gui_toolbox_private_show_changes( gui_toolbox_t *this_,
     805              :                                        ctrl_undo_redo_iterator_t *action_iterator )
     806              : {
     807            0 :     U8_TRACE_BEGIN();
     808            0 :     data_id_t display_diag_nav = DATA_ID_VOID;  /* display this diagram in navigation mode, prio 1 */
     809            0 :     data_id_t display_diag_edit = DATA_ID_VOID;  /* display this diagram in edit mode, prio 2 */
     810            0 :     data_id_t display_classifier = DATA_ID_VOID;  /* display this classifier somehow, prio 3 */
     811              : 
     812            0 :     while( ctrl_undo_redo_iterator_has_next( action_iterator ) )
     813              :     {
     814            0 :         const ctrl_undo_redo_entry_t *const probe = ctrl_undo_redo_iterator_next( action_iterator );
     815              : 
     816            0 :         switch( ctrl_undo_redo_entry_get_action_type( probe ) )
     817              :         {
     818            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_DELETE_DIAGRAM:
     819              :             {
     820              :                 const data_diagram_t *const diag
     821            0 :                     = ctrl_undo_redo_entry_get_diagram_before_action_const( probe );
     822            0 :                 assert( data_diagram_is_valid( diag ) );
     823            0 :                 display_diag_nav = data_diagram_get_parent_data_id( diag );
     824              :             }
     825            0 :             break;
     826              : 
     827            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_CREATE_DIAGRAM:
     828              :             {
     829              :                 const data_diagram_t *const diag
     830            0 :                     = ctrl_undo_redo_entry_get_diagram_after_action_const( probe );
     831            0 :                 assert( data_diagram_is_valid( diag ) );
     832            0 :                 display_diag_nav = data_diagram_get_parent_data_id( diag );
     833              :             }
     834            0 :             break;
     835              : 
     836            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_UPDATE_DIAGRAM:
     837              :             {
     838              :                 const data_diagram_t *const diag
     839            0 :                     = ctrl_undo_redo_entry_get_diagram_after_action_const( probe );
     840            0 :                 assert( data_diagram_is_valid( diag ) );
     841            0 :                 display_diag_edit = data_diagram_get_data_id( diag );
     842              :             }
     843            0 :             break;
     844              : 
     845            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_DELETE_DIAGRAMELEMENT:
     846              :             {
     847              :                 const data_diagramelement_t *const diagele
     848            0 :                     = ctrl_undo_redo_entry_get_diagramelement_before_action_const( probe );
     849            0 :                 assert( data_diagramelement_is_valid( diagele ) );
     850            0 :                 display_diag_edit = data_diagramelement_get_diagram_data_id( diagele );
     851              :             }
     852            0 :             break;
     853              : 
     854            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_CREATE_DIAGRAMELEMENT:  /* ... or ... */
     855              :             case CTRL_UNDO_REDO_ENTRY_TYPE_UPDATE_DIAGRAMELEMENT:
     856              :             {
     857              :                 const data_diagramelement_t *const diagele
     858            0 :                     = ctrl_undo_redo_entry_get_diagramelement_after_action_const( probe );
     859            0 :                 assert( data_diagramelement_is_valid( diagele ) );
     860            0 :                 display_diag_edit = data_diagramelement_get_diagram_data_id( diagele );
     861              :             }
     862            0 :             break;
     863              : 
     864            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_DELETE_CLASSIFIER:  /* ... or ... */
     865              :             case CTRL_UNDO_REDO_ENTRY_TYPE_CREATE_CLASSIFIER:
     866              :             {
     867              :                 /* Nothing to do: When a classifier is created or deleted, also */
     868              :                 /* a diagramelement is created or deleted. */
     869              :             }
     870            0 :             break;
     871              : 
     872            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_UPDATE_CLASSIFIER:
     873              :             {
     874              :                 const data_classifier_t *const classifier
     875            0 :                     = ctrl_undo_redo_entry_get_classifier_after_action_const( probe );
     876            0 :                 assert( data_classifier_is_valid( classifier ) );
     877            0 :                 display_classifier = data_classifier_get_data_id( classifier );
     878              :             }
     879            0 :             break;
     880              : 
     881            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_DELETE_FEATURE:
     882              :             {
     883              :                 const data_feature_t *const feature
     884            0 :                     = ctrl_undo_redo_entry_get_feature_before_action_const( probe );
     885            0 :                 assert( data_feature_is_valid( feature ) );
     886            0 :                 display_classifier = data_feature_get_classifier_data_id( feature );
     887              :             }
     888            0 :             break;
     889              : 
     890            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_UPDATE_FEATURE:  /* ... or ... */
     891              :             case CTRL_UNDO_REDO_ENTRY_TYPE_CREATE_FEATURE:
     892              :             {
     893              :                 const data_feature_t *const feature
     894            0 :                     = ctrl_undo_redo_entry_get_feature_after_action_const( probe );
     895            0 :                 assert( data_feature_is_valid( feature ) );
     896            0 :                 display_classifier = data_feature_get_classifier_data_id( feature );
     897              :             }
     898            0 :             break;
     899              : 
     900            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_DELETE_RELATIONSHIP:
     901              :             {
     902              :                 const data_relationship_t *const relationship
     903            0 :                     = ctrl_undo_redo_entry_get_relationship_before_action_const( probe );
     904            0 :                 assert( data_relationship_is_valid( relationship ) );
     905            0 :                 display_classifier = data_relationship_get_from_classifier_data_id( relationship );
     906              :             }
     907            0 :             break;
     908              : 
     909            0 :             case CTRL_UNDO_REDO_ENTRY_TYPE_UPDATE_RELATIONSHIP:  /* ... or ... */
     910              :             case CTRL_UNDO_REDO_ENTRY_TYPE_CREATE_RELATIONSHIP:
     911              :             {
     912              :                 const data_relationship_t *const relationship
     913            0 :                     = ctrl_undo_redo_entry_get_relationship_after_action_const( probe );
     914            0 :                 assert( data_relationship_is_valid( relationship ) );
     915            0 :                 display_classifier = data_relationship_get_from_classifier_data_id( relationship );
     916              :             }
     917            0 :             break;
     918              : 
     919            0 :             default:  /* ... or ... */
     920              :             case CTRL_UNDO_REDO_ENTRY_TYPE_BOUNDARY:
     921              :             {
     922            0 :                 U8_LOG_WARNING( "gui_toolbox_private_show_changes runs into unexpected switch-case." );
     923            0 :                 assert( false );
     924              :             }
     925              :             break;
     926              :         }
     927              :     }
     928              : 
     929            0 :     if ( data_id_is_valid( &display_diag_nav ) )
     930              :     {
     931            0 :         gui_toolbox_set_selected_tool_and_focus( this_, GUI_TOOL_NAVIGATE, display_diag_nav );
     932              :     }
     933            0 :     else if ( data_id_is_valid( &display_diag_edit ) )
     934              :     {
     935            0 :         gui_toolbox_set_selected_tool_and_focus( this_, GUI_TOOL_EDIT, display_diag_edit );
     936              :     }
     937            0 :     else if ( data_id_is_valid( &display_classifier ) )
     938              :     {
     939              :         /* try to find ANY diagram that MAY show the modified object: */
     940            0 :         assert( data_id_get_table( &display_classifier ) == DATA_TABLE_CLASSIFIER );
     941              :         data_small_set_t diagram_ids;
     942            0 :         data_small_set_init( &diagram_ids );
     943              :         const u8_error_t d_err
     944            0 :             =  data_database_reader_get_diagram_ids_by_classifier_id( (*this_).db_reader,
     945              :                                                                       data_id_get_row_id( &display_classifier ),
     946              :                                                                       &diagram_ids
     947              :                                                                     );
     948            0 :         if (( d_err == U8_ERROR_NONE )||( d_err == U8_ERROR_ARRAY_BUFFER_EXCEEDED ))
     949              :         {
     950            0 :             if ( data_small_set_contains( &diagram_ids, gui_marked_set_get_focused_diagram( (*this_).marker ) ) )
     951              :             {
     952              :                 /* the right diagram is already shown, just update the tool */
     953            0 :                 gui_toolbox_set_selected_tool( this_, GUI_TOOL_EDIT );
     954              :             }
     955            0 :             else if ( ! data_small_set_is_empty( &diagram_ids ) )
     956              :             {
     957            0 :                 gui_toolbox_set_selected_tool_and_focus( this_, GUI_TOOL_EDIT, data_small_set_get_id( &diagram_ids, 0 ) );
     958              :             }
     959              :             else
     960              :             {
     961            0 :                 U8_LOG_ANOMALY( "gui_toolbox_private_show_changes found a classifier without a diagram." );
     962              :             }
     963              :         }
     964            0 :         data_small_set_destroy( &diagram_ids );
     965              :     }
     966              :     else
     967              :     {
     968            0 :         U8_LOG_ANOMALY( "gui_toolbox_private_show_changes did not find a diagram to show the changes." );
     969              :     }
     970              : 
     971            0 :     U8_TRACE_END();
     972            0 : }
     973              : 
     974            0 : void gui_toolbox_private_notify_listeners( gui_toolbox_t *this_ )
     975              : {
     976            0 :     U8_TRACE_BEGIN();
     977              : 
     978            0 :     U8_TRACE_INFO( "g_signal_emit to listeners" );
     979            0 :     g_signal_emit( (*this_).toolbar, gui_toolbox_glib_signal_id, 0, (*this_).selected_tool );
     980              : 
     981            0 :     U8_TRACE_END();
     982            0 : }
     983              : 
     984              : 
     985              : /*
     986              : Copyright 2016-2025 Andreas Warnke
     987              : 
     988              : Licensed under the Apache License, Version 2.0 (the "License");
     989              : you may not use this file except in compliance with the License.
     990              : You may obtain a copy of the License at
     991              : 
     992              :     http://www.apache.org/licenses/LICENSE-2.0
     993              : 
     994              : Unless required by applicable law or agreed to in writing, software
     995              : distributed under the License is distributed on an "AS IS" BASIS,
     996              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     997              : See the License for the specific language governing permissions and
     998              : limitations under the License.
     999              : */
        

Generated by: LCOV version 2.0-1