LCOV - code coverage report
Current view: top level - gui/source - gui_toolbox.c (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.61.0_covts Lines: 0 451 0.0 %
Date: 2024-10-26 21:44:38 Functions: 0 28 0.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 <gtk/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_id_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_id_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-2024 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 1.16