diff options
author | Perberos <[email protected]> | 2011-12-01 22:24:23 -0300 |
---|---|---|
committer | Perberos <[email protected]> | 2011-12-01 22:24:23 -0300 |
commit | 0e004c696b0e68b2cff37a4c3315b022a35eaf43 (patch) | |
tree | 43261e815529cb9518ed7be37af13b846af8b26b /src/caja-location-bar.c | |
download | caja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.bz2 caja-0e004c696b0e68b2cff37a4c3315b022a35eaf43.tar.xz |
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'src/caja-location-bar.c')
-rw-r--r-- | src/caja-location-bar.c | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/src/caja-location-bar.c b/src/caja-location-bar.c new file mode 100644 index 00000000..2e35d50d --- /dev/null +++ b/src/caja-location-bar.c @@ -0,0 +1,617 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ + +/* + * Caja + * + * Copyright (C) 2000 Eazel, Inc. + * + * Caja 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. + * + * Caja 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; see the file COPYING. If not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Maciej Stachowiak <[email protected]> + * Ettore Perazzoli <[email protected]> + * Michael Meeks <[email protected]> + * Andy Hertzfeld <[email protected]> + * + */ + +/* caja-location-bar.c - Location bar for Caja + */ + +#include <config.h> +#include "caja-location-bar.h" + +#include "caja-location-entry.h" +#include "caja-window-private.h" +#include "caja-window.h" +#include "caja-navigation-window-pane.h" +#include <eel/eel-accessibility.h> +#include <eel/eel-glib-extensions.h> +#include <eel/eel-gtk-macros.h> +#include <eel/eel-stock-dialogs.h> +#include <eel/eel-string.h> +#include <eel/eel-vfs-extensions.h> +#include <gtk/gtk.h> +#include <glib/gi18n.h> +#include <libcaja-private/caja-icon-dnd.h> +#include <libcaja-private/caja-clipboard.h> +#include <stdio.h> +#include <string.h> + +#define CAJA_DND_URI_LIST_TYPE "text/uri-list" +#define CAJA_DND_TEXT_PLAIN_TYPE "text/plain" + +static const char untranslated_location_label[] = N_("Location:"); +static const char untranslated_go_to_label[] = N_("Go To:"); +#define LOCATION_LABEL _(untranslated_location_label) +#define GO_TO_LABEL _(untranslated_go_to_label) + +struct CajaLocationBarDetails +{ + GtkLabel *label; + CajaEntry *entry; + + char *last_location; + + guint idle_id; +}; + +enum +{ + CAJA_DND_MC_DESKTOP_ICON, + CAJA_DND_URI_LIST, + CAJA_DND_TEXT_PLAIN, + CAJA_DND_NTARGETS +}; + +static const GtkTargetEntry drag_types [] = +{ + { CAJA_DND_URI_LIST_TYPE, 0, CAJA_DND_URI_LIST }, + { CAJA_DND_TEXT_PLAIN_TYPE, 0, CAJA_DND_TEXT_PLAIN }, +}; + +static const GtkTargetEntry drop_types [] = +{ + { CAJA_DND_URI_LIST_TYPE, 0, CAJA_DND_URI_LIST }, + { CAJA_DND_TEXT_PLAIN_TYPE, 0, CAJA_DND_TEXT_PLAIN }, +}; + +static char *caja_location_bar_get_location (CajaNavigationBar *navigation_bar); +static void caja_location_bar_set_location (CajaNavigationBar *navigation_bar, + const char *location); +static void caja_location_bar_class_init (CajaLocationBarClass *class); +static void caja_location_bar_init (CajaLocationBar *bar); +static void caja_location_bar_update_label (CajaLocationBar *bar); + +EEL_CLASS_BOILERPLATE (CajaLocationBar, + caja_location_bar, + CAJA_TYPE_NAVIGATION_BAR) + +static CajaNavigationWindow * +caja_location_bar_get_window (GtkWidget *bar) +{ + return CAJA_NAVIGATION_WINDOW (gtk_widget_get_ancestor (bar, CAJA_TYPE_WINDOW)); +} + +static void +drag_data_received_callback (GtkWidget *widget, + GdkDragContext *context, + int x, + int y, + GtkSelectionData *data, + guint info, + guint32 time, + gpointer callback_data) +{ + char **names; + CajaApplication *application; + int name_count; + CajaWindow *new_window; + CajaNavigationWindow *window; + GdkScreen *screen; + gboolean new_windows_for_extras; + char *prompt; + char *detail; + GFile *location; + + g_assert (CAJA_IS_LOCATION_BAR (widget)); + g_assert (data != NULL); + g_assert (callback_data == NULL); + + names = g_uri_list_extract_uris (gtk_selection_data_get_data (data)); + + if (names == NULL || *names == NULL) + { + g_warning ("No D&D URI's"); + gtk_drag_finish (context, FALSE, FALSE, time); + return; + } + + window = caja_location_bar_get_window (widget); + new_windows_for_extras = FALSE; + /* Ask user if they really want to open multiple windows + * for multiple dropped URIs. This is likely to have been + * a mistake. + */ + name_count = g_strv_length (names); + if (name_count > 1) + { + prompt = g_strdup_printf (ngettext("Do you want to view %d location?", + "Do you want to view %d locations?", + name_count), + name_count); + detail = g_strdup_printf (ngettext("This will open %d separate window.", + "This will open %d separate windows.", + name_count), + name_count); + /* eel_run_simple_dialog should really take in pairs + * like gtk_dialog_new_with_buttons() does. */ + new_windows_for_extras = eel_run_simple_dialog + (GTK_WIDGET (window), + TRUE, + GTK_MESSAGE_QUESTION, + prompt, + detail, + GTK_STOCK_CANCEL, GTK_STOCK_OK, + NULL) != 0 /* MATE_OK */; + + g_free (prompt); + g_free (detail); + + if (!new_windows_for_extras) + { + gtk_drag_finish (context, FALSE, FALSE, time); + return; + } + } + + caja_navigation_bar_set_location (CAJA_NAVIGATION_BAR (widget), + names[0]); + caja_navigation_bar_location_changed (CAJA_NAVIGATION_BAR (widget)); + + if (new_windows_for_extras) + { + int i; + + application = CAJA_WINDOW (window)->application; + screen = gtk_window_get_screen (GTK_WINDOW (window)); + + for (i = 1; names[i] != NULL; ++i) + { + new_window = caja_application_create_navigation_window (application, NULL, screen); + location = g_file_new_for_uri (names[i]); + caja_window_go_to (new_window, location); + g_object_unref (location); + } + } + + g_strfreev (names); + + gtk_drag_finish (context, TRUE, FALSE, time); +} + +static void +drag_data_get_callback (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time, + gpointer callback_data) +{ + CajaNavigationBar *bar; + char *entry_text; + + g_assert (selection_data != NULL); + bar = CAJA_NAVIGATION_BAR (callback_data); + + entry_text = caja_navigation_bar_get_location (bar); + + switch (info) + { + case CAJA_DND_URI_LIST: + case CAJA_DND_TEXT_PLAIN: + gtk_selection_data_set (selection_data, + gtk_selection_data_get_target (selection_data), + 8, (guchar *) entry_text, + eel_strlen (entry_text)); + break; + default: + g_assert_not_reached (); + } + g_free (entry_text); +} + +/* routine that determines the usize for the label widget as larger + then the size of the largest string and then sets it to that so + that we don't have localization problems. see + gtk_label_finalize_lines in gtklabel.c (line 618) for the code that + we are imitating here. */ + +static void +style_set_handler (GtkWidget *widget, GtkStyle *previous_style) +{ + PangoLayout *layout; + int width, width2; + int xpad; + + layout = gtk_label_get_layout (GTK_LABEL(widget)); + + layout = pango_layout_copy (layout); + + pango_layout_set_text (layout, LOCATION_LABEL, -1); + pango_layout_get_pixel_size (layout, &width, NULL); + + pango_layout_set_text (layout, GO_TO_LABEL, -1); + pango_layout_get_pixel_size (layout, &width2, NULL); + width = MAX (width, width2); + + gtk_misc_get_padding (GTK_MISC (widget), + &xpad, NULL); + + width += 2 * xpad; + + gtk_widget_set_size_request (widget, width, -1); + + g_object_unref (layout); +} + +static gboolean +label_button_pressed_callback (GtkWidget *widget, + GdkEventButton *event) +{ + CajaNavigationWindow *window; + CajaWindowSlot *slot; + CajaView *view; + GtkWidget *label; + + if (event->button != 3) + { + return FALSE; + } + + window = caja_location_bar_get_window (gtk_widget_get_parent (widget)); + slot = CAJA_WINDOW (window)->details->active_pane->active_slot; + view = slot->content_view; + label = gtk_bin_get_child (GTK_BIN (widget)); + /* only pop-up if the URI in the entry matches the displayed location */ + if (view == NULL || + strcmp (gtk_label_get_text (GTK_LABEL (label)), LOCATION_LABEL)) + { + return FALSE; + } + + caja_view_pop_up_location_context_menu (view, event, NULL); + + return FALSE; +} + +static void +editable_activate_callback (GtkEntry *entry, + gpointer user_data) +{ + CajaNavigationBar *bar; + const char *entry_text; + + bar = CAJA_NAVIGATION_BAR (user_data); + + entry_text = gtk_entry_get_text (entry); + if (entry_text != NULL && *entry_text != '\0') + { + caja_navigation_bar_location_changed (bar); + } +} + +static void +editable_changed_callback (GtkEntry *entry, + gpointer user_data) +{ + caja_location_bar_update_label (CAJA_LOCATION_BAR (user_data)); +} + +static void +real_activate (CajaNavigationBar *navigation_bar) +{ + CajaLocationBar *bar; + + bar = CAJA_LOCATION_BAR (navigation_bar); + + /* Put the keyboard focus in the text field when switching to this mode, + * and select all text for easy overtyping + */ + gtk_widget_grab_focus (GTK_WIDGET (bar->details->entry)); + caja_entry_select_all (bar->details->entry); +} + +static void +real_cancel (CajaNavigationBar *navigation_bar) +{ + char *last_location; + + last_location = CAJA_LOCATION_BAR (navigation_bar)->details->last_location; + caja_navigation_bar_set_location (navigation_bar, last_location); +} + +static void +finalize (GObject *object) +{ + CajaLocationBar *bar; + + bar = CAJA_LOCATION_BAR (object); + + g_free (bar->details); + + EEL_CALL_PARENT (G_OBJECT_CLASS, finalize, (object)); +} + +static void +destroy (GtkObject *object) +{ + CajaLocationBar *bar; + + bar = CAJA_LOCATION_BAR (object); + + /* cancel the pending idle call, if any */ + if (bar->details->idle_id != 0) + { + g_source_remove (bar->details->idle_id); + bar->details->idle_id = 0; + } + + g_free (bar->details->last_location); + bar->details->last_location = NULL; + + EEL_CALL_PARENT (GTK_OBJECT_CLASS, destroy, (object)); +} + +static void +caja_location_bar_class_init (CajaLocationBarClass *class) +{ + GObjectClass *gobject_class; + GtkObjectClass *object_class; + CajaNavigationBarClass *navigation_bar_class; + + gobject_class = G_OBJECT_CLASS (class); + gobject_class->finalize = finalize; + + object_class = GTK_OBJECT_CLASS (class); + object_class->destroy = destroy; + + navigation_bar_class = CAJA_NAVIGATION_BAR_CLASS (class); + + navigation_bar_class->activate = real_activate; + navigation_bar_class->cancel = real_cancel; + navigation_bar_class->get_location = caja_location_bar_get_location; + navigation_bar_class->set_location = caja_location_bar_set_location; +} + +static void +caja_location_bar_init (CajaLocationBar *bar) +{ + GtkWidget *label; + GtkWidget *entry; + GtkWidget *event_box; + GtkWidget *hbox; + + bar->details = g_new0 (CajaLocationBarDetails, 1); + + hbox = gtk_hbox_new (0, FALSE); + + event_box = gtk_event_box_new (); + gtk_event_box_set_visible_window (GTK_EVENT_BOX (event_box), FALSE); + + gtk_container_set_border_width (GTK_CONTAINER (event_box), 4); + label = gtk_label_new (LOCATION_LABEL); + gtk_container_add (GTK_CONTAINER (event_box), label); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_signal_connect (label, "style_set", + G_CALLBACK (style_set_handler), NULL); + + gtk_box_pack_start (GTK_BOX (hbox), event_box, FALSE, TRUE, 4); + + entry = caja_location_entry_new (); + + g_signal_connect_object (entry, "activate", + G_CALLBACK (editable_activate_callback), bar, G_CONNECT_AFTER); + g_signal_connect_object (entry, "changed", + G_CALLBACK (editable_changed_callback), bar, 0); + + gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0); + + eel_accessibility_set_up_label_widget_relation (label, entry); + + gtk_container_add (GTK_CONTAINER (bar), hbox); + + + /* Label context menu */ + g_signal_connect (event_box, "button-press-event", + G_CALLBACK (label_button_pressed_callback), NULL); + + /* Drag source */ + gtk_drag_source_set (GTK_WIDGET (event_box), + GDK_BUTTON1_MASK | GDK_BUTTON3_MASK, + drag_types, G_N_ELEMENTS (drag_types), + GDK_ACTION_COPY | GDK_ACTION_LINK); + g_signal_connect_object (event_box, "drag_data_get", + G_CALLBACK (drag_data_get_callback), bar, 0); + + /* Drag dest. */ + gtk_drag_dest_set (GTK_WIDGET (bar), + GTK_DEST_DEFAULT_ALL, + drop_types, G_N_ELEMENTS (drop_types), + GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); + g_signal_connect (bar, "drag_data_received", + G_CALLBACK (drag_data_received_callback), NULL); + + gtk_widget_show_all (hbox); + + bar->details->label = GTK_LABEL (label); + bar->details->entry = CAJA_ENTRY (entry); +} + +GtkWidget * +caja_location_bar_new (CajaNavigationWindowPane *pane) +{ + GtkWidget *bar; + CajaLocationBar *location_bar; + + bar = gtk_widget_new (CAJA_TYPE_LOCATION_BAR, NULL); + location_bar = CAJA_LOCATION_BAR (bar); + + /* Clipboard */ + caja_clipboard_set_up_editable + (GTK_EDITABLE (location_bar->details->entry), + caja_window_get_ui_manager (CAJA_WINDOW (CAJA_WINDOW_PANE(pane)->window)), + TRUE); + + return bar; +} + +static void +caja_location_bar_set_location (CajaNavigationBar *navigation_bar, + const char *location) +{ + CajaLocationBar *bar; + char *formatted_location; + GFile *file; + + g_assert (location != NULL); + + bar = CAJA_LOCATION_BAR (navigation_bar); + + /* Note: This is called in reaction to external changes, and + * thus should not emit the LOCATION_CHANGED signal. */ + + if (eel_uri_is_search (location)) + { + caja_location_entry_set_special_text (CAJA_LOCATION_ENTRY (bar->details->entry), + ""); + } + else + { + file = g_file_new_for_uri (location); + formatted_location = g_file_get_parse_name (file); + g_object_unref (file); + caja_location_entry_update_current_location (CAJA_LOCATION_ENTRY (bar->details->entry), + formatted_location); + g_free (formatted_location); + } + + /* remember the original location for later comparison */ + + if (bar->details->last_location != location) + { + g_free (bar->details->last_location); + bar->details->last_location = g_strdup (location); + } + + caja_location_bar_update_label (bar); +} + +/** + * caja_location_bar_get_location + * + * Get the "URI" represented by the text in the location bar. + * + * @bar: A CajaLocationBar. + * + * returns a newly allocated "string" containing the mangled + * (by g_file_parse_name) text that the user typed in...maybe a URI + * but not guaranteed. + * + **/ +static char * +caja_location_bar_get_location (CajaNavigationBar *navigation_bar) +{ + CajaLocationBar *bar; + char *user_location, *uri; + GFile *location; + + bar = CAJA_LOCATION_BAR (navigation_bar); + + user_location = gtk_editable_get_chars (GTK_EDITABLE (bar->details->entry), 0, -1); + location = g_file_parse_name (user_location); + g_free (user_location); + uri = g_file_get_uri (location); + g_object_unref (location); + return uri; +} + +/** + * caja_location_bar_update_label + * + * if the text in the entry matches the uri, set the label to "location", otherwise use "goto" + * + **/ +static void +caja_location_bar_update_label (CajaLocationBar *bar) +{ + const char *current_text; + GFile *location; + GFile *last_location; + + if (bar->details->last_location == NULL) + { + gtk_label_set_text (GTK_LABEL (bar->details->label), GO_TO_LABEL); + caja_location_entry_set_secondary_action (CAJA_LOCATION_ENTRY (bar->details->entry), + CAJA_LOCATION_ENTRY_ACTION_GOTO); + return; + } + + current_text = gtk_entry_get_text (GTK_ENTRY (bar->details->entry)); + location = g_file_parse_name (current_text); + last_location = g_file_parse_name (bar->details->last_location); + + if (g_file_equal (last_location, location)) + { + gtk_label_set_text (GTK_LABEL (bar->details->label), LOCATION_LABEL); + caja_location_entry_set_secondary_action (CAJA_LOCATION_ENTRY (bar->details->entry), + CAJA_LOCATION_ENTRY_ACTION_CLEAR); + } + else + { + gtk_label_set_text (GTK_LABEL (bar->details->label), GO_TO_LABEL); + caja_location_entry_set_secondary_action (CAJA_LOCATION_ENTRY (bar->details->entry), + CAJA_LOCATION_ENTRY_ACTION_GOTO); + } + + g_object_unref (location); + g_object_unref (last_location); +} + +/* change background color based on activity state */ +void +caja_location_bar_set_active(CajaLocationBar *location_bar, gboolean is_active) +{ + if(is_active) + { + /* reset style to default */ + gtk_widget_modify_base (GTK_WIDGET (location_bar->details->entry), GTK_STATE_NORMAL, NULL); + } + else + { + GtkStyle *style; + GdkColor color; + style = gtk_widget_get_style (GTK_WIDGET (location_bar->details->entry)); + color = style->base[GTK_STATE_INSENSITIVE]; + gtk_widget_modify_base(GTK_WIDGET (location_bar->details->entry), GTK_STATE_NORMAL, &color); + } +} + +CajaEntry * +caja_location_bar_get_entry (CajaLocationBar *location_bar) +{ + return location_bar->details->entry; +} |