LCOV - code coverage report
Current view: top level - gui/source - gui_main_window.c (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.67.0_covts Lines: 0.0 % 620 0
Test Date: 2025-11-06 17:22:08 Functions: 0.0 % 18 0

            Line data    Source code
       1              : /* File: gui_main_window.c; Copyright and License: see below */
       2              : 
       3              : #include "gui_main_window.h"
       4              : #include "gui_clipboard.h"
       5              : #include "gui_type_resource.h"
       6              : #include "u8/u8_trace.h"
       7              : #include "entity/data_diagram_type.h"
       8              : #include "entity/data_classifier_type.h"
       9              : #include "entity/data_feature_type.h"
      10              : #include "entity/data_relationship_type.h"
      11              : #include "storage/data_database.h"
      12              : #include "storage/data_change_notifier.h"
      13              : #include "meta/meta_info.h"
      14              : #include "gui_gtk.h"
      15              : #include "gui_gdk.h"
      16              : #include <stdio.h>
      17              : #include <stdbool.h>
      18              : 
      19            0 : void gui_main_window_init( gui_main_window_t *this_,
      20              :                            ctrl_controller_t *controller,
      21              :                            io_data_file_t *data_file,
      22              :                            data_database_reader_t *db_reader,
      23              :                            const gui_resources_t *resources,
      24              :                            GtkApplication *gtk_app,
      25              :                            observer_t *window_close_observer,
      26              :                            observer_t *window_open_observer )
      27              : {
      28            0 :     U8_TRACE_BEGIN();
      29            0 :     assert( gtk_app != NULL );
      30              : 
      31              :     /* init own attributes */
      32            0 :     (*this_).window_close_observer = window_close_observer;
      33            0 :     (*this_).window_open_observer = window_open_observer;
      34            0 :     (*this_).data_file = data_file;
      35            0 :     (*this_).resources = resources;
      36              : 
      37              :     /* init window */
      38              :     {
      39            0 :         (*this_).window = gtk_application_window_new( gtk_app );
      40              :         const char *window_title;
      41            0 :         window_title = io_data_file_get_filename_const( data_file );
      42            0 :         gtk_window_set_title(GTK_WINDOW( (*this_).window ), ( window_title == NULL ) ? META_INFO_PROGRAM_NAME_STR : window_title );
      43            0 :         gtk_widget_set_size_request( (*this_).window, 800, 400 );
      44            0 :         gtk_window_set_default_size( GTK_WINDOW( (*this_).window ), 16*70, 9*70 );
      45              :     }
      46              : 
      47              :     /* init the message widgets */
      48            0 :     gui_main_window_private_init_simple_message_to_user( this_ );
      49            0 :     gui_simple_message_to_user_init( &((*this_).message_to_user), (*this_).message_text_label, (*this_).message_icon_image, resources );
      50              : 
      51              :     /* init the keyboard shortcuts */
      52              :     {
      53            0 :         (*this_).keyboard_shortcut_ctrl = GTK_SHORTCUT_CONTROLLER(gtk_shortcut_controller_new());
      54            0 :         gtk_widget_add_controller( (*this_).window, GTK_EVENT_CONTROLLER((*this_).keyboard_shortcut_ctrl) );
      55              :     }
      56              : 
      57              :     /* init tools */
      58            0 :     gui_main_window_private_init_toolbox( this_ );
      59              : 
      60              :     /* determine the current/main clipboard */
      61            0 :     GdkClipboard *current_clipboard = NULL;
      62              :     {
      63            0 :         current_clipboard = gtk_widget_get_clipboard( GTK_WIDGET((*this_).window) );  /* idea taken from gtk demo */
      64              :     }
      65              : 
      66            0 :     gui_marked_set_init( &((*this_).marker_data),
      67            0 :                          G_OBJECT((*this_).window),
      68              :                          &gui_sketch_area_show_diagram,
      69            0 :                          &((*this_).sketcharea_data)
      70              :                        );
      71            0 :     gui_toolbox_init( &((*this_).tools_data),
      72            0 :                       GTK_WIDGET( (*this_).tool_row ),
      73            0 :                       gui_button_get_widget_ptr( &((*this_).view_navigate) ),
      74            0 :                       gui_button_get_widget_ptr( &((*this_).view_edit) ),
      75            0 :                       gui_button_get_widget_ptr( &((*this_).view_create) ),
      76            0 :                       gui_button_get_widget_ptr( &((*this_).view_search) ),
      77              :                       current_clipboard,
      78              :                       &((*this_).marker_data),
      79              :                       &((*this_).message_to_user),
      80              :                       db_reader,
      81              :                       controller
      82              :                     );
      83              : 
      84              :     /* init search widgets and sketch area */
      85              :     observer_t search_result_observer;
      86            0 :     observer_init( &search_result_observer,
      87            0 :                    &((*this_).sketcharea_data),
      88              :                    (void(*)(void*,void*))&gui_sketch_area_show_result_list,
      89              :                    "search_results_available"
      90              :                  );
      91            0 :     gui_main_window_private_init_search_and_sketch_area( this_ );
      92            0 :     gui_search_runner_init( &((*this_).search_runner),
      93              :                             &((*this_).message_to_user),
      94              :                             db_reader,
      95              :                             io_data_file_get_database_ptr( data_file ),
      96              :                             search_result_observer
      97              :                           );
      98            0 :     gui_search_request_init( &((*this_).search_request),
      99              :                              (*this_).search_label,
     100              :                              (*this_).search_entry,
     101              :                              (*this_).search_button,
     102              :                              &((*this_).marker_data),
     103              :                              &((*this_).search_runner)
     104              :                            );
     105            0 :     gui_sketch_area_init( &((*this_).sketcharea_data),
     106              :                           (*this_).sketcharea,
     107              :                           &((*this_).marker_data),
     108              :                           &((*this_).tools_data),
     109              :                           &((*this_).search_runner),
     110              :                           &((*this_).message_to_user),
     111              :                           resources,
     112              :                           controller,
     113              :                           db_reader
     114              :                         );
     115              : 
     116              :     /* init attribute editor widgets */
     117            0 :     gui_main_window_private_init_attributes_editor( this_ );
     118              : 
     119            0 :     gui_attributes_editor_init( &((*this_).attributes_editor),
     120            0 :                                 GTK_LABEL( (*this_).id_label ),
     121            0 :                                 GTK_ENTRY( (*this_).name_entry ),
     122            0 :                                 GTK_ENTRY( (*this_).stereotype_entry ),
     123              :                                 (*this_).type_dropdown,
     124            0 :                                 GTK_WIDGET( (*this_).type_diag_grid ),
     125            0 :                                 GTK_WIDGET( (*this_).type_clas_grid ),
     126            0 :                                 GTK_WIDGET( (*this_).type_feat_grid ),
     127            0 :                                 GTK_WIDGET( (*this_).type_rel_grid ),
     128            0 :                                 GTK_TEXT_VIEW( (*this_).description_text_view ),
     129            0 :                                 gui_button_get_button_ptr( &((*this_).file_save ) ),
     130              :                                 resources,
     131              :                                 controller,
     132              :                                 db_reader,
     133              :                                 io_data_file_get_database_ptr( data_file ),
     134              :                                 &((*this_).message_to_user)
     135              :                               );
     136              : 
     137              :     /* init the file choosers */
     138            0 :     gui_file_action_init( &((*this_).file_action),
     139              :                           controller,
     140              :                           data_file,
     141              :                           &((*this_).message_to_user)
     142              :                         );
     143            0 :     gui_file_use_db_dialog_init( &((*this_).file_use_db_dialog),
     144            0 :                                  GTK_WINDOW( (*this_).window ),
     145              :                                  &((*this_).file_action)
     146              :                                );
     147            0 :     gui_file_export_dialog_init( &((*this_).file_export_dialog),
     148              :                                  io_data_file_get_database_ptr( data_file ),
     149              :                                  db_reader,
     150              :                                  (*this_).resources,
     151            0 :                                  GTK_WINDOW( (*this_).window ),
     152              :                                  &((*this_).message_to_user)
     153              :                                );
     154              : 
     155            0 :     U8_TRACE_INFO("GTK+ Widgets are created.");
     156              : 
     157            0 :     (*this_).two_panes = gtk_paned_new( GTK_ORIENTATION_HORIZONTAL );
     158            0 :     gtk_paned_set_start_child( GTK_PANED((*this_).two_panes), (*this_).sketch_stack_column );
     159            0 :     gtk_paned_set_resize_start_child( GTK_PANED((*this_).two_panes), true );
     160            0 :     gtk_paned_set_shrink_start_child( GTK_PANED((*this_).two_panes), false );
     161            0 :     gtk_paned_set_end_child( GTK_PANED((*this_).two_panes), (*this_).attr_edit_column );
     162            0 :     gtk_paned_set_resize_end_child( GTK_PANED((*this_).two_panes), false );
     163            0 :     gtk_paned_set_shrink_end_child( GTK_PANED((*this_).two_panes), true );
     164            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).sketch_stack_column ), true );
     165            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).sketch_stack_column ), true );
     166            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).attr_edit_column ), true );
     167            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).attr_edit_column ), false );
     168            0 :     gtk_paned_set_position( GTK_PANED((*this_).two_panes), 11*70 );
     169              : 
     170            0 :     (*this_).main_stack_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 0 );
     171            0 :     gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).tool_row) );
     172            0 :     (*this_).options_layout = gui_file_export_dialog_get_options( &((*this_).file_export_dialog) );
     173            0 :     gtk_box_append( GTK_BOX((*this_).main_stack_column), (*this_).options_layout );
     174            0 :     gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).two_panes) );
     175            0 :     gtk_box_append( GTK_BOX((*this_).main_stack_column), GTK_WIDGET((*this_).message_row) );
     176            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).tool_row ), false );
     177            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).tool_row ), true );
     178            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).two_panes ), true );
     179            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).two_panes ), true );
     180            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_row ), false );
     181            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_row ), true );
     182              : 
     183            0 :     gtk_window_set_child( GTK_WINDOW((*this_).window), (*this_).main_stack_column );
     184            0 :     gtk_window_set_resizable( GTK_WINDOW((*this_).window), true );
     185              : 
     186            0 :     U8_TRACE_INFO("GTK+ Widgets are added to containers.");
     187              : 
     188              :     /* inject dependencies by signals */
     189              :     /* parameter info: g_signal_connect( instance-that-emits-the-signal, signal-name, callback-handler, data-to-be-passed-to-callback-handler) */
     190            0 :     g_signal_connect( G_OBJECT((*this_).window), "close-request", G_CALLBACK(gui_main_window_delete_event_callback), this_ );
     191            0 :     g_signal_connect( G_OBJECT((*this_).window), "destroy", G_CALLBACK(gui_main_window_destroy_event_callback), this_ );
     192            0 :     g_signal_connect( G_OBJECT((*this_).window), "state-flags-changed", G_CALLBACK( gui_main_window_state_callback ), this_ );
     193            0 :     g_signal_connect( G_OBJECT((*this_).window), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_main_window_data_changed_callback), this_ );
     194            0 :     g_signal_connect( G_OBJECT((*this_).sketcharea), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_sketch_area_data_changed_callback), &((*this_).sketcharea_data) );
     195            0 :     g_signal_connect( G_OBJECT((*this_).tool_row), GUI_TOOLBOX_GLIB_SIGNAL_NAME, G_CALLBACK(gui_sketch_area_tool_changed_callback), &((*this_).sketcharea_data) );
     196            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_new) ), "clicked", G_CALLBACK(gui_main_window_new_db_btn_callback), this_ );
     197            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_open) ), "clicked", G_CALLBACK(gui_main_window_open_db_btn_callback), this_ );
     198            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_save) ), "clicked", G_CALLBACK(gui_main_window_save_btn_callback), this_ );
     199            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).file_export) ), "clicked", G_CALLBACK(gui_main_window_export_btn_callback), this_ );
     200              : 
     201            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_new_window) ), "clicked", G_CALLBACK(gui_main_window_new_window_btn_callback), this_ );
     202              : 
     203            0 :     gui_toolbox_t *const tools = &((*this_).tools_data);
     204            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_navigate) ), "clicked", G_CALLBACK(gui_toolbox_navigate_btn_callback), tools );
     205            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_edit) ), "clicked", G_CALLBACK(gui_toolbox_edit_btn_callback), tools );
     206            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_create) ), "clicked", G_CALLBACK(gui_toolbox_create_btn_callback), tools );
     207            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).view_search) ), "clicked", G_CALLBACK(gui_toolbox_search_btn_callback), tools );
     208              : 
     209              :     /* The search id button is connected to two callback functions: one to switch to search mode, one to perform a search: */
     210            0 :     g_signal_connect( G_OBJECT((*this_).id_search_btn),
     211              :                       "clicked",
     212              :                       G_CALLBACK(gui_toolbox_search_id_btn_callback),
     213              :                       tools
     214              :                     );
     215            0 :     g_signal_connect( G_OBJECT((*this_).id_search_btn),
     216              :                       "clicked",
     217              :                       G_CALLBACK(gui_search_request_id_search_callback),
     218              :                       &((*this_).search_request)
     219              :                     );
     220              : 
     221            0 :     g_signal_connect( G_OBJECT((*this_).tool_row), GUI_TOOLBOX_GLIB_SIGNAL_NAME, G_CALLBACK(gui_search_request_tool_changed_callback), &((*this_).search_request) );
     222            0 :     g_signal_connect( G_OBJECT((*this_).search_entry), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_search_request_data_changed_callback), &((*this_).search_request) );
     223            0 :     g_signal_connect( G_OBJECT((*this_).search_entry), "activate", G_CALLBACK(gui_search_request_search_start_callback), &((*this_).search_request) );
     224            0 :     g_signal_connect( G_OBJECT((*this_).search_button), "clicked", G_CALLBACK(gui_search_request_search_start_callback), &((*this_).search_request) );
     225              : 
     226            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_undo) ), "clicked", G_CALLBACK(gui_toolbox_undo_btn_callback), tools );
     227            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_redo) ), "clicked", G_CALLBACK(gui_toolbox_redo_btn_callback), tools );
     228            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_cut) ), "clicked", G_CALLBACK(gui_toolbox_cut_btn_callback), tools );
     229            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_copy) ), "clicked", G_CALLBACK(gui_toolbox_copy_btn_callback), tools );
     230            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_paste) ), "clicked", G_CALLBACK(gui_toolbox_paste_btn_callback), tools );
     231            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_delete) ), "clicked", G_CALLBACK(gui_toolbox_delete_btn_callback), tools );
     232            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_instantiate) ), "clicked", G_CALLBACK(gui_toolbox_instantiate_btn_callback), tools );
     233            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_highlight) ), "clicked", G_CALLBACK(gui_toolbox_highlight_btn_callback), tools );
     234            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).edit_reset) ), "clicked", G_CALLBACK(gui_toolbox_reset_btn_callback), tools );
     235              : 
     236            0 :     g_signal_connect( G_OBJECT((*this_).name_entry),
     237              :                       "activate",
     238              :                       G_CALLBACK(gui_attributes_editor_name_enter_callback),
     239              :                       &((*this_).attributes_editor)
     240              :                     );
     241              :     {
     242            0 :         GtkEventControllerFocus *evt_focus_n = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
     243            0 :         g_signal_connect( evt_focus_n,
     244              :                           "leave",
     245              :                           G_CALLBACK(gui_attributes_editor_name_focus_left_callback),
     246              :                           &((*this_).attributes_editor)
     247              :                         );
     248            0 :         gtk_widget_add_controller( (*this_).name_entry, GTK_EVENT_CONTROLLER(evt_focus_n) );
     249              :     }
     250              :     {
     251            0 :         GtkEventControllerFocus *evt_focus_s = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
     252            0 :         g_signal_connect( evt_focus_s,
     253              :                           "leave",
     254              :                           G_CALLBACK(gui_attributes_editor_stereotype_focus_left_callback),
     255              :                           &((*this_).attributes_editor)
     256              :                         );
     257            0 :         gtk_widget_add_controller( (*this_).stereotype_entry, GTK_EVENT_CONTROLLER(evt_focus_s) );
     258              :     }
     259              :     {
     260            0 :         GtkEventControllerFocus *evt_focus_d = GTK_EVENT_CONTROLLER_FOCUS(gtk_event_controller_focus_new());
     261            0 :         g_signal_connect( evt_focus_d,
     262              :                           "leave",
     263              :                           G_CALLBACK(gui_attributes_editor_description_focus_left_callback),
     264              :                           &((*this_).attributes_editor)
     265              :                         );
     266            0 :         gtk_widget_add_controller( (*this_).description_text_view, GTK_EVENT_CONTROLLER(evt_focus_d) );
     267              :     }
     268            0 :     g_signal_connect( G_OBJECT((*this_).stereotype_entry), "activate", G_CALLBACK(gui_attributes_editor_stereotype_enter_callback), &((*this_).attributes_editor) );
     269            0 :     g_signal_connect_after( G_OBJECT((*this_).type_dropdown), "notify::selected", G_CALLBACK(gui_attributes_editor_type_changed_callback), &((*this_).attributes_editor));
     270            0 :     for( int_fast32_t diag_idx = 0; diag_idx < GUI_TYPE_RESOURCE_LIST_DIAGRAMS; diag_idx ++ )
     271              :     {
     272            0 :         g_signal_connect( G_OBJECT((*this_).type_diag_btn[ diag_idx ]),
     273              :                           "clicked",
     274              :                           G_CALLBACK( gui_attributes_editor_type_of_diagram_btn_callback ),
     275              :                           &((*this_).type_diag_data[diag_idx])
     276              :                         );
     277              :     }
     278            0 :     for( int_fast32_t clas_idx = 0; clas_idx < GUI_TYPE_RESOURCE_LIST_CLASSIFIERS; clas_idx ++ )
     279              :     {
     280            0 :         g_signal_connect( G_OBJECT((*this_).type_clas_btn[ clas_idx ]),
     281              :                           "clicked",
     282              :                           G_CALLBACK( gui_attributes_editor_type_of_classifier_btn_callback ),
     283              :                           &((*this_).type_clas_data[clas_idx])
     284              :                         );
     285              :     }
     286            0 :     for( int_fast32_t feat_idx = 0; feat_idx < GUI_TYPE_RESOURCE_LIST_INV_FEATURES; feat_idx ++ )
     287              :     {
     288            0 :         g_signal_connect( G_OBJECT((*this_).type_feat_btn[ feat_idx ]),
     289              :                           "clicked",
     290              :                           G_CALLBACK( gui_attributes_editor_type_of_feature_btn_callback ),
     291              :                           &((*this_).type_feat_data[feat_idx])
     292              :                         );
     293              :     }
     294            0 :     for( int_fast32_t rel_idx = 0; rel_idx < GUI_TYPE_RESOURCE_LIST_RELATIONS; rel_idx ++ )
     295              :     {
     296            0 :         g_signal_connect( G_OBJECT((*this_).type_rel_btn[ rel_idx ]),
     297              :                           "clicked",
     298              :                           G_CALLBACK( gui_attributes_editor_type_of_relationship_btn_callback ),
     299              :                           &((*this_).type_rel_data[rel_idx])
     300              :                         );
     301              :     }
     302            0 :     g_signal_connect( G_OBJECT((*this_).window), GUI_MARKED_SET_GLIB_SIGNAL_NAME, G_CALLBACK(gui_attributes_editor_focused_object_changed_callback), &((*this_).attributes_editor) );
     303            0 :     g_signal_connect( G_OBJECT((*this_).name_entry), DATA_CHANGE_NOTIFIER_GLIB_SIGNAL_NAME, G_CALLBACK(gui_attributes_editor_data_changed_callback), &((*this_).attributes_editor) );
     304              :         /* ^-- name_entry is the  proxy for all widgets of attributes_editor */
     305              : 
     306            0 :     g_signal_connect( gui_button_get_widget_ptr( &((*this_).help_about) ), "clicked", G_CALLBACK(gui_main_window_about_btn_callback), this_ );
     307              : 
     308            0 :     U8_TRACE_INFO("GTK+ Callbacks are connected to widget events.");
     309              : 
     310              :     /* register observers */
     311              : 
     312            0 :     (*this_).data_notifier = data_database_get_notifier_ptr( io_data_file_get_database_ptr( data_file ) );
     313            0 :     data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).window) );
     314            0 :     data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).sketcharea) );
     315            0 :     data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).name_entry) );
     316              :         /* ^-- name_entry is the  proxy for all widgets of attributes_editor */
     317            0 :     data_change_notifier_add_listener( (*this_).data_notifier, G_OBJECT((*this_).search_entry) );
     318              : 
     319            0 :     U8_TRACE_INFO("GTK+ Widgets are registered as listeners at signal emitter.");
     320              : 
     321            0 :     gtk_widget_set_visible( (*this_).window, TRUE );
     322            0 :     gtk_widget_set_sensitive( GTK_WIDGET((*this_).window), TRUE );  /* idea taken from gtk demo */
     323              : 
     324            0 :     GdkSurface *surface = gtk_native_get_surface( GTK_NATIVE((*this_).window) );
     325            0 :     gdk_surface_set_cursor( surface, NULL );  /* idea taken from gtk3->4 guide */
     326              : 
     327            0 :     gui_attributes_editor_update_widgets( &((*this_).attributes_editor) );  /* hide some widgets again */
     328              : #ifdef NDEBUG
     329              :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
     330              : #else
     331            0 :     gui_simple_message_to_user_show_message ( &((*this_).message_to_user), GUI_SIMPLE_MESSAGE_TYPE_INFO, GUI_SIMPLE_MESSAGE_CONTENT_DEBUG_MODE );
     332              : #endif
     333            0 :     gui_search_request_hide( &((*this_).search_request) );
     334            0 :     U8_TRACE_INFO("GTK+ Widgets are shown.");
     335            0 :     U8_TRACE_END();
     336            0 : }
     337              : 
     338            0 : void gui_main_window_destroy( gui_main_window_t *this_ )
     339              : {
     340            0 :     U8_TRACE_BEGIN();
     341              : 
     342              :     /* Note: The widgets may be destroyed already. A cast by G_OBJECT is therefore illegal. */
     343            0 :     data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).window );
     344            0 :     data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).name_entry );
     345            0 :     data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).sketcharea );
     346            0 :     data_change_notifier_remove_listener( (*this_).data_notifier, (GObject*)(*this_).search_entry );
     347              : 
     348            0 :     U8_TRACE_INFO("GTK+ Widgets are unregistered as listeners from data module.");
     349            0 :     gui_file_export_dialog_destroy ( &((*this_).file_export_dialog) );
     350            0 :     gui_file_use_db_dialog_destroy ( &((*this_).file_use_db_dialog) );
     351            0 :     U8_TRACE_INFO("GTK+ hidden windows are destroyed.");
     352            0 :     gui_file_action_destroy( &((*this_).file_action) );
     353              : 
     354            0 :     gui_search_request_destroy( &((*this_).search_request) );
     355            0 :     gui_search_runner_destroy( &((*this_).search_runner) );
     356            0 :     gui_sketch_area_destroy( &((*this_).sketcharea_data) );
     357            0 :     gui_toolbox_destroy( &((*this_).tools_data) );
     358            0 :     gui_marked_set_destroy( &((*this_).marker_data) );
     359            0 :     gui_attributes_editor_destroy( &((*this_).attributes_editor) );
     360            0 :     gui_simple_message_to_user_destroy( &((*this_).message_to_user) );
     361            0 :     (*this_).data_file = NULL;
     362            0 :     (*this_).resources = NULL;
     363              : 
     364            0 :     gui_button_destroy( &((*this_).file_new) );
     365            0 :     gui_button_destroy( &((*this_).file_open) );
     366            0 :     gui_button_destroy( &((*this_).file_save) );
     367            0 :     gui_button_destroy( &((*this_).file_export) );
     368            0 :     gui_button_destroy( &((*this_).view_new_window) );
     369            0 :     gui_button_destroy( &((*this_).view_navigate) );
     370            0 :     gui_button_destroy( &((*this_).view_edit) );
     371            0 :     gui_button_destroy( &((*this_).view_create) );
     372            0 :     gui_button_destroy( &((*this_).view_search) );
     373            0 :     gui_button_destroy( &((*this_).edit_undo) );
     374            0 :     gui_button_destroy( &((*this_).edit_redo) );
     375            0 :     gui_button_destroy( &((*this_).edit_cut) );
     376            0 :     gui_button_destroy( &((*this_).edit_copy) );
     377            0 :     gui_button_destroy( &((*this_).edit_paste) );
     378            0 :     gui_button_destroy( &((*this_).edit_delete) );
     379            0 :     gui_button_destroy( &((*this_).edit_instantiate) );
     380            0 :     gui_button_destroy( &((*this_).edit_highlight) );
     381            0 :     gui_button_destroy( &((*this_).edit_reset) );
     382            0 :     gui_button_destroy( &((*this_).help_about) );
     383              : 
     384            0 :     U8_TRACE_END();
     385            0 : }
     386              : 
     387            0 : static inline void gtk_button_set_image( GtkButton *btn, GtkWidget *icon )
     388              : {
     389            0 :     gtk_button_set_child( btn, icon );
     390            0 : }
     391              : 
     392            0 : void gui_main_window_private_init_toolbox( gui_main_window_t *this_ )
     393              : {
     394            0 :     U8_TRACE_BEGIN();
     395            0 :     const gui_resources_t *const res = (*this_).resources;
     396              : 
     397            0 :     gui_button_init( &((*this_).file_new),
     398            0 :                      GDK_PAINTABLE( gui_resources_get_file_new( res ) ),
     399              :                      "new",
     400              :                      "New..."
     401              :                     );
     402              : 
     403            0 :     gui_button_init( &((*this_).file_open),
     404            0 :                      GDK_PAINTABLE( gui_resources_get_file_open( res ) ),
     405              :                      "open",
     406              :                      "Open..."
     407              :                     );
     408              : 
     409              :     /* save icon depends if latest changes are already saved */
     410            0 :     const bool is_saved = io_data_file_is_in_sync( (*this_).data_file );
     411            0 :     gui_button_init( &((*this_).file_save),
     412              :                      is_saved
     413            0 :                      ? GDK_PAINTABLE( gui_resources_get_file_saved( res ) )
     414            0 :                      : GDK_PAINTABLE( gui_resources_get_file_save( res ) ),
     415              :                      "save",
     416              :                      "Save (Ctrl-S)"
     417              :                     );
     418            0 :     GtkShortcutTrigger *commit_trig = gtk_shortcut_trigger_parse_string( "<Control>S" );
     419            0 :     GtkShortcutAction *commit_act = gtk_callback_action_new( &gui_main_window_save_shortcut_callback,
     420              :                                                              this_,
     421              :                                                              NULL
     422              :                                                            );
     423            0 :     GtkShortcut* ctrl_s = gtk_shortcut_new_with_arguments( commit_trig,
     424              :                                                            commit_act,
     425              :                                                            NULL /* = format_string */
     426              :                                                          );
     427            0 :     gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_s );
     428              : 
     429            0 :     gui_button_init( &((*this_).file_export),
     430            0 :                      GDK_PAINTABLE( gui_resources_get_file_export( res ) ),
     431              :                      "export",
     432              :                      "Export..."
     433              :                     );
     434              : 
     435            0 :     (*this_).tool_sect_1_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_tool_sect( res ) ) );
     436            0 :     gtk_image_set_pixel_size( GTK_IMAGE((*this_).tool_sect_1_icon), 32 /*=max(w,h)*/ );
     437            0 :     gtk_widget_set_halign( (*this_).tool_sect_1_icon, GTK_ALIGN_START );
     438              : 
     439            0 :     gui_button_init( &((*this_).view_new_window),
     440            0 :                      GDK_PAINTABLE( gui_resources_get_view_new_window( res ) ),
     441              :                      "win",
     442              :                      "New Window"
     443              :                     );
     444              : 
     445            0 :     gui_button_init_toggle( &((*this_).view_navigate),
     446            0 :                             GDK_PAINTABLE( gui_resources_get_view_navigate( res ) ),
     447              :                             "nav",
     448              :                             "Navigate"
     449              :                            );
     450              : 
     451            0 :     gui_button_init_toggle( &((*this_).view_edit),
     452            0 :                             GDK_PAINTABLE( gui_resources_get_view_edit( res ) ),
     453              :                             "edit",
     454              :                             "Edit"
     455              :                            );
     456            0 :     gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_edit) ) ),
     457            0 :                                  GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_navigate) ) )
     458              :                                );
     459              : 
     460            0 :     gui_button_init_toggle( &((*this_).view_create),
     461            0 :                             GDK_PAINTABLE( gui_resources_get_view_create( res ) ),
     462              :                             "create",
     463              :                             "Create"
     464              :                            );
     465            0 :     gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_create) ) ),
     466            0 :                                  GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_edit) ) )
     467              :                                );
     468              : 
     469            0 :     gui_button_init_toggle( &((*this_).view_search),
     470            0 :                             GDK_PAINTABLE( gui_resources_get_view_search( res ) ),
     471              :                             "search",
     472              :                             "Search"
     473              :                            );
     474            0 :     gtk_toggle_button_set_group( GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_search) ) ),
     475            0 :                                  GTK_TOGGLE_BUTTON( gui_button_get_widget_ptr( &((*this_).view_create) ) )
     476              :                                );
     477              : 
     478            0 :     (*this_).tool_sect_2_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_tool_sect( res ) ) );
     479            0 :     gtk_image_set_pixel_size( GTK_IMAGE((*this_).tool_sect_2_icon), 32 /*=max(w,h)*/ );
     480            0 :     gtk_widget_set_halign( (*this_).tool_sect_2_icon, GTK_ALIGN_START );
     481              : 
     482            0 :     gui_button_init( &((*this_).edit_undo),
     483            0 :                      GDK_PAINTABLE( gui_resources_get_edit_undo( res ) ),
     484              :                      "undo",
     485              :                      "Undo (Ctrl-Z)"
     486              :                     );
     487            0 :     GtkShortcutTrigger *undo_trig = gtk_shortcut_trigger_parse_string( "<Control>Z" );
     488            0 :     GtkShortcutAction *undo_act = gtk_callback_action_new( &gui_toolbox_undo_shortcut_callback,
     489            0 :                                                            &((*this_).tools_data),
     490              :                                                            NULL
     491              :                                                          );
     492            0 :     GtkShortcut* ctrl_z = gtk_shortcut_new_with_arguments( undo_trig,
     493              :                                                            undo_act,
     494              :                                                            NULL /* = format_string */
     495              :                                                          );
     496            0 :     gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_z );
     497              : 
     498            0 :     gui_button_init( &((*this_).edit_redo),
     499            0 :                      GDK_PAINTABLE( gui_resources_get_edit_redo( res ) ),
     500              :                      "redo",
     501              :                      "Redo (Ctrl-Y)"
     502              :                    );
     503            0 :     GtkShortcutTrigger *redo_trig = gtk_shortcut_trigger_parse_string( "<Control>Y" );
     504            0 :     GtkShortcutAction *redo_act = gtk_callback_action_new( &gui_toolbox_redo_shortcut_callback,
     505            0 :                                                            &((*this_).tools_data),
     506              :                                                            NULL
     507              :                                                          );
     508            0 :     GtkShortcut* ctrl_y = gtk_shortcut_new_with_arguments( redo_trig,
     509              :                                                            redo_act,
     510              :                                                            NULL /* = format_string */
     511              :                                                          );
     512            0 :     gtk_shortcut_controller_add_shortcut( (*this_).keyboard_shortcut_ctrl, ctrl_y );
     513              : 
     514            0 :     gui_button_init( &((*this_).edit_cut),
     515            0 :                      GDK_PAINTABLE( gui_resources_get_edit_cut( res ) ),
     516              :                      "cut",
     517              :                      "Cut (Ctrl-X)"
     518              :                    );
     519              :     /*
     520              :     GDK_KEY_x + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
     521              :     moved there to not interfere with text input fields
     522              :     */
     523              : 
     524            0 :     gui_button_init( &((*this_).edit_copy),
     525            0 :                      GDK_PAINTABLE( gui_resources_get_edit_copy( res ) ),
     526              :                      "copy",
     527              :                      "Copy (Ctrl-C)"
     528              :                    );
     529              :     /*
     530              :     GDK_KEY_c + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
     531              :     moved there to not interfere with text input fields
     532              :     */
     533              : 
     534            0 :     gui_button_init( &((*this_).edit_paste),
     535            0 :                      GDK_PAINTABLE( gui_resources_get_edit_paste( res ) ),
     536              :                      "paste",
     537              :                      "Paste (Ctrl-V)"
     538              :                    );
     539              :     /*
     540              :     GK_KEY_v + GDK_CONTROL_MASK handling see gui_sketch_area_key_press_callback();
     541              :     moved there to not interfere with text input fields
     542              :     */
     543              : 
     544            0 :     gui_button_init( &((*this_).edit_delete),
     545            0 :                      GDK_PAINTABLE( gui_resources_get_edit_delete( res ) ),
     546              :                      "del",
     547              :                      "Delete (DEL)"
     548              :                    );
     549              :     /*
     550              :     GDK_KEY_Delete handling see gui_sketch_area_key_press_callback();
     551              :     moved there to not interfere with text input fields
     552              :     */
     553              : 
     554            0 :     gui_button_init( &((*this_).edit_instantiate),
     555            0 :                      GDK_PAINTABLE( gui_resources_get_edit_instantiate( res ) ),
     556              :                      "inst",
     557              :                      "Instantiate"
     558              :                    );
     559              : 
     560            0 :     gui_button_init( &((*this_).edit_highlight),
     561            0 :                      GDK_PAINTABLE( gui_resources_get_edit_highlight( res ) ),
     562              :                      "mark",
     563              :                      "Mark"
     564              :                    );
     565              : 
     566            0 :     gui_button_init( &((*this_).edit_reset),
     567            0 :                      GDK_PAINTABLE( gui_resources_get_edit_reset( res ) ),
     568              :                      "zero",
     569              :                      "Reset Selection"
     570              :                    );
     571              : 
     572            0 :     gui_button_init( &((*this_).help_about),
     573            0 :                      GDK_PAINTABLE( gui_resources_get_crystal_facet_uml( res ) ),
     574              :                      "info",
     575              :                      "About"
     576              :                    );
     577              : 
     578              :     /* insert widgets to box container */
     579              :     {
     580            0 :         (*this_).tool_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 4 );
     581            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_new) ) );
     582            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_open) ) );
     583            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_save) ) );
     584            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).file_export) ) );
     585            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), GTK_WIDGET((*this_).tool_sect_1_icon) );
     586            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_new_window) ) );
     587            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_search) ) );
     588            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_navigate) ) );
     589            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_edit) ) );
     590            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).view_create) ) );
     591            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), GTK_WIDGET((*this_).tool_sect_2_icon) );
     592            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_undo) ) );
     593            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_redo) ) );
     594            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_cut) ) );
     595            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_copy) ) );
     596            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_paste) ) );
     597            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_delete) ) );
     598            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_instantiate) ) );
     599            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_highlight) ) );
     600            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).edit_reset) ) );
     601            0 :         gtk_box_append( GTK_BOX((*this_).tool_row), gui_button_get_widget_ptr( &((*this_).help_about) ) );
     602              :     }
     603              : 
     604            0 :     U8_TRACE_END();
     605            0 : }
     606              : 
     607            0 : void gui_main_window_private_init_attributes_editor( gui_main_window_t *this_ )
     608              : {
     609            0 :     U8_TRACE_BEGIN();
     610            0 :     const gui_resources_t *const res = (*this_).resources;
     611              : 
     612            0 :     (*this_).attr_section_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_edit_attributes_sect( res ) ) );
     613            0 :     gtk_widget_set_margin_start( GTK_WIDGET((*this_).attr_section_icon), 8 );
     614            0 :     gtk_widget_set_margin_end( GTK_WIDGET((*this_).attr_section_icon), 8 );
     615            0 :     gtk_widget_set_margin_top( GTK_WIDGET((*this_).attr_section_icon), 0 );
     616            0 :     gtk_widget_set_margin_bottom( GTK_WIDGET((*this_).attr_section_icon), 0 );
     617            0 :     gtk_image_set_pixel_size( GTK_IMAGE((*this_).attr_section_icon), 32 /*=max(w,h)*/ );
     618            0 :     gtk_widget_set_halign( (*this_).attr_section_icon, GTK_ALIGN_START );
     619              : 
     620            0 :     (*this_).id_label = gtk_label_new( "" );
     621            0 :     gtk_label_set_selectable( GTK_LABEL( (*this_).id_label ), true );
     622            0 :     (*this_).name_label = gtk_label_new( "Name:" );
     623            0 :     (*this_).description_label = gtk_label_new( "Description:" );
     624            0 :     (*this_).stereotype_label = gtk_label_new( "Stereotype:" );
     625            0 :     (*this_).type_label = gtk_label_new( "Type:" );
     626            0 :     gtk_label_set_xalign( GTK_LABEL( (*this_).id_label ), 1.0 ); /* align right */
     627            0 :     gtk_label_set_xalign( GTK_LABEL( (*this_).name_label ), 0.0 );
     628            0 :     gtk_label_set_xalign( GTK_LABEL( (*this_).description_label ), 0.0 );
     629            0 :     gtk_label_set_xalign( GTK_LABEL( (*this_).stereotype_label ), 0.0 );
     630            0 :     gtk_label_set_xalign( GTK_LABEL( (*this_).type_label ), 0.0 );
     631              : 
     632            0 :     (*this_).id_search_btn = gtk_button_new();
     633            0 :     (*this_).id_search_btn_icon = gtk_image_new_from_paintable( GDK_PAINTABLE( gui_resources_get_view_search_now( res ) ) );
     634            0 :     gtk_image_set_pixel_size( GTK_IMAGE((*this_).id_search_btn_icon), 32 /*=max(w,h)*/ );
     635            0 :     gtk_button_set_image( GTK_BUTTON((*this_).id_search_btn), (*this_).id_search_btn_icon );
     636            0 :     gtk_widget_set_tooltip_text( GTK_WIDGET((*this_).id_search_btn), "Find Occurrences" );
     637            0 :     gtk_widget_set_size_request( GTK_WIDGET((*this_).id_search_btn_icon), 32 /*=w*/ , 32 /*=h*/ );
     638              : 
     639              :     /* insert widgets to box container */
     640              :     {
     641            0 :         (*this_).id_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 8 );
     642            0 :         gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).attr_section_icon) );
     643            0 :         gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).id_label) );
     644            0 :         gtk_box_append( GTK_BOX((*this_).id_row), GTK_WIDGET((*this_).id_search_btn) );
     645              : 
     646            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).attr_section_icon ), false );
     647            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).attr_section_icon ), false );
     648            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).id_label ), false );
     649            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).id_label ), true );
     650            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).id_search_btn ), false );
     651            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).id_search_btn ), false );
     652              :     }
     653              : 
     654            0 :     (*this_).name_entry = gtk_entry_new();
     655              : 
     656            0 :     (*this_).stereotype_entry = gtk_entry_new();
     657              : 
     658            0 :     (*this_).description_text_view = gtk_text_view_new();
     659            0 :     gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( (*this_).description_text_view ),
     660              :                                  GTK_WRAP_WORD_CHAR
     661              :                                );
     662            0 :     gtk_widget_set_vexpand( GTK_WIDGET( (*this_).description_text_view ), true );
     663            0 :     gtk_widget_set_hexpand( GTK_WIDGET( (*this_).description_text_view ), false );
     664              :     //gtk_widget_set_size_request( GTK_WIDGET((*this_).description_text_view), 128 /*=w*/ , 48 /*=h*/ );
     665              :     /* need own scroll window container */
     666            0 :     gtk_text_view_set_bottom_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
     667            0 :     gtk_text_view_set_left_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
     668            0 :     gtk_text_view_set_right_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
     669            0 :     gtk_text_view_set_top_margin( GTK_TEXT_VIEW( (*this_).description_text_view ), 12 );
     670            0 :     (*this_).description_scroll_win = gtk_scrolled_window_new();
     671            0 :     gtk_scrolled_window_set_child( GTK_SCROLLED_WINDOW((*this_).description_scroll_win), (*this_).description_text_view );
     672            0 :     gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( (*this_).description_scroll_win ),
     673              :                                     GTK_POLICY_AUTOMATIC,
     674              :                                     GTK_POLICY_AUTOMATIC
     675              :                                   );
     676              : 
     677            0 :     GListStore *model = NULL;  /* the model is set later */
     678            0 :     GtkExpression *expression = NULL;  /* not needed: there is no search entry that could find list elements */
     679            0 :     (*this_).type_dropdown = GTK_DROP_DOWN( gtk_drop_down_new ( G_LIST_MODEL( model ), expression ) );
     680            0 :     GtkBuilderScope *scope = gtk_builder_cscope_new();
     681              :     static const char bytes[] =
     682              :     "<interface>\n"
     683              :     "<template class=\"GtkListItem\">\n"
     684              :     "  <property name=\"child\">\n"
     685              :     "    <object class=\"GtkPaned\">\n"
     686              :     "      <property name=\"start-child\">\n"
     687              :     "        <object class=\"GtkImage\">\n"
     688              :     "          <property name=\"pixel-size\">32</property>\n"
     689              :     "          <binding name=\"paintable\">\n"
     690              :     "            <lookup name=\"icon\" type=\"GuiTypeResource\">\n"
     691              :     "              <lookup name=\"item\">GtkListItem</lookup>\n"
     692              :     "            </lookup>\n"
     693              :     "          </binding>\n"
     694              :     "        </object>\n"
     695              :     "      </property>\n"
     696              :     "      <property name=\"end-child\">\n"
     697              :     "        <object class=\"GtkLabel\">\n"
     698              :     "          <property name=\"xalign\">0</property>\n"
     699              :     "          <binding name=\"label\">\n"
     700              :     "            <lookup name=\"name\" type=\"GuiTypeResource\">\n"
     701              :     "              <lookup name=\"item\">GtkListItem</lookup>\n"
     702              :     "            </lookup>\n"
     703              :     "          </binding>\n"
     704              :     "        </object>\n"
     705              :     "      </property>\n"
     706              :     "      <property name=\"position\">48</property>\n"
     707              :     "    </object>\n"
     708              :     "  </property>\n"
     709              :     "</template>\n"
     710              :     "</interface>\n";
     711            0 :     GBytes *byteptr = g_bytes_new( &bytes, sizeof(bytes)-sizeof(char) );
     712            0 :     GtkListItemFactory *factory = gtk_builder_list_item_factory_new_from_bytes( scope, byteptr );
     713            0 :     gtk_drop_down_set_factory( (*this_).type_dropdown, factory );
     714            0 :     g_object_unref( scope );
     715            0 :     g_object_unref( factory );
     716            0 :     g_bytes_unref( byteptr );
     717              : 
     718              :     static gui_type_resource_list_t res_select;
     719            0 :     gui_type_resource_list_init( &res_select, res );
     720              :     {
     721            0 :         (*this_).type_diag_grid = GTK_GRID( gtk_grid_new() );
     722            0 :         gtk_widget_set_halign( GTK_WIDGET( (*this_).type_diag_grid ), GTK_ALIGN_END );
     723              :         const gui_type_resource_t (*diag_data)[];
     724              :         unsigned int diag_data_length;
     725            0 :         gui_type_resource_list_get_all_diagram_types( &res_select, &diag_data, &diag_data_length );
     726            0 :         assert( diag_data_length == GUI_TYPE_RESOURCE_LIST_DIAGRAMS );
     727            0 :         for( int_fast32_t diag_idx = 0; diag_idx < GUI_TYPE_RESOURCE_LIST_DIAGRAMS; diag_idx ++ )
     728              :         {
     729            0 :             const gui_type_resource_t *const type_data = &((*diag_data)[diag_idx]);
     730            0 :             const data_diagram_type_t diag_type = data_type_get_diagram_type( gui_type_resource_get_type_id( type_data ) );
     731            0 :             GdkTexture *const diag_icon = gui_type_resource_get_icon( type_data );
     732            0 :             const char *const diag_name = gui_type_resource_get_name( type_data );
     733              : 
     734            0 :             gui_attribute_type_of_diagram_init( &((*this_).type_diag_data[diag_idx]), diag_type, &((*this_).attributes_editor) );
     735            0 :             (*this_).type_diag_img[ diag_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( diag_icon ) ) );
     736            0 :             gtk_image_set_pixel_size( GTK_IMAGE((*this_).type_diag_img[ diag_idx ]), 32 /*=max(w,h)*/ );
     737            0 :             (*this_).type_diag_btn[ diag_idx ] = GTK_BUTTON( gtk_button_new() );
     738            0 :             gtk_button_set_image( (*this_).type_diag_btn[ diag_idx ], GTK_WIDGET( (*this_).type_diag_img[ diag_idx ] ) );
     739            0 :             gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_diag_btn[ diag_idx ] ), diag_name );
     740            0 :             gtk_grid_attach( (*this_).type_diag_grid, GTK_WIDGET( (*this_).type_diag_btn[ diag_idx ] ), diag_idx%7, diag_idx/7, 1, 1 );
     741              :         }
     742              : 
     743            0 :         (*this_).type_clas_grid = GTK_GRID( gtk_grid_new() );
     744            0 :         gtk_widget_set_halign( GTK_WIDGET( (*this_).type_clas_grid ), GTK_ALIGN_END );
     745              :         const gui_type_resource_t (*clas_data)[];
     746              :         unsigned int clas_data_length;
     747            0 :         gui_type_resource_list_get_all_classifier_types( &res_select, &clas_data, &clas_data_length );
     748            0 :         assert( clas_data_length == GUI_TYPE_RESOURCE_LIST_CLASSIFIERS );
     749            0 :         for( int_fast32_t clas_idx = 0; clas_idx < GUI_TYPE_RESOURCE_LIST_CLASSIFIERS; clas_idx ++ )
     750              :         {
     751            0 :             const gui_type_resource_t *const type_data = &((*clas_data)[clas_idx]);
     752            0 :             const data_classifier_type_t clas_type = data_type_get_classifier_type( gui_type_resource_get_type_id( type_data ) );
     753            0 :             GdkTexture *const clas_icon = gui_type_resource_get_icon( type_data );
     754            0 :             const char *const clas_name = gui_type_resource_get_name( type_data );
     755              : 
     756            0 :             gui_attribute_type_of_classifier_init( &((*this_).type_clas_data[clas_idx]), clas_type, &((*this_).attributes_editor) );
     757            0 :             (*this_).type_clas_img[ clas_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( clas_icon ) ) );
     758            0 :             gtk_image_set_pixel_size( GTK_IMAGE((*this_).type_clas_img[ clas_idx ]), 32 /*=max(w,h)*/ );
     759            0 :             (*this_).type_clas_btn[ clas_idx ] = GTK_BUTTON( gtk_button_new() );
     760            0 :             gtk_button_set_image( (*this_).type_clas_btn[ clas_idx ], GTK_WIDGET( (*this_).type_clas_img[ clas_idx ] ) );
     761            0 :             gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_clas_btn[ clas_idx ] ), clas_name );
     762            0 :             gtk_grid_attach( (*this_).type_clas_grid, GTK_WIDGET( (*this_).type_clas_btn[ clas_idx ] ), clas_idx%7, clas_idx/7, 1, 1 );
     763              :         }
     764              : 
     765            0 :         (*this_).type_feat_grid = GTK_GRID( gtk_grid_new() );
     766            0 :         gtk_widget_set_halign( GTK_WIDGET( (*this_).type_feat_grid ), GTK_ALIGN_END );
     767              :         const gui_type_resource_t (*feat_data)[];
     768              :         unsigned int feat_data_length;
     769            0 :         gui_type_resource_list_get_invariant_feature_types( &res_select, &feat_data, &feat_data_length );
     770            0 :         assert( feat_data_length == GUI_TYPE_RESOURCE_LIST_INV_FEATURES );
     771            0 :         for( int_fast32_t feat_idx = 0; feat_idx < GUI_TYPE_RESOURCE_LIST_INV_FEATURES; feat_idx ++ )  /* ignore the lifeline */
     772              :         {
     773            0 :             const gui_type_resource_t *const type_data = &((*feat_data)[feat_idx]);
     774            0 :             const data_feature_type_t feat_type = data_type_get_feature_type( gui_type_resource_get_type_id( type_data ) );
     775            0 :             GdkTexture *const feat_icon = gui_type_resource_get_icon( type_data );
     776            0 :             const char *const feat_name = gui_type_resource_get_name( type_data );
     777              : 
     778            0 :             gui_attribute_type_of_feature_init( &((*this_).type_feat_data[feat_idx]), feat_type, &((*this_).attributes_editor) );
     779            0 :             (*this_).type_feat_img[ feat_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( feat_icon ) ) );
     780            0 :             gtk_image_set_pixel_size( GTK_IMAGE((*this_).type_feat_img[ feat_idx ]), 32 /*=max(w,h)*/ );
     781            0 :             (*this_).type_feat_btn[ feat_idx ] = GTK_BUTTON( gtk_button_new() );
     782            0 :             gtk_button_set_image( (*this_).type_feat_btn[ feat_idx ], GTK_WIDGET( (*this_).type_feat_img[ feat_idx ] ) );
     783            0 :             gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_feat_btn[ feat_idx ] ), feat_name );
     784            0 :             gtk_grid_attach( (*this_).type_feat_grid, GTK_WIDGET( (*this_).type_feat_btn[ feat_idx ] ), feat_idx%7, feat_idx/7, 1, 1 );
     785              :         }
     786              : 
     787            0 :         (*this_).type_rel_grid = GTK_GRID( gtk_grid_new() );
     788            0 :         gtk_widget_set_halign( GTK_WIDGET( (*this_).type_rel_grid ), GTK_ALIGN_END );
     789              :         const gui_type_resource_t (*rel_data)[];
     790              :         unsigned int rel_data_length;
     791            0 :         gui_type_resource_list_get_all_relationship_types( &res_select, &rel_data, &rel_data_length );
     792            0 :         assert( rel_data_length == GUI_TYPE_RESOURCE_LIST_RELATIONS );
     793            0 :         for( int_fast32_t rel_idx = 0; rel_idx < GUI_TYPE_RESOURCE_LIST_RELATIONS; rel_idx ++ )
     794              :         {
     795            0 :             const gui_type_resource_t *const type_data = &((*rel_data)[rel_idx]);
     796            0 :             const data_relationship_type_t rel_type = data_type_get_relationship_type( gui_type_resource_get_type_id( type_data ) );
     797            0 :             GdkTexture *const rel_icon = gui_type_resource_get_icon( type_data );
     798            0 :             const char *const rel_name = gui_type_resource_get_name( type_data );
     799              : 
     800            0 :             gui_attribute_type_of_relationship_init( &((*this_).type_rel_data[rel_idx]), rel_type, &((*this_).attributes_editor) );
     801            0 :             (*this_).type_rel_img[ rel_idx ] = GTK_IMAGE( gtk_image_new_from_paintable( GDK_PAINTABLE( rel_icon ) ) );
     802            0 :             gtk_image_set_pixel_size( GTK_IMAGE((*this_).type_rel_img[ rel_idx ]), 32 /*=max(w,h)*/ );
     803            0 :             (*this_).type_rel_btn[ rel_idx ] = GTK_BUTTON( gtk_button_new() );
     804            0 :             gtk_button_set_image( (*this_).type_rel_btn[ rel_idx ], GTK_WIDGET( (*this_).type_rel_img[ rel_idx ] ) );
     805            0 :             gtk_widget_set_tooltip_text( GTK_WIDGET( (*this_).type_rel_btn[ rel_idx ] ), rel_name );
     806            0 :             gtk_grid_attach( (*this_).type_rel_grid, GTK_WIDGET( (*this_).type_rel_btn[ rel_idx ] ), rel_idx%7, rel_idx/7, 1, 1 );
     807              :         }
     808              :     }
     809            0 :     gui_type_resource_list_destroy( &res_select );
     810              : 
     811              :     /* insert widgets to box container */
     812              :     {
     813            0 :         (*this_).attr_edit_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 4 );
     814            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).id_row) );
     815            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).name_label) );
     816            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).name_entry) );
     817            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).stereotype_label) );
     818            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).stereotype_entry) );
     819            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_label) );
     820            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_dropdown) );
     821            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_diag_grid) );
     822            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_clas_grid) );
     823            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_feat_grid) );
     824            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).type_rel_grid) );
     825            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).description_label) );
     826            0 :         gtk_box_append( GTK_BOX((*this_).attr_edit_column), GTK_WIDGET((*this_).description_scroll_win) );
     827              : 
     828            0 :         gtk_widget_set_vexpand( GTK_WIDGET( (*this_).description_scroll_win ), true );
     829            0 :         gtk_widget_set_hexpand( GTK_WIDGET( (*this_).description_scroll_win ), true );
     830              :     }
     831              : 
     832            0 :     U8_TRACE_END();
     833            0 : }
     834              : 
     835            0 : void gui_main_window_private_init_simple_message_to_user( gui_main_window_t *this_ )
     836              : {
     837            0 :     U8_TRACE_BEGIN();
     838            0 :     const gui_resources_t *const res = (*this_).resources;
     839              : 
     840            0 :     (*this_).message_text_label = gtk_label_new( "" );
     841            0 :     gtk_label_set_xalign(GTK_LABEL( (*this_).message_text_label ), 0.0 );
     842              : 
     843            0 :     (*this_).message_icon_image = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_crystal_facet_uml( res ) ) );
     844            0 :     gtk_image_set_pixel_size( GTK_IMAGE((*this_).message_icon_image), 32 /*=max(w,h)*/ );
     845            0 :     gtk_widget_set_margin_start( GTK_WIDGET((*this_).message_icon_image), 8 );
     846            0 :     gtk_widget_set_margin_end( GTK_WIDGET((*this_).message_icon_image), 8 );
     847            0 :     gtk_widget_set_margin_top( GTK_WIDGET((*this_).message_icon_image), 0 );
     848            0 :     gtk_widget_set_margin_bottom( GTK_WIDGET((*this_).message_icon_image), 0 );
     849              : 
     850              :     /* insert widgets to box container */
     851              :     {
     852            0 :         (*this_).message_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 20 );
     853            0 :         gtk_box_append( GTK_BOX((*this_).message_row), GTK_WIDGET((*this_).message_icon_image) );
     854            0 :         gtk_box_append( GTK_BOX((*this_).message_row), GTK_WIDGET((*this_).message_text_label) );
     855              : 
     856            0 :         gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_icon_image ), false );
     857            0 :         gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_icon_image ), false );
     858            0 :         gtk_widget_set_vexpand( GTK_WIDGET( (*this_).message_text_label ), false );
     859            0 :         gtk_widget_set_hexpand( GTK_WIDGET( (*this_).message_text_label ), true );
     860              :     }
     861              : 
     862            0 :     U8_TRACE_END();
     863            0 : }
     864              : 
     865            0 : void gui_main_window_private_init_search_and_sketch_area( gui_main_window_t *this_ )
     866              : {
     867            0 :     U8_TRACE_BEGIN();
     868            0 :     const gui_resources_t *const res = (*this_).resources;
     869              : 
     870              :     /* init search widgets */
     871              :     {
     872            0 :         (*this_).search_label = gtk_label_new ( "Search:" );
     873            0 :         gtk_label_set_xalign( GTK_LABEL( (*this_).search_label ), 1.0 ); /* align right */
     874            0 :         gtk_label_set_yalign( GTK_LABEL( (*this_).search_label ), 0.5 ); /* align middle-height */
     875              : 
     876            0 :         (*this_).search_entry = gtk_entry_new();
     877              : 
     878            0 :         (*this_).search_button = gtk_button_new();
     879            0 :         (*this_).search_btn_icon = gtk_image_new_from_paintable( GDK_PAINTABLE( gui_resources_get_view_search_now( res ) ) );
     880            0 :         gtk_image_set_pixel_size( GTK_IMAGE((*this_).search_btn_icon), 32 /*=max(w,h)*/ );
     881            0 :         gtk_button_set_image( GTK_BUTTON((*this_).search_button), (*this_).search_btn_icon );
     882            0 :         gtk_widget_set_tooltip_text( GTK_WIDGET((*this_).search_button), "Search" );
     883              :     }
     884              : 
     885              :     /* insert widgets to box container */
     886              :     {
     887            0 :         (*this_).search_row = gtk_box_new( GTK_ORIENTATION_HORIZONTAL, /*spacing:*/ 4 );
     888            0 :         gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_label) );
     889            0 :         gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_entry) );
     890            0 :         gtk_box_append( GTK_BOX((*this_).search_row), GTK_WIDGET((*this_).search_button) );
     891              : 
     892            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_label ), false );
     893            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_label ), false );
     894            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_entry ), false );
     895            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_entry ), true );
     896            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_button ), false );
     897            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_button ), false );
     898              :     }
     899              : 
     900              :     /* init sketch area */
     901              :     {
     902            0 :         (*this_).sketcharea = gtk_drawing_area_new();
     903            0 :         gtk_widget_set_can_focus( GTK_WIDGET( (*this_).sketcharea ), TRUE );  /* this allows the text entry widgets to lose the focus */
     904            0 :         gtk_widget_set_size_request( GTK_WIDGET( (*this_).sketcharea ), 600, 360);  /* set a minimum initial size */
     905              :         /*gtk_widget_set_focus_on_click( GTK_WIDGET( (*this_).sketcharea ), TRUE ); not yet existing: since GTK 3.2 */
     906              :     }
     907              : 
     908              :     /* insert widgets to box container */
     909              :     {
     910            0 :         (*this_).sketch_stack_column = gtk_box_new( GTK_ORIENTATION_VERTICAL, /*spacing:*/ 0 );
     911            0 :         gtk_box_append( GTK_BOX((*this_).sketch_stack_column), GTK_WIDGET((*this_).search_row) );
     912            0 :         gtk_box_append( GTK_BOX((*this_).sketch_stack_column), GTK_WIDGET((*this_).sketcharea) );
     913              : 
     914            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).search_row ), false );
     915            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).search_row ), true );
     916            0 :         gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).sketcharea ), true );
     917            0 :         gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).sketcharea ), true );
     918              :     }
     919              : 
     920            0 :     U8_TRACE_END();
     921            0 : }
     922              : 
     923            0 : void gui_main_window_destroy_event_callback( GtkWidget *widget, gpointer data )
     924              : {
     925            0 :     U8_TRACE_BEGIN();
     926            0 :     gui_main_window_t *this_ = data;
     927            0 :     assert( (*this_).window == (void*)widget );
     928              : 
     929              :     /* forward destroy request to gui_window_manager: */
     930            0 :     observer_notify( (*this_).window_close_observer, this_ );
     931              : 
     932            0 :     U8_TRACE_TIMESTAMP();
     933            0 :     U8_TRACE_END();
     934            0 : }
     935              : 
     936            0 : gboolean gui_main_window_delete_event_callback( GtkWindow *widget, gpointer data )
     937              : {
     938            0 :     U8_TRACE_BEGIN();
     939            0 :     gui_main_window_t *this_ = data;
     940            0 :     assert( (*this_).window == (void*)widget );
     941              :     (void) this_;  /* unused in case of NDEBUG */
     942              : 
     943            0 :     U8_TRACE_TIMESTAMP();
     944            0 :     U8_TRACE_END();
     945            0 :     return false;  /* return false to trigger destroy event */
     946              : }
     947              : 
     948            0 : void gui_main_window_new_db_btn_callback( GtkWidget* button, gpointer data )
     949              : {
     950            0 :     U8_TRACE_BEGIN();
     951            0 :     gui_main_window_t *this_ = data;
     952              : 
     953            0 :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
     954              : 
     955            0 :     gui_file_use_db_dialog_show( &((*this_).file_use_db_dialog), false /* open_existing*/ );
     956              : 
     957            0 :     U8_TRACE_TIMESTAMP();
     958            0 :     U8_TRACE_END();
     959            0 : }
     960              : 
     961            0 : void gui_main_window_open_db_btn_callback( GtkWidget* button, gpointer data )
     962              : {
     963            0 :     U8_TRACE_BEGIN();
     964            0 :     gui_main_window_t *this_ = data;
     965              : 
     966            0 :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
     967              : 
     968            0 :     gui_file_use_db_dialog_show( &((*this_).file_use_db_dialog), true /* open_existing*/ );
     969              : 
     970            0 :     U8_TRACE_TIMESTAMP();
     971            0 :     U8_TRACE_END();
     972            0 : }
     973              : 
     974            0 : void gui_main_window_save_btn_callback( GtkButton *button, gpointer user_data )
     975              : {
     976            0 :     U8_TRACE_BEGIN();
     977              :     gui_main_window_t *this_;
     978            0 :     this_ = (gui_main_window_t*) user_data;
     979            0 :     assert( this_ != NULL );
     980              : 
     981            0 :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
     982              : 
     983            0 :     gui_attributes_editor_commit_changes ( &((*this_).attributes_editor) );
     984              : 
     985            0 :     const u8_error_t err = gui_file_action_save( &((*this_).file_action) );
     986            0 :     if ( err == U8_ERROR_NONE )
     987              :     {
     988            0 :         GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
     989            0 :         const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
     990            0 :         GdkPaintable *const saved_icon = GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) );
     991            0 :         if ( shown_icon != saved_icon )
     992              :         {
     993            0 :             gtk_image_set_from_paintable( save_image, saved_icon );
     994            0 :             U8_TRACE_INFO("icon of save button set to SAVED(/)");
     995              :         }
     996              :     }
     997              : 
     998            0 :     U8_TRACE_TIMESTAMP();
     999            0 :     U8_TRACE_END();
    1000            0 : }
    1001              : 
    1002            0 : gboolean gui_main_window_save_shortcut_callback( GtkWidget* widget, GVariant* args, gpointer user_data )
    1003              : {
    1004            0 :     gui_main_window_save_btn_callback( (GtkButton*)widget, user_data );
    1005            0 :     return TRUE;
    1006              : }
    1007              : 
    1008            0 : void gui_main_window_export_btn_callback( GtkWidget* button, gpointer data )
    1009              : {
    1010            0 :     U8_TRACE_BEGIN();
    1011            0 :     gui_main_window_t *this_ = data;
    1012              : 
    1013            0 :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
    1014              : 
    1015            0 :     const bool was_visible = gtk_widget_get_visible( (*this_).options_layout );
    1016            0 :     gtk_widget_set_visible( (*this_).options_layout, ! was_visible );
    1017              : 
    1018            0 :     U8_TRACE_TIMESTAMP();
    1019            0 :     U8_TRACE_END();
    1020            0 : }
    1021              : 
    1022            0 : void gui_main_window_new_window_btn_callback( GtkWidget* button, gpointer data )
    1023              : {
    1024            0 :     U8_TRACE_BEGIN();
    1025            0 :     gui_main_window_t *this_ = data;
    1026              : 
    1027              :     /* hide last message */
    1028            0 :     gui_simple_message_to_user_hide( &((*this_).message_to_user) );
    1029              : 
    1030              :     /* forward new window request to gui_window_manager: */
    1031            0 :     observer_notify( (*this_).window_open_observer, &((*this_).message_to_user) );
    1032              : 
    1033            0 :     U8_TRACE_TIMESTAMP();
    1034            0 :     U8_TRACE_END();
    1035            0 : }
    1036              : 
    1037            0 : void gui_main_window_about_btn_callback( GtkWidget* button, gpointer data )
    1038              : {
    1039            0 :     U8_TRACE_BEGIN();
    1040            0 :     gui_main_window_t *this_ = data;
    1041              : 
    1042            0 :     if ( GUI_SIMPLE_MESSAGE_TYPE_ABOUT == gui_simple_message_to_user_get_type_id( &((*this_).message_to_user) ) )
    1043              :     {
    1044              :         /* hide the already visible about message */
    1045            0 :         gui_simple_message_to_user_hide( &((*this_).message_to_user) );
    1046              :     }
    1047              :     else
    1048              :     {
    1049            0 :         gui_simple_message_to_user_show_message( &((*this_).message_to_user),
    1050              :                                                  GUI_SIMPLE_MESSAGE_TYPE_ABOUT,
    1051              :                                                  GUI_SIMPLE_MESSAGE_CONTENT_ABOUT
    1052              :                                                );
    1053              :     }
    1054              : 
    1055            0 :     U8_TRACE_TIMESTAMP();
    1056            0 :     U8_TRACE_END();
    1057            0 : }
    1058              : 
    1059            0 : void gui_main_window_data_changed_callback( GtkWidget *window, data_change_message_t *msg, gpointer user_data )
    1060              : {
    1061            0 :     U8_TRACE_BEGIN();
    1062            0 :     gui_main_window_t *this_ = user_data;
    1063              : 
    1064              :     /* update the window title */
    1065            0 :     if (( DATA_CHANGE_EVENT_TYPE_DB_OPENED == data_change_message_get_event( msg ) )
    1066            0 :         || ( DATA_CHANGE_EVENT_TYPE_DB_CLOSED == data_change_message_get_event( msg ) ))
    1067              :     {
    1068              :         /* the database has changed */
    1069            0 :         const char *filename = io_data_file_get_filename_const( (*this_).data_file );
    1070            0 :         if ( NULL == filename )
    1071              :         {
    1072            0 :             gtk_window_set_title(GTK_WINDOW((*this_).window), META_INFO_PROGRAM_NAME_STR );
    1073              :         }
    1074              :         else
    1075              :         {
    1076            0 :             gtk_window_set_title(GTK_WINDOW((*this_).window), filename );
    1077              :         }
    1078              :     }
    1079              : 
    1080              :     /* update the save button status indicator */
    1081            0 :     GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
    1082            0 :     const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
    1083              : 
    1084            0 :     if (( DATA_CHANGE_EVENT_TYPE_DB_OPENED == data_change_message_get_event( msg ) )
    1085            0 :         || ( DATA_CHANGE_EVENT_TYPE_DB_CLOSED == data_change_message_get_event( msg ) ))
    1086            0 :     {
    1087            0 :         GdkPaintable *const saved_icon = GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) );
    1088            0 :         if ( shown_icon != saved_icon )
    1089              :         {
    1090            0 :             gtk_image_set_from_paintable( save_image, saved_icon );
    1091            0 :             U8_TRACE_INFO("icon of save button set to SAVED(/)");
    1092              :         }
    1093              :     }
    1094            0 :     else if ( DATA_CHANGE_EVENT_TYPE_REVISION_CHANGED == data_change_message_get_event( msg ) )
    1095              :     {
    1096              :         /* undo or redo caused a rewriting of the database revision */
    1097            0 :         const bool is_saved = io_data_file_is_in_sync( (*this_).data_file );
    1098            0 :         GdkPaintable *const save_icon
    1099              :             = is_saved
    1100            0 :             ? GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) )
    1101            0 :             : GDK_PAINTABLE( gui_resources_get_file_save( (*this_).resources ) );
    1102            0 :         if ( shown_icon != save_icon )
    1103              :         {
    1104            0 :             gtk_image_set_from_paintable( save_image, save_icon );
    1105            0 :             U8_TRACE_INFO("icon of save button set to NOT-SAVED(*)");
    1106              :         }
    1107              :     }
    1108            0 :     else if ( DATA_CHANGE_EVENT_TYPE_DB_PREPARE_CLOSE != data_change_message_get_event( msg ) )
    1109              :     {
    1110            0 :         GdkPaintable *const save_icon = GDK_PAINTABLE( gui_resources_get_file_save( (*this_).resources ) );
    1111            0 :         if ( shown_icon != save_icon )
    1112              :         {
    1113            0 :             gtk_image_set_from_paintable( save_image, save_icon );
    1114            0 :             U8_TRACE_INFO("icon of save button set to NOT-SAVED(*)");
    1115              :         }
    1116              :     }
    1117              : 
    1118            0 :     U8_TRACE_TIMESTAMP();
    1119            0 :     U8_TRACE_END();
    1120            0 : }
    1121              : 
    1122            0 : void gui_main_window_state_callback( GtkWidget* window, GtkStateFlags old_flags, gpointer user_data )
    1123              : {
    1124            0 :     U8_TRACE_BEGIN();
    1125            0 :     gui_main_window_t *this_ = user_data;
    1126              : 
    1127              :     /* GTK_STATE_FLAG_ACTIVE is close to what is needed */
    1128              :     /* but it is sometimes not called when window loses focus */
    1129              :     /* and it is sometimes activated multiple times when window gains focus */
    1130              : 
    1131            0 :     GtkStateFlags new_flags = gtk_widget_get_state_flags ( window );
    1132            0 :     GtkStateFlags changed = old_flags ^ new_flags;
    1133              : 
    1134            0 :     if ( 0 != ( changed & GTK_STATE_FLAG_BACKDROP ) )
    1135              :     {
    1136            0 :         U8_TRACE_INFO_INT("GTK_STATE_FLAGS & GTK_STATE_FLAG_BACKDROP:", changed & GTK_STATE_FLAG_BACKDROP );
    1137              : 
    1138              :         /* check if latest changes are already saved */
    1139            0 :         const bool is_saved = io_data_file_is_in_sync( (*this_).data_file );
    1140              : 
    1141              :         /* update the icon of the save button */
    1142            0 :         GtkImage *const save_image = gui_button_get_icon_ptr( &((*this_).file_save) );
    1143            0 :         const GdkPaintable *const shown_icon = gtk_image_get_paintable( save_image );
    1144              : 
    1145            0 :         GdkPaintable *const current_icon
    1146              :             = is_saved
    1147            0 :             ? GDK_PAINTABLE( gui_resources_get_file_saved( (*this_).resources ) )
    1148            0 :             : ( 0 != ( new_flags & GTK_STATE_FLAG_BACKDROP ) )
    1149            0 :             ? GDK_PAINTABLE( gui_resources_get_file_unsaved( (*this_).resources ) )
    1150            0 :             : GDK_PAINTABLE( gui_resources_get_file_save( (*this_).resources ) );
    1151              : 
    1152              :         /* update the save button status indicator */
    1153            0 :         if ( shown_icon != current_icon )
    1154              :         {
    1155            0 :             gtk_image_set_from_paintable( save_image, current_icon );
    1156            0 :             U8_TRACE_INFO("icon of save button updated");
    1157              :         }
    1158              :         // U8_TRACE_FLUSH();
    1159              : 
    1160              :         /* check if json file on disk was modified in the meantime */
    1161            0 :         const bool json_was_modified = io_data_file_is_externally_modified( (*this_).data_file );
    1162            0 :         if ( json_was_modified )
    1163              :         {
    1164            0 :             gui_simple_message_to_user_show_message_with_name( &((*this_).message_to_user),
    1165              :                                                                GUI_SIMPLE_MESSAGE_TYPE_ERROR,
    1166              :                                                                GUI_SIMPLE_MESSAGE_CONTENT_JSON_MODIFIED,
    1167            0 :                                                                io_data_file_get_filename_const( (*this_).data_file )
    1168              :                                                              );
    1169              :         }
    1170              : 
    1171              :     }
    1172              : 
    1173            0 :     U8_TRACE_TIMESTAMP();
    1174            0 :     U8_TRACE_END();
    1175            0 : }
    1176              : 
    1177              : 
    1178              : /*
    1179              : Copyright 2016-2025 Andreas Warnke
    1180              : 
    1181              : Licensed under the Apache License, Version 2.0 (the "License");
    1182              : you may not use this file except in compliance with the License.
    1183              : You may obtain a copy of the License at
    1184              : 
    1185              :     http://www.apache.org/licenses/LICENSE-2.0
    1186              : 
    1187              : Unless required by applicable law or agreed to in writing, software
    1188              : distributed under the License is distributed on an "AS IS" BASIS,
    1189              : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    1190              : See the License for the specific language governing permissions and
    1191              : limitations under the License.
    1192              : */
        

Generated by: LCOV version 2.0-1