[gthumb] added a Location dialog to enter the path to display
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] added a Location dialog to enter the path to display
- Date: Sun, 25 Mar 2012 17:42:08 +0000 (UTC)
commit cc689b5b2f5c6e8d8befa6d5c65fe39b36b89ca1
Author: Paolo Bacchilega <paobac src gnome org>
Date: Sun Mar 25 19:39:10 2012 +0200
added a Location dialog to enter the path to display
[new feature]
data/ui/Makefile.am | 1 +
data/ui/location.ui | 110 ++++++++
gthumb/Makefile.am | 2 +
gthumb/dlg-location.c | 445 ++++++++++++++++++++++++++++++++
gthumb/dlg-location.h | 29 ++
gthumb/gth-browser-actions-callbacks.c | 9 +
gthumb/gth-browser-actions-callbacks.h | 1 +
gthumb/gth-browser-actions-entries.h | 6 +
gthumb/gth-browser-ui.h | 1 +
gthumb/gth-browser.c | 2 +-
10 files changed, 605 insertions(+), 1 deletions(-)
---
diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am
index 4db747e..1bf7f37 100644
--- a/data/ui/Makefile.am
+++ b/data/ui/Makefile.am
@@ -3,6 +3,7 @@ ui_DATA = \
extensions-preferences.ui \
filter-editor.ui \
histogram-info.ui \
+ location.ui \
overwrite-dialog.ui \
personalize-filters.ui \
preferences.ui \
diff --git a/data/ui/location.ui b/data/ui/location.ui
new file mode 100644
index 0000000..413fd10
--- /dev/null
+++ b/data/ui/location.ui
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkDialog" id="location_dialog">
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="modal">True</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox1">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area1">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="label">gtk-cancel</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="ok_button">
+ <property name="label">gtk-jump-to</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="receives_default">True</property>
+ <property name="use_action_appearance">False</property>
+ <property name="use_stock">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">5</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Location:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">location_entry</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="location_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">â</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">80</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <action-widgets>
+ <action-widget response="0">cancel_button</action-widget>
+ <action-widget response="0">ok_button</action-widget>
+ </action-widgets>
+ </object>
+</interface>
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 436db80..1fe4d91 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -126,6 +126,7 @@ PUBLIC_HEADER_FILES = \
$(NULL)
PRIVATE_HEADER_FILES = \
+ dlg-location.h \
dlg-preferences-extensions.h \
gth-browser-actions-callbacks.h \
gth-browser-actions-entries.h \
@@ -146,6 +147,7 @@ gthumb_SOURCES = \
$(PUBLIC_HEADER_FILES) \
$(PRIVATE_HEADER_FILES) \
cairo-utils.c \
+ dlg-location.c \
dlg-personalize-filters.c \
dlg-preferences.c \
dlg-preferences-extensions.c \
diff --git a/gthumb/dlg-location.c b/gthumb/dlg-location.c
new file mode 100644
index 0000000..3a17890
--- /dev/null
+++ b/gthumb/dlg-location.c
@@ -0,0 +1,445 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2001-2012 The Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include "dlg-location.h"
+#include "glib-utils.h"
+#include "gth-browser.h"
+#include "gth-file-source-vfs.h"
+#include "gth-main.h"
+#include "gtk-utils.h"
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (data->builder, (name))
+#define UPDATE_DELAY 200
+
+
+enum {
+ COMPLETION_NAME_COLUMN = 0,
+ COMPLETION_N_COLUMNS
+};
+
+
+typedef struct _DialogData DialogData;
+
+
+typedef struct {
+ guint ref_count;
+ char *uri;
+ GFile *folder;
+ GthFileSource *source;
+ DialogData *data;
+ gboolean keep_scheme;
+} CompletionJob;
+
+
+struct _DialogData {
+ guint ref_count;
+ GthBrowser *browser;
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkEntryCompletion *completion;
+ GtkListStore *completion_store;
+ guint update_event;
+ CompletionJob *job;
+ GFile *last_folder;
+};
+
+
+static DialogData *
+dialog_data_ref (DialogData *data)
+{
+ data->ref_count++;
+ return data;
+}
+
+
+static void completion_job_unref (CompletionJob *job);
+
+
+static void
+dialog_data_unref (DialogData *data)
+{
+ if (data == NULL)
+ return;
+
+ data->ref_count--;
+ if (data->ref_count > 0)
+ return;
+
+ if (data->update_event != 0)
+ g_source_remove (data->update_event);
+ data->update_event = 0;
+ g_object_unref (data->builder);
+ completion_job_unref (data->job);
+ _g_object_unref (data->last_folder);
+ g_free (data);
+}
+
+
+static CompletionJob *
+completion_job_new_for_uri (DialogData *data,
+ const char *uri)
+{
+ CompletionJob *job = NULL;
+
+ job = g_new0 (CompletionJob, 1);
+ job->ref_count = 1;
+ job->data = dialog_data_ref (data);
+ job->uri = g_strdup (uri);
+ job->source = gth_main_get_file_source_for_uri (job->uri);
+ if (job->source == NULL) {
+ completion_job_unref (job);
+ job = NULL;
+ }
+ job->folder = NULL;
+
+ return job;
+}
+
+
+static void
+completion_job_ref (CompletionJob *job)
+{
+ job->ref_count++;
+}
+
+
+static void
+completion_job_unref (CompletionJob *job)
+{
+ if (job == NULL)
+ return;
+ job->ref_count--;
+ if (job->ref_count > 0)
+ return;
+
+ _g_object_unref (job->source);
+ job->source = NULL;
+ dialog_data_unref (job->data);
+ _g_object_unref (job->folder);
+ g_free (job->uri);
+ g_free (job);
+}
+
+
+static void
+destroy_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ gth_browser_set_dialog (data->browser, "location", NULL);
+ if ((data->job != NULL) && (data->job->source != NULL))
+ gth_file_source_cancel (data->job->source);
+ dialog_data_unref (data);
+}
+
+
+static void
+cancel_button_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ gtk_widget_destroy (data->dialog);
+}
+
+
+static char *
+get_location_uri (DialogData *data,
+ gboolean *has_scheme,
+ GError **error)
+{
+ char *uri;
+ char *scheme;
+
+ uri = g_strdup (gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("location_entry"))));
+ scheme = _g_uri_get_scheme (uri);
+ if (scheme == NULL) {
+ char *tmp = uri;
+ uri = g_filename_to_uri (tmp, NULL, error);
+ g_free (tmp);
+ }
+ if (has_scheme != NULL)
+ *has_scheme = (scheme != NULL);
+
+ g_free (scheme);
+
+ return uri;
+}
+
+
+static void
+ok_button_clicked_cb (GtkWidget *widget,
+ DialogData *data)
+{
+ char *uri;
+ GError *error = NULL;
+ GFile *location;
+
+ uri = get_location_uri (data, NULL, &error);
+ if (uri == NULL) {
+ char *title;
+
+ title = g_strdup_printf (_("Could not load the position \"%s\""), gtk_entry_get_text (GTK_ENTRY (GET_WIDGET ("location_entry"))));
+ _gtk_error_dialog_from_gerror_show (GTK_WINDOW (GET_WIDGET ("location_dialog")), title, error);
+
+ g_free (title);
+ g_clear_error (&error);
+
+ return;
+ }
+
+ location = g_file_new_for_uri (uri);
+ gth_browser_load_location (data->browser, location);
+
+ g_object_unref (location);
+ g_free (uri);
+ gtk_widget_destroy (data->dialog);
+}
+
+
+
+static int
+file_data_compare_by_name (gconstpointer a,
+ gconstpointer b)
+{
+ GthFileData *fa = (GthFileData *) a;
+ GthFileData *fb = (GthFileData *) b;
+ char *sa;
+ char *sb;
+ int result;
+
+ sa = g_utf8_collate_key_for_filename (g_file_info_get_name (fa->info), -1);
+ sb = g_utf8_collate_key_for_filename (g_file_info_get_name (fb->info), -1);
+ result = strcmp (sa, sb);
+
+ g_free (sa);
+ g_free (sb);
+
+ return result;
+}
+
+
+static void
+completion_job_list_ready_cb (GthFileSource *file_source,
+ GList *files,
+ GError *error,
+ gpointer user_data)
+{
+ CompletionJob *job = user_data;
+ DialogData *data;
+ GList *ordered;
+ GList *scan;
+
+ if (error != NULL) {
+ completion_job_unref (job);
+ return;
+ }
+
+ data = job->data;
+
+ ordered = g_list_copy (files);
+ ordered = g_list_sort (ordered, file_data_compare_by_name);
+
+ gtk_list_store_clear (data->completion_store);
+ for (scan = ordered; scan; scan = scan->next) {
+ GthFileData *file_data = scan->data;
+
+ if (g_file_info_get_file_type (file_data->info) == G_FILE_TYPE_DIRECTORY) {
+ GtkTreeIter iter;
+ GFile *child;
+ char *uri;
+
+ child = g_file_get_child (job->folder, g_file_info_get_name (file_data->info));
+ if (job->keep_scheme)
+ uri = g_file_get_uri (child);
+ else
+ uri = g_file_get_path (child);
+
+ gtk_list_store_append (data->completion_store, &iter);
+ gtk_list_store_set (data->completion_store, &iter,
+ COMPLETION_NAME_COLUMN, uri,
+ -1);
+
+ g_free (uri);
+ g_object_unref (child);
+ }
+ }
+
+ g_list_free (ordered);
+
+ if (job == data->job) {
+ completion_job_unref (data->job);
+ data->job = NULL;
+ }
+ completion_job_unref (job);
+}
+
+
+static void
+update_completion_list (DialogData *data)
+{
+ gboolean has_scheme;
+ char *uri;
+
+
+ uri = get_location_uri (data, &has_scheme, NULL);
+ if (uri == NULL) {
+ gtk_list_store_clear (data->completion_store);
+ return;
+ }
+
+ if (data->job != NULL) {
+ if (data->job->source != NULL)
+ gth_file_source_cancel (data->job->source);
+ completion_job_unref (data->job);
+ }
+
+ data->job = completion_job_new_for_uri (data, uri);
+ if (data->job != NULL) {
+ data->job->keep_scheme = has_scheme;
+ data->job->folder = g_file_new_for_uri (uri);
+ if (! g_str_has_suffix (uri, "/")) {
+ GFile *parent;
+
+ parent = g_file_get_parent (data->job->folder);
+ if (parent != NULL) {
+ g_object_unref (data->job->folder);
+ data->job->folder = parent;
+ }
+ }
+
+ if ((data->last_folder == NULL) || ! g_file_equal (data->last_folder, data->job->folder)) {
+ _g_object_unref (data->last_folder);
+ data->last_folder = g_object_ref (data->job->folder);
+
+ completion_job_ref (data->job);
+ gth_file_source_list (data->job->source,
+ data->job->folder,
+ "standard::type,standard::name",
+ completion_job_list_ready_cb,
+ data->job);
+ }
+ else {
+ completion_job_unref (data->job);
+ data->job = NULL;
+ }
+
+ }
+
+ g_free (uri);
+}
+
+
+static gboolean
+update_completion_list_cb (gpointer user_data)
+{
+ DialogData *data = user_data;
+
+ data->update_event = 0;
+ update_completion_list (data);
+
+ return FALSE;
+}
+
+
+static void
+location_entry_changed_cb (GtkEntry *entry,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ DialogData *data = user_data;
+
+ if (data->update_event != 0)
+ g_source_remove (data->update_event);
+ data->update_event = g_timeout_add (UPDATE_DELAY, update_completion_list_cb, data);
+}
+
+
+void
+dlg_location (GthBrowser *browser)
+{
+ DialogData *data;
+ char *text;
+ GFile *location;
+ GthFileSource *source;
+
+ if (gth_browser_get_dialog (browser, "location") != NULL) {
+ gtk_window_present (GTK_WINDOW (gth_browser_get_dialog (browser, "location")));
+ return;
+ }
+
+ data = g_new0 (DialogData, 1);
+ data->ref_count = 1;
+ data->browser = browser;
+ data->builder = _gtk_builder_new_from_file ("location.ui", NULL);
+ data->dialog = GET_WIDGET ("location_dialog");
+
+ gth_browser_set_dialog (browser, "location", data->dialog);
+
+ /* set the widget data */
+
+ data->completion = gtk_entry_completion_new ();
+ gtk_entry_completion_set_popup_completion (data->completion, TRUE);
+ gtk_entry_completion_set_popup_single_match (data->completion, FALSE);
+ gtk_entry_completion_set_inline_completion (data->completion, TRUE);
+ data->completion_store = gtk_list_store_new (COMPLETION_N_COLUMNS, G_TYPE_STRING);
+ gtk_entry_completion_set_model (data->completion, GTK_TREE_MODEL (data->completion_store));
+ g_object_unref (data->completion_store);
+ gtk_entry_completion_set_text_column (data->completion, COMPLETION_NAME_COLUMN);
+ gtk_entry_set_completion (GTK_ENTRY (GET_WIDGET ("location_entry")), data->completion);
+
+ text = NULL;
+ location = gth_browser_get_location (browser);
+ source = gth_main_get_file_source (location);
+ if (GTH_IS_FILE_SOURCE_VFS (source))
+ text = g_file_get_path (location);
+ if (text == NULL)
+ text = g_file_get_uri (location);
+ gtk_entry_set_text (GTK_ENTRY (GET_WIDGET ("location_entry")), text);
+
+ g_free (text);
+ g_object_unref (source);
+
+ /* set the signals handlers. */
+
+ g_signal_connect (G_OBJECT (data->dialog),
+ "destroy",
+ G_CALLBACK (destroy_cb),
+ data);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("cancel_button")),
+ "clicked",
+ G_CALLBACK (cancel_button_clicked_cb),
+ data);
+ g_signal_connect (G_OBJECT (GET_WIDGET ("ok_button")),
+ "clicked",
+ G_CALLBACK (ok_button_clicked_cb),
+ data);
+ g_signal_connect (GET_WIDGET ("location_entry"),
+ "notify::text",
+ G_CALLBACK (location_entry_changed_cb),
+ data);
+
+ /* run dialog. */
+
+ update_completion_list (data);
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), GTK_WINDOW (browser));
+ gtk_widget_show (data->dialog);
+}
diff --git a/gthumb/dlg-location.h b/gthumb/dlg-location.h
new file mode 100644
index 0000000..db443c9
--- /dev/null
+++ b/gthumb/dlg-location.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2001-2012 The Free Software Foundation, Inc.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DLG_LOCATION_H
+#define DLG_LOCATION_H
+
+#include "gth-browser.h"
+
+void dlg_location (GthBrowser *browser);
+
+#endif /* DLG_LOCATION_H */
diff --git a/gthumb/gth-browser-actions-callbacks.c b/gthumb/gth-browser-actions-callbacks.c
index b5058b6..c569138 100644
--- a/gthumb/gth-browser-actions-callbacks.c
+++ b/gthumb/gth-browser-actions-callbacks.c
@@ -21,6 +21,7 @@
#include <config.h>
#include <glib/gi18n.h>
+#include "dlg-location.h"
#include "dlg-personalize-filters.h"
#include "dlg-preferences.h"
#include "dlg-sort-order.h"
@@ -140,6 +141,14 @@ gth_browser_activate_action_go_up (GtkAction *action,
void
+gth_browser_activate_action_go_location (GtkAction *action,
+ GthBrowser *browser)
+{
+ dlg_location (browser);
+}
+
+
+void
gth_browser_activate_action_go_home (GtkAction *action,
GthBrowser *browser)
{
diff --git a/gthumb/gth-browser-actions-callbacks.h b/gthumb/gth-browser-actions-callbacks.h
index d2b7860..da23eb1 100644
--- a/gthumb/gth-browser-actions-callbacks.h
+++ b/gthumb/gth-browser-actions-callbacks.h
@@ -43,6 +43,7 @@ DEFINE_ACTION(gth_browser_activate_action_folder_open_in_file_manager)
DEFINE_ACTION(gth_browser_activate_action_go_back)
DEFINE_ACTION(gth_browser_activate_action_go_forward)
DEFINE_ACTION(gth_browser_activate_action_go_up)
+DEFINE_ACTION(gth_browser_activate_action_go_location)
DEFINE_ACTION(gth_browser_activate_action_go_clear_history)
DEFINE_ACTION(gth_browser_activate_action_go_home)
DEFINE_ACTION(gth_browser_activate_action_help_help)
diff --git a/gthumb/gth-browser-actions-entries.h b/gthumb/gth-browser-actions-entries.h
index 405e22f..1432569 100644
--- a/gthumb/gth-browser-actions-entries.h
+++ b/gthumb/gth-browser-actions-entries.h
@@ -157,6 +157,12 @@ static GthActionEntryExt gth_browser_action_entries[] = {
GTH_ACTION_FLAG_NONE,
G_CALLBACK (gth_browser_activate_action_go_up) },
+ { "Go_Location", NULL,
+ N_("_Location..."), "<control>L",
+ N_("Specify a location to open"),
+ GTH_ACTION_FLAG_NONE,
+ G_CALLBACK (gth_browser_activate_action_go_location) },
+
{ "Go_Home", NULL,
NULL, "<alt>Home",
NULL,
diff --git a/gthumb/gth-browser-ui.h b/gthumb/gth-browser-ui.h
index 3c6077b..b72dcdc 100644
--- a/gthumb/gth-browser-ui.h
+++ b/gthumb/gth-browser-ui.h
@@ -90,6 +90,7 @@ static const char *fixed_ui_info =
" <menuitem action='Go_Back'/>"
" <menuitem action='Go_Forward'/>"
" <menuitem action='Go_Up'/>"
+" <menuitem action='Go_Location'/>"
" <separator name='BeforeEntryPointList'/>"
" <placeholder name='EntryPointList'/>"
" <separator name='EntryPointListSeparator'/>"
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 53d9a0b..9e74f87 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -859,7 +859,7 @@ _gth_browser_update_entry_point_list (GthBrowser *browser)
separator2 = gtk_ui_manager_get_widget (browser->priv->ui, "/MenuBar/Go/EntryPointListSeparator");
_gtk_container_remove_children (GTK_CONTAINER (menu), separator1, separator2);
- position = 5;
+ position = 6;
entry_points = gth_main_get_all_entry_points ();
for (scan = entry_points; scan; scan = scan->next) {
GthFileData *file_data = scan->data;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]