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