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