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 <glib/gi18n.h>
35 #include <string.h>
36 
37 #include <api/na-core-utils.h>
38 #include <api/na-object-api.h>
39 
40 #include "base-window.h"
41 #include "base-gtk-utils.h"
42 #include "nact-application.h"
43 #include "nact-main-tab.h"
44 #include "nact-match-list.h"
45 #include "nact-ifolders-tab.h"
46 
47 /* private interface data
48  */
49 struct _NactIFoldersTabInterfacePrivate {
50 	void *empty;						/* so that gcc -pedantic is happy */
51 };
52 
53 /* the identifier of this notebook page in the Match dialog
54  */
55 #define ITAB_NAME						"folders"
56 
57 static guint st_initializations = 0;	/* interface initialization count */
58 
59 static GType   register_type( void );
60 static void    interface_base_init( NactIFoldersTabInterface *klass );
61 static void    interface_base_finalize( NactIFoldersTabInterface *klass );
62 
63 static void    on_base_initialize_gtk( NactIFoldersTab *instance, GtkWindow *toplevel, gpointer user_data );
64 static void    on_base_initialize_window( NactIFoldersTab *instance, gpointer user_data );
65 
66 static void    on_main_selection_changed( NactIFoldersTab *instance, GList *selected_items, gpointer user_data );
67 
68 static void    on_browse_folder_clicked( GtkButton *button, BaseWindow *window );
69 static GSList *get_folders( void *context );
70 static void    set_folders( void *context, GSList *filters );
71 
72 static void    on_instance_finalized( gpointer user_data, NactIFoldersTab *instance );
73 
74 GType
nact_ifolders_tab_get_type(void)75 nact_ifolders_tab_get_type( void )
76 {
77 	static GType iface_type = 0;
78 
79 	if( !iface_type ){
80 		iface_type = register_type();
81 	}
82 
83 	return( iface_type );
84 }
85 
86 static GType
register_type(void)87 register_type( void )
88 {
89 	static const gchar *thisfn = "nact_ifolders_tab_register_type";
90 	GType type;
91 
92 	static const GTypeInfo info = {
93 		sizeof( NactIFoldersTabInterface ),
94 		( GBaseInitFunc ) interface_base_init,
95 		( GBaseFinalizeFunc ) interface_base_finalize,
96 		NULL,
97 		NULL,
98 		NULL,
99 		0,
100 		0,
101 		NULL
102 	};
103 
104 	g_debug( "%s", thisfn );
105 
106 	type = g_type_register_static( G_TYPE_INTERFACE, "NactIFoldersTab", &info, 0 );
107 
108 	g_type_interface_add_prerequisite( type, BASE_TYPE_WINDOW );
109 
110 	return( type );
111 }
112 
113 static void
interface_base_init(NactIFoldersTabInterface * klass)114 interface_base_init( NactIFoldersTabInterface *klass )
115 {
116 	static const gchar *thisfn = "nact_ifolders_tab_interface_base_init";
117 
118 	if( !st_initializations ){
119 
120 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
121 
122 		klass->private = g_new0( NactIFoldersTabInterfacePrivate, 1 );
123 	}
124 
125 	st_initializations += 1;
126 }
127 
128 static void
interface_base_finalize(NactIFoldersTabInterface * klass)129 interface_base_finalize( NactIFoldersTabInterface *klass )
130 {
131 	static const gchar *thisfn = "nact_ifolders_tab_interface_base_finalize";
132 
133 	st_initializations -= 1;
134 
135 	if( !st_initializations ){
136 
137 		g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
138 
139 		g_free( klass->private );
140 	}
141 }
142 
143 /**
144  * nact_ifolders_tab_init:
145  * @instance: this #NactIFoldersTab instance.
146  *
147  * Initialize the interface
148  * Connect to #BaseWindow signals
149  */
150 void
nact_ifolders_tab_init(NactIFoldersTab * instance)151 nact_ifolders_tab_init( NactIFoldersTab *instance )
152 {
153 	static const gchar *thisfn = "nact_ifolders_tab_init";
154 
155 	g_return_if_fail( NACT_IS_IFOLDERS_TAB( instance ));
156 
157 	g_debug( "%s: instance=%p (%s)",
158 			thisfn,
159 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ));
160 
161 	base_window_signal_connect(
162 			BASE_WINDOW( instance ),
163 			G_OBJECT( instance ),
164 			BASE_SIGNAL_INITIALIZE_GTK,
165 			G_CALLBACK( on_base_initialize_gtk ));
166 
167 	base_window_signal_connect(
168 			BASE_WINDOW( instance ),
169 			G_OBJECT( instance ),
170 			BASE_SIGNAL_INITIALIZE_WINDOW,
171 			G_CALLBACK( on_base_initialize_window ));
172 
173 	nact_main_tab_init( NACT_MAIN_WINDOW( instance ), TAB_FOLDERS );
174 
175 	g_object_weak_ref( G_OBJECT( instance ), ( GWeakNotify ) on_instance_finalized, NULL );
176 }
177 
178 static void
on_base_initialize_gtk(NactIFoldersTab * instance,GtkWindow * toplevel,void * user_data)179 on_base_initialize_gtk( NactIFoldersTab *instance, GtkWindow *toplevel, void *user_data )
180 {
181 	static const gchar *thisfn = "nact_ifolders_tab_on_base_initialize_gtk";
182 
183 	g_return_if_fail( NACT_IS_IFOLDERS_TAB( instance ));
184 
185 	g_debug( "%s: instance=%p (%s), toplevel=%p, user_data=%p",
186 			thisfn,
187 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
188 			( void * ) toplevel,
189 			( void * ) user_data );
190 
191 	nact_match_list_init_with_args(
192 			BASE_WINDOW( instance ),
193 			ITAB_NAME,
194 			TAB_FOLDERS,
195 			base_window_get_widget( BASE_WINDOW( instance ), "FoldersTreeView" ),
196 			base_window_get_widget( BASE_WINDOW( instance ), "AddFolderButton" ),
197 			base_window_get_widget( BASE_WINDOW( instance ), "RemoveFolderButton" ),
198 			( pget_filters ) get_folders,
199 			( pset_filters ) set_folders,
200 			NULL,
201 			NULL,
202 			MATCH_LIST_MUST_MATCH_ONE_OF,
203 			_( "Folder filter" ),
204 			TRUE );
205 }
206 
207 static void
on_base_initialize_window(NactIFoldersTab * instance,void * user_data)208 on_base_initialize_window( NactIFoldersTab *instance, void *user_data )
209 {
210 	static const gchar *thisfn = "nact_ifolders_tab_on_base_initialize_window";
211 	GtkWidget *button;
212 
213 	g_return_if_fail( NACT_IS_IFOLDERS_TAB( instance ));
214 
215 	g_debug( "%s: instance=%p (%s), user_data=%p",
216 			thisfn,
217 			( void * ) instance, G_OBJECT_TYPE_NAME( instance ),
218 			( void * ) user_data );
219 
220 	base_window_signal_connect(
221 			BASE_WINDOW( instance ),
222 			G_OBJECT( instance ),
223 			MAIN_SIGNAL_SELECTION_CHANGED,
224 			G_CALLBACK( on_main_selection_changed ));
225 
226 	button = base_window_get_widget( BASE_WINDOW( instance ), "FolderBrowseButton" );
227 	base_window_signal_connect(
228 			BASE_WINDOW( instance ),
229 			G_OBJECT( button ),
230 			"clicked",
231 			G_CALLBACK( on_browse_folder_clicked ));
232 }
233 
234 static void
on_main_selection_changed(NactIFoldersTab * instance,GList * selected_items,gpointer user_data)235 on_main_selection_changed( NactIFoldersTab *instance, GList *selected_items, gpointer user_data )
236 {
237 	NAIContext *context;
238 	gboolean editable;
239 	gboolean enable_tab;
240 	GtkWidget *button;
241 
242 	g_object_get( G_OBJECT( instance ),
243 			MAIN_PROP_CONTEXT, &context, MAIN_PROP_EDITABLE, &editable,
244 			NULL );
245 
246 	enable_tab = ( context != NULL );
247 	nact_main_tab_enable_page( NACT_MAIN_WINDOW( instance ), TAB_FOLDERS, enable_tab );
248 
249 	button = base_window_get_widget( BASE_WINDOW( instance ), "FolderBrowseButton" );
250 	base_gtk_utils_set_editable( G_OBJECT( button ), editable );
251 }
252 
253 static void
on_browse_folder_clicked(GtkButton * button,BaseWindow * window)254 on_browse_folder_clicked( GtkButton *button, BaseWindow *window )
255 {
256 #if 0
257 	/* this is the code I sent to gtk-app-devel list
258 	 * to know why one is not able to just enter '/' in the location entry
259 	 */
260 	GtkWidget *dialog;
261 	gchar *path;
262 
263 	dialog = gtk_file_chooser_dialog_new( _( "Select a folder" ),
264 			NULL,
265 			GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
266 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
267 			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
268 			NULL );
269 
270 	gtk_file_chooser_set_filename( GTK_FILE_CHOOSER( dialog ), "/" );
271 
272 	if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_ACCEPT ){
273 		path = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER( dialog ));
274 		g_debug( "nact_ifolders_tab_on_add_folder_clicked: path=%s", path );
275 		g_free( path );
276 	}
277 
278 	gtk_widget_destroy( dialog );
279 #endif
280 
281 	gchar *uri, *path;
282 	GtkWindow *toplevel;
283 	GtkWidget *dialog;
284 
285 	uri = NULL;
286 	toplevel = base_window_get_gtk_toplevel( window );
287 
288 	/* i18n: title of the FileChoose dialog when selecting an URI which
289 	 * will be compare to Nautilus 'current_folder'
290 	 */
291 	dialog = gtk_file_chooser_dialog_new( _( "Select a folder" ),
292 			toplevel,
293 			GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
294 			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
295 			GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
296 			NULL );
297 
298 	base_gtk_utils_restore_window_position( window, NA_IPREFS_FOLDER_CHOOSER_WSP );
299 
300 	uri = na_settings_get_string( NA_IPREFS_FOLDER_CHOOSER_URI, NULL, NULL );
301 	if( uri && g_utf8_strlen( uri, -1 )){
302 		gtk_file_chooser_set_current_folder_uri( GTK_FILE_CHOOSER( dialog ), uri );
303 	}
304 	g_free( uri );
305 
306 	if( gtk_dialog_run( GTK_DIALOG( dialog )) == GTK_RESPONSE_ACCEPT ){
307 		uri = gtk_file_chooser_get_current_folder_uri( GTK_FILE_CHOOSER( dialog ));
308 		na_settings_set_string( NA_IPREFS_FOLDER_CHOOSER_URI, uri );
309 
310 		path = g_filename_from_uri( uri, NULL, NULL );
311 		nact_match_list_insert_row( window, ITAB_NAME, path, FALSE, FALSE );
312 		g_free( path );
313 
314 		g_free( uri );
315 	}
316 
317 	base_gtk_utils_save_window_position( window, NA_IPREFS_FOLDER_CHOOSER_WSP );
318 
319 	gtk_widget_destroy( dialog );
320 }
321 
322 static GSList *
get_folders(void * context)323 get_folders( void *context )
324 {
325 	return( na_object_get_folders( context ));
326 }
327 
328 static void
set_folders(void * context,GSList * filters)329 set_folders( void *context, GSList *filters )
330 {
331 	na_object_set_folders( context, filters );
332 }
333 
334 static void
on_instance_finalized(gpointer user_data,NactIFoldersTab * instance)335 on_instance_finalized( gpointer user_data, NactIFoldersTab *instance )
336 {
337 	static const gchar *thisfn = "nact_ifolders_tab_on_instance_finalized";
338 
339 	g_debug( "%s: instance=%p, user_data=%p", thisfn, ( void * ) instance, ( void * ) user_data );
340 }
341