[yelp] First pass at bookmarks
- From: Shaun McCance <shaunm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [yelp] First pass at bookmarks
- Date: Thu, 29 Apr 2010 21:50:51 +0000 (UTC)
commit efbdbbf5f36697d4f0402d76b759720bf5b25b9b
Author: Shaun McCance <shaunm gnome org>
Date: Thu Apr 29 16:44:11 2010 -0500
First pass at bookmarks
Bookmarks are now stored per-document in GSettings. They're stored as
page IDs along with the icon and title. Problems to fix:
* On the index page, the page ID might be NULL. Yelp will crash if
you try to bookmark this. We need to track the real page ID from
the view. This will also help us solve the double-index-entry in
the location entry drop-down.
* Bookmarks aren't sorted in any meaningful way. We should sort by
page type (icon) first, then title. Again, same thing for location
entry completion.
* There's no way to remove bookmarks.
* (Wish list) We should automatically reset the icon and title on
existing bookmarks if they're different (e.g. after an upgrade).
* We need to hook up the bookmarking to the location entry.
data/org.gnome.yelp.gschema.xml | 3 +
src/yelp-application.c | 114 +++++++++++++++++++++++-----
src/yelp-application.h | 10 ++-
src/yelp-window.c | 158 ++++++++++++++++++++++++++++++++++++++-
4 files changed, 262 insertions(+), 23 deletions(-)
---
diff --git a/data/org.gnome.yelp.gschema.xml b/data/org.gnome.yelp.gschema.xml
index 046f9d5..250c12a 100644
--- a/data/org.gnome.yelp.gschema.xml
+++ b/data/org.gnome.yelp.gschema.xml
@@ -20,5 +20,8 @@
<key name="geometry" type="(ii)">
<default>(520,580)</default>
</key>
+ <key name="bookmarks" type="a(sss)">
+ <default>[]</default>
+ </key>
</schema>
</schemalist>
diff --git a/src/yelp-application.c b/src/yelp-application.c
index 341c00a..f239292 100644
--- a/src/yelp-application.c
+++ b/src/yelp-application.c
@@ -45,6 +45,12 @@
static gboolean editor_mode = FALSE;
+enum {
+ BOOKMARKS_CHANGED,
+ LAST_SIGNAL
+};
+static gint signals[LAST_SIGNAL] = { 0 };
+
static const GOptionEntry entries[] = {
{"editor-mode", 0, 0, G_OPTION_ARG_NONE, &editor_mode, N_("Turn on editor mode"), NULL},
{ NULL }
@@ -68,6 +74,8 @@ static void application_uri_resolved (YelpUri *u
static gboolean application_window_deleted (YelpWindow *window,
GdkEvent *event,
YelpApplication *app);
+GSettings * application_get_doc_settings (YelpApplication *app,
+ const gchar *doc_uri);
static gboolean application_maybe_quit (YelpApplication *app);
static void application_adjust_font (GtkAction *action,
YelpApplication *app);
@@ -123,6 +131,14 @@ yelp_application_class_init (YelpApplicationClass *klass)
object_class->dispose = yelp_application_dispose;
object_class->finalize = yelp_application_finalize;
+ signals[BOOKMARKS_CHANGED] =
+ g_signal_new ("bookmarks-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0, NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
dbus_g_object_type_install_info (YELP_TYPE_APPLICATION,
&dbus_glib_yelp_object_info);
@@ -424,28 +440,12 @@ application_uri_resolved (YelpUri *uri,
if (window == NULL) {
gint width, height;
- GSettings *settings = g_hash_table_lookup (priv->docsettings, doc_uri);
- if (settings == NULL) {
- gchar *tmp;
- gchar *settings_path;
- tmp = g_uri_escape_string (doc_uri, "", FALSE);
- settings_path = g_strconcat ("/apps/yelp/documents/", tmp, "/", NULL);
- g_free (tmp);
- if (priv->gsettings_context)
- settings = g_settings_new_with_context_and_path ("org.gnome.yelp.documents",
- priv->gsettings_context,
- settings_path);
- else
- settings = g_settings_new_with_path ("org.gnome.yelp.document",
- settings_path);
- g_hash_table_insert (priv->docsettings, g_strdup (doc_uri), settings);
- g_free (settings_path);
- }
+ GSettings *settings = application_get_doc_settings (data->app, doc_uri);
g_settings_get (settings, "geometry", "(ii)", &width, &height);
window = yelp_window_new (data->app);
gtk_window_set_default_size (GTK_WINDOW (window), width, height);
- g_signal_connect (window, "resized", window_resized, data->app);
+ g_signal_connect (window, "resized", G_CALLBACK (window_resized), data->app);
priv->windows = g_slist_prepend (priv->windows, window);
if (!data->new) {
@@ -476,6 +476,30 @@ application_uri_resolved (YelpUri *uri,
g_free (data);
}
+GSettings *
+application_get_doc_settings (YelpApplication *app, const gchar *doc_uri)
+{
+ YelpApplicationPrivate *priv = GET_PRIV (app);
+ GSettings *settings = g_hash_table_lookup (priv->docsettings, doc_uri);
+ if (settings == NULL) {
+ gchar *tmp;
+ gchar *settings_path;
+ tmp = g_uri_escape_string (doc_uri, "", FALSE);
+ settings_path = g_strconcat ("/apps/yelp/documents/", tmp, "/", NULL);
+ g_free (tmp);
+ if (priv->gsettings_context)
+ settings = g_settings_new_with_context_and_path ("org.gnome.yelp.documents",
+ priv->gsettings_context,
+ settings_path);
+ else
+ settings = g_settings_new_with_path ("org.gnome.yelp.document",
+ settings_path);
+ g_hash_table_insert (priv->docsettings, g_strdup (doc_uri), settings);
+ g_free (settings_path);
+ }
+ return settings;
+}
+
static gboolean
application_window_deleted (YelpWindow *window,
GdkEvent *event,
@@ -539,6 +563,60 @@ packages_installed (DBusGProxy *proxy,
}
void
+yelp_application_add_bookmark (YelpApplication *app,
+ YelpUri *uri,
+ const gchar *icon,
+ const gchar *title)
+{
+ GSettings *settings;
+ gchar *doc_uri, *page_id;
+ YelpApplicationPrivate *priv = GET_PRIV (app);
+
+ doc_uri = yelp_uri_get_document_uri (uri);
+ page_id = yelp_uri_get_page_id (uri);
+ settings = application_get_doc_settings (app, doc_uri);
+
+ if (settings) {
+ GVariantBuilder builder;
+ GVariantIter *iter;
+ gchar *this_id, *this_icon, *this_title;
+ gboolean broken = FALSE;
+ g_settings_get (settings, "bookmarks", "a(sss)", &iter);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sss)"));
+ while (g_variant_iter_loop (iter, "(&s&s&s)", &this_id, &this_icon, &this_title)) {
+ if (g_str_equal (page_id, this_id)) {
+ /* Already have this bookmark */
+ broken = TRUE;
+ break;
+ }
+ g_variant_builder_add (&builder, "(sss)", this_id, this_icon, this_title);
+ }
+ g_variant_iter_free (iter);
+
+ if (!broken) {
+ GVariant *value;
+ g_variant_builder_add (&builder, "(sss)", page_id, icon, title);
+ value = g_variant_builder_end (&builder);
+ g_settings_set_value (settings, "bookmarks", value);
+ g_variant_unref (value);
+ g_signal_emit (app, signals[BOOKMARKS_CHANGED], 0, doc_uri, 0);
+ }
+ }
+
+ g_free (doc_uri);
+ g_free (page_id);
+}
+
+GVariant *
+yelp_application_get_bookmarks (YelpApplication *app,
+ const gchar *doc_uri)
+{
+ GSettings *settings = application_get_doc_settings (app, doc_uri);
+
+ return g_settings_get_value (settings, "bookmarks");
+}
+
+void
yelp_application_install_package (YelpApplication *app,
const gchar *pkg,
const gchar *alt)
diff --git a/src/yelp-application.h b/src/yelp-application.h
index c753212..9ae9d1c 100644
--- a/src/yelp-application.h
+++ b/src/yelp-application.h
@@ -25,6 +25,8 @@
#include <glib-object.h>
+#include "yelp-uri.h"
+
#define YELP_TYPE_APPLICATION (yelp_application_get_type ())
#define YELP_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), YELP_TYPE_APPLICATION, YelpApplication))
#define YELP_APPLICATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), YELP_TYPE_APPLICATION, YelpApplicationClass))
@@ -55,7 +57,13 @@ gboolean yelp_application_load_uri (YelpApplication *app,
GError **error);
void yelp_application_new_window (YelpApplication *app,
const gchar *uri);
-GtkActionGroup * yelp_application_get_action_group (YelpApplication *app);
+GtkActionGroup * yelp_application_get_action_group (YelpApplication *app);
+void yelp_application_add_bookmark (YelpApplication *app,
+ YelpUri *uri,
+ const gchar *icon,
+ const gchar *title);
+GVariant * yelp_application_get_bookmarks (YelpApplication *app,
+ const gchar *doc_uri);
void yelp_application_install_package (YelpApplication *app,
const gchar *pkg,
const gchar *alt);
diff --git a/src/yelp-window.c b/src/yelp-window.c
index 59c930b..1724d87 100644
--- a/src/yelp-window.c
+++ b/src/yelp-window.c
@@ -58,9 +58,19 @@ static gboolean window_configure_event (YelpWindow *window,
static gboolean window_resize_signal (YelpWindow *window);
static void window_close (GtkAction *action,
YelpWindow *window);
+static void window_add_bookmark (GtkAction *action,
+ YelpWindow *window);
+static void window_load_bookmark (GtkAction *action,
+ YelpWindow *window);
static void window_open_location (GtkAction *action,
YelpWindow *window);
+static void app_bookmarks_changed (YelpApplication *app,
+ const gchar *doc_uri,
+ YelpWindow *window);
+static void window_set_bookmarks (YelpWindow *window,
+ const gchar *doc_uri);
+
static void entry_location_selected (YelpLocationEntry *entry,
YelpWindow *window);
static void entry_completion_selected (YelpLocationEntry *entry,
@@ -143,6 +153,11 @@ static const gchar *YELP_UI =
"<menuitem action='YelpViewGoPrevious'/>"
"<menuitem action='YelpViewGoNext'/>"
"</menu>"
+ "<menu action='BookmarksMenu'>"
+ "<menuitem action='AddBookmark'/>"
+ "<separator/>"
+ "<placeholder name='Bookmarks'/>"
+ "</menu>"
"</menubar>"
"<accelerator action='OpenLocation'/>"
"</ui>";
@@ -167,6 +182,11 @@ struct _YelpWindowPrivate {
gulong entry_location_selected;
+ gchar *doc_uri;
+
+ GtkActionGroup *bookmark_actions;
+ guint bookmarks_merge_id;
+
guint resize_signal;
gint width;
gint height;
@@ -176,6 +196,7 @@ static const GtkActionEntry entries[] = {
{ "PageMenu", NULL, N_("_Page") },
{ "ViewMenu", NULL, N_("_View") },
{ "GoMenu", NULL, N_("_Go") },
+ { "BookmarksMenu", NULL, N_("_Bookmarks") },
{ "NewWindow", GTK_STOCK_NEW,
N_("_New Window"),
@@ -187,6 +208,11 @@ static const GtkActionEntry entries[] = {
"<Control>W",
NULL,
G_CALLBACK (window_close) },
+ { "AddBookmark", NULL,
+ N_("_Add Bookmark"),
+ "<Control>D",
+ NULL,
+ G_CALLBACK (window_add_bookmark) },
{ "OpenLocation", NULL,
N_("Open Location"),
"<Control>L",
@@ -197,7 +223,7 @@ static const GtkActionEntry entries[] = {
static void
yelp_window_init (YelpWindow *window)
{
- g_signal_connect (window, "configure-event", window_configure_event, NULL);
+ g_signal_connect (window, "configure-event", G_CALLBACK (window_configure_event), NULL);
}
static void
@@ -246,6 +272,11 @@ yelp_window_dispose (GObject *object)
priv->action_group = NULL;
}
+ if (priv->bookmark_actions) {
+ g_object_unref (priv->bookmark_actions);
+ priv->bookmark_actions = NULL;
+ }
+
if (priv->align_location) {
g_object_unref (priv->align_location);
priv->align_location = NULL;
@@ -262,6 +293,8 @@ yelp_window_dispose (GObject *object)
static void
yelp_window_finalize (GObject *object)
{
+ YelpWindowPrivate *priv = GET_PRIV (object);
+ g_free (priv->doc_uri);
G_OBJECT_CLASS (yelp_window_parent_class)->finalize (object);
}
@@ -323,19 +356,25 @@ window_construct (YelpWindow *window)
entries, G_N_ELEMENTS (entries),
window);
+ priv->bookmark_actions = gtk_action_group_new ("BookmarkActions");
+ gtk_action_group_set_translate_func (priv->bookmark_actions, NULL, NULL, NULL);
+
priv->ui_manager = gtk_ui_manager_new ();
gtk_ui_manager_insert_action_group (priv->ui_manager, priv->action_group, 0);
+ gtk_ui_manager_insert_action_group (priv->ui_manager, priv->bookmark_actions, 1);
gtk_ui_manager_insert_action_group (priv->ui_manager,
yelp_application_get_action_group (priv->application),
- 1);
+ 2);
view_actions = yelp_view_get_action_group (priv->view);
- gtk_ui_manager_insert_action_group (priv->ui_manager, view_actions, 2);
+ gtk_ui_manager_insert_action_group (priv->ui_manager, view_actions, 3);
gtk_window_add_accel_group (GTK_WINDOW (window),
gtk_ui_manager_get_accel_group (priv->ui_manager));
gtk_ui_manager_add_ui_from_string (priv->ui_manager, YELP_UI, -1, NULL);
gtk_box_pack_start (GTK_BOX (vbox),
gtk_ui_manager_get_widget (priv->ui_manager, "/ui/menubar"),
FALSE, FALSE, 0);
+ priv->bookmarks_merge_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+ g_signal_connect (priv->application, "bookmarks-changed", G_CALLBACK (app_bookmarks_changed), window);
priv->hbox = gtk_hbox_new (FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), priv->hbox, FALSE, FALSE, 0);
@@ -520,6 +559,107 @@ window_close (GtkAction *action, YelpWindow *window)
}
static void
+window_add_bookmark (GtkAction *action,
+ YelpWindow *window)
+{
+ YelpUri *uri;
+ gchar *icon, *title;
+ YelpWindowPrivate *priv = GET_PRIV (window);
+
+ g_object_get (priv->view,
+ "yelp-uri", &uri,
+ "page-icon", &icon,
+ "page-title", &title,
+ NULL);
+ yelp_application_add_bookmark (priv->application, uri, icon, title);
+ g_free (icon);
+ g_free (title);
+ g_object_unref (uri);
+}
+
+static void
+window_load_bookmark (GtkAction *action,
+ YelpWindow *window)
+{
+ YelpUri *base, *uri;
+ gchar *xref;
+ YelpWindowPrivate *priv = GET_PRIV (window);
+
+ /* Bookmark action names are prefixed with 'LoadBookmark-' */
+ xref = g_strconcat ("xref:", gtk_action_get_name (action) + 13, NULL);
+ g_object_get (priv->view, "yelp-uri", &base, NULL);
+ uri = yelp_uri_new_relative (base, xref);
+
+ yelp_view_load_uri (priv->view, uri);
+
+ g_object_unref (base);
+ g_object_unref (uri);
+ g_free (xref);
+}
+
+static void
+app_bookmarks_changed (YelpApplication *app,
+ const gchar *doc_uri,
+ YelpWindow *window)
+{
+ YelpUri *uri;
+ gchar *this_doc_uri;
+ YelpWindowPrivate *priv = GET_PRIV (window);
+
+ g_object_get (priv->view, "yelp-uri", &uri, NULL);
+ this_doc_uri = yelp_uri_get_document_uri (uri);
+
+ if (g_str_equal (this_doc_uri, doc_uri))
+ window_set_bookmarks (window, doc_uri);
+
+ g_free (this_doc_uri);
+ g_object_unref (uri);
+}
+
+static void
+window_set_bookmarks (YelpWindow *window,
+ const gchar *doc_uri)
+{
+ GVariant *value;
+ GVariantIter *iter;
+ gchar *page_id, *icon, *title;
+ YelpWindowPrivate *priv = GET_PRIV (window);
+
+ gtk_ui_manager_remove_ui (priv->ui_manager, priv->bookmarks_merge_id);
+
+ value = yelp_application_get_bookmarks (priv->application, doc_uri);
+ g_variant_get (value, "a(sss)", &iter);
+ while (g_variant_iter_loop (iter, "(&s&s&s)", &page_id, &icon, &title)) {
+ GSList *cur;
+ GtkAction *bookmark;
+ gchar *action_id = g_strconcat ("LoadBookmark-", page_id, NULL);
+
+ bookmark = gtk_action_group_get_action (priv->bookmark_actions, action_id);
+ if (bookmark == NULL) {
+ bookmark = gtk_action_new (action_id, title, NULL, NULL);
+ g_signal_connect (bookmark, "activate", window_load_bookmark, window);
+ gtk_action_set_icon_name (bookmark, icon);
+ gtk_action_group_add_action (priv->bookmark_actions, bookmark);
+ }
+ gtk_ui_manager_add_ui (priv->ui_manager,
+ priv->bookmarks_merge_id,
+ "ui/menubar/BookmarksMenu/Bookmarks",
+ action_id, action_id,
+ GTK_UI_MANAGER_MENUITEM,
+ FALSE);
+ gtk_ui_manager_ensure_update (priv->ui_manager);
+ for (cur = gtk_action_get_proxies (bookmark); cur != NULL; cur = cur->next) {
+ if (GTK_IS_IMAGE_MENU_ITEM (cur->data))
+ g_object_set (cur->data, "always-show-image", TRUE, NULL);
+ }
+ g_free (action_id);
+ }
+
+ g_variant_iter_free (iter);
+ g_variant_unref (value);
+}
+
+static void
window_open_location (GtkAction *action, YelpWindow *window)
{
YelpUri *yuri = NULL;
@@ -674,13 +814,23 @@ view_uri_selected (YelpView *view,
gchar *iter_uri;
gboolean cont;
YelpUri *uri;
- gchar *struri;
+ gchar *struri, *doc_uri;
YelpWindowPrivate *priv = GET_PRIV (window);
g_object_get (G_OBJECT (view), "yelp-uri", &uri, NULL);
if (uri == NULL)
return;
+ doc_uri = yelp_uri_get_document_uri (uri);
+ if (priv->doc_uri == NULL || !g_str_equal (priv->doc_uri, doc_uri)) {
+ window_set_bookmarks (window, doc_uri);
+ g_free (priv->doc_uri);
+ priv->doc_uri = doc_uri;
+ }
+ else {
+ g_free (doc_uri);
+ }
+
struri = yelp_uri_get_canonical_uri (uri);
cont = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->history), &iter);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]