Line data Source code
1 : /* File: gui_file_use_db_dialog.c; Copyright and License: see below */
2 :
3 : #include "gui_file_use_db_dialog.h"
4 : #include "u8/u8_trace.h"
5 : #include <gdk/gdk.h>
6 : #include <gtk/gtk.h>
7 : #include <stdio.h>
8 : #include <stdbool.h>
9 :
10 0 : void gui_file_use_db_dialog_init ( gui_file_use_db_dialog_t *this_,
11 : ctrl_controller_t *controller,
12 : io_data_file_t *database,
13 : GtkWindow *parent_window,
14 : gui_simple_message_to_user_t *message_to_user )
15 : {
16 0 : U8_TRACE_BEGIN();
17 :
18 0 : (*this_).parent_window = parent_window;
19 :
20 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
21 0 : (*this_).new_file_chooser = gtk_file_chooser_dialog_new ( "Select new file",
22 : parent_window,
23 : GTK_FILE_CHOOSER_ACTION_SAVE,
24 : "Cancel",
25 : GTK_RESPONSE_CANCEL,
26 : "New",
27 : GTK_RESPONSE_ACCEPT,
28 : NULL
29 : );
30 : /* set name postponed, see https://gitlab.gnome.org/GNOME/gtk/-/issues/4832 */
31 0 : (*this_).open_file_chooser = gtk_file_chooser_dialog_new ( "Select file to open",
32 : parent_window,
33 : GTK_FILE_CHOOSER_ACTION_OPEN,
34 : "Cancel",
35 : GTK_RESPONSE_CANCEL,
36 : "Open",
37 : GTK_RESPONSE_ACCEPT,
38 : NULL
39 : );
40 : #else
41 : (*this_).new_file_dialog = gtk_file_dialog_new();
42 : gtk_file_dialog_set_accept_label( (*this_).new_file_dialog, "New" );
43 : gtk_file_dialog_set_modal( (*this_).new_file_dialog, false );
44 : gtk_file_dialog_set_title( (*this_).new_file_dialog, "Select new file" );
45 : gtk_file_dialog_set_initial_name( (*this_).new_file_dialog, "NewModel.cfuJ" );
46 :
47 : (*this_).open_file_dialog = gtk_file_dialog_new();
48 : gtk_file_dialog_set_accept_label( (*this_).open_file_dialog, "Open" );
49 : gtk_file_dialog_set_modal( (*this_).open_file_dialog, false );
50 : gtk_file_dialog_set_title( (*this_).open_file_dialog, "Select file to open" );
51 : #endif
52 :
53 0 : gui_file_db_manager_init( &((*this_).file_manager), controller, database, message_to_user );
54 :
55 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
56 0 : g_signal_connect( G_OBJECT((*this_).new_file_chooser),
57 : "response",
58 : G_CALLBACK(gui_file_use_db_dialog_response_callback),
59 : this_
60 : );
61 0 : gtk_window_set_hide_on_close( GTK_WINDOW((*this_).new_file_chooser), true);
62 0 : g_signal_connect( G_OBJECT((*this_).open_file_chooser),
63 : "response",
64 : G_CALLBACK(gui_file_use_db_dialog_response_callback),
65 : this_
66 : );
67 0 : gtk_window_set_hide_on_close( GTK_WINDOW((*this_).open_file_chooser), true);
68 : #else
69 : /* no signal at new FileDialog - this works with Async, see gtk_file_dialog_save */
70 : #endif
71 :
72 0 : U8_TRACE_END();
73 0 : }
74 :
75 0 : void gui_file_use_db_dialog_destroy( gui_file_use_db_dialog_t *this_ )
76 : {
77 0 : U8_TRACE_BEGIN();
78 :
79 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
80 0 : gtk_window_destroy( GTK_WINDOW((*this_).new_file_chooser) );
81 : /* no need to g_object_unref ( (*this_).new_file_chooser ); here */
82 0 : gtk_window_destroy( GTK_WINDOW((*this_).open_file_chooser) );
83 : /* no need to g_object_unref ( (*this_).open_file_chooser ); here */
84 : #else
85 : g_object_unref( (*this_).new_file_dialog );
86 : g_object_unref( (*this_).open_file_dialog );
87 : #endif
88 :
89 0 : gui_file_db_manager_destroy( &((*this_).file_manager) );
90 :
91 0 : (*this_).parent_window = NULL;
92 :
93 0 : U8_TRACE_END();
94 0 : }
95 :
96 0 : void gui_file_use_db_dialog_show( gui_file_use_db_dialog_t *this_, bool open_existing )
97 : {
98 0 : U8_TRACE_BEGIN();
99 :
100 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
101 0 : if( ! open_existing )
102 : {
103 : /* moved here as workaround for disabled file dialog widgets, see https://gitlab.gnome.org/GNOME/gtk/-/issues/4832 */
104 0 : gtk_file_chooser_set_current_name( GTK_FILE_CHOOSER( (*this_).new_file_chooser ), "NewModel.cfuJ" );
105 :
106 0 : gtk_widget_set_visible( GTK_WIDGET( (*this_).new_file_chooser ), TRUE );
107 0 : gtk_widget_set_sensitive( GTK_WIDGET((*this_).new_file_chooser), TRUE ); /* idea taken from gtk demo */
108 0 : GdkSurface *surface = gtk_native_get_surface( GTK_NATIVE((*this_).new_file_chooser) );
109 0 : gdk_surface_set_cursor( surface, NULL ); /* idea taken from gtk3->4 guide */
110 : }
111 : else
112 : {
113 0 : gtk_widget_set_visible( GTK_WIDGET( (*this_).open_file_chooser ), TRUE );
114 0 : gtk_widget_set_sensitive( GTK_WIDGET((*this_).open_file_chooser), TRUE ); /* idea taken from gtk demo */
115 0 : GdkSurface *surface = gtk_native_get_surface( GTK_NATIVE((*this_).open_file_chooser) );
116 0 : gdk_surface_set_cursor( surface, NULL ); /* idea taken from gtk3->4 guide */
117 : }
118 : #else
119 : if ( open_existing )
120 : {
121 : gtk_file_dialog_open( (*this_).open_file_dialog,
122 : (*this_).parent_window,
123 : NULL,
124 : &gui_file_use_db_dialog_async_ready_callback_on_open,
125 : this_
126 : );
127 : }
128 : else
129 : {
130 : gtk_file_dialog_save( (*this_).new_file_dialog,
131 : (*this_).parent_window,
132 : NULL,
133 : &gui_file_use_db_dialog_async_ready_callback_on_new,
134 : this_
135 : );
136 : }
137 : #endif
138 :
139 0 : U8_TRACE_END();
140 0 : }
141 :
142 : #if (( GTK_MAJOR_VERSION == 4 )&&( GTK_MINOR_VERSION < 10 ))
143 :
144 0 : void gui_file_use_db_dialog_response_callback( GtkDialog *dialog, gint response_id, gpointer user_data )
145 : {
146 0 : U8_TRACE_BEGIN();
147 0 : gui_file_use_db_dialog_t *this_ = user_data;
148 :
149 0 : switch ( response_id )
150 : {
151 0 : case GTK_RESPONSE_ACCEPT:
152 : {
153 0 : U8_LOG_EVENT( "GTK_RESPONSE_ACCEPT" );
154 0 : gtk_widget_set_visible( GTK_WIDGET ( dialog ), FALSE );
155 :
156 0 : gchar *filename = NULL;
157 0 : GFile *selected_file = gtk_file_chooser_get_file( GTK_FILE_CHOOSER(dialog) );
158 0 : if ( selected_file != NULL )
159 : {
160 0 : filename = g_file_get_path( selected_file );
161 : }
162 0 : if ( filename != NULL )
163 : {
164 0 : U8_TRACE_INFO_STR( "File chosen:", filename );
165 :
166 0 : gui_file_db_manager_use_db( &((*this_).file_manager), filename );
167 :
168 0 : g_free (filename);
169 : }
170 : else
171 : {
172 0 : U8_LOG_WARNING( "Use DB dialog returned no file name" );
173 : }
174 0 : if ( selected_file != NULL )
175 : {
176 0 : g_object_unref( selected_file );
177 : }
178 : }
179 0 : break;
180 :
181 0 : case GTK_RESPONSE_CANCEL:
182 : {
183 0 : U8_LOG_EVENT( "GTK_RESPONSE_CANCEL" );
184 0 : gtk_widget_set_visible( GTK_WIDGET ( dialog ), FALSE );
185 : }
186 0 : break;
187 :
188 0 : case GTK_RESPONSE_DELETE_EVENT:
189 : {
190 0 : U8_LOG_EVENT( "GTK_RESPONSE_DELETE_EVENT" );
191 : }
192 0 : break;
193 :
194 0 : default:
195 : {
196 0 : U8_LOG_ERROR( "unexpected response_id" );
197 : }
198 : }
199 :
200 0 : U8_TRACE_END();
201 0 : }
202 :
203 : #else /* GTK >= 4.10 */
204 :
205 : void gui_file_use_db_dialog_async_ready_callback_on_open( GObject* source_object,
206 : GAsyncResult* res,
207 : gpointer user_data )
208 : {
209 : U8_TRACE_BEGIN();
210 :
211 : gui_file_use_db_dialog_t *this_ = user_data;
212 : GError* error = NULL;
213 : GFile *result = gtk_file_dialog_open_finish( GTK_FILE_DIALOG(source_object), res, &error );
214 : if ( error != NULL )
215 : {
216 : /* User pressed cancel */
217 : U8_TRACE_INFO_STR( "unexpected response from file dialog:", error->message );
218 : g_error_free( error );
219 : }
220 : else if ( result != NULL )
221 : {
222 : gchar *folder_path = g_file_get_path ( result );
223 : if ( folder_path != NULL )
224 : {
225 : U8_LOG_EVENT( "User selected a database file to open." );
226 : U8_TRACE_INFO_STR( "File to open:", folder_path );
227 :
228 : /* react immediately, handle events */
229 : bool events_handled = true;
230 : for ( uint_fast8_t max_loop = 40; events_handled && ( max_loop > 0 ); max_loop-- )
231 : {
232 : events_handled = g_main_context_iteration( NULL, /*may_block*/ FALSE );
233 : }
234 :
235 : gui_file_db_manager_use_db( &((*this_).file_manager), folder_path );
236 :
237 : g_free (folder_path);
238 : }
239 : }
240 : if ( result != NULL )
241 : {
242 : g_object_unref( result );
243 : }
244 :
245 : U8_TRACE_END();
246 : }
247 :
248 : void gui_file_use_db_dialog_async_ready_callback_on_new( GObject* source_object,
249 : GAsyncResult* res,
250 : gpointer user_data )
251 : {
252 : U8_TRACE_BEGIN();
253 :
254 : gui_file_use_db_dialog_t *this_ = user_data;
255 : GError* error = NULL;
256 : GFile *result = gtk_file_dialog_save_finish( GTK_FILE_DIALOG(source_object), res, &error );
257 : if ( error != NULL )
258 : {
259 : /* User pressed cancel */
260 : U8_TRACE_INFO_STR( "unexpected response from file dialog:", error->message );
261 : g_error_free( error );
262 : }
263 : else if ( result != NULL )
264 : {
265 : gchar *folder_path = g_file_get_path ( result );
266 : if ( folder_path != NULL )
267 : {
268 : U8_LOG_EVENT( "User selected a new database file." );
269 : U8_TRACE_INFO_STR( "File to create:", folder_path );
270 :
271 : /* react immediately, handle events */
272 : bool events_handled = true;
273 : for ( uint_fast8_t max_loop = 40; events_handled && ( max_loop > 0 ); max_loop-- )
274 : {
275 : events_handled = g_main_context_iteration( NULL, /*may_block*/ FALSE );
276 : }
277 :
278 : gui_file_db_manager_use_db( &((*this_).file_manager), folder_path );
279 :
280 : g_free (folder_path);
281 : }
282 : }
283 : if ( result != NULL )
284 : {
285 : g_object_unref( result );
286 : }
287 :
288 : U8_TRACE_END();
289 : }
290 :
291 : #endif
292 :
293 :
294 : /*
295 : Copyright 2019-2024 Andreas Warnke
296 :
297 : Licensed under the Apache License, Version 2.0 (the "License");
298 : you may not use this file except in compliance with the License.
299 : You may obtain a copy of the License at
300 :
301 : http://www.apache.org/licenses/LICENSE-2.0
302 :
303 : Unless required by applicable law or agreed to in writing, software
304 : distributed under the License is distributed on an "AS IS" BASIS,
305 : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
306 : See the License for the specific language governing permissions and
307 : limitations under the License.
308 : */
|