Remove BaseWindow::get_ui_filename() virtual method
[nautilus-actions.git] / src / nact / nact-icon-chooser.c
blob91d9efe57d6a135628ad165f4d1472f4b9a59e6b
1 /*
2 * Nautilus Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program 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.
14 * This Program 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
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include "base-keysyms.h"
36 #include "base-iprefs.h"
37 #include "nact-application.h"
38 #include "nact-gtk-utils.h"
39 #include "nact-icon-chooser.h"
41 /* private class data
43 struct _NactIconChooserClassPrivate {
44 void *empty; /* so that gcc -pedantic is happy */
47 /* private instance data
49 struct _NactIconChooserPrivate {
50 gboolean dispose_has_run;
51 BaseWindow *main_window;
52 const gchar *initial_icon;
53 gchar *current_icon;
54 GtkWidget *path_preview;
57 #define VIEW_ICON_SIZE GTK_ICON_SIZE_DND
58 #define VIEW_ICON_DEFAULT_WIDTH 32 /* width of the GTK_ICON_SIZE_DND icon size */
59 #define PREVIEW_ICON_SIZE GTK_ICON_SIZE_DIALOG
60 #define PREVIEW_ICON_WIDTH 64
61 #define CURRENT_ICON_SIZE GTK_ICON_SIZE_DIALOG
63 /* column ordering in the Stock model
65 enum {
66 STOCK_NAME_COLUMN = 0,
67 STOCK_LABEL_COLUMN,
68 STOCK_PIXBUF_COLUMN,
69 STOCK_N_COLUMN
72 /* column ordering in the ThemeContext model
73 * this is the list store on the left which lets the user select the context
75 enum {
76 THEME_CONTEXT_LABEL_COLUMN = 0,
77 THEME_CONTEXT_STORE_COLUMN,
78 THEME_CONTEXT_LAST_SELECTED_COLUMN,
79 THEME_CONTEXT_N_COLUMN
82 /* column ordering in the ThemeIconView model
83 * foreach selected context, we display in the icon view the list of
84 * corresponding icons
86 enum {
87 THEME_ICON_LABEL_COLUMN = 0,
88 THEME_ICON_PIXBUF_COLUMN,
89 THEME_ICON_N_COLUMN
92 static const gchar *st_xmlui_filename = PKGDATADIR "/nact-icon-chooser.ui";
94 static BaseDialogClass *st_parent_class = NULL;
96 static GType register_type( void );
97 static void class_init( NactIconChooserClass *klass );
98 static void instance_init( GTypeInstance *instance, gpointer klass );
99 static void instance_dispose( GObject *dialog );
100 static void instance_finalize( GObject *dialog );
102 static NactIconChooser *icon_chooser_new( BaseWindow *parent );
104 static gchar *base_get_iprefs_window_id( const BaseWindow *window );
105 static gchar *base_get_dialog_name( const BaseWindow *window );
106 static void on_base_initial_load_dialog( NactIconChooser *editor, gpointer user_data );
107 static void do_initialize_themed_icons( NactIconChooser *editor );
108 static void do_initialize_icons_by_path( NactIconChooser *editor );
109 static void on_base_runtime_init_dialog( NactIconChooser *editor, gpointer user_data );
110 static void fillup_themed_icons( NactIconChooser *editor );
111 static void fillup_icons_by_path( NactIconChooser *editor );
112 static void on_base_all_widgets_showed( NactIconChooser *editor, gpointer user_data );
113 static void on_cancel_clicked( GtkButton *button, NactIconChooser *editor );
114 static void on_ok_clicked( GtkButton *button, NactIconChooser *editor );
115 static gboolean base_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window );
116 static void on_current_icon_changed( const NactIconChooser *editor );
117 static gboolean on_destroy( GtkWidget *widget, GdkEvent *event, void *foo );
118 static gboolean on_icon_view_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIconChooser *editor );
119 static gboolean on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIconChooser *editor );
120 static void on_themed_context_changed( GtkTreeSelection *selection, NactIconChooser *editor );
121 static void on_themed_icon_changed( GtkIconView *icon_view, NactIconChooser *editor );
122 static void on_themed_apply_button_clicked( GtkButton *button, NactIconChooser *editor );
123 static void on_themed_apply_triggered( NactIconChooser *editor );
124 static void on_path_selection_changed( GtkFileChooser *chooser, NactIconChooser *editor );
125 static void on_path_update_preview( GtkFileChooser *chooser, NactIconChooser *editor );
126 static void on_path_apply_button_clicked( GtkButton *button, NactIconChooser *editor );
127 static GtkListStore *theme_context_load_icons( NactIconChooser *editor, const gchar *context );
129 GType
130 nact_icon_chooser_get_type( void )
132 static GType dialog_type = 0;
134 if( !dialog_type ){
135 dialog_type = register_type();
138 return( dialog_type );
141 static GType
142 register_type( void )
144 static const gchar *thisfn = "nact_icon_chooser_register_type";
145 GType type;
147 static GTypeInfo info = {
148 sizeof( NactIconChooserClass ),
149 ( GBaseInitFunc ) NULL,
150 ( GBaseFinalizeFunc ) NULL,
151 ( GClassInitFunc ) class_init,
152 NULL,
153 NULL,
154 sizeof( NactIconChooser ),
156 ( GInstanceInitFunc ) instance_init
159 g_debug( "%s", thisfn );
161 type = g_type_register_static( BASE_DIALOG_TYPE, "NactIconChooser", &info, 0 );
163 return( type );
166 static void
167 class_init( NactIconChooserClass *klass )
169 static const gchar *thisfn = "nact_icon_chooser_class_init";
170 GObjectClass *object_class;
171 BaseWindowClass *base_class;
173 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
175 st_parent_class = g_type_class_peek_parent( klass );
177 object_class = G_OBJECT_CLASS( klass );
178 object_class->dispose = instance_dispose;
179 object_class->finalize = instance_finalize;
181 klass->private = g_new0( NactIconChooserClassPrivate, 1 );
183 base_class = BASE_WINDOW_CLASS( klass );
184 base_class->dialog_response = base_dialog_response;
185 base_class->get_toplevel_name = base_get_dialog_name;
186 base_class->get_iprefs_window_id = base_get_iprefs_window_id;
189 static void
190 instance_init( GTypeInstance *instance, gpointer klass )
192 static const gchar *thisfn = "nact_icon_chooser_instance_init";
193 NactIconChooser *self;
195 g_return_if_fail( NACT_IS_ICON_CHOOSER( instance ));
197 g_debug( "%s: instance=%p (%s), klass=%p",
198 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
200 self = NACT_ICON_CHOOSER( instance );
202 self->private = g_new0( NactIconChooserPrivate, 1 );
204 base_window_signal_connect(
205 BASE_WINDOW( self ),
206 G_OBJECT( self ),
207 BASE_SIGNAL_INITIALIZE_GTK,
208 G_CALLBACK( on_base_initial_load_dialog ));
210 base_window_signal_connect(
211 BASE_WINDOW( self ),
212 G_OBJECT( self ),
213 BASE_SIGNAL_INITIALIZE_WINDOW,
214 G_CALLBACK( on_base_runtime_init_dialog ));
216 base_window_signal_connect(
217 BASE_WINDOW( self ),
218 G_OBJECT( self ),
219 BASE_SIGNAL_ALL_WIDGETS_SHOWED,
220 G_CALLBACK( on_base_all_widgets_showed));
222 self->private->dispose_has_run = FALSE;
225 static void
226 instance_dispose( GObject *dialog )
228 static const gchar *thisfn = "nact_icon_chooser_instance_dispose";
229 NactIconChooser *self;
230 guint pos;
231 GtkWidget *paned;
232 NactApplication *application;
233 NAUpdater *updater;
234 NASettings *settings;
236 g_return_if_fail( NACT_IS_ICON_CHOOSER( dialog ));
238 g_debug( "%s: dialog=%p (%s)", thisfn, ( void * ) dialog, G_OBJECT_TYPE_NAME( dialog ));
240 self = NACT_ICON_CHOOSER( dialog );
242 if( !self->private->dispose_has_run ){
244 self->private->dispose_has_run = TRUE;
246 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( self )));
247 updater = nact_application_get_updater( application );
248 settings = na_pivot_get_settings( NA_PIVOT( updater ));
250 paned = base_window_get_widget( BASE_WINDOW( self ), "IconPaned" );
251 pos = gtk_paned_get_position( GTK_PANED( paned ));
252 na_settings_set_uint( settings, NA_IPREFS_ICON_CHOOSER_PANED, pos );
254 /* chain up to the parent class */
255 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
256 G_OBJECT_CLASS( st_parent_class )->dispose( dialog );
261 static void
262 instance_finalize( GObject *dialog )
264 static const gchar *thisfn = "nact_icon_chooser_instance_finalize";
265 NactIconChooser *self;
267 g_return_if_fail( NACT_IS_ICON_CHOOSER( dialog ));
269 g_debug( "%s: dialog=%p", thisfn, ( void * ) dialog );
271 self = NACT_ICON_CHOOSER( dialog );
273 g_free( self->private->current_icon );
275 g_free( self->private );
277 /* chain call to parent class */
278 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
279 G_OBJECT_CLASS( st_parent_class )->finalize( dialog );
284 * Returns a newly allocated NactIconChooser object.
286 static NactIconChooser *
287 icon_chooser_new( BaseWindow *parent )
289 return( g_object_new( NACT_ICON_CHOOSER_TYPE,
290 BASE_PROP_PARENT, parent,
291 BASE_PROP_XMLUI_FILENAME, st_xmlui_filename,
292 NULL ));
296 * nact_icon_chooser_choose_icon:
297 * @parent: the #BaseWindow parent of this dialog.
298 * @icon_name: the current icon at startup.
300 * Initializes and runs the dialog.
302 * This dialog lets the user choose an icon, either as the name of a
303 * themed icon, or as the path of an image.
305 * Returns: the selected icon, as a new string which should be g_free()
306 * by the caller.
308 gchar *
309 nact_icon_chooser_choose_icon( BaseWindow *parent, const gchar *icon_name )
311 static const gchar *thisfn = "nact_icon_chooser_choose_icon";
312 NactIconChooser *editor;
313 gchar *new_name;
315 g_return_val_if_fail( BASE_IS_WINDOW( parent ), NULL );
317 g_debug( "%s: parent=%p, icon_name=%s", thisfn, ( void * ) parent, icon_name );
319 editor = icon_chooser_new( parent );
320 editor->private->main_window = parent;
321 editor->private->initial_icon = icon_name;
323 new_name = g_strdup( editor->private->initial_icon );
325 if( base_window_run( BASE_WINDOW( editor ))){
326 g_free( new_name );
327 new_name = g_strdup( editor->private->current_icon );
330 g_object_unref( editor );
332 return( new_name );
335 static gchar *
336 base_get_iprefs_window_id( const BaseWindow *window )
338 return( g_strdup( NA_IPREFS_ICON_CHOOSER_WSP ));
341 static gchar *
342 base_get_dialog_name( const BaseWindow *window )
344 return( g_strdup( "IconChooserDialog" ));
347 static void
348 on_base_initial_load_dialog( NactIconChooser *editor, gpointer user_data )
350 static const gchar *thisfn = "nact_icon_chooser_on_initial_load_dialog";
352 g_return_if_fail( NACT_IS_ICON_CHOOSER( editor ));
354 g_debug( "%s: editor=%p, user_data=%p", thisfn, ( void * ) editor, ( void * ) user_data );
356 /* initialize the notebook
358 do_initialize_themed_icons( editor );
359 do_initialize_icons_by_path( editor );
361 /* destroy event
362 * there is here that we are going to release our stores
364 GtkDialog *dialog = GTK_DIALOG( base_window_get_gtk_toplevel( BASE_WINDOW( editor )));
365 g_signal_connect( G_OBJECT( dialog ), "destroy", G_CALLBACK( on_destroy ), NULL );
369 * initialize the themed icon tab
370 * first, the listview which handles the context list
371 * each context carries a list store which handles the corresponding icons
372 * this store is initialized the first time the context is selected
374 static void
375 do_initialize_themed_icons( NactIconChooser *editor )
377 GtkTreeView *context_view;
378 GtkTreeModel *context_model;
379 GtkCellRenderer *text_cell;
380 GtkTreeViewColumn *column;
381 GtkIconView *icon_view;
382 GtkTreeSelection *selection;
383 GtkIconTheme *icon_theme;
384 GList *theme_contexts, *it;
385 const gchar *context_label;
386 GtkTreeIter iter;
388 context_view = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedTreeView" ));
389 context_model = GTK_TREE_MODEL(
390 gtk_list_store_new( THEME_CONTEXT_N_COLUMN,
391 G_TYPE_STRING, G_TYPE_OBJECT, G_TYPE_STRING ));
392 gtk_tree_view_set_model( context_view, context_model );
393 gtk_tree_view_set_headers_visible( context_view, FALSE );
395 text_cell = gtk_cell_renderer_text_new();
396 column = gtk_tree_view_column_new_with_attributes(
397 "theme-context",
398 text_cell,
399 "text", THEME_CONTEXT_LABEL_COLUMN,
400 NULL );
401 gtk_tree_view_append_column( context_view, column );
403 icon_view = GTK_ICON_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconView" ));
404 gtk_icon_view_set_text_column( icon_view, THEME_ICON_LABEL_COLUMN );
405 gtk_icon_view_set_pixbuf_column( icon_view, THEME_ICON_PIXBUF_COLUMN );
406 gtk_icon_view_set_selection_mode( icon_view, GTK_SELECTION_BROWSE );
408 selection = gtk_tree_view_get_selection( context_view );
409 gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE );
411 icon_theme = gtk_icon_theme_get_default();
412 theme_contexts = g_list_sort(
413 gtk_icon_theme_list_contexts( icon_theme ), ( GCompareFunc ) g_utf8_collate );
415 for( it = theme_contexts ; it ; it = it->next ){
416 context_label = ( const gchar *) it->data;
417 gtk_list_store_append( GTK_LIST_STORE( context_model ), &iter );
418 gtk_list_store_set( GTK_LIST_STORE( context_model ), &iter,
419 THEME_CONTEXT_LABEL_COLUMN, context_label,
420 THEME_CONTEXT_STORE_COLUMN, NULL,
421 -1 );
423 g_list_foreach( theme_contexts, ( GFunc ) g_free, NULL );
424 g_list_free( theme_contexts );
426 g_object_unref( context_model );
429 static void
430 do_initialize_icons_by_path( NactIconChooser *editor )
432 GtkFileChooser *file_chooser;
434 file_chooser = GTK_FILE_CHOOSER( base_window_get_widget( BASE_WINDOW( editor ), "FileChooser" ));
435 gtk_file_chooser_set_action( file_chooser, GTK_FILE_CHOOSER_ACTION_OPEN );
436 gtk_file_chooser_set_select_multiple( file_chooser, FALSE );
439 static void
440 on_base_runtime_init_dialog( NactIconChooser *editor, gpointer user_data )
442 static const gchar *thisfn = "nact_icon_chooser_on_runtime_init_dialog";
443 guint pos;
444 GtkWidget *paned;
445 NactApplication *application;
446 NAUpdater *updater;
447 NASettings *settings;
449 g_return_if_fail( NACT_IS_ICON_CHOOSER( editor ));
451 g_debug( "%s: editor=%p, user_data=%p", thisfn, ( void * ) editor, ( void * ) user_data );
453 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( editor )));
454 updater = nact_application_get_updater( application );
455 settings = na_pivot_get_settings( NA_PIVOT( updater ));
457 pos = na_settings_get_uint( settings, NA_IPREFS_ICON_CHOOSER_PANED, NULL, NULL );
458 if( pos ){
459 paned = base_window_get_widget( BASE_WINDOW( editor ), "IconPaned" );
460 gtk_paned_set_position( GTK_PANED( paned ), pos );
463 /* setup the initial icon
465 editor->private->current_icon = g_strdup( editor->private->initial_icon );
466 on_current_icon_changed( editor );
468 /* fillup the icon stores
470 fillup_themed_icons( editor );
471 fillup_icons_by_path( editor );
473 /* intercept Escape key: we do not quit on Esc.
475 base_window_signal_connect(
476 BASE_WINDOW( editor ),
477 G_OBJECT( base_window_get_gtk_toplevel( BASE_WINDOW( editor ))),
478 "key-press-event",
479 G_CALLBACK( on_key_pressed_event ));
481 /* OK/Cancel buttons
483 base_window_signal_connect_by_name(
484 BASE_WINDOW( editor ), "CancelButton", "clicked", G_CALLBACK( on_cancel_clicked ));
486 base_window_signal_connect_by_name(
487 BASE_WINDOW( editor ), "OKButton", "clicked", G_CALLBACK( on_ok_clicked ));
490 static void
491 fillup_themed_icons( NactIconChooser *editor )
493 GtkTreeView *context_view;
494 GtkTreeSelection *selection;
495 GtkTreePath *path;
496 GtkIconView *icon_view;
498 icon_view = GTK_ICON_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconView" ));
499 base_window_signal_connect(
500 BASE_WINDOW( editor ), G_OBJECT( icon_view ), "selection-changed", G_CALLBACK( on_themed_icon_changed ));
501 /* catch double-click */
502 base_window_signal_connect(
503 BASE_WINDOW( editor ), G_OBJECT( icon_view ), "button-press-event", G_CALLBACK( on_icon_view_button_press_event ));
505 context_view = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedTreeView" ));
506 selection = gtk_tree_view_get_selection( context_view );
507 base_window_signal_connect(
508 BASE_WINDOW( editor ), G_OBJECT( selection ), "changed", G_CALLBACK( on_themed_context_changed ));
510 path = gtk_tree_path_new_first();
511 gtk_tree_selection_select_path( selection, path );
512 gtk_tree_path_free( path );
514 base_window_signal_connect_by_name(
515 BASE_WINDOW( editor ), "ThemedApplyButton", "clicked", G_CALLBACK( on_themed_apply_button_clicked ));
518 static void
519 fillup_icons_by_path( NactIconChooser *editor )
521 GtkFileChooser *file_chooser;
522 NactApplication *application;
523 NAUpdater *updater;
524 NASettings *settings;
525 gchar *uri;
527 file_chooser = GTK_FILE_CHOOSER( base_window_get_widget( BASE_WINDOW( editor ), "FileChooser" ));
528 editor->private->path_preview = gtk_image_new();
529 gtk_file_chooser_set_preview_widget( file_chooser, editor->private->path_preview );
531 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( editor )));
532 updater = nact_application_get_updater( application );
533 settings = na_pivot_get_settings( NA_PIVOT( updater ));
535 gtk_file_chooser_unselect_all( file_chooser );
537 uri = na_settings_get_string( settings, NA_IPREFS_ICON_CHOOSER_URI, NULL, NULL );
538 if( uri ){
539 gtk_file_chooser_set_current_folder_uri( file_chooser, uri );
540 g_free( uri );
541 } else if( editor->private->current_icon ){
542 gtk_file_chooser_set_filename( file_chooser, editor->private->current_icon );
545 base_window_signal_connect(
546 BASE_WINDOW( editor ), G_OBJECT( file_chooser ), "selection-changed", G_CALLBACK( on_path_selection_changed ));
547 base_window_signal_connect(
548 BASE_WINDOW( editor ), G_OBJECT( file_chooser ), "update-preview", G_CALLBACK( on_path_update_preview ));
550 base_window_signal_connect_by_name(
551 BASE_WINDOW( editor ), "PathApplyButton", "clicked", G_CALLBACK( on_path_apply_button_clicked ));
554 static void
555 on_base_all_widgets_showed( NactIconChooser *editor, gpointer user_data )
557 static const gchar *thisfn = "nact_icon_chooser_on_all_widgets_showed";
558 GtkWidget *about_button;
560 g_return_if_fail( NACT_IS_ICON_CHOOSER( editor ));
562 g_debug( "%s: editor=%p, user_data=%p", thisfn, ( void * ) editor, ( void * ) user_data );
564 /* hide about button not used here
566 about_button = base_window_get_widget( BASE_WINDOW( editor ), "AboutButton" );
567 gtk_widget_hide( about_button );
570 static void
571 on_cancel_clicked( GtkButton *button, NactIconChooser *editor )
573 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( editor ));
574 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_CLOSE );
577 static void
578 on_ok_clicked( GtkButton *button, NactIconChooser *editor )
580 GtkWindow *toplevel = base_window_get_gtk_toplevel( BASE_WINDOW( editor ));
581 gtk_dialog_response( GTK_DIALOG( toplevel ), GTK_RESPONSE_OK );
584 static gboolean
585 base_dialog_response( GtkDialog *dialog, gint code, BaseWindow *window )
587 static const gchar *thisfn = "nact_icon_chooser_on_dialog_response";
588 NactIconChooser *editor;
590 g_return_val_if_fail( NACT_IS_ICON_CHOOSER( window ), FALSE );
592 g_debug( "%s: dialog=%p, code=%d, window=%p", thisfn, ( void * ) dialog, code, ( void * ) window );
594 editor = NACT_ICON_CHOOSER( window );
596 switch( code ){
597 case GTK_RESPONSE_NONE:
598 case GTK_RESPONSE_DELETE_EVENT:
599 case GTK_RESPONSE_CLOSE:
600 case GTK_RESPONSE_CANCEL:
602 g_free( editor->private->current_icon );
603 editor->private->current_icon = g_strdup( editor->private->initial_icon );
604 return( TRUE );
605 break;
607 case GTK_RESPONSE_OK:
608 return( TRUE );
609 break;
612 return( FALSE );
616 * display at the top of the dialog the icon addressed in @icon
617 * this is this icon which will be returned if the user validates
618 * this dialog
620 static void
621 on_current_icon_changed( const NactIconChooser *editor )
623 GtkImage *image;
624 gchar *icon_label;
625 GtkLabel *label;
627 image = GTK_IMAGE( base_window_get_widget( BASE_WINDOW( editor ), "IconImage" ));
628 nact_gtk_utils_render( editor->private->current_icon, image, CURRENT_ICON_SIZE );
630 if( editor->private->current_icon ){
631 if( g_path_is_absolute( editor->private->current_icon )){
632 icon_label = g_filename_to_utf8( editor->private->current_icon, -1, NULL, NULL, NULL );
633 } else {
634 icon_label = g_strdup( editor->private->current_icon );
636 label = GTK_LABEL( base_window_get_widget( BASE_WINDOW( editor ), "IconLabel" ));
637 gtk_label_set_label( label, icon_label );
638 g_free( icon_label );
642 static gboolean
643 on_destroy( GtkWidget *widget, GdkEvent *event, void *foo )
645 static const gchar *thisfn = "nact_icon_chooser_on_destroy";
646 GtkTreeView *context_view;
647 GtkListStore *context_store;
648 GtkTreeIter context_iter;
649 GtkListStore *icon_store;
650 gchar *context_label;
652 g_debug( "%s: widget=%p", thisfn, ( void * ) widget );
654 /* clear the various models
656 context_view = GTK_TREE_VIEW( nact_gtk_utils_get_widget_by_name( GTK_WINDOW( widget ), "ThemedTreeView" ));
657 context_store = GTK_LIST_STORE( gtk_tree_view_get_model( context_view ));
659 if( gtk_tree_model_get_iter_first( GTK_TREE_MODEL( context_store ), &context_iter )){
660 while( TRUE ){
662 gtk_tree_model_get( GTK_TREE_MODEL( context_store ), &context_iter,
663 THEME_CONTEXT_LABEL_COLUMN, &context_label,
664 THEME_CONTEXT_STORE_COLUMN, &icon_store,
665 -1 );
666 if( icon_store ){
667 g_debug( "%s: context=%s, clearing store=%p", thisfn, context_label, ( void * ) icon_store );
668 gtk_list_store_clear( icon_store );
669 g_object_unref( icon_store );
672 g_free( context_label );
674 if( !gtk_tree_model_iter_next( GTK_TREE_MODEL( context_store ), &context_iter )){
675 break;
680 gtk_list_store_clear( context_store );
682 /* let other handlers get this message */
683 return( FALSE );
687 * mouse click on the themed icons icon view
689 static gboolean
690 on_icon_view_button_press_event( GtkWidget *widget, GdkEventButton *event, NactIconChooser *editor )
692 gboolean stop = FALSE;
694 /* double-click of left button
695 * > triggers a 'Apply' action
697 if( event->type == GDK_2BUTTON_PRESS && event->button == 1 ){
698 on_themed_apply_triggered( editor );
699 stop = TRUE;
702 return( stop );
705 static gboolean
706 on_key_pressed_event( GtkWidget *widget, GdkEventKey *event, NactIconChooser *editor )
708 gboolean stop = FALSE;
710 g_return_val_if_fail( NACT_IS_ICON_CHOOSER( editor ), FALSE );
712 if( !editor->private->dispose_has_run ){
714 /* inhibit Escape key */
715 if( event->keyval == NACT_KEY_Escape ){
716 stop = TRUE;
720 return( stop );
723 static void
724 on_themed_context_changed( GtkTreeSelection *selection, NactIconChooser *editor )
726 GtkTreeModel *model;
727 GtkTreeIter iter;
728 GtkListStore *store;
729 gchar *context, *last_path;
730 GtkTreePath *path;
731 GtkWidget *preview_image, *preview_label;
733 if( gtk_tree_selection_get_selected( selection, &model, &iter )){
734 gtk_tree_model_get( model, &iter,
735 THEME_CONTEXT_LABEL_COLUMN, &context,
736 THEME_CONTEXT_STORE_COLUMN, &store,
737 THEME_CONTEXT_LAST_SELECTED_COLUMN, &last_path,
738 -1 );
740 if( !store ){
741 store = theme_context_load_icons( editor, context );
742 gtk_list_store_set( GTK_LIST_STORE( model ), &iter, THEME_CONTEXT_STORE_COLUMN, store, -1 );
745 GtkIconView *iconview = GTK_ICON_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconView" ));
746 gtk_icon_view_set_model( iconview, GTK_TREE_MODEL( store ));
748 if( last_path ){
749 path = gtk_tree_path_new_from_string( last_path );
750 gtk_icon_view_select_path( iconview, path );
751 gtk_tree_path_free( path );
753 } else {
754 preview_image = base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconImage" );
755 gtk_image_set_from_pixbuf( GTK_IMAGE( preview_image ), NULL );
756 preview_label = base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconName" );
757 gtk_label_set_text( GTK_LABEL( preview_label ), "" );
760 g_free( last_path );
761 g_free( context );
762 g_object_unref( store );
766 static void
767 on_themed_icon_changed( GtkIconView *icon_view, NactIconChooser *editor )
769 GList *selected;
770 GtkTreeModel *model;
771 GtkTreeIter iter;
772 gchar *label;
773 GtkWidget *preview_image, *preview_label;
774 GtkTreeView *context_view;
775 GtkListStore *context_store;
776 GtkTreeSelection *context_selection;
777 GtkTreeIter context_iter;
778 gchar *icon_path;
780 selected = gtk_icon_view_get_selected_items( icon_view );
781 if( selected ){
782 model = gtk_icon_view_get_model( icon_view );
784 if( gtk_tree_model_get_iter( model, &iter, ( GtkTreePath * ) selected->data )){
785 gtk_tree_model_get( model, &iter,
786 THEME_ICON_LABEL_COLUMN, &label,
787 -1 );
789 preview_image = base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconImage" );
790 nact_gtk_utils_render( label, GTK_IMAGE( preview_image ), PREVIEW_ICON_SIZE );
791 preview_label = base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconName" );
792 gtk_label_set_text( GTK_LABEL( preview_label ), label );
794 /* record in context tree view the path to the last selected icon
796 context_view = GTK_TREE_VIEW( base_window_get_widget( BASE_WINDOW( editor ), "ThemedTreeView" ));
797 context_selection = gtk_tree_view_get_selection( context_view );
798 if( gtk_tree_selection_get_selected( context_selection, ( GtkTreeModel ** ) &context_store, &context_iter )){
799 icon_path = gtk_tree_model_get_string_from_iter( model, &iter );
800 gtk_list_store_set( context_store, &context_iter, THEME_CONTEXT_LAST_SELECTED_COLUMN, icon_path, -1 );
801 g_free( icon_path );
804 g_free( label );
807 g_list_foreach( selected, ( GFunc ) gtk_tree_path_free, NULL );
808 g_list_free( selected );
812 static void
813 on_themed_apply_button_clicked( GtkButton *button, NactIconChooser *editor )
815 on_themed_apply_triggered( editor );
818 static void
819 on_themed_apply_triggered( NactIconChooser *editor )
821 GtkWidget *icon_label;
822 const gchar *icon_name;
824 icon_label = base_window_get_widget( BASE_WINDOW( editor ), "ThemedIconName" );
825 icon_name = gtk_label_get_text( GTK_LABEL( icon_label ));
827 g_free( editor->private->current_icon );
828 editor->private->current_icon = g_strdup( icon_name );
829 on_current_icon_changed( editor );
832 static void
833 on_path_selection_changed( GtkFileChooser *file_chooser, NactIconChooser *editor )
835 gchar *uri;
836 NactApplication *application;
837 NAUpdater *updater;
838 NASettings *settings;
840 uri = gtk_file_chooser_get_current_folder_uri( file_chooser );
841 if( uri ){
842 application = NACT_APPLICATION( base_window_get_application( BASE_WINDOW( editor )));
843 updater = nact_application_get_updater( application );
844 settings = na_pivot_get_settings( NA_PIVOT( updater ));
845 na_settings_set_string( settings, NA_IPREFS_ICON_CHOOSER_URI, uri );
846 g_free( uri );
850 static void
851 on_path_update_preview( GtkFileChooser *file_chooser, NactIconChooser *editor )
853 static const gchar *thisfn = "nact_icon_chooser_on_path_update_preview";
854 char *filename;
855 GdkPixbuf *pixbuf;
856 gboolean have_preview;
857 gint width, height;
859 if( !gtk_icon_size_lookup( PREVIEW_ICON_SIZE, &width, &height )){
860 width = PREVIEW_ICON_WIDTH;
861 height = PREVIEW_ICON_WIDTH;
864 have_preview = FALSE;
865 filename = gtk_file_chooser_get_preview_filename( file_chooser );
866 g_debug( "%s: file_chooser=%p, editor=%p, filename=%s",
867 thisfn, ( void * ) file_chooser, ( void * ) editor, filename );
869 if( filename ){
870 pixbuf = gdk_pixbuf_new_from_file_at_size( filename, width, height, NULL );
871 have_preview = ( pixbuf != NULL );
872 g_free( filename );
875 if( have_preview ){
876 gtk_image_set_from_pixbuf( GTK_IMAGE( editor->private->path_preview ), pixbuf );
877 g_object_unref( pixbuf );
880 gtk_file_chooser_set_preview_widget_active( file_chooser, TRUE );
883 static void
884 on_path_apply_button_clicked( GtkButton *button, NactIconChooser *editor )
886 GtkFileChooser *file_chooser = GTK_FILE_CHOOSER( base_window_get_widget( BASE_WINDOW( editor ), "FileChooser" ));
888 /* this is a filename in the character set specified by the G_FILENAME_ENCODING
889 * environment variable
891 g_free( editor->private->current_icon );
892 editor->private->current_icon = gtk_file_chooser_get_filename( file_chooser );
893 on_current_icon_changed( editor );
896 static GtkListStore *
897 theme_context_load_icons( NactIconChooser *editor, const gchar *context )
899 static const gchar *thisfn = "nact_icon_chooser_theme_context_load_icons";
900 GtkTreeIter iter;
901 GList *ic;
902 GError *error;
903 gint width, height;
905 g_debug( "%s: editor=%p, context=%s", thisfn, ( void * ) editor, context );
907 GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
908 GtkListStore *store = gtk_list_store_new( THEME_ICON_N_COLUMN, G_TYPE_STRING, GDK_TYPE_PIXBUF );
910 GList *icon_list = g_list_sort( gtk_icon_theme_list_icons( icon_theme, context ), ( GCompareFunc ) g_utf8_collate );
912 if( !gtk_icon_size_lookup( VIEW_ICON_SIZE, &width, &height )){
913 width = VIEW_ICON_DEFAULT_WIDTH;
915 g_debug( "%s: width=%d", thisfn, width );
917 for( ic = icon_list ; ic ; ic = ic->next ){
918 const gchar *icon_name = ( const gchar * ) ic->data;
919 error = NULL;
920 GdkPixbuf *pixbuf = gtk_icon_theme_load_icon(
921 icon_theme, icon_name, width, GTK_ICON_LOOKUP_GENERIC_FALLBACK, &error );
922 if( error ){
923 g_warning( "%s: %s", thisfn, error->message );
924 g_error_free( error );
925 } else {
926 gtk_list_store_append( store, &iter );
927 gtk_list_store_set( store, &iter,
928 THEME_ICON_LABEL_COLUMN, icon_name,
929 THEME_ICON_PIXBUF_COLUMN, pixbuf,
930 -1 );
931 g_object_unref( pixbuf );
934 g_debug( "%s: %d loaded icons in store=%p", thisfn, g_list_length( icon_list ), ( void * ) store );
935 g_list_foreach( icon_list, ( GFunc ) g_free, NULL );
936 g_list_free( icon_list );
938 return( store );