diff --git a/ChangeLog b/ChangeLog index 85fa1abeb9d5ddf9b0d22fbe11a600fa3b26c909..b184ab70c0e97b1cbbbed6279e4a6591009e2a3d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2005-07-15 Benedikt Meurer <benny@xfce.org> + + * thunar/thunar-details-view.c: Unselect all selected items if the + user clicks on an empty area of the treeview and neither Control + nor Shift is active. + * thunar/thunar-properties-dialog.{c,h}: Add the first draft for the + ThunarPropertiesDialog class, which implements a properties dialog for + a single file. + * thunar/Makefile.am: Add ThunarPropertiesDialog to the build framework. + * thunar/thunar-standard-view-ui.xml, thunar/thunar-standard-view.c, + thunar/thunar-window-ui.xml: Add the "properties" action to the + menu structure, which displays a properties dialog for the selected + file. + 2005-07-15 Benedikt Meurer <benny@xfce.org> * thunar-vfs/thunar-vfs-volume.{c,h}: Extend the ThunarVfsVolumeManager diff --git a/thunar/Makefile.am b/thunar/Makefile.am index ce3e9e7663185d46ca39a7d9e9285afb8b63b10e..455e62d46dd8597abed944e504731a699f0aaeaa 100644 --- a/thunar/Makefile.am +++ b/thunar/Makefile.am @@ -53,6 +53,8 @@ Thunar_SOURCES = \ thunar-navigator.h \ thunar-preferences.c \ thunar-preferences.h \ + thunar-properties-dialog.c \ + thunar-properties-dialog.h \ thunar-side-pane.c \ thunar-side-pane.h \ thunar-standard-view.c \ diff --git a/thunar/thunar-details-view.c b/thunar/thunar-details-view.c index d0f6b1a0da29304d28c4f7989def6d23996929f1..f2d4c8ae47d35e685ec7b662f6df32bddfca9523 100644 --- a/thunar/thunar-details-view.c +++ b/thunar/thunar-details-view.c @@ -30,6 +30,9 @@ static void thunar_details_view_class_init (ThunarDetailsViewClas static void thunar_details_view_init (ThunarDetailsView *details_view); static AtkObject *thunar_details_view_get_accessible (GtkWidget *widget); static GList *thunar_details_view_get_selected_items (ThunarStandardView *standard_view); +static gboolean thunar_details_view_button_press_event (GtkTreeView *tree_view, + GdkEventButton *event, + ThunarDetailsView *details_view); static void thunar_details_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, @@ -78,6 +81,8 @@ thunar_details_view_init (ThunarDetailsView *details_view) /* create the tree view to embed */ tree_view = gtk_tree_view_new (); + g_signal_connect (G_OBJECT (tree_view), "button-press-event", + G_CALLBACK (thunar_details_view_button_press_event), details_view); g_signal_connect (G_OBJECT (tree_view), "row-activated", G_CALLBACK (thunar_details_view_row_activated), details_view); gtk_container_add (GTK_CONTAINER (details_view), tree_view); @@ -216,6 +221,29 @@ thunar_details_view_get_selected_items (ThunarStandardView *standard_view) +static gboolean +thunar_details_view_button_press_event (GtkTreeView *tree_view, + GdkEventButton *event, + ThunarDetailsView *details_view) +{ + GtkTreeSelection *selection; + + /* we unselect all selected items if the user clicks on an empty + * area of the treeview and no modifier key is active. + */ + if ((event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0 + && !gtk_tree_view_get_path_at_pos (tree_view, event->x, event->y, NULL, NULL, NULL, NULL)) + { + selection = gtk_tree_view_get_selection (tree_view); + gtk_tree_selection_unselect_all (selection); + return TRUE; + } + + return FALSE; +} + + + static void thunar_details_view_row_activated (GtkTreeView *tree_view, GtkTreePath *path, diff --git a/thunar/thunar-properties-dialog.c b/thunar/thunar-properties-dialog.c new file mode 100644 index 0000000000000000000000000000000000000000..91535d43cb530f9cdf0d31adbbbcaa5b0bfbe6f3 --- /dev/null +++ b/thunar/thunar-properties-dialog.c @@ -0,0 +1,602 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gdk/gdkkeysyms.h> + +#include <thunar/thunar-icon-factory.h> +#include <thunar/thunar-properties-dialog.h> + + + +enum +{ + PROP_0, + PROP_FILE, +}; + + + +static void thunar_properties_dialog_class_init (ThunarPropertiesDialogClass *klass); +static void thunar_properties_dialog_init (ThunarPropertiesDialog *dialog); +static void thunar_properties_dialog_dispose (GObject *object); +static void thunar_properties_dialog_finalize (GObject *object); +static void thunar_properties_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void thunar_properties_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static gboolean thunar_properties_dialog_key_press_event (GtkWidget *widget, + GdkEventKey *event); +static void thunar_properties_dialog_response (GtkDialog *dialog, + gint response); +static void thunar_properties_dialog_update (ThunarPropertiesDialog *dialog); + + + +struct _ThunarPropertiesDialogClass +{ + GtkDialogClass __parent__; +}; + +struct _ThunarPropertiesDialog +{ + GtkDialog __parent__; + + ThunarVfsVolumeManager *volume_manager; + ThunarFile *file; + + GtkWidget *notebook; + GtkWidget *icon_image; + GtkWidget *name_entry; + GtkWidget *kind_label; + GtkWidget *modified_label; + GtkWidget *accessed_label; + GtkWidget *volume_image; + GtkWidget *volume_label; + GtkWidget *size_label; +}; + + + +G_DEFINE_TYPE (ThunarPropertiesDialog, thunar_properties_dialog, GTK_TYPE_DIALOG); + + + +static void +thunar_properties_dialog_class_init (ThunarPropertiesDialogClass *klass) +{ + GtkDialogClass *gtkdialog_class; + GtkWidgetClass *gtkwidget_class; + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->dispose = thunar_properties_dialog_dispose; + gobject_class->finalize = thunar_properties_dialog_finalize; + gobject_class->get_property = thunar_properties_dialog_get_property; + gobject_class->set_property = thunar_properties_dialog_set_property; + + gtkwidget_class = GTK_WIDGET_CLASS (klass); + gtkwidget_class->key_press_event = thunar_properties_dialog_key_press_event; + + gtkdialog_class = GTK_DIALOG_CLASS (klass); + gtkdialog_class->response = thunar_properties_dialog_response; + + /** + * ThunarPropertiesDialog:file: + * + * The #ThunarFile whose properties are currently displayed by + * this #ThunarPropertiesDialog. This property may also be %NULL + * in which case nothing is displayed. + **/ + g_object_class_install_property (gobject_class, + PROP_FILE, + g_param_spec_object ("file", + _("File"), + _("The file displayed by the dialog"), + THUNAR_TYPE_FILE, + EXO_PARAM_READWRITE)); +} + + + +static void +thunar_properties_dialog_init (ThunarPropertiesDialog *dialog) +{ + GtkWidget *table; + GtkWidget *label; + GtkWidget *box; + GtkWidget *spacer; + gchar *text; + gint row = 0; + + dialog->volume_manager = thunar_vfs_volume_manager_get_default (); + + gtk_dialog_add_buttons (GTK_DIALOG (dialog), + GTK_STOCK_HELP, GTK_RESPONSE_HELP, + GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + NULL); + gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + + dialog->notebook = gtk_notebook_new (); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), dialog->notebook, TRUE, TRUE, 0); + gtk_widget_show (dialog->notebook); + + table = g_object_new (GTK_TYPE_TABLE, + "border-width", 6, + "column-spacing", 12, + "row-spacing", 6, + NULL); + label = gtk_label_new (_("General")); + gtk_notebook_append_page (GTK_NOTEBOOK (dialog->notebook), table, label); + gtk_widget_show (label); + gtk_widget_show (table); + + + /* + First box (icon, name) + */ + box = gtk_hbox_new (FALSE, 6); + gtk_table_attach (GTK_TABLE (table), box, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (box); + + dialog->icon_image = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (box), dialog->icon_image, FALSE, TRUE, 0); + gtk_widget_show (dialog->icon_image); + + text = g_strdup_printf ("<b>%s</b>", _("Name:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0); + gtk_widget_show (label); + g_free (text); + + dialog->name_entry = g_object_new (GTK_TYPE_ENTRY, "editable", FALSE, NULL); + gtk_table_attach (GTK_TABLE (table), dialog->name_entry, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (dialog->name_entry); + + ++row; + + + spacer = g_object_new (GTK_TYPE_ALIGNMENT, "height-request", 12, NULL); + gtk_table_attach (GTK_TABLE (table), spacer, 0, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (spacer); + + ++row; + + + /* + Second box (kind) + */ + text = g_strdup_printf ("<b>%s</b>", _("Kind:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + exo_binding_new (G_OBJECT (label), "visible", G_OBJECT (spacer), "visible"); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + g_free (text); + + dialog->kind_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL); + exo_binding_new (G_OBJECT (dialog->kind_label), "visible", G_OBJECT (label), "visible"); + gtk_table_attach (GTK_TABLE (table), dialog->kind_label, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (dialog->kind_label); + + ++row; + + + spacer = g_object_new (GTK_TYPE_ALIGNMENT, "height-request", 12, NULL); + gtk_table_attach (GTK_TABLE (table), spacer, 0, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (spacer); + + ++row; + + + /* + Third box (modified, accessed) + */ + text = g_strdup_printf ("<b>%s</b>", _("Modified:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + g_free (text); + + dialog->modified_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL); + exo_binding_new (G_OBJECT (dialog->modified_label), "visible", G_OBJECT (label), "visible"); + gtk_table_attach (GTK_TABLE (table), dialog->modified_label, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (dialog->modified_label); + + ++row; + + text = g_strdup_printf ("<b>%s</b>", _("Accessed:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + g_free (text); + + dialog->accessed_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL); + exo_binding_new (G_OBJECT (dialog->accessed_label), "visible", G_OBJECT (label), "visible"); + gtk_table_attach (GTK_TABLE (table), dialog->accessed_label, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (dialog->accessed_label); + + ++row; + + + spacer = g_object_new (GTK_TYPE_ALIGNMENT, "height-request", 12, NULL); + gtk_table_attach (GTK_TABLE (table), spacer, 0, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (spacer); + + ++row; + + + /* + Fourth box (volume, size) + */ + text = g_strdup_printf ("<b>%s</b>", _("Volume:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + g_free (text); + + box = gtk_hbox_new (FALSE, 6); + exo_binding_new (G_OBJECT (box), "visible", G_OBJECT (label), "visible"); + gtk_table_attach (GTK_TABLE (table), box, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (box); + + dialog->volume_image = gtk_image_new (); + exo_binding_new (G_OBJECT (dialog->volume_image), "visible", G_OBJECT (box), "visible"); + gtk_box_pack_start (GTK_BOX (box), dialog->volume_image, FALSE, TRUE, 0); + gtk_widget_show (dialog->volume_image); + + dialog->volume_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL); + exo_binding_new (G_OBJECT (dialog->volume_label), "visible", G_OBJECT (dialog->volume_image), "visible"); + gtk_box_pack_start (GTK_BOX (box), dialog->volume_label, TRUE, TRUE, 0); + gtk_widget_show (dialog->volume_label); + + ++row; + + text = g_strdup_printf ("<b>%s</b>", _("Size:")); + label = g_object_new (GTK_TYPE_LABEL, "label", text, "use-markup", TRUE, "xalign", 1.0f, NULL); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (label); + g_free (text); + + dialog->size_label = g_object_new (GTK_TYPE_LABEL, "xalign", 0.0f, NULL); + exo_binding_new (G_OBJECT (dialog->size_label), "visible", G_OBJECT (label), "visible"); + gtk_table_attach (GTK_TABLE (table), dialog->size_label, 1, 2, row, row + 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (dialog->size_label); + + ++row; + + + spacer = g_object_new (GTK_TYPE_ALIGNMENT, "height-request", 12, NULL); + gtk_table_attach (GTK_TABLE (table), spacer, 0, 2, row, row + 1, GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (spacer); + + ++row; +} + + + +static void +thunar_properties_dialog_dispose (GObject *object) +{ + ThunarPropertiesDialog *dialog = THUNAR_PROPERTIES_DIALOG (object); + thunar_properties_dialog_set_file (dialog, NULL); + G_OBJECT_CLASS (thunar_properties_dialog_parent_class)->dispose (object); +} + + + +static void +thunar_properties_dialog_finalize (GObject *object) +{ + ThunarPropertiesDialog *dialog = THUNAR_PROPERTIES_DIALOG (object); + g_object_unref (G_OBJECT (dialog->volume_manager)); + G_OBJECT_CLASS (thunar_properties_dialog_parent_class)->finalize (object); +} + + + +static void +thunar_properties_dialog_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ThunarPropertiesDialog *dialog = THUNAR_PROPERTIES_DIALOG (object); + + switch (prop_id) + { + case PROP_FILE: + g_value_set_object (value, thunar_properties_dialog_get_file (dialog)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static void +thunar_properties_dialog_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ThunarPropertiesDialog *dialog = THUNAR_PROPERTIES_DIALOG (object); + + switch (prop_id) + { + case PROP_FILE: + thunar_properties_dialog_set_file (dialog, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + + +static gboolean +thunar_properties_dialog_key_press_event (GtkWidget *widget, + GdkEventKey *event) +{ + if (event->keyval == GDK_Escape) + { + gtk_widget_destroy (widget); + return TRUE; + } + + return GTK_WIDGET_CLASS (thunar_properties_dialog_parent_class)->key_press_event (widget, event); +} + + + +static void +thunar_properties_dialog_response (GtkDialog *dialog, + gint response) +{ + if (response == GTK_RESPONSE_CLOSE) + { + gtk_widget_destroy (GTK_WIDGET (dialog)); + } + else if (GTK_DIALOG_CLASS (thunar_properties_dialog_parent_class)->response != NULL) + { + (*GTK_DIALOG_CLASS (thunar_properties_dialog_parent_class)->response) (dialog, response); + } +} + + + +static void +thunar_properties_dialog_update (ThunarPropertiesDialog *dialog) +{ + ThunarIconFactory *icon_factory; + ThunarVfsFileSize size; + ThunarVfsVolume *volume; + GtkIconTheme *icon_theme; + ExoMimeInfo *info; + const gchar *icon_name; + const gchar *name; + GdkPixbuf *icon; + gchar *size_string; + gchar *str; + + g_return_if_fail (THUNAR_IS_PROPERTIES_DIALOG (dialog)); + g_return_if_fail (THUNAR_IS_FILE (dialog->file)); + + icon_factory = thunar_icon_factory_get_default (); + icon_theme = thunar_icon_factory_get_icon_theme (icon_factory); + + /* update the icon */ + icon = thunar_file_load_icon (dialog->file, 48); + gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->icon_image), icon); + gtk_window_set_icon (GTK_WINDOW (dialog), icon); + if (G_LIKELY (icon != NULL)) + g_object_unref (G_OBJECT (icon)); + + /* update the name */ + name = thunar_file_get_display_name (dialog->file); + gtk_entry_set_text (GTK_ENTRY (dialog->name_entry), name); + str = g_strdup_printf (_("%s Info"), name); + gtk_window_set_title (GTK_WINDOW (dialog), str); + g_free (str); + + /* update the mime type */ + info = thunar_file_get_mime_info (dialog->file); + if (G_LIKELY (info != NULL)) + { + gtk_label_set_text (GTK_LABEL (dialog->kind_label), exo_mime_info_get_comment (info)); + gtk_widget_show (dialog->kind_label); + g_object_unref (G_OBJECT (info)); + } + else + { + gtk_widget_hide (dialog->kind_label); + } + + /* update the modified time */ + str = thunar_file_get_date_string (dialog->file, THUNAR_FILE_DATE_MODIFIED); + if (G_LIKELY (str != NULL)) + { + gtk_label_set_text (GTK_LABEL (dialog->modified_label), str); + gtk_widget_show (dialog->modified_label); + g_free (str); + } + else + { + gtk_widget_hide (dialog->modified_label); + } + + /* update the accessed time */ + str = thunar_file_get_date_string (dialog->file, THUNAR_FILE_DATE_ACCESSED); + if (G_LIKELY (str != NULL)) + { + gtk_label_set_text (GTK_LABEL (dialog->accessed_label), str); + gtk_widget_show (dialog->accessed_label); + g_free (str); + } + else + { + gtk_widget_hide (dialog->accessed_label); + } + + /* update the volume */ + volume = thunar_file_get_volume (dialog->file, dialog->volume_manager); + if (G_LIKELY (volume != NULL)) + { + icon_name = thunar_vfs_volume_lookup_icon_name (volume, icon_theme); + icon = thunar_icon_factory_load_icon (icon_factory, icon_name, 16, NULL, FALSE); + gtk_image_set_from_pixbuf (GTK_IMAGE (dialog->volume_image), icon); + if (G_LIKELY (icon != NULL)) + g_object_unref (G_OBJECT (icon)); + + name = thunar_vfs_volume_get_name (volume); + gtk_label_set_text (GTK_LABEL (dialog->volume_label), name); + gtk_widget_show (dialog->volume_label); + } + else + { + gtk_widget_hide (dialog->volume_label); + } + + /* update the size */ + size_string = thunar_file_get_size_string (dialog->file); + if (G_LIKELY (size_string != NULL)) + { + if (G_LIKELY (thunar_file_get_size (dialog->file, &size))) + { + str = g_strdup_printf (_("%s (%u Bytes)"), size_string, (guint) size); + gtk_label_set_text (GTK_LABEL (dialog->size_label), str); + g_free (str); + } + else + { + gtk_label_set_text (GTK_LABEL (dialog->size_label), size_string); + } + + gtk_widget_show (dialog->size_label); + g_free (size_string); + } + else + { + gtk_widget_hide (dialog->size_label); + } +} + + + +/** + * thunar_properties_dialog_new: + * + * Allocates a new #ThunarPropertiesDialog instance, + * that is not associated with any #ThunarFile. + * + * Return value: the newly allocated #ThunarPropertiesDialog + * instance. + **/ +GtkWidget* +thunar_properties_dialog_new (void) +{ + return g_object_new (THUNAR_TYPE_PROPERTIES_DIALOG, NULL); +} + + + +/** + * thunar_properties_dialog_get_file: + * @dialog : a #ThunarPropertiesDialog. + * + * Returns the #ThunarFile currently being displayed + * by @dialog or %NULL if @dialog doesn't display + * any file right now. + * + * Return value: the #ThunarFile displayed by @dialog + * or %NULL. + **/ +ThunarFile* +thunar_properties_dialog_get_file (ThunarPropertiesDialog *dialog) +{ + g_return_val_if_fail (THUNAR_IS_PROPERTIES_DIALOG (dialog), NULL); + return dialog->file; +} + + + +/** + * thunar_properties_dialog_set_file: + * @dialog : a #ThunarPropertiesDialog. + * @file : a #ThunarFile or %NULL. + * + * Sets the #ThunarFile that is displayed by @dialog + * to @file. + **/ +void +thunar_properties_dialog_set_file (ThunarPropertiesDialog *dialog, + ThunarFile *file) +{ + g_return_if_fail (THUNAR_IS_PROPERTIES_DIALOG (dialog)); + g_return_if_fail (file == NULL || THUNAR_IS_FILE (file)); + + /* disconnect from any previously set file */ + if (dialog->file != NULL) + { + /* unregister our file watch */ + thunar_file_unwatch (dialog->file); + + /* unregister handlers */ + g_signal_handlers_disconnect_by_func (G_OBJECT (dialog->file), thunar_properties_dialog_update, dialog); + g_signal_handlers_disconnect_by_func (G_OBJECT (dialog->file), gtk_widget_destroy, dialog); + + g_object_unref (G_OBJECT (dialog->file)); + } + + /* activate the new file */ + dialog->file = file; + + /* connect to the new file */ + if (file != NULL) + { + g_object_ref (G_OBJECT (file)); + + /* watch the file for changes */ + thunar_file_watch (file); + + /* install signal handlers */ + g_signal_connect_swapped (G_OBJECT (file), "changed", G_CALLBACK (thunar_properties_dialog_update), dialog); + g_signal_connect_swapped (G_OBJECT (file), "destroy", G_CALLBACK (gtk_widget_destroy), dialog); + + /* update the UI for the new file */ + thunar_properties_dialog_update (dialog); + } + + /* tell everybody that we have a new file here */ + g_object_notify (G_OBJECT (dialog), "file"); +} + + + diff --git a/thunar/thunar-properties-dialog.h b/thunar/thunar-properties-dialog.h new file mode 100644 index 0000000000000000000000000000000000000000..616023bcc2c9932b29cc3eccd60fc19c7642b1d3 --- /dev/null +++ b/thunar/thunar-properties-dialog.h @@ -0,0 +1,47 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005 Benedikt Meurer <benny@xfce.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __THUNAR_PROPERTIES_DIALOG_H__ +#define __THUNAR_PROPERTIES_DIALOG_H__ + +#include <thunar/thunar-file.h> + +G_BEGIN_DECLS; + +typedef struct _ThunarPropertiesDialogClass ThunarPropertiesDialogClass; +typedef struct _ThunarPropertiesDialog ThunarPropertiesDialog; + +#define THUNAR_TYPE_PROPERTIES_DIALOG (thunar_properties_dialog_get_type ()) +#define THUNAR_PROPERTIES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), THUNAR_TYPE_PROPERTIES_DIALOG, ThunarPropertiesDialog)) +#define THUNAR_PROPERTIES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), THUNAR_TYPE_PROPERTIES_DIALOG, ThunarPropertiesDialogClass)) +#define THUNAR_IS_PROPERTIES_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), THUNAR_TYPE_PROPERTIES_DIALOG)) +#define THUNAR_IS_PROPERTIES_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), THUNAR_TYPE_PROPERTIES_DIALOG)) +#define THUNAR_PROPERTIES_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), THUNAR_TYPE_PROPERTIES_DIALOG, ThunarPropertiesDialog)) + +GType thunar_properties_dialog_get_type (void) G_GNUC_CONST; + +GtkWidget *thunar_properties_dialog_new (void); + +ThunarFile *thunar_properties_dialog_get_file (ThunarPropertiesDialog *dialog); +void thunar_properties_dialog_set_file (ThunarPropertiesDialog *dialog, + ThunarFile *file); + +G_END_DECLS; + +#endif /* !__THUNAR_PROPERTIES_DIALOG_H__ */ diff --git a/thunar/thunar-standard-view-ui.xml b/thunar/thunar-standard-view-ui.xml index d2d38309f91e23223096bf14bd3c3006f004b4f5..1605a62630936907e033d9686bb5ac95c96a47c7 100644 --- a/thunar/thunar-standard-view-ui.xml +++ b/thunar/thunar-standard-view-ui.xml @@ -11,6 +11,12 @@ --> <menubar name="main-menu"> + <menu action="file-menu" name="file-menu"> + <placeholder name="placeholder-file-properties"> + <menuitem action="properties" name="properties" /> + </placeholder> + </menu> + <menu action="edit-menu" name="edit-menu"> <placeholder name="placeholder-edit-clipboard-actions"> <menuitem action="copy" name="copy" /> diff --git a/thunar/thunar-standard-view.c b/thunar/thunar-standard-view.c index f0cc0a42836d2cae2db14d8e499e3b3b642f941e..be209d8612321ea60d8db98ed114388564942750 100644 --- a/thunar/thunar-standard-view.c +++ b/thunar/thunar-standard-view.c @@ -21,6 +21,7 @@ #include <config.h> #endif +#include <thunar/thunar-properties-dialog.h> #include <thunar/thunar-standard-view.h> #include <thunar/thunar-standard-view-ui.h> @@ -64,7 +65,10 @@ static const gchar *thunar_standard_view_get_statusbar_text (ThunarView static GtkUIManager *thunar_standard_view_get_ui_manager (ThunarView *view); static void thunar_standard_view_set_ui_manager (ThunarView *view, GtkUIManager *ui_manager); +static GList *thunar_standard_view_get_selected_files (ThunarStandardView *standard_view); static GList *thunar_standard_view_get_selected_uris (ThunarStandardView *standard_view); +static void thunar_standard_view_action_properties (GtkAction *action, + ThunarStandardView *standard_view); static void thunar_standard_view_action_copy (GtkAction *action, ThunarStandardView *standard_view); static void thunar_standard_view_action_cut (GtkAction *action, @@ -80,6 +84,7 @@ static void thunar_standard_view_loading_idle_destroy (gpointer static const GtkActionEntry const action_entries[] = { + { "properties", GTK_STOCK_PROPERTIES, N_ ("_Properties"), "<alt>Return", N_ ("View the properties of the selected item"), G_CALLBACK (thunar_standard_view_action_properties), }, { "copy", GTK_STOCK_COPY, N_ ("_Copy files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_copy), }, { "cut", GTK_STOCK_CUT, N_ ("Cu_t files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_cut), }, { "paste", GTK_STOCK_PASTE, N_ ("_Paste files"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_paste), }, @@ -545,6 +550,7 @@ thunar_standard_view_set_ui_manager (ThunarView *view, GtkUIManager *ui_manager) { ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (view); + GError *error = NULL; /* disconnect from the previous UI manager */ if (G_LIKELY (standard_view->ui_manager != NULL)) @@ -573,7 +579,12 @@ thunar_standard_view_set_ui_manager (ThunarView *view, /* merge our UI control items with the new manager */ standard_view->ui_merge_id = gtk_ui_manager_add_ui_from_string (ui_manager, thunar_standard_view_ui, - thunar_standard_view_ui_length, NULL); + thunar_standard_view_ui_length, &error); + if (G_UNLIKELY (standard_view->ui_merge_id == 0)) + { + g_error ("Failed to merge ThunarStandardView menus: %s", error->message); + g_error_free (error); + } } /* let others know that we have a new manager */ @@ -582,6 +593,30 @@ thunar_standard_view_set_ui_manager (ThunarView *view, +static GList* +thunar_standard_view_get_selected_files (ThunarStandardView *standard_view) +{ + GtkTreeIter iter; + ThunarFile *file; + GList *selected_items; + GList *selected_files = NULL; + GList *lp; + + selected_items = THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->get_selected_items (standard_view); + for (lp = selected_items; lp != NULL; lp = lp->next) + { + gtk_tree_model_get_iter (GTK_TREE_MODEL (standard_view->model), &iter, lp->data); + file = thunar_list_model_get_file (standard_view->model, &iter); + selected_files = g_list_append (selected_files, file); + gtk_tree_path_free (lp->data); + } + g_list_free (selected_items); + + return selected_files; +} + + + static GList* thunar_standard_view_get_selected_uris (ThunarStandardView *standard_view) { @@ -607,6 +642,38 @@ thunar_standard_view_get_selected_uris (ThunarStandardView *standard_view) +static void +thunar_standard_view_action_properties (GtkAction *action, + ThunarStandardView *standard_view) +{ + GtkWidget *toplevel; + GtkWidget *dialog; + GList *files; + + g_return_if_fail (GTK_IS_ACTION (action)); + g_return_if_fail (THUNAR_IS_STANDARD_VIEW (standard_view)); + + files = thunar_standard_view_get_selected_files (standard_view); + if (G_LIKELY (g_list_length (files) == 1)) + { + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (standard_view)); + if (G_LIKELY (toplevel != NULL)) + { + dialog = g_object_new (THUNAR_TYPE_PROPERTIES_DIALOG, + "destroy-with-parent", TRUE, + "file", files->data, + NULL); + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel)); + gtk_widget_show (dialog); + } + } + + g_list_foreach (files, (GFunc) g_object_unref, NULL); + g_list_free (files); +} + + + static void thunar_standard_view_action_copy (GtkAction *action, ThunarStandardView *standard_view) @@ -739,6 +806,12 @@ thunar_standard_view_selection_changed (ThunarStandardView *standard_view) g_list_foreach (selected_items, (GFunc) gtk_tree_path_free, NULL); g_list_free (selected_items); + /* update the "Properties" action */ + action = gtk_action_group_get_action (standard_view->action_group, "properties"); + g_object_set (G_OBJECT (action), + "sensitive", (n_selected_items == 1), + NULL); + /* update the "Copy file(s)" action */ action = gtk_action_group_get_action (standard_view->action_group, "copy"); g_object_set (G_OBJECT (action), diff --git a/thunar/thunar-window-ui.xml b/thunar/thunar-window-ui.xml index 5a1fa5899d293df0ed02d7f2c443bca3eae75756..77c977f37030320f2be0a17d1909b9741adcf523 100644 --- a/thunar/thunar-window-ui.xml +++ b/thunar/thunar-window-ui.xml @@ -12,6 +12,8 @@ <menubar name="main-menu"> <menu action="file-menu" name="file-menu"> + <placeholder name="placeholder-file-properties" /> + <separator /> <menuitem action="close" name="close" /> </menu>