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