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