Line data Source code
1 : /* File: gui_file_export_dialog.c; Copyright and License: see below */
2 :
3 : #include "gui_file_export_dialog.h"
4 : #include "set/data_stat.h"
5 : #include "u8/u8_trace.h"
6 : #include "utf8stringbuf/utf8string.h"
7 : #include "utf8stringbuf/utf8stringbuf.h"
8 : #include "gui_gtk.h"
9 : #include "gui_gdk.h"
10 : #include <stdio.h>
11 : #include <stdbool.h>
12 :
13 0 : void gui_file_export_dialog_init ( gui_file_export_dialog_t *this_,
14 : data_database_t *database,
15 : data_database_reader_t *db_reader,
16 : const gui_resources_t *resources,
17 : GtkWindow *parent_window,
18 : gui_simple_message_to_user_t *message_to_user )
19 : {
20 0 : U8_TRACE_BEGIN();
21 0 : assert( NULL != database );
22 0 : assert( NULL != db_reader );
23 0 : assert( NULL != parent_window );
24 0 : assert( NULL != message_to_user );
25 :
26 0 : (*this_).database = database;
27 0 : (*this_).parent_window = parent_window;
28 0 : (*this_).message_to_user = message_to_user;
29 :
30 0 : (*this_).format_docbook = gtk_check_button_new_with_label ("docbook");
31 0 : (*this_).format_html = gtk_check_button_new_with_label ("html");
32 0 : (*this_).format_xmi2 = gtk_check_button_new_with_label ("xmi");
33 0 : (*this_).format_json= gtk_check_button_new_with_label ("json");
34 :
35 0 : (*this_).format_pdf = gtk_check_button_new_with_label ("pdf");
36 0 : (*this_).format_png = gtk_check_button_new_with_label ("png");
37 0 : (*this_).format_ps = gtk_check_button_new_with_label ("ps");
38 0 : (*this_).format_svg = gtk_check_button_new_with_label ("svg");
39 0 : (*this_).format_txt = gtk_check_button_new_with_label ("txt");
40 :
41 0 : gtk_check_button_set_active( GTK_CHECK_BUTTON((*this_).format_html), TRUE );
42 :
43 0 : (*this_).options_layout = gtk_grid_new();
44 :
45 0 : (*this_).file_export_icon = gtk_image_new_from_paintable( GDK_PAINTABLE ( gui_resources_get_file_export( resources ) ) );
46 0 : gtk_widget_set_size_request( GTK_WIDGET((*this_).file_export_icon), 32 /*=w*/ , 32 /*=h*/ );
47 0 : gtk_widget_set_margin_start( GTK_WIDGET((*this_).file_export_icon), 192 );
48 0 : gtk_widget_set_margin_end( GTK_WIDGET((*this_).file_export_icon), 16 );
49 0 : gtk_widget_set_margin_top( GTK_WIDGET((*this_).file_export_icon), 0 );
50 0 : gtk_widget_set_margin_bottom( GTK_WIDGET((*this_).file_export_icon), 0 );
51 0 : gtk_image_set_pixel_size( GTK_IMAGE((*this_).file_export_icon), 32 /*=max(w,h)*/ );
52 0 : gtk_widget_set_halign( (*this_).file_export_icon, GTK_ALIGN_START );
53 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).file_export_icon ), false );
54 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).file_export_icon ), false );
55 :
56 0 : (*this_).diagram_set_label = gtk_label_new ( "Diagram-sets:" );
57 0 : (*this_).document_label = gtk_label_new ( "Documents:" );
58 0 : gtk_label_set_xalign (GTK_LABEL( (*this_).document_label ), 0.0 );
59 0 : gtk_label_set_xalign (GTK_LABEL( (*this_).diagram_set_label ), 0.0 );
60 0 : (*this_).export_button = GTK_BUTTON( gtk_button_new() );
61 0 : gtk_button_set_label( (*this_).export_button, "Export to folder..." );
62 0 : gtk_widget_set_vexpand ( GTK_WIDGET( (*this_).export_button ), false );
63 0 : gtk_widget_set_hexpand ( GTK_WIDGET( (*this_).export_button ), false );
64 :
65 : /* parameter info: gtk_grid_attach (GtkGrid *grid, GtkWidget *child, gint left, gint top, gint width, gint height); */
66 0 : gtk_grid_set_column_homogeneous ( GTK_GRID((*this_).options_layout), false );
67 0 : gtk_grid_set_row_homogeneous ( GTK_GRID((*this_).options_layout), false );
68 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).file_export_icon, 0, 0, 1, 2 );
69 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).diagram_set_label, 1, 0, 1, 1 );
70 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).document_label, 1, 1, 1, 1 );
71 :
72 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_docbook, 2, 1, 2, 1 );
73 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_html, 4, 1, 1, 1 );
74 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_json, 5, 1, 1, 1 );
75 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_xmi2, 6, 1, 2, 1 );
76 :
77 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_pdf, 2, 0, 1, 1 );
78 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_png, 3, 0, 1, 1 );
79 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_ps, 4, 0, 1, 1 );
80 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_svg, 5, 0, 1, 1 );
81 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), (*this_).format_txt, 6, 0, 1, 1 );
82 :
83 0 : gtk_grid_attach( GTK_GRID((*this_).options_layout), GTK_WIDGET( (*this_).export_button ), 8, 0, 1, 2 );
84 :
85 0 : gtk_widget_set_visible( (*this_).options_layout, FALSE );
86 :
87 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
88 : (*this_).export_file_chooser = gtk_file_chooser_dialog_new ( "Select Export Folder",
89 : parent_window,
90 : GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
91 : "Cancel",
92 : GTK_RESPONSE_CANCEL,
93 : "Export Files",
94 : GTK_RESPONSE_ACCEPT,
95 : NULL
96 : );
97 :
98 : #if 0
99 : GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG((*this_).export_file_chooser));
100 : gtk_box_append( GTK_BOX(content_area), GTK_WIDGET( (*this_).options_layout ) );
101 : /* no need to g_object_unref( content_area ); here */
102 : #endif
103 : #else
104 0 : (*this_).export_file_dialog = gtk_file_dialog_new();
105 0 : gtk_file_dialog_set_accept_label( (*this_).export_file_dialog, "Export Files" );
106 0 : gtk_file_dialog_set_modal( (*this_).export_file_dialog, false );
107 0 : gtk_file_dialog_set_title( (*this_).export_file_dialog, "Select Export Folder" );
108 : #endif
109 :
110 0 : io_exporter_init( &((*this_).file_exporter), db_reader );
111 :
112 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
113 : g_signal_connect( G_OBJECT((*this_).export_file_chooser),
114 : "response",
115 : G_CALLBACK(gui_file_export_dialog_response_callback),
116 : this_
117 : );
118 : gtk_window_set_hide_on_close( GTK_WINDOW((*this_).export_file_chooser), true);
119 : #else
120 : /* no signal at new FileDialog - this works with Async, see gtk_file_dialog_save */
121 : #endif
122 0 : g_signal_connect( G_OBJECT((*this_).export_button), "clicked", G_CALLBACK( gui_file_export_dialog_export_btn_callback ), this_ );
123 :
124 0 : U8_TRACE_END();
125 0 : }
126 :
127 0 : void gui_file_export_dialog_destroy( gui_file_export_dialog_t *this_ )
128 : {
129 0 : U8_TRACE_BEGIN();
130 :
131 : /* no need to g_object_unref ( (*this_).format_html ); here */
132 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
133 : gtk_window_destroy( GTK_WINDOW((*this_).export_file_chooser) );
134 : /* no need to g_object_unref ( (*this_).export_file_chooser ); here */
135 : #else
136 0 : g_object_unref( (*this_).export_file_dialog );
137 : #endif
138 :
139 0 : io_exporter_destroy( &((*this_).file_exporter) );
140 :
141 0 : (*this_).message_to_user = NULL;
142 0 : (*this_).parent_window = NULL;
143 0 : (*this_).database = NULL;
144 :
145 0 : U8_TRACE_END();
146 0 : }
147 :
148 0 : GtkWidget *gui_file_export_dialog_get_options( gui_file_export_dialog_t *this_ )
149 : {
150 0 : return GTK_WIDGET( (*this_).options_layout );
151 : }
152 :
153 0 : void gui_file_export_dialog_export_btn_callback( GtkWidget* button, gpointer data )
154 : {
155 0 : U8_TRACE_BEGIN();
156 0 : gui_file_export_dialog_t *this_ = data;
157 :
158 0 : gui_simple_message_to_user_hide( (*this_).message_to_user );
159 :
160 0 : gui_file_export_dialog_show ( this_ );
161 :
162 0 : U8_TRACE_TIMESTAMP();
163 0 : U8_TRACE_END();
164 0 : }
165 :
166 0 : void gui_file_export_dialog_show( gui_file_export_dialog_t *this_ )
167 : {
168 0 : U8_TRACE_BEGIN();
169 :
170 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
171 : gtk_widget_set_visible( GTK_WIDGET( (*this_).export_file_chooser ), TRUE );
172 : gtk_widget_set_sensitive( GTK_WIDGET((*this_).export_file_chooser), TRUE ); /* idea taken from gtk demo */
173 :
174 : GdkSurface *surface = gtk_native_get_surface( GTK_NATIVE((*this_).export_file_chooser) );
175 : gdk_surface_set_cursor( surface, NULL ); /* idea taken from gtk3->4 guide */
176 : #else
177 0 : gtk_file_dialog_select_folder( (*this_).export_file_dialog,
178 : (*this_).parent_window,
179 : NULL,
180 : &gui_file_export_dialog_async_ready_callback,
181 : this_
182 : );
183 : #endif
184 :
185 0 : U8_TRACE_END();
186 0 : }
187 :
188 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
189 :
190 : void gui_file_export_dialog_response_callback( GtkDialog *dialog, gint response_id, gpointer user_data )
191 : {
192 : U8_TRACE_BEGIN();
193 : gui_file_export_dialog_t *this_ = user_data;
194 :
195 : gtk_widget_set_visible( (*this_).options_layout, FALSE );
196 :
197 : switch ( response_id )
198 : {
199 : case GTK_RESPONSE_CANCEL:
200 : {
201 : U8_LOG_EVENT( "GTK_RESPONSE_CANCEL" );
202 : gtk_widget_set_visible( GTK_WIDGET ( dialog ), FALSE );
203 : }
204 : break;
205 :
206 : case GTK_RESPONSE_ACCEPT:
207 : {
208 : U8_LOG_EVENT( "GTK_RESPONSE_ACCEPT" );
209 : u8_error_t export_err = U8_ERROR_NONE;
210 : data_stat_t export_stat;
211 : data_stat_init ( &export_stat );
212 : io_file_format_t selected_format = IO_FILE_FORMAT_NONE;
213 :
214 : gchar *folder_path = NULL;
215 : GFile *selected_file = NULL;
216 : selected_file = gtk_file_chooser_get_file( GTK_FILE_CHOOSER(dialog) );
217 : if ( selected_file != NULL )
218 : {
219 : folder_path = g_file_get_path( selected_file );
220 : }
221 : gtk_widget_set_visible( GTK_WIDGET ( dialog ), FALSE );
222 : if ( folder_path != NULL )
223 : {
224 : U8_TRACE_INFO_STR( "chosen folder:", folder_path );
225 :
226 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_pdf) )) { selected_format |= IO_FILE_FORMAT_PDF; }
227 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_png) )) { selected_format |= IO_FILE_FORMAT_PNG; }
228 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_ps) )) { selected_format |= IO_FILE_FORMAT_PS; }
229 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_svg) )) { selected_format |= IO_FILE_FORMAT_SVG; }
230 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_txt) )) { selected_format |= IO_FILE_FORMAT_TXT; }
231 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_docbook) )) { selected_format |= IO_FILE_FORMAT_DOCBOOK; }
232 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_html) )) { selected_format |= IO_FILE_FORMAT_HTML; }
233 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_xmi2) )) { selected_format |= IO_FILE_FORMAT_XMI2; }
234 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_json) )) { selected_format |= IO_FILE_FORMAT_JSON; }
235 :
236 : /* react immediately */
237 : gui_simple_message_to_user_show_message_with_name( (*this_).message_to_user,
238 : GUI_SIMPLE_MESSAGE_TYPE_INFO,
239 : GUI_SIMPLE_MESSAGE_CONTENT_EXPORTING_WAIT,
240 : folder_path
241 : );
242 : bool events_handled = true;
243 : for ( uint_fast8_t max_loop = 40; events_handled && ( max_loop > 0 ); max_loop-- )
244 : {
245 : events_handled = g_main_context_iteration( NULL, /*may_block*/ FALSE );
246 : }
247 :
248 : /* determine the database file path for a document title and export: */
249 : const char *db_path = data_database_get_filename_ptr( (*this_).database );
250 : if ( data_database_is_open((*this_).database) )
251 : {
252 : export_err = io_exporter_export_files( &((*this_).file_exporter), selected_format, folder_path, db_path, &export_stat );
253 : }
254 : else
255 : {
256 : export_err = U8_ERROR_NO_DB;
257 : }
258 :
259 : /* finished, notify user */
260 : char temp_format_buf[64];
261 : utf8stringbuf_t temp_fileformat = UTF8STRINGBUF( temp_format_buf );
262 : io_file_format_to_string( selected_format, temp_fileformat );
263 :
264 : if ( U8_ERROR_NONE == export_err )
265 : {
266 : gui_simple_message_to_user_show_message_with_names_and_stat( (*this_).message_to_user,
267 : GUI_SIMPLE_MESSAGE_TYPE_INFO,
268 : GUI_SIMPLE_MESSAGE_CONTENT_EXPORT_FINISHED,
269 : utf8stringbuf_get_string( &temp_fileformat ),
270 : &export_stat
271 : );
272 :
273 : }
274 : else
275 : {
276 : gui_simple_message_to_user_show_message_with_name( (*this_).message_to_user,
277 : GUI_SIMPLE_MESSAGE_TYPE_ERROR,
278 : GUI_SIMPLE_MESSAGE_CONTENT_FILE_EXPORT_FAILED,
279 : folder_path
280 : );
281 : }
282 :
283 : g_free (folder_path);
284 : }
285 : else
286 : {
287 : U8_LOG_WARNING( "Export dialog returned no folder path" );
288 : }
289 : if ( selected_file != NULL )
290 : {
291 : g_object_unref( selected_file );
292 : }
293 : data_stat_trace( &export_stat );
294 : data_stat_destroy ( &export_stat );
295 : }
296 : break;
297 :
298 : case GTK_RESPONSE_DELETE_EVENT:
299 : {
300 : U8_LOG_EVENT( "GTK_RESPONSE_DELETE_EVENT" );
301 : }
302 : break;
303 :
304 : default:
305 : {
306 : U8_LOG_ERROR( "unexpected response_id" );
307 : }
308 : }
309 :
310 : U8_TRACE_END();
311 : }
312 :
313 : #else /* GTK >= 4.10 */
314 :
315 0 : void gui_file_export_dialog_async_ready_callback( GObject* source_object,
316 : GAsyncResult* res,
317 : gpointer user_data )
318 : {
319 0 : U8_TRACE_BEGIN();
320 :
321 0 : gui_file_export_dialog_t *this_ = user_data;
322 :
323 0 : gtk_widget_set_visible( (*this_).options_layout, FALSE );
324 :
325 0 : GError* error = NULL;
326 0 : GFile *result = gtk_file_dialog_select_folder_finish( GTK_FILE_DIALOG(source_object), res, &error );
327 0 : if ( error != NULL )
328 : {
329 : /* User pressed cancel */
330 0 : U8_TRACE_INFO_STR( "unexpected response from file dialog:", error->message );
331 0 : g_error_free( error );
332 : }
333 0 : if ( result != NULL )
334 : {
335 0 : gchar *folder_path = g_file_get_path ( result );
336 0 : if ( folder_path != NULL )
337 : {
338 0 : u8_error_t export_err = U8_ERROR_NONE;
339 : data_stat_t export_stat;
340 0 : data_stat_init ( &export_stat );
341 0 : io_file_format_t selected_format = IO_FILE_FORMAT_NONE;
342 :
343 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_pdf) )) { selected_format |= IO_FILE_FORMAT_PDF; }
344 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_png) )) { selected_format |= IO_FILE_FORMAT_PNG; }
345 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_ps) )) { selected_format |= IO_FILE_FORMAT_PS; }
346 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_svg) )) { selected_format |= IO_FILE_FORMAT_SVG; }
347 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_txt) )) { selected_format |= IO_FILE_FORMAT_TXT; }
348 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_docbook) )) { selected_format |= IO_FILE_FORMAT_DOCBOOK; }
349 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_html) )) { selected_format |= IO_FILE_FORMAT_HTML; }
350 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_xmi2) )) { selected_format |= IO_FILE_FORMAT_XMI2; }
351 0 : if ( gtk_check_button_get_active( GTK_CHECK_BUTTON((*this_).format_json) )) { selected_format |= IO_FILE_FORMAT_JSON; }
352 :
353 : /* react immediately, handle events */
354 0 : gui_simple_message_to_user_show_message_with_name( (*this_).message_to_user,
355 : GUI_SIMPLE_MESSAGE_TYPE_INFO,
356 : GUI_SIMPLE_MESSAGE_CONTENT_EXPORTING_WAIT,
357 : folder_path
358 : );
359 0 : bool events_handled = true;
360 0 : for ( uint_fast8_t max_loop = 40; events_handled && ( max_loop > 0 ); max_loop-- )
361 : {
362 0 : events_handled = g_main_context_iteration( NULL, /*may_block*/ FALSE );
363 : }
364 :
365 : /* determine the database file path for a document title and export: */
366 0 : const char *db_path = data_database_get_filename_ptr( (*this_).database );
367 0 : if ( data_database_is_open((*this_).database) )
368 : {
369 0 : export_err = io_exporter_export_files( &((*this_).file_exporter),
370 : selected_format,
371 : folder_path,
372 : db_path,
373 : &export_stat
374 : );
375 : }
376 : else
377 : {
378 0 : export_err = U8_ERROR_NO_DB;
379 : }
380 :
381 : /* finished, notify user */
382 : char temp_format_buf[64];
383 0 : utf8stringbuf_t temp_fileformat = UTF8STRINGBUF( temp_format_buf );
384 0 : io_file_format_to_string( selected_format, temp_fileformat );
385 :
386 0 : if ( U8_ERROR_NONE == export_err )
387 : {
388 0 : gui_simple_message_to_user_show_message_with_names_and_stat( (*this_).message_to_user,
389 : GUI_SIMPLE_MESSAGE_TYPE_INFO,
390 : GUI_SIMPLE_MESSAGE_CONTENT_EXPORT_FINISHED,
391 0 : utf8stringbuf_get_string( &temp_fileformat ),
392 : &export_stat
393 : );
394 :
395 : }
396 : else
397 : {
398 0 : gui_simple_message_to_user_show_message_with_name( (*this_).message_to_user,
399 : GUI_SIMPLE_MESSAGE_TYPE_ERROR,
400 : GUI_SIMPLE_MESSAGE_CONTENT_FILE_EXPORT_FAILED,
401 : folder_path
402 : );
403 : }
404 :
405 0 : data_stat_trace( &export_stat );
406 0 : data_stat_destroy ( &export_stat );
407 0 : g_free (folder_path);
408 : }
409 0 : g_object_unref( result );
410 : }
411 :
412 0 : U8_TRACE_END();
413 0 : }
414 :
415 : #endif /* GTK ? 4.10 */
416 :
417 :
418 : /*
419 : Copyright 2019-2025 Andreas Warnke
420 :
421 : Licensed under the Apache License, Version 2.0 (the "License");
422 : you may not use this file except in compliance with the License.
423 : You may obtain a copy of the License at
424 :
425 : http://www.apache.org/licenses/LICENSE-2.0
426 :
427 : Unless required by applicable law or agreed to in writing, software
428 : distributed under the License is distributed on an "AS IS" BASIS,
429 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
430 : See the License for the specific language governing permissions and
431 : limitations under the License.
432 : */
|