mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2025-01-12 05:20:17 +00:00
Add over-big test case for preview (much of size from a modified copy of
Wed Jul 23 17:52:01 2003 Owen Taylor <otaylor@redhat.com> * testfilechooser.c: Add over-big test case for preview (much of size from a modified copy of gdk_pixbuf_new_from_file_at_size()) * gtkfilechooserutils.[ch] gtkfilechooser.c gtkfilechooserprivate.h gtkfilechooserimpldefault.c: Add get_preview_path() as a virtual function; implement update-preview signal that was in the header file. * gtkfilechooserimpldefault.c: Finish a simple preview widget implementation.
This commit is contained in:
parent
a19781c504
commit
d97d7df947
@ -28,7 +28,6 @@
|
||||
static void gtk_file_chooser_base_init (gpointer g_iface);
|
||||
|
||||
static GtkFilePath *gtk_file_chooser_get_path (GtkFileChooser *chooser);
|
||||
static GtkFilePath *gtk_file_chooser_get_preview_path (GtkFileChooser *chooser);
|
||||
|
||||
GType
|
||||
gtk_file_chooser_get_type (void)
|
||||
@ -77,6 +76,13 @@ gtk_file_chooser_base_init (gpointer g_iface)
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
g_signal_new ("update-preview",
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkFileChooserIface, update_preview),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_object_interface_install_property (g_iface,
|
||||
g_param_spec_enum ("action",
|
||||
@ -771,7 +777,7 @@ gtk_file_chooser_get_current_folder_uri (GtkFileChooser *chooser)
|
||||
* @path: the #GtkFilePath for the new folder
|
||||
*
|
||||
* Sets the current folder for @chooser from a #GtkFilePath.
|
||||
* Internal function, see _gtk_file_chooser_set_current_folder_uri().
|
||||
* Internal function, see gtk_file_chooser_set_current_folder_uri().
|
||||
**/
|
||||
void
|
||||
_gtk_file_chooser_set_current_folder_path (GtkFileChooser *chooser,
|
||||
@ -993,10 +999,22 @@ gtk_file_chooser_get_preview_widget_active (GtkFileChooser *chooser)
|
||||
return active;
|
||||
}
|
||||
|
||||
static GtkFilePath *
|
||||
gtk_file_chooser_get_preview_path (GtkFileChooser *chooser)
|
||||
/**
|
||||
* gtk_file_chooser_get_preview_filename:
|
||||
* @chooser: a #GtkFileChooser
|
||||
*
|
||||
* Gets the filename that should be previewed in a custom preview
|
||||
* Internal function, see gtk_file_chooser_get_preview_uri().n
|
||||
*
|
||||
* Return value: the #GtkFilePath for the file to preview, or %NULL if no file
|
||||
* is selected. Free with gtk_file_path_free().
|
||||
**/
|
||||
GtkFilePath *
|
||||
_gtk_file_chooser_get_preview_path (GtkFileChooser *chooser)
|
||||
{
|
||||
return NULL;
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
return GTK_FILE_CHOOSER_GET_IFACE (chooser)->get_preview_path (chooser);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1006,11 +1024,11 @@ gtk_file_chooser_get_preview_path (GtkFileChooser *chooser)
|
||||
* Gets the filename that should be previewed in a custom preview
|
||||
* widget. See gtk_file_chooser_set_preview_widget().
|
||||
*
|
||||
* Return value: the filename to display, or %NULL if no file
|
||||
* Return value: the filename to preview, or %NULL if no file
|
||||
* is selected, or if the selected file cannot be represented
|
||||
* as a local filename. Free with g_free()
|
||||
**/
|
||||
const char *
|
||||
char *
|
||||
gtk_file_chooser_get_preview_filename (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileSystem *file_system;
|
||||
@ -1020,7 +1038,7 @@ gtk_file_chooser_get_preview_filename (GtkFileChooser *chooser)
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
file_system = _gtk_file_chooser_get_file_system (chooser);
|
||||
path = gtk_file_chooser_get_preview_path (chooser);
|
||||
path = _gtk_file_chooser_get_preview_path (chooser);
|
||||
if (path)
|
||||
{
|
||||
result = gtk_file_system_path_to_filename (file_system, path);
|
||||
@ -1037,10 +1055,10 @@ gtk_file_chooser_get_preview_filename (GtkFileChooser *chooser)
|
||||
* Gets the URI that should be previewed in a custom preview
|
||||
* widget. See gtk_file_chooser_set_preview_widget().
|
||||
*
|
||||
* Return value: the URI to display, or %NULL if no file
|
||||
* is selected.
|
||||
* Return value: the URI for the file to preview, or %NULL if no file
|
||||
* is selected. Free with g_free().
|
||||
**/
|
||||
const char *
|
||||
char *
|
||||
gtk_file_chooser_get_preview_uri (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileSystem *file_system;
|
||||
@ -1050,7 +1068,7 @@ gtk_file_chooser_get_preview_uri (GtkFileChooser *chooser)
|
||||
g_return_val_if_fail (GTK_IS_FILE_CHOOSER (chooser), NULL);
|
||||
|
||||
file_system = _gtk_file_chooser_get_file_system (chooser);
|
||||
path = gtk_file_chooser_get_path (chooser);
|
||||
path = _gtk_file_chooser_get_preview_path (chooser);
|
||||
if (path)
|
||||
{
|
||||
result = gtk_file_system_path_to_uri (file_system, path);
|
||||
@ -1161,5 +1179,3 @@ gtk_file_chooser_get_filter (GtkFileChooser *chooser)
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,8 +98,8 @@ void gtk_file_chooser_set_preview_widget_active (GtkFileChooser *chooser,
|
||||
gboolean active);
|
||||
gboolean gtk_file_chooser_get_preview_widget_active (GtkFileChooser *chooser);
|
||||
|
||||
const char *gtk_file_chooser_get_preview_filename (GtkFileChooser *file_chooser);
|
||||
const char *gtk_file_chooser_get_preview_uri (GtkFileChooser *file_chooser);
|
||||
char *gtk_file_chooser_get_preview_filename (GtkFileChooser *file_chooser);
|
||||
char *gtk_file_chooser_get_preview_uri (GtkFileChooser *file_chooser);
|
||||
|
||||
/* List of user selectable filters
|
||||
*/
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <gtk/gtkcellrendererpixbuf.h>
|
||||
#include <gtk/gtkcellrenderertext.h>
|
||||
#include <gtk/gtkentry.h>
|
||||
#include <gtk/gtkframe.h>
|
||||
#include <gtk/gtkhbox.h>
|
||||
#include <gtk/gtkhpaned.h>
|
||||
#include <gtk/gtkicontheme.h>
|
||||
@ -36,6 +37,7 @@
|
||||
#include <gtk/gtkmenuitem.h>
|
||||
#include <gtk/gtkoptionmenu.h>
|
||||
#include <gtk/gtkscrolledwindow.h>
|
||||
#include <gtk/gtktable.h>
|
||||
#include <gtk/gtktreeview.h>
|
||||
#include <gtk/gtktreemodelsort.h>
|
||||
#include <gtk/gtktreeselection.h>
|
||||
@ -69,6 +71,9 @@ struct _GtkFileChooserImplDefault
|
||||
GSList *filters;
|
||||
|
||||
GtkFilePath *current_folder;
|
||||
GtkFilePath *preview_path;
|
||||
|
||||
GtkWidget *preview_frame;
|
||||
|
||||
guint folder_mode : 1;
|
||||
guint local_only : 1;
|
||||
@ -116,6 +121,7 @@ static void gtk_file_chooser_impl_default_unselect_path (GtkFileC
|
||||
static void gtk_file_chooser_impl_default_select_all (GtkFileChooser *chooser);
|
||||
static void gtk_file_chooser_impl_default_unselect_all (GtkFileChooser *chooser);
|
||||
static GSList * gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser);
|
||||
static GtkFilePath * gtk_file_chooser_impl_default_get_preview_path (GtkFileChooser *chooser);
|
||||
static GtkFileSystem *gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser);
|
||||
static void gtk_file_chooser_impl_default_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
@ -123,8 +129,9 @@ static void gtk_file_chooser_impl_default_remove_filter (GtkFileC
|
||||
GtkFileFilter *filter);
|
||||
static GSList * gtk_file_chooser_impl_default_list_filters (GtkFileChooser *chooser);
|
||||
|
||||
static void set_current_filter (GtkFileChooserImplDefault *impl,
|
||||
GtkFileFilter *filter);
|
||||
static void set_current_filter (GtkFileChooserImplDefault *impl,
|
||||
GtkFileFilter *filter);
|
||||
static void check_preview_change (GtkFileChooserImplDefault *impl);
|
||||
|
||||
static void filter_option_menu_changed (GtkOptionMenu *option_menu,
|
||||
GtkFileChooserImplDefault *impl);
|
||||
@ -221,6 +228,7 @@ gtk_file_chooser_impl_default_iface_init (GtkFileChooserIface *iface)
|
||||
iface->select_all = gtk_file_chooser_impl_default_select_all;
|
||||
iface->unselect_all = gtk_file_chooser_impl_default_unselect_all;
|
||||
iface->get_paths = gtk_file_chooser_impl_default_get_paths;
|
||||
iface->get_preview_path = gtk_file_chooser_impl_default_get_preview_path;
|
||||
iface->get_file_system = gtk_file_chooser_impl_default_get_file_system;
|
||||
iface->set_current_folder = gtk_file_chooser_impl_default_set_current_folder;
|
||||
iface->get_current_folder = gtk_file_chooser_impl_default_get_current_folder;
|
||||
@ -252,6 +260,15 @@ gtk_file_chooser_impl_default_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
update_preview_widget_visibility (GtkFileChooserImplDefault *impl)
|
||||
{
|
||||
if (impl->preview_widget_active && impl->preview_widget)
|
||||
gtk_widget_show (impl->preview_frame);
|
||||
else
|
||||
gtk_widget_hide (impl->preview_frame);
|
||||
}
|
||||
|
||||
static void
|
||||
set_preview_widget (GtkFileChooserImplDefault *impl,
|
||||
GtkWidget *preview_widget)
|
||||
@ -263,6 +280,9 @@ set_preview_widget (GtkFileChooserImplDefault *impl,
|
||||
{
|
||||
g_object_unref (impl->preview_widget);
|
||||
impl->preview_widget = NULL;
|
||||
|
||||
gtk_container_remove (GTK_CONTAINER (impl->preview_frame),
|
||||
impl->preview_widget);
|
||||
}
|
||||
|
||||
impl->preview_widget = preview_widget;
|
||||
@ -270,7 +290,13 @@ set_preview_widget (GtkFileChooserImplDefault *impl,
|
||||
{
|
||||
g_object_ref (impl->preview_widget);
|
||||
gtk_object_sink (GTK_OBJECT (impl->preview_widget));
|
||||
|
||||
gtk_widget_show (impl->preview_widget);
|
||||
gtk_container_add (GTK_CONTAINER (impl->preview_frame),
|
||||
impl->preview_widget);
|
||||
}
|
||||
|
||||
update_preview_widget_visibility (impl);
|
||||
}
|
||||
|
||||
static GObject*
|
||||
@ -282,6 +308,7 @@ gtk_file_chooser_impl_default_constructor (GType type,
|
||||
GtkTreeViewColumn *column;
|
||||
GtkCellRenderer *renderer;
|
||||
GObject *object;
|
||||
GtkWidget *table;
|
||||
GtkWidget *hpaned;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *label;
|
||||
@ -299,9 +326,17 @@ gtk_file_chooser_impl_default_constructor (GType type,
|
||||
|
||||
gtk_widget_push_composite_child ();
|
||||
|
||||
table = gtk_table_new (3, 2, FALSE);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 6);
|
||||
gtk_box_pack_start (GTK_BOX (impl), table, TRUE, TRUE, 0);
|
||||
gtk_widget_show (table);
|
||||
|
||||
impl->filter_alignment = gtk_alignment_new (0.0, 0.5, 0.0, 1.0);
|
||||
gtk_alignment_set_padding (GTK_ALIGNMENT (impl->filter_alignment), 0, 6, 0, 0);
|
||||
gtk_box_pack_start (GTK_BOX (impl), impl->filter_alignment, FALSE, FALSE, 0);
|
||||
gtk_table_attach (GTK_TABLE (table), impl->filter_alignment,
|
||||
0, 1, 0, 1,
|
||||
GTK_EXPAND | GTK_FILL, 0,
|
||||
0, 0);
|
||||
/* Don't show filter initially */
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 6);
|
||||
@ -324,7 +359,10 @@ gtk_file_chooser_impl_default_constructor (GType type,
|
||||
G_CALLBACK (filter_option_menu_changed), impl);
|
||||
|
||||
hpaned = gtk_hpaned_new ();
|
||||
gtk_box_pack_start (GTK_BOX (impl), hpaned, TRUE, TRUE, 0);
|
||||
gtk_table_attach (GTK_TABLE (table), hpaned,
|
||||
0, 1, 1, 2,
|
||||
GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL,
|
||||
0, 0);
|
||||
gtk_widget_show (hpaned);
|
||||
|
||||
impl->tree_scrollwin = gtk_scrolled_window_new (NULL, NULL);
|
||||
@ -365,7 +403,10 @@ gtk_file_chooser_impl_default_constructor (GType type,
|
||||
G_CALLBACK (list_selection_changed), impl);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 6);
|
||||
gtk_box_pack_start (GTK_BOX (impl), hbox, FALSE, FALSE, 6);
|
||||
gtk_table_attach (GTK_TABLE (table), hbox,
|
||||
0, 2, 2, 3,
|
||||
GTK_EXPAND | GTK_FILL, 0,
|
||||
0, 6);
|
||||
gtk_widget_show (hbox);
|
||||
|
||||
label = gtk_label_new_with_mnemonic ("_Location:");
|
||||
@ -382,6 +423,13 @@ gtk_file_chooser_impl_default_constructor (GType type,
|
||||
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), impl->entry);
|
||||
|
||||
impl->preview_frame = gtk_frame_new ("Preview");
|
||||
gtk_table_attach (GTK_TABLE (table), impl->preview_frame,
|
||||
1, 2, 0, 2,
|
||||
0, GTK_EXPAND | GTK_FILL,
|
||||
0, 0);
|
||||
/* Don't show preview frame initially */
|
||||
|
||||
#if 0
|
||||
focus_chain = g_list_append (NULL, impl->entry);
|
||||
focus_chain = g_list_append (focus_chain, impl->tree);
|
||||
@ -488,6 +536,7 @@ gtk_file_chooser_impl_default_set_property (GObject *object,
|
||||
break;
|
||||
case GTK_FILE_CHOOSER_PROP_PREVIEW_WIDGET_ACTIVE:
|
||||
impl->preview_widget_active = g_value_get_boolean (value);
|
||||
update_preview_widget_visibility (impl);
|
||||
break;
|
||||
case GTK_FILE_CHOOSER_PROP_SELECT_MULTIPLE:
|
||||
{
|
||||
@ -500,6 +549,8 @@ gtk_file_chooser_impl_default_set_property (GObject *object,
|
||||
gtk_tree_selection_set_mode (selection,
|
||||
(select_multiple ?
|
||||
GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE));
|
||||
/* FIXME: See note in check_preview_change() */
|
||||
check_preview_change (impl);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -722,7 +773,7 @@ get_paths_foreach (GtkTreeModel *model,
|
||||
gtk_tree_model_get_iter (GTK_TREE_MODEL (info->impl->list_model), &child_iter, child_path);
|
||||
gtk_tree_path_free (child_path);
|
||||
|
||||
file_path = _gtk_file_system_model_get_path (info->impl->tree_model, &child_iter);
|
||||
file_path = _gtk_file_system_model_get_path (info->impl->list_model, &child_iter);
|
||||
info->result = g_slist_prepend (info->result, gtk_file_path_copy (file_path));
|
||||
}
|
||||
|
||||
@ -737,7 +788,7 @@ gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser)
|
||||
GtkFileChooserImplDefault *impl;
|
||||
} info = { NULL, };
|
||||
|
||||
if (!gtk_tree_view_get_model (GTK_TREE_VIEW (impl->list)))
|
||||
if (!impl->sort_model)
|
||||
return NULL;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
|
||||
@ -748,6 +799,17 @@ gtk_file_chooser_impl_default_get_paths (GtkFileChooser *chooser)
|
||||
return g_slist_reverse (info.result);
|
||||
}
|
||||
|
||||
static GtkFilePath *
|
||||
gtk_file_chooser_impl_default_get_preview_path (GtkFileChooser *chooser)
|
||||
{
|
||||
GtkFileChooserImplDefault *impl = GTK_FILE_CHOOSER_IMPL_DEFAULT (chooser);
|
||||
|
||||
if (impl->preview_path)
|
||||
return gtk_file_path_copy (impl->preview_path);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GtkFileSystem *
|
||||
gtk_file_chooser_impl_default_get_file_system (GtkFileChooser *chooser)
|
||||
{
|
||||
@ -1052,7 +1114,13 @@ update_chooser_entry (GtkFileChooserImplDefault *impl)
|
||||
GtkTreeIter iter;
|
||||
GtkTreeIter child_iter;
|
||||
|
||||
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
/* Fixing this for multiple selection involves getting the full
|
||||
* selection and diffing to find out what the most recently selected
|
||||
* file is; there is logic in GtkFileSelection that probably can
|
||||
* be copied; check_preview_change() is similar.
|
||||
*/
|
||||
if (impl->select_multiple ||
|
||||
!gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
return;
|
||||
|
||||
gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
|
||||
@ -1075,6 +1143,49 @@ filter_option_menu_changed (GtkOptionMenu *option_menu,
|
||||
set_current_filter (impl, new_filter);
|
||||
}
|
||||
|
||||
static void
|
||||
check_preview_change (GtkFileChooserImplDefault *impl)
|
||||
{
|
||||
const GtkFilePath *new_path = NULL;
|
||||
|
||||
/* Fixing preview for multiple selection involves getting the full
|
||||
* selection and diffing to find out what the most recently selected
|
||||
* file is; there is logic in GtkFileSelection that probably can
|
||||
* be copied. update_chooser_entry() is similar.
|
||||
*/
|
||||
if (impl->sort_model && !impl->select_multiple)
|
||||
{
|
||||
GtkTreeSelection *selection;
|
||||
GtkTreeIter iter;
|
||||
|
||||
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (impl->list));
|
||||
if (gtk_tree_selection_get_selected (selection, NULL, &iter))
|
||||
{
|
||||
GtkTreeIter child_iter;
|
||||
|
||||
gtk_tree_model_sort_convert_iter_to_child_iter (impl->sort_model,
|
||||
&child_iter, &iter);
|
||||
|
||||
new_path = _gtk_file_system_model_get_path (impl->list_model, &child_iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_path != impl->preview_path &&
|
||||
!(new_path && impl->preview_path &&
|
||||
gtk_file_path_compare (new_path, impl->preview_path) == 0))
|
||||
{
|
||||
if (impl->preview_path)
|
||||
gtk_file_path_free (impl->preview_path);
|
||||
|
||||
if (new_path)
|
||||
impl->preview_path = gtk_file_path_copy (new_path);
|
||||
else
|
||||
impl->preview_path = NULL;
|
||||
|
||||
g_signal_emit_by_name (impl, "update-preview");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tree_selection_changed (GtkTreeSelection *selection,
|
||||
GtkFileChooserImplDefault *impl)
|
||||
@ -1137,9 +1248,9 @@ tree_selection_changed (GtkTreeSelection *selection,
|
||||
g_signal_emit_by_name (impl, "current-folder-changed", 0);
|
||||
|
||||
update_chooser_entry (impl);
|
||||
check_preview_change (impl);
|
||||
|
||||
g_signal_emit_by_name (impl, "selection-changed", 0);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1147,6 +1258,7 @@ list_selection_changed (GtkTreeSelection *selection,
|
||||
GtkFileChooserImplDefault *impl)
|
||||
{
|
||||
update_chooser_entry (impl);
|
||||
check_preview_change (impl);
|
||||
|
||||
g_signal_emit_by_name (impl, "selection-changed", 0);
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ struct _GtkFileChooserIface
|
||||
void (*select_all) (GtkFileChooser *chooser);
|
||||
void (*unselect_all) (GtkFileChooser *chooser);
|
||||
GSList * (*get_paths) (GtkFileChooser *chooser);
|
||||
GtkFilePath * (*get_preview_path) (GtkFileChooser *chooser);
|
||||
GtkFileSystem *(*get_file_system) (GtkFileChooser *chooser);
|
||||
void (*add_filter) (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
@ -60,8 +61,7 @@ struct _GtkFileChooserIface
|
||||
*/
|
||||
void (*current_folder_changed) (GtkFileChooser *chooser);
|
||||
void (*selection_changed) (GtkFileChooser *chooser);
|
||||
void (*update_preview) (GtkFileChooser *chooser,
|
||||
const gchar *uri);
|
||||
void (*update_preview) (GtkFileChooser *chooser);
|
||||
};
|
||||
|
||||
GtkFileSystem *_gtk_file_chooser_get_file_system (GtkFileChooser *chooser);
|
||||
@ -73,6 +73,7 @@ void _gtk_file_chooser_select_path (GtkFileChooser *cho
|
||||
void _gtk_file_chooser_unselect_path (GtkFileChooser *chooser,
|
||||
const GtkFilePath *path);
|
||||
GSList * _gtk_file_chooser_get_paths (GtkFileChooser *chooser);
|
||||
GtkFilePath * _gtk_file_chooser_get_preview_path (GtkFileChooser *chooser);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -36,6 +36,7 @@ static void delegate_unselect_path (GtkFileChooser *choose
|
||||
static void delegate_select_all (GtkFileChooser *chooser);
|
||||
static void delegate_unselect_all (GtkFileChooser *chooser);
|
||||
static GSList * delegate_get_paths (GtkFileChooser *chooser);
|
||||
static GtkFilePath * delegate_get_preview_path (GtkFileChooser *chooser);
|
||||
static GtkFileSystem *delegate_get_file_system (GtkFileChooser *chooser);
|
||||
static void delegate_add_filter (GtkFileChooser *chooser,
|
||||
GtkFileFilter *filter);
|
||||
@ -49,6 +50,8 @@ static void delegate_current_folder_changed (GtkFileChooser *choose
|
||||
gpointer data);
|
||||
static void delegate_selection_changed (GtkFileChooser *chooser,
|
||||
gpointer data);
|
||||
static void delegate_update_preview (GtkFileChooser *chooser,
|
||||
gpointer data);
|
||||
|
||||
/**
|
||||
* _gtk_file_chooser_install_properties:
|
||||
@ -133,6 +136,7 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
|
||||
iface->select_all = delegate_select_all;
|
||||
iface->unselect_all = delegate_unselect_all;
|
||||
iface->get_paths = delegate_get_paths;
|
||||
iface->get_preview_path = delegate_get_preview_path;
|
||||
iface->get_file_system = delegate_get_file_system;
|
||||
iface->add_filter = delegate_add_filter;
|
||||
iface->remove_filter = delegate_remove_filter;
|
||||
@ -165,6 +169,8 @@ _gtk_file_chooser_set_delegate (GtkFileChooser *receiver,
|
||||
G_CALLBACK (delegate_current_folder_changed), receiver);
|
||||
g_signal_connect (delegate, "selection-changed",
|
||||
G_CALLBACK (delegate_selection_changed), receiver);
|
||||
g_signal_connect (delegate, "update-preview",
|
||||
G_CALLBACK (delegate_update_preview), receiver);
|
||||
}
|
||||
|
||||
static GtkFileChooser *
|
||||
@ -205,6 +211,12 @@ delegate_get_paths (GtkFileChooser *chooser)
|
||||
return _gtk_file_chooser_get_paths (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static GtkFilePath *
|
||||
delegate_get_preview_path (GtkFileChooser *chooser)
|
||||
{
|
||||
return _gtk_file_chooser_get_preview_path (get_delegate (chooser));
|
||||
}
|
||||
|
||||
static GtkFileSystem *
|
||||
delegate_get_file_system (GtkFileChooser *chooser)
|
||||
{
|
||||
@ -267,12 +279,19 @@ static void
|
||||
delegate_selection_changed (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "selection-changed", 0);
|
||||
g_signal_emit_by_name (data, "selection-changed");
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_current_folder_changed (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "current-folder-changed", 0);
|
||||
g_signal_emit_by_name (data, "current-folder-changed");
|
||||
}
|
||||
|
||||
static void
|
||||
delegate_update_preview (GtkFileChooser *chooser,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_emit_by_name (data, "update-preview");
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include "gtkfilechooserdialog.h"
|
||||
@ -11,6 +16,9 @@
|
||||
#include "gtkfilesystemunix.h"
|
||||
#endif
|
||||
|
||||
static GtkWidget *preview_label;
|
||||
static GtkWidget *preview_image;
|
||||
|
||||
static void
|
||||
print_current_folder (GtkFileChooser *chooser)
|
||||
{
|
||||
@ -56,6 +64,195 @@ no_backup_files_filter (const GtkFileFilterInfo *filter_info,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static char *
|
||||
format_time (time_t t)
|
||||
{
|
||||
gchar buf[128];
|
||||
struct tm tm_buf;
|
||||
time_t now = time (NULL);
|
||||
const char *format;
|
||||
|
||||
if (abs (now - t) < 24*60*60)
|
||||
format = "%X";
|
||||
else
|
||||
format = "%x";
|
||||
|
||||
localtime_r (&t, &tm_buf);
|
||||
if (strftime (buf, sizeof (buf), format, &tm_buf) == 0)
|
||||
return g_strdup ("<unknown>");
|
||||
else
|
||||
return g_strdup (buf);
|
||||
}
|
||||
|
||||
static char *
|
||||
format_size (gint64 size)
|
||||
{
|
||||
if (size < (gint64)1024)
|
||||
return g_strdup_printf ("%d bytes", (gint)size);
|
||||
else if (size < (gint64)1024*1024)
|
||||
return g_strdup_printf ("%.1f K", size / (1024.));
|
||||
else if (size < (gint64)1024*1024*1024)
|
||||
return g_strdup_printf ("%.1f M", size / (1024.*1024.));
|
||||
else
|
||||
return g_strdup_printf ("%.1f G", size / (1024.*1024.*1024.));
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#define _(s) (s)
|
||||
|
||||
static void
|
||||
size_prepared_cb (GdkPixbufLoader *loader,
|
||||
int width,
|
||||
int height,
|
||||
gpointer data)
|
||||
{
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
} *info = data;
|
||||
|
||||
if ((double)height * (double)info->width >
|
||||
(double)width * (double)info->height) {
|
||||
width = 0.5 + (double)width * (double)info->height / (double)height;
|
||||
height = info->height;
|
||||
} else {
|
||||
height = 0.5 + (double)height * (double)info->width / (double)width;
|
||||
width = info->width;
|
||||
}
|
||||
|
||||
gdk_pixbuf_loader_set_size (loader, width, height);
|
||||
}
|
||||
|
||||
GdkPixbuf *
|
||||
my_new_from_file_at_size (const char *filename,
|
||||
int width,
|
||||
int height,
|
||||
GError **error)
|
||||
{
|
||||
GdkPixbufLoader *loader;
|
||||
GdkPixbuf *pixbuf;
|
||||
struct {
|
||||
int width;
|
||||
int height;
|
||||
} info;
|
||||
|
||||
guchar buffer [4096];
|
||||
int length;
|
||||
FILE *f;
|
||||
|
||||
g_return_val_if_fail (filename != NULL, NULL);
|
||||
g_return_val_if_fail (width > 0 && height > 0, NULL);
|
||||
|
||||
f = fopen (filename, "rb");
|
||||
if (!f) {
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
_("Failed to open file '%s': %s"),
|
||||
filename, g_strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
loader = gdk_pixbuf_loader_new ();
|
||||
#ifdef DONT_PRESERVE_ASPECT
|
||||
gdk_pixbuf_loader_set_size (loader, width, height);
|
||||
#else
|
||||
info.width = width;
|
||||
info.height = height;
|
||||
g_signal_connect (loader, "size-prepared", G_CALLBACK (&size_prepared_cb), &info);
|
||||
#endif
|
||||
|
||||
while (!feof (f)) {
|
||||
length = fread (buffer, 1, sizeof (buffer), f);
|
||||
if (length > 0)
|
||||
if (!gdk_pixbuf_loader_write (loader, buffer, length, error)) {
|
||||
gdk_pixbuf_loader_close (loader, NULL);
|
||||
fclose (f);
|
||||
g_object_unref (G_OBJECT (loader));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
fclose (f);
|
||||
|
||||
if (!gdk_pixbuf_loader_close (loader, error)) {
|
||||
g_object_unref (G_OBJECT (loader));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
|
||||
|
||||
if (!pixbuf) {
|
||||
g_object_unref (G_OBJECT (loader));
|
||||
g_set_error (error,
|
||||
GDK_PIXBUF_ERROR,
|
||||
GDK_PIXBUF_ERROR_FAILED,
|
||||
_("Failed to load image '%s': reason not known, probably a corrupt image file"),
|
||||
filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_ref (pixbuf);
|
||||
|
||||
g_object_unref (G_OBJECT (loader));
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
update_preview_cb (GtkFileChooser *chooser)
|
||||
{
|
||||
gchar *filename = gtk_file_chooser_get_preview_filename (chooser);
|
||||
gboolean have_preview = FALSE;
|
||||
|
||||
if (filename)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
GError *error = NULL;
|
||||
|
||||
pixbuf = my_new_from_file_at_size (filename, 128, 128, &error);
|
||||
if (pixbuf)
|
||||
{
|
||||
gtk_image_set_from_pixbuf (GTK_IMAGE (preview_image), pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
gtk_widget_show (preview_image);
|
||||
gtk_widget_hide (preview_label);
|
||||
have_preview = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct stat buf;
|
||||
if (stat (filename, &buf) == 0)
|
||||
{
|
||||
gchar *preview_text;
|
||||
gchar *size_str;
|
||||
gchar *modified_time;
|
||||
|
||||
size_str = format_size (buf.st_size);
|
||||
modified_time = format_time (buf.st_mtime);
|
||||
|
||||
preview_text = g_strdup_printf ("<i>Modified:</i>\t%s\n"
|
||||
"<i>Size:</i>\t%s\n",
|
||||
modified_time,
|
||||
size_str);
|
||||
gtk_label_set_markup (GTK_LABEL (preview_label), preview_text);
|
||||
g_free (modified_time);
|
||||
g_free (size_str);
|
||||
g_free (preview_text);
|
||||
|
||||
gtk_widget_hide (preview_image);
|
||||
gtk_widget_show (preview_label);
|
||||
have_preview = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (filename);
|
||||
}
|
||||
|
||||
gtk_file_chooser_set_preview_widget_active (chooser, have_preview);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
@ -66,6 +263,7 @@ main (int argc, char **argv)
|
||||
GtkWidget *prop_editor;
|
||||
GtkFileSystem *file_system;
|
||||
GtkFileFilter *filter;
|
||||
GtkWidget *preview_vbox;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
@ -116,10 +314,28 @@ main (int argc, char **argv)
|
||||
gtk_file_filter_add_mime_type (filter, "image/png");
|
||||
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
|
||||
|
||||
/* Preview widget */
|
||||
preview_vbox = gtk_vbox_new (0, FALSE);
|
||||
gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog), preview_vbox);
|
||||
|
||||
preview_label = gtk_label_new (NULL);
|
||||
gtk_box_pack_start (GTK_BOX (preview_vbox), preview_label, TRUE, TRUE, 0);
|
||||
gtk_misc_set_padding (GTK_MISC (preview_label), 6, 6);
|
||||
|
||||
preview_image = gtk_image_new ();
|
||||
gtk_box_pack_start (GTK_BOX (preview_vbox), preview_image, TRUE, TRUE, 0);
|
||||
gtk_misc_set_padding (GTK_MISC (preview_image), 6, 6);
|
||||
|
||||
update_preview_cb (GTK_FILE_CHOOSER (dialog));
|
||||
g_signal_connect (dialog, "update-preview",
|
||||
G_CALLBACK (update_preview_cb), NULL);
|
||||
|
||||
gtk_window_set_default_size (GTK_WINDOW (dialog), 600, 400);
|
||||
/* show_all() to reveal bugs in composite widget handling */
|
||||
gtk_widget_show_all (dialog);
|
||||
|
||||
/* Extra controls for manipulating the test environment
|
||||
*/
|
||||
prop_editor = create_prop_editor (G_OBJECT (dialog), GTK_TYPE_FILE_CHOOSER);
|
||||
|
||||
control_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
||||
|
Loading…
Reference in New Issue
Block a user