1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
4 *
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2014 Pierre Wieser and others (see AUTHORS)
8 *
9 * Nautilus-Actions is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * Nautilus-Actions is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with Nautilus-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
22 *
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
28 */
29
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
33
34 #include <gdk/gdkkeysyms.h>
35
36 #include <api/na-core-utils.h>
37
38 #include <core/na-settings.h>
39
40 #include "nact-schemes-list.h"
41 #include "nact-add-scheme-dialog.h"
42
43 /* private class data
44 */
45 struct _NactAddSchemeDialogClassPrivate {
46 void *empty; /* so that gcc -pedantic is happy */
47 };
48
49 /* private instance data
50 */
51 struct _NactAddSchemeDialogPrivate {
52 gboolean dispose_has_run;
53 GSList *already_used;
54 gchar *scheme;
55 };
56
57 static const gchar *st_xmlui_filename = PKGUIDIR "/nact-add-scheme.ui";
58 static const gchar *st_toplevel_name = "AddSchemeDialog";
59 static const gchar *st_wsp_name = NA_IPREFS_SCHEME_ADD_SCHEME_WSP;
60
61 static GObjectClass *st_parent_class = NULL;
62
63 static GType register_type( void );
64 static void class_init( NactAddSchemeDialogClass *klass );
65 static void instance_init( GTypeInstance *instance, gpointer klass );
66 static void instance_constructed( GObject *dialog );
67 static void instance_dispose( GObject *dialog );
68 static void instance_finalize( GObject *dialog );
69
70 static void on_base_initialize_gtk( NactAddSchemeDialog *editor, GtkDialog *toplevel, gpointer user_data );
71 static void on_base_initialize_window( NactAddSchemeDialog *editor, gpointer user_data );
72 static void on_base_show_widgets( NactAddSchemeDialog *editor, gpointer user_data );
73 static gboolean on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactAddSchemeDialog *dialog );
74 static void on_cancel_clicked( GtkButton *button, NactAddSchemeDialog *editor );
75 static void on_ok_clicked( GtkButton *button, NactAddSchemeDialog *editor );
76 static void on_selection_changed( const gchar *scheme, gboolean used, NactAddSchemeDialog *dialog );
77 static void try_for_send_ok( NactAddSchemeDialog *dialog );
78 static void send_ok( NactAddSchemeDialog *dialog );
79 static void on_dialog_ok( BaseDialog *dialog );
80
81 GType
nact_add_scheme_dialog_get_type(void)82 nact_add_scheme_dialog_get_type( void )
83 {
84 static GType dialog_type = 0;
85
86 if( !dialog_type ){
87 dialog_type = register_type();
88 }
89
90 return( dialog_type );
91 }
92
93 static GType
register_type(void)94 register_type( void )
95 {
96 static const gchar *thisfn = "nact_add_scheme_dialog_register_type";
97 GType type;
98
99 static GTypeInfo info = {
100 sizeof( NactAddSchemeDialogClass ),
101 ( GBaseInitFunc ) NULL,
102 ( GBaseFinalizeFunc ) NULL,
103 ( GClassInitFunc ) class_init,
104 NULL,
105 NULL,
106 sizeof( NactAddSchemeDialog ),
107 0,
108 ( GInstanceInitFunc ) instance_init
109 };
110
111 g_debug( "%s", thisfn );
112
113 type = g_type_register_static( BASE_TYPE_DIALOG, "NactAddSchemeDialog", &info, 0 );
114
115 return( type );
116 }
117
118 static void
class_init(NactAddSchemeDialogClass * klass)119 class_init( NactAddSchemeDialogClass *klass )
120 {
121 static const gchar *thisfn = "nact_add_scheme_dialog_class_init";
122 GObjectClass *object_class;
123 BaseDialogClass *dialog_class;
124
125 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
126
127 st_parent_class = g_type_class_peek_parent( klass );
128
129 object_class = G_OBJECT_CLASS( klass );
130 object_class->constructed = instance_constructed;
131 object_class->dispose = instance_dispose;
132 object_class->finalize = instance_finalize;
133
134 klass->private = g_new0( NactAddSchemeDialogClassPrivate, 1 );
135
136 dialog_class = BASE_DIALOG_CLASS( klass );
137 dialog_class->ok = on_dialog_ok;
138 }
139
140 static void
instance_init(GTypeInstance * instance,gpointer klass)141 instance_init( GTypeInstance *instance, gpointer klass )
142 {
143 static const gchar *thisfn = "nact_add_scheme_dialog_instance_init";
144 NactAddSchemeDialog *self;
145
146 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( instance ));
147
148 g_debug( "%s: instance=%p, klass=%p", thisfn, ( void * ) instance, ( void * ) klass );
149
150 self = NACT_ADD_SCHEME_DIALOG( instance );
151
152 self->private = g_new0( NactAddSchemeDialogPrivate, 1 );
153
154 self->private->dispose_has_run = FALSE;
155 self->private->scheme = NULL;
156 }
157
158 static void
instance_constructed(GObject * dialog)159 instance_constructed( GObject *dialog )
160 {
161 static const gchar *thisfn = "nact_add_scheme_dialog_instance_constructed";
162 NactAddSchemeDialogPrivate *priv;
163
164 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
165
166 priv = NACT_ADD_SCHEME_DIALOG( dialog )->private;
167
168 if( !priv->dispose_has_run ){
169
170 /* chain up to the parent class */
171 if( G_OBJECT_CLASS( st_parent_class )->constructed ){
172 G_OBJECT_CLASS( st_parent_class )->constructed( dialog );
173 }
174
175 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
176
177 base_window_signal_connect(
178 BASE_WINDOW( dialog ),
179 G_OBJECT( dialog ),
180 BASE_SIGNAL_INITIALIZE_GTK,
181 G_CALLBACK( on_base_initialize_gtk ));
182
183 base_window_signal_connect(
184 BASE_WINDOW( dialog ),
185 G_OBJECT( dialog ),
186 BASE_SIGNAL_INITIALIZE_WINDOW,
187 G_CALLBACK( on_base_initialize_window ));
188
189 base_window_signal_connect(
190 BASE_WINDOW( dialog ),
191 G_OBJECT( dialog ),
192 BASE_SIGNAL_SHOW_WIDGETS,
193 G_CALLBACK( on_base_show_widgets ));
194 }
195 }
196
197 static void
instance_dispose(GObject * dialog)198 instance_dispose( GObject *dialog )
199 {
200 static const gchar *thisfn = "nact_add_scheme_dialog_instance_dispose";
201 NactAddSchemeDialog *self;
202 GtkTreeView *listview;
203 GtkTreeModel *model;
204 GtkTreeSelection *selection;
205
206 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
207
208 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
209
210 self = NACT_ADD_SCHEME_DIALOG( dialog );
211
212 if( !self->private->dispose_has_run ){
213
214 self->private->dispose_has_run = TRUE;
215
216 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "SchemesTreeView" ));
217 model = gtk_tree_view_get_model( listview );
218 selection = gtk_tree_view_get_selection( listview );
219 gtk_tree_selection_unselect_all( selection );
220 gtk_list_store_clear( GTK_LIST_STORE( model ));
221
222 /* chain up to the parent class */
223 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
224 G_OBJECT_CLASS( st_parent_class )->dispose( dialog );
225 }
226 }
227 }
228
229 static void
instance_finalize(GObject * dialog)230 instance_finalize( GObject *dialog )
231 {
232 static const gchar *thisfn = "nact_add_scheme_dialog_instance_finalize";
233 NactAddSchemeDialog *self;
234
235 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
236
237 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
238
239 self = NACT_ADD_SCHEME_DIALOG( dialog );
240
241 na_core_utils_slist_free( self->private->already_used );
242 g_free( self->private->scheme );
243
244 g_free( self->private );
245
246 /* chain call to parent class */
247 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
248 G_OBJECT_CLASS( st_parent_class )->finalize( dialog );
249 }
250 }
251
252 /**
253 * nact_add_scheme_dialog_run:
254 * @parent: the BaseWindow parent of this dialog
255 * (usually the NactMainWindow).
256 * @schemes: list of already used schemes.
257 *
258 * Initializes and runs the dialog.
259 *
260 * Returns: the selected scheme, as a newly allocated string which should
261 * be g_free() by the caller, or NULL.
262 */
263 gchar *
nact_add_scheme_dialog_run(BaseWindow * parent,GSList * schemes)264 nact_add_scheme_dialog_run( BaseWindow *parent, GSList *schemes )
265 {
266 static const gchar *thisfn = "nact_add_scheme_dialog_run";
267 NactAddSchemeDialog *dialog;
268 gchar *scheme;
269
270 g_debug( "%s: parent=%p", thisfn, ( void * ) parent );
271
272 g_return_val_if_fail( BASE_IS_WINDOW( parent ), NULL );
273
274 dialog = g_object_new( NACT_TYPE_ADD_SCHEME_DIALOG,
275 BASE_PROP_PARENT, parent,
276 BASE_PROP_XMLUI_FILENAME, st_xmlui_filename,
277 BASE_PROP_TOPLEVEL_NAME, st_toplevel_name,
278 BASE_PROP_WSP_NAME, st_wsp_name,
279 NULL );
280
281 dialog->private->already_used = na_core_utils_slist_duplicate( schemes );
282 scheme = NULL;
283
284 if( base_window_run( BASE_WINDOW( dialog )) == GTK_RESPONSE_OK ){
285 scheme = g_strdup( dialog->private->scheme );
286 }
287
288 g_object_unref( dialog );
289
290 return( scheme );
291 }
292
293 static void
on_base_initialize_gtk(NactAddSchemeDialog * dialog,GtkDialog * toplevel,gpointer user_data)294 on_base_initialize_gtk( NactAddSchemeDialog *dialog, GtkDialog *toplevel, gpointer user_data )
295 {
296 static const gchar *thisfn = "nact_add_scheme_dialog_on_base_initialize_gtk";
297 GtkTreeView *listview;
298
299 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
300
301 if( !dialog->private->dispose_has_run ){
302
303 g_debug( "%s: dialog=%p, toplevel=%p, user_data=%p",
304 thisfn, ( void * ) dialog, ( void * ) toplevel, ( void * ) user_data );
305
306 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "SchemesTreeView" ));
307 nact_schemes_list_create_model( listview, SCHEMES_LIST_FOR_ADD_FROM_DEFAULTS );
308
309 #if !GTK_CHECK_VERSION( 2,22,0 )
310 gtk_dialog_set_has_separator( toplevel, FALSE );
311 #endif
312 }
313 }
314
315 static void
on_base_initialize_window(NactAddSchemeDialog * dialog,gpointer user_data)316 on_base_initialize_window( NactAddSchemeDialog *dialog, gpointer user_data )
317 {
318 static const gchar *thisfn = "nact_add_scheme_dialog_on_base_initialize_window";
319 GtkTreeView *listview;
320
321 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
322
323 if( !dialog->private->dispose_has_run ){
324
325 g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
326
327 listview = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( dialog ), "SchemesTreeView" ));
328 nact_schemes_list_init_view( listview, BASE_WINDOW( dialog ), ( pf_new_selection_cb ) on_selection_changed, ( void * ) dialog );
329
330 nact_schemes_list_setup_values( BASE_WINDOW( dialog ), dialog->private->already_used );
331
332 /* catch double-click */
333 base_window_signal_connect(
334 BASE_WINDOW( dialog ),
335 G_OBJECT( listview ),
336 "button-press-event",
337 G_CALLBACK( on_button_press_event ));
338
339 /* dialog buttons
340 */
341 base_window_signal_connect_by_name(
342 BASE_WINDOW( dialog ),
343 "CancelButton",
344 "clicked",
345 G_CALLBACK( on_cancel_clicked ));
346
347 base_window_signal_connect_by_name(
348 BASE_WINDOW( dialog ),
349 "OKButton",
350 "clicked",
351 G_CALLBACK( on_ok_clicked ));
352 }
353 }
354
355 static void
on_base_show_widgets(NactAddSchemeDialog * dialog,gpointer user_data)356 on_base_show_widgets( NactAddSchemeDialog *dialog, gpointer user_data )
357 {
358 static const gchar *thisfn = "nact_add_scheme_dialog_on_base_show_widgets";
359
360 g_return_if_fail( NACT_IS_ADD_SCHEME_DIALOG( dialog ));
361
362 if( !dialog->private->dispose_has_run ){
363
364 g_debug( "%s: dialog=%p, user_data=%p", thisfn, ( void * ) dialog, ( void * ) user_data );
365
366 nact_schemes_list_show_all( BASE_WINDOW( dialog ));
367 }
368 }
369
370 static gboolean
on_button_press_event(GtkWidget * widget,GdkEventButton * event,NactAddSchemeDialog * dialog)371 on_button_press_event( GtkWidget *widget, GdkEventButton *event, NactAddSchemeDialog *dialog )
372 {
373 gboolean stop = FALSE;
374
375 /* double-click of left button */
376 if( event->type == GDK_2BUTTON_PRESS && event->button == 1 ){
377 try_for_send_ok( dialog );
378 stop = TRUE;
379 }
380
381 return( stop );
382 }
383
384 static void
on_cancel_clicked(GtkButton * button,NactAddSchemeDialog * dialog)385 on_cancel_clicked( GtkButton *button, NactAddSchemeDialog *dialog )
386 {
387 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( dialog ));
388
389 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_CLOSE );
390 }
391
392 static void
on_ok_clicked(GtkButton * button,NactAddSchemeDialog * dialog)393 on_ok_clicked( GtkButton *button, NactAddSchemeDialog *dialog )
394 {
395 send_ok( dialog );
396 }
397
398 /*
399 * this function is a callback, called from nact-schemes-list:on_selection_changed
400 * this let us validate/invalidate the OK button
401 */
402 static void
on_selection_changed(const gchar * scheme,gboolean used,NactAddSchemeDialog * dialog)403 on_selection_changed( const gchar *scheme, gboolean used, NactAddSchemeDialog *dialog )
404 {
405 GtkWidget *button;
406
407 button = base_window_get_widget( BASE_WINDOW( dialog ), "OKButton" );
408 gtk_widget_set_sensitive( button, !used );
409 }
410
411 static void
try_for_send_ok(NactAddSchemeDialog * dialog)412 try_for_send_ok( NactAddSchemeDialog *dialog )
413 {
414 GtkWidget *button;
415 gboolean is_sensitive;
416
417 button = base_window_get_widget( BASE_WINDOW( dialog ), "OKButton" );
418
419 is_sensitive = gtk_widget_is_sensitive( button );
420
421 if( is_sensitive ){
422 send_ok( dialog );
423 }
424 }
425
426 static void
send_ok(NactAddSchemeDialog * dialog)427 send_ok( NactAddSchemeDialog *dialog )
428 {
429 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( dialog ));
430
431 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_OK );
432 }
433
434 static void
on_dialog_ok(BaseDialog * dialog)435 on_dialog_ok( BaseDialog *dialog )
436 {
437 NactAddSchemeDialog *editor = NACT_ADD_SCHEME_DIALOG( dialog );
438 editor->private->scheme = nact_schemes_list_get_current_scheme( BASE_WINDOW( dialog ));
439 }
440