diff options
author | Shaun McCance <shaunm@gnome.org> | 2010-06-08 15:09:45 -0500 |
---|---|---|
committer | Shaun McCance <shaunm@gnome.org> | 2010-06-08 15:09:45 -0500 |
commit | 885494dc58e61b5421858bea8ffa3b1e5968aea4 (patch) | |
tree | bdaf58eb8a196ba502ba9cd0ad0b483aafc31d21 | |
parent | 2d0a34fc32d3d77e8309bac3183cbf050f708470 (diff) | |
download | yelp-885494dc58e61b5421858bea8ffa3b1e5968aea4.tar.gz |
[yelp-view] Added "Copy Code Block" and "Save Code Block As"
-rw-r--r-- | libyelp/yelp-view.c | 173 |
1 files changed, 172 insertions, 1 deletions
diff --git a/libyelp/yelp-view.c b/libyelp/yelp-view.c index 18a2229e..78116bbf 100644 --- a/libyelp/yelp-view.c +++ b/libyelp/yelp-view.c @@ -67,6 +67,10 @@ static void popup_save_image (GtkMenuItem *item, YelpView *view); static void popup_send_image (GtkMenuItem *item, YelpView *view); +static void popup_copy_code (GtkMenuItem *item, + YelpView *view); +static void popup_save_code (GtkMenuItem *item, + YelpView *view); static void view_populate_popup (YelpView *view, GtkMenu *menu, gpointer data); @@ -195,6 +199,9 @@ struct _YelpViewPrivate { gchar *popup_link_uri; gchar *popup_link_text; gchar *popup_image_uri; + WebKitDOMNode *popup_code_node; + WebKitDOMNode *popup_code_title; + gchar *popup_code_text; YelpViewState state; @@ -306,6 +313,7 @@ yelp_view_finalize (GObject *object) g_free (priv->popup_link_uri); g_free (priv->popup_link_text); g_free (priv->popup_image_uri); + g_free (priv->popup_code_text); g_free (priv->page_id); g_free (priv->root_title); @@ -828,6 +836,97 @@ popup_send_image (GtkMenuItem *item, } static void +popup_copy_code (GtkMenuItem *item, + YelpView *view) +{ + YelpViewPrivate *priv = GET_PRIV (view); + GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); + gchar *content = webkit_dom_node_get_text_content (priv->popup_code_node); + gtk_clipboard_set_text (clipboard, content, -1); + g_free (content); +} + +static void +popup_save_code (GtkMenuItem *item, + YelpView *view) +{ + YelpViewPrivate *priv = GET_PRIV (view); + GtkWidget *dialog, *window; + gint res; + + g_free (priv->popup_code_text); + priv->popup_code_text = webkit_dom_node_get_text_content (priv->popup_code_node); + if (!g_str_has_suffix (priv->popup_code_text, "\n")) { + gchar *tmp = g_strconcat (priv->popup_code_text, "\n", NULL); + g_free (priv->popup_code_text); + priv->popup_code_text = tmp; + } + + for (window = gtk_widget_get_parent (GTK_WIDGET (view)); + window && !GTK_IS_WINDOW (window); + window = gtk_widget_get_parent (window)); + + dialog = gtk_file_chooser_dialog_new (_("Save Code"), + GTK_WINDOW (window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_OK, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + if (priv->popup_code_title) { + gchar *filename = webkit_dom_node_get_text_content (priv->popup_code_title); + gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), filename); + g_free (filename); + } + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), + g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); + + res = gtk_dialog_run (GTK_DIALOG (dialog)); + + if (res == GTK_RESPONSE_OK) { + GError *error = NULL; + GFile *file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); + GFileOutputStream *stream = g_file_replace (file, NULL, FALSE, + G_FILE_CREATE_NONE, + NULL, + &error); + if (stream == NULL) { + GtkWidget *dialog = gtk_message_dialog_new (GTK_WIDGET_VISIBLE (window) ? GTK_WINDOW (window) : NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", error->message); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } + else { + /* FIXME: we should do this async */ + GDataOutputStream *datastream = g_data_output_stream_new (G_OUTPUT_STREAM (stream)); + if (!g_data_output_stream_put_string (datastream, priv->popup_code_text, NULL, &error)) { + GtkWidget *dialog = gtk_message_dialog_new (GTK_WIDGET_VISIBLE (window) ? GTK_WINDOW (window) : NULL, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", error->message); + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (dialog); + g_error_free (error); + } + g_object_unref (datastream); + } + g_object_unref (file); + } + + priv->popup_code_node = NULL; + priv->popup_code_title = NULL; + g_free (priv->popup_code_text); + priv->popup_code_text = NULL; + + gtk_widget_destroy (dialog); +} + +static void view_populate_popup (YelpView *view, GtkMenu *menu, gpointer data) @@ -838,7 +937,7 @@ view_populate_popup (YelpView *view, YelpViewPrivate *priv = GET_PRIV (view); GList *children; GtkWidget *item; - WebKitDOMNode *node, *cur, *link_node = NULL; + WebKitDOMNode *node, *cur, *link_node = NULL, *code_node = NULL, *code_title_node = NULL; children = gtk_container_get_children (GTK_CONTAINER (menu)); while (children) { @@ -859,6 +958,60 @@ view_populate_popup (YelpView *view, gchar *name = webkit_dom_node_get_node_name (cur); if (g_str_equal (name, "a")) link_node = cur; + if (g_str_equal (name, "div")) { + WebKitDOMNamedNodeMap *map = webkit_dom_node_get_attributes (cur); + WebKitDOMNode *attr = webkit_dom_named_node_map_get_named_item (map, "class"); + if (attr) { + gchar *htmlclass = webkit_dom_node_get_text_content (attr); + if (g_str_equal (htmlclass, "code")) { + WebKitDOMNode *title; + + code_node = cur; + + title = webkit_dom_node_get_parent_node (cur); + if (title) { + g_free (name); + name = webkit_dom_node_get_node_name (title); + if (g_str_equal (name, "div")) { + map = webkit_dom_node_get_attributes (title); + attr = webkit_dom_named_node_map_get_named_item (map, "class"); + if (attr) { + g_free (htmlclass); + htmlclass = webkit_dom_node_get_text_content (attr); + if (g_str_equal (htmlclass, "contents")) { + title = webkit_dom_node_get_previous_sibling (title); + if (title) { + g_free (name); + name = webkit_dom_node_get_node_name (title); + if (g_str_equal (name, "div")) { + map = webkit_dom_node_get_attributes (title); + attr = webkit_dom_named_node_map_get_named_item (map, "class"); + if (attr) { + gchar **classes; + gint classi; + gboolean titleq = FALSE; + g_free (htmlclass); + htmlclass = webkit_dom_node_get_text_content (attr); + classes = g_strsplit (htmlclass, " ", -1); + for (classi = 0; classes[classi] != NULL; classi++) + if (g_str_equal (classes[classi], "title")) { + titleq = TRUE; + break; + } + if (titleq) + code_title_node = title; + g_strfreev (classes); + } + } + } + } + } + } + } + } + g_free (htmlclass); + } + } g_free (name); } @@ -1001,6 +1154,24 @@ view_populate_popup (YelpView *view, gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); } + if (code_node != NULL) { + item = gtk_separator_menu_item_new (); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + priv->popup_code_node = code_node; + priv->popup_code_title = code_title_node; + + item = gtk_menu_item_new_with_mnemonic (_("C_opy Code Block")); + g_signal_connect (item, "activate", + G_CALLBACK (popup_copy_code), view); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_mnemonic (_("Save Code _Block As...")); + g_signal_connect (item, "activate", + G_CALLBACK (popup_save_code), view); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + } + g_object_unref (result); gdk_event_free (event); gtk_widget_show_all (GTK_WIDGET (menu)); |