1349 lines
48 KiB
C
1349 lines
48 KiB
C
|
/* PIKA - Photo and Image Kooker Application
|
||
|
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||
|
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||
|
*
|
||
|
* Original copyright, applying to most contents (license remains unchanged):
|
||
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||
|
*
|
||
|
* PIKA Help Browser
|
||
|
* Copyright (C) 1999-2008 Sven Neumann <sven@gimp.org>
|
||
|
* Michael Natterer <mitch@gimp.org>
|
||
|
* Róman Joost <romanofski@gimp.org>
|
||
|
* Niels De Graef <nielsdg@redhat.com>
|
||
|
*
|
||
|
* dialog.c
|
||
|
*
|
||
|
* 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 3 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 <https://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include <gtk/gtk.h>
|
||
|
|
||
|
#include <gdk/gdkkeysyms.h>
|
||
|
|
||
|
#include <webkit2/webkit2.h>
|
||
|
|
||
|
#include "libpika/pika.h"
|
||
|
#include "libpika/pikaui.h"
|
||
|
|
||
|
#include "plug-ins/help/pikahelp.h"
|
||
|
|
||
|
#include "dialog.h"
|
||
|
#include "uri.h"
|
||
|
|
||
|
#include "libpika/stdplugins-intl.h"
|
||
|
|
||
|
|
||
|
#define PIKA_HELP_BROWSER_DIALOG_DATA "pika-help-browser-dialog"
|
||
|
#define PIKA_HELP_BROWSER_INDEX_MAX_DEPTH 4
|
||
|
|
||
|
|
||
|
typedef struct
|
||
|
{
|
||
|
int width;
|
||
|
int height;
|
||
|
int paned_position;
|
||
|
gboolean show_index;
|
||
|
double zoom;
|
||
|
} DialogData;
|
||
|
|
||
|
struct _PikaHelpBrowserDialog
|
||
|
{
|
||
|
GtkApplicationWindow parent_instance;
|
||
|
|
||
|
GHashTable *uri_hash_table; /* (char*) → (GtkTreeIter) */
|
||
|
|
||
|
GtkWidget *webview;
|
||
|
GtkWidget *paned;
|
||
|
GtkWidget *sidebar;
|
||
|
GtkWidget *searchbar;
|
||
|
GtkWidget *search_entry;
|
||
|
GtkWidget *tree_view;
|
||
|
GtkWidget *button_prev;
|
||
|
GtkWidget *button_next;
|
||
|
GdkCursor *busy_cursor;
|
||
|
|
||
|
GMenuModel *popup_menu_model;
|
||
|
GMenuModel *copy_popup_menu_model;
|
||
|
};
|
||
|
|
||
|
G_DEFINE_TYPE (PikaHelpBrowserDialog, pika_help_browser_dialog, GTK_TYPE_APPLICATION_WINDOW)
|
||
|
|
||
|
|
||
|
static void pika_help_browser_dialog_finalize (GObject *object);
|
||
|
|
||
|
/* Actions. */
|
||
|
|
||
|
static void back_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void step_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void forward_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void reload_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void stop_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void home_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void find_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void find_again_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void search_next_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void search_previous_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void copy_location_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void copy_selection_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void show_index_change_state (GSimpleAction *action,
|
||
|
GVariant *new_state,
|
||
|
gpointer user_data);
|
||
|
static void zoom_in_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void zoom_out_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void load_uri_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
static void close_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data);
|
||
|
|
||
|
/* Callbacks. */
|
||
|
|
||
|
static void webview_realize (GtkWidget *webview,
|
||
|
gpointer user_data);
|
||
|
static void webview_unrealize (GtkWidget *widget,
|
||
|
gpointer user_data);
|
||
|
static void do_popup_menu (PikaHelpBrowserDialog *self,
|
||
|
GtkWidget *webview,
|
||
|
GdkEvent *event);
|
||
|
static gboolean webview_popup_menu (GtkWidget *webview,
|
||
|
gpointer user_data);
|
||
|
static gboolean webview_button_press (GtkWidget *webview,
|
||
|
GdkEventButton *event,
|
||
|
gpointer user_data);
|
||
|
static gboolean webview_key_press (GtkWidget *widget,
|
||
|
GdkEventKey *event,
|
||
|
gpointer user_data);
|
||
|
static void webview_title_changed (WebKitWebView *webview,
|
||
|
GParamSpec *pspec,
|
||
|
gpointer user_data);
|
||
|
static void select_index (PikaHelpBrowserDialog *self,
|
||
|
const char *uri);
|
||
|
static gboolean webview_decide_policy (WebKitWebView *webview,
|
||
|
WebKitPolicyDecision *decision,
|
||
|
WebKitPolicyDecisionType decision_type,
|
||
|
gpointer user_data);
|
||
|
static gboolean webview_load_failed (WebKitWebView *webview,
|
||
|
WebKitLoadEvent load_event,
|
||
|
char *failing_uri,
|
||
|
GError *error,
|
||
|
gpointer user_data);
|
||
|
static void webview_load_changed (WebKitWebView *webview,
|
||
|
WebKitLoadEvent event,
|
||
|
gpointer user_data);
|
||
|
static void row_activated (GtkTreeView *tree_view,
|
||
|
GtkTreePath *path,
|
||
|
GtkTreeViewColumn *column,
|
||
|
gpointer user_data);
|
||
|
static void search_close_clicked (GtkWidget *button,
|
||
|
gpointer user_data);
|
||
|
static void search_entry_changed (GtkWidget *search_entry,
|
||
|
gpointer user_data);
|
||
|
static gboolean search_entry_key_press (GtkWidget *search_entry,
|
||
|
GdkEventKey *event,
|
||
|
gpointer user_data);
|
||
|
static void dialog_unmap (GtkWidget *window,
|
||
|
gpointer user_data);
|
||
|
|
||
|
/* Utilities. */
|
||
|
|
||
|
static void search (PikaHelpBrowserDialog *self,
|
||
|
const char *text);
|
||
|
|
||
|
static GtkWidget * build_menu (const GList *items,
|
||
|
gboolean back);
|
||
|
|
||
|
static void update_actions (PikaHelpBrowserDialog *self);
|
||
|
|
||
|
static void add_tool_button (GtkWidget *toolbar,
|
||
|
const char *action,
|
||
|
const char *icon,
|
||
|
const char *label,
|
||
|
const char *tooltip);
|
||
|
static GtkWidget * build_searchbar (PikaHelpBrowserDialog *self);
|
||
|
|
||
|
static void browser_dialog_make_index_foreach (const gchar *help_id,
|
||
|
PikaHelpItem *item,
|
||
|
PikaHelpLocale *locale);
|
||
|
static gint help_item_compare (gconstpointer a,
|
||
|
gconstpointer b);
|
||
|
static void add_child (PikaHelpBrowserDialog *self,
|
||
|
GtkTreeStore *store,
|
||
|
PikaHelpDomain *domain,
|
||
|
PikaHelpLocale *locale,
|
||
|
GtkTreeIter *parent,
|
||
|
PikaHelpItem *item,
|
||
|
int depth);
|
||
|
|
||
|
|
||
|
static const GActionEntry ACTIONS[] =
|
||
|
{
|
||
|
{ "back", back_action },
|
||
|
{ "forward", forward_action },
|
||
|
{ "step", step_action, "i" },
|
||
|
{ "reload", reload_action },
|
||
|
{ "stop", stop_action },
|
||
|
{ "home", home_action },
|
||
|
{ "load-uri", load_uri_action, "s" },
|
||
|
{ "copy-location", copy_location_action },
|
||
|
{ "copy-selection", copy_selection_action },
|
||
|
{ "zoom-in", zoom_in_action },
|
||
|
{ "zoom-out", zoom_out_action },
|
||
|
{ "find", find_action },
|
||
|
{ "find-again", find_again_action },
|
||
|
{ "search-next", search_next_action },
|
||
|
{ "search-previous", search_previous_action },
|
||
|
{ "close", close_action },
|
||
|
{ "show-index", NULL, NULL, "true", show_index_change_state },
|
||
|
};
|
||
|
|
||
|
|
||
|
static void
|
||
|
pika_help_browser_dialog_class_init (PikaHelpBrowserDialogClass *klass)
|
||
|
{
|
||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||
|
|
||
|
object_class->finalize = pika_help_browser_dialog_finalize;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_help_browser_dialog_init (PikaHelpBrowserDialog *self)
|
||
|
{
|
||
|
GtkWindow *window = GTK_WINDOW (self);
|
||
|
GtkWidget *vbox;
|
||
|
GtkWidget *toolbar;
|
||
|
GtkBuilder *builder;
|
||
|
GtkToolItem *item;
|
||
|
GtkWidget *main_vbox;
|
||
|
WebKitSettings *settings;
|
||
|
|
||
|
/* the dialog window */
|
||
|
gtk_window_set_title (GTK_WINDOW (window), _("PIKA Help Browser"));
|
||
|
gtk_window_set_icon_name (GTK_WINDOW (window), PIKA_ICON_HELP_USER_MANUAL);
|
||
|
|
||
|
g_action_map_add_action_entries (G_ACTION_MAP (self),
|
||
|
ACTIONS, G_N_ELEMENTS (ACTIONS),
|
||
|
self);
|
||
|
|
||
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
|
||
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
||
|
gtk_widget_show (vbox);
|
||
|
|
||
|
/* Toolbar */
|
||
|
toolbar = gtk_toolbar_new ();
|
||
|
|
||
|
add_tool_button (toolbar, "win.reload", PIKA_ICON_VIEW_REFRESH, _("_Reload"), _("Reload current page"));
|
||
|
add_tool_button (toolbar, "win.stop", PIKA_ICON_PROCESS_STOP, _("_Stop"), _("Stop loading this page"));
|
||
|
add_tool_button (toolbar, "win.home", PIKA_ICON_GO_HOME, NULL, _("Go to the index page"));
|
||
|
item = gtk_separator_tool_item_new ();
|
||
|
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, -1);
|
||
|
gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (item), FALSE);
|
||
|
gtk_tool_item_set_expand (item, TRUE);
|
||
|
gtk_widget_show (GTK_WIDGET (item));
|
||
|
add_tool_button (toolbar, "win.load-uri('https://docs.pika.org')", PIKA_ICON_HELP_USER_MANUAL, "docs.pika.org", _("Visit the PIKA documentation website"));
|
||
|
|
||
|
item = gtk_menu_tool_button_new (gtk_image_new_from_icon_name (PIKA_ICON_GO_NEXT, GTK_ICON_SIZE_BUTTON), NULL);
|
||
|
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
|
||
|
gtk_widget_show (GTK_WIDGET (item));
|
||
|
gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "win.forward");
|
||
|
self->button_next = GTK_WIDGET (item);
|
||
|
|
||
|
item = gtk_menu_tool_button_new (gtk_image_new_from_icon_name (PIKA_ICON_GO_PREVIOUS, GTK_ICON_SIZE_BUTTON), NULL);
|
||
|
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), item, 0);
|
||
|
gtk_widget_show (GTK_WIDGET (item));
|
||
|
gtk_actionable_set_action_name (GTK_ACTIONABLE (item), "win.back");
|
||
|
self->button_prev = GTK_WIDGET (item);
|
||
|
|
||
|
gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS);
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
|
||
|
gtk_widget_show (toolbar);
|
||
|
|
||
|
/* Context menu */
|
||
|
builder = gtk_builder_new_from_resource ("/technology.heckin/help/help-menu.ui");
|
||
|
self->popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "help_browser_popup_menu"));
|
||
|
g_object_ref (self->popup_menu_model);
|
||
|
self->copy_popup_menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "help_browser_copy_popup_menu"));
|
||
|
g_object_ref (self->copy_popup_menu_model);
|
||
|
g_object_unref (builder);
|
||
|
|
||
|
/* the horizontal paned */
|
||
|
self->paned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
|
||
|
gtk_box_pack_start (GTK_BOX (vbox), self->paned, TRUE, TRUE, 0);
|
||
|
gtk_widget_show (self->paned);
|
||
|
|
||
|
self->sidebar = gtk_scrolled_window_new (NULL, NULL);
|
||
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->sidebar),
|
||
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||
|
gtk_paned_add1 (GTK_PANED (self->paned), self->sidebar);
|
||
|
|
||
|
self->tree_view = gtk_tree_view_new ();
|
||
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (self->tree_view), FALSE);
|
||
|
gtk_container_add (GTK_CONTAINER (self->sidebar), self->tree_view);
|
||
|
gtk_widget_show (self->tree_view);
|
||
|
|
||
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->tree_view), -1,
|
||
|
NULL,
|
||
|
gtk_cell_renderer_text_new (),
|
||
|
"text", 1,
|
||
|
NULL);
|
||
|
|
||
|
g_signal_connect (self->tree_view, "row-activated",
|
||
|
G_CALLBACK (row_activated),
|
||
|
self);
|
||
|
|
||
|
/* HTML webview */
|
||
|
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||
|
gtk_widget_show (main_vbox);
|
||
|
gtk_paned_pack2 (GTK_PANED (self->paned), main_vbox, TRUE, TRUE);
|
||
|
|
||
|
settings = webkit_settings_new_with_settings ("default-charset", "utf-8",
|
||
|
NULL);
|
||
|
self->webview = webkit_web_view_new_with_settings (settings);
|
||
|
g_object_unref (settings);
|
||
|
|
||
|
gtk_widget_set_size_request (self->webview, 300, 200);
|
||
|
gtk_widget_show (self->webview);
|
||
|
|
||
|
gtk_box_pack_start (GTK_BOX (main_vbox), self->webview, TRUE, TRUE, 0);
|
||
|
|
||
|
g_signal_connect (self->webview, "realize",
|
||
|
G_CALLBACK (webview_realize),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "unrealize",
|
||
|
G_CALLBACK (webview_unrealize),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "popup-menu",
|
||
|
G_CALLBACK (webview_popup_menu),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "button-press-event",
|
||
|
G_CALLBACK (webview_button_press),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "key-press-event",
|
||
|
G_CALLBACK (webview_key_press),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "notify::title",
|
||
|
G_CALLBACK (webview_title_changed),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "load-changed",
|
||
|
G_CALLBACK (webview_load_changed),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "load-failed",
|
||
|
G_CALLBACK (webview_load_failed),
|
||
|
self);
|
||
|
g_signal_connect (self->webview, "decide-policy",
|
||
|
G_CALLBACK (webview_decide_policy),
|
||
|
self);
|
||
|
|
||
|
gtk_widget_grab_focus (self->webview);
|
||
|
|
||
|
g_signal_connect (window, "unmap",
|
||
|
G_CALLBACK (dialog_unmap),
|
||
|
self);
|
||
|
|
||
|
update_actions (self);
|
||
|
|
||
|
/* Searchbar */
|
||
|
self->searchbar = build_searchbar (self);
|
||
|
gtk_box_pack_start (GTK_BOX (main_vbox), self->searchbar, FALSE, FALSE, 0);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
pika_help_browser_dialog_finalize (GObject *object)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (object);
|
||
|
|
||
|
g_clear_pointer (&self->uri_hash_table, g_hash_table_unref);
|
||
|
g_clear_object (&self->popup_menu_model);
|
||
|
g_clear_object (&self->copy_popup_menu_model);
|
||
|
|
||
|
G_OBJECT_CLASS (pika_help_browser_dialog_parent_class)->finalize (object);
|
||
|
}
|
||
|
|
||
|
/* Public functions. */
|
||
|
|
||
|
PikaHelpBrowserDialog *
|
||
|
pika_help_browser_dialog_new (const gchar *plug_in_binary,
|
||
|
GApplication *app)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *window;
|
||
|
DialogData data = { 720, 560, 240, TRUE, 1.0 };
|
||
|
|
||
|
pika_ui_init (plug_in_binary);
|
||
|
|
||
|
pika_get_data (PIKA_HELP_BROWSER_DIALOG_DATA, &data);
|
||
|
|
||
|
window = g_object_new (PIKA_TYPE_HELP_BROWSER_DIALOG,
|
||
|
"application", app,
|
||
|
"role", plug_in_binary,
|
||
|
"default-width", data.width,
|
||
|
"default-height", data.height,
|
||
|
NULL);
|
||
|
gtk_paned_set_position (GTK_PANED (window->paned), data.paned_position);
|
||
|
if (data.show_index)
|
||
|
gtk_widget_show (window->sidebar);
|
||
|
webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (window->webview), data.zoom);
|
||
|
|
||
|
return window;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pika_help_browser_dialog_load (PikaHelpBrowserDialog *self,
|
||
|
const char *uri)
|
||
|
{
|
||
|
g_return_if_fail (uri && *uri);
|
||
|
|
||
|
webkit_web_view_load_uri (WEBKIT_WEB_VIEW (self->webview), uri);
|
||
|
|
||
|
select_index (self, uri);
|
||
|
|
||
|
gtk_window_present (GTK_WINDOW (gtk_widget_get_toplevel (self->webview)));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
pika_help_browser_dialog_make_index (PikaHelpBrowserDialog *self,
|
||
|
PikaHelpDomain *domain,
|
||
|
PikaHelpLocale *locale)
|
||
|
{
|
||
|
GtkTreeStore *store;
|
||
|
GList *list;
|
||
|
|
||
|
if (! locale->toplevel_items)
|
||
|
{
|
||
|
g_hash_table_foreach (locale->help_id_mapping,
|
||
|
(GHFunc) browser_dialog_make_index_foreach,
|
||
|
locale);
|
||
|
|
||
|
locale->toplevel_items = g_list_sort (locale->toplevel_items,
|
||
|
help_item_compare);
|
||
|
}
|
||
|
|
||
|
store = gtk_tree_store_new (2,
|
||
|
G_TYPE_POINTER,
|
||
|
G_TYPE_STRING);
|
||
|
|
||
|
g_object_set_data (G_OBJECT (store), "domain", domain);
|
||
|
g_object_set_data (G_OBJECT (store), "locale", locale);
|
||
|
|
||
|
if (self->uri_hash_table)
|
||
|
g_hash_table_unref (self->uri_hash_table);
|
||
|
|
||
|
self->uri_hash_table = g_hash_table_new_full (g_str_hash,
|
||
|
g_str_equal,
|
||
|
(GDestroyNotify) g_free,
|
||
|
(GDestroyNotify) gtk_tree_iter_free);
|
||
|
|
||
|
for (list = locale->toplevel_items; list; list = g_list_next (list))
|
||
|
{
|
||
|
PikaHelpItem *item = list->data;
|
||
|
|
||
|
add_child (self, store, domain, locale, NULL, item, 0);
|
||
|
}
|
||
|
|
||
|
gtk_tree_view_set_model (GTK_TREE_VIEW (self->tree_view), GTK_TREE_MODEL (store));
|
||
|
g_object_unref (store);
|
||
|
}
|
||
|
|
||
|
/* Private functions. */
|
||
|
|
||
|
static void
|
||
|
back_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
webkit_web_view_go_back (WEBKIT_WEB_VIEW (self->webview));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
step_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
gint steps;
|
||
|
WebKitBackForwardList *back_fw_list;
|
||
|
WebKitBackForwardListItem *back_fw_list_item;
|
||
|
|
||
|
g_return_if_fail (parameter);
|
||
|
|
||
|
steps = g_variant_get_int32 (parameter);
|
||
|
|
||
|
back_fw_list =
|
||
|
webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (self->webview));
|
||
|
back_fw_list_item = webkit_back_forward_list_get_nth_item (back_fw_list, steps);
|
||
|
if (back_fw_list_item)
|
||
|
webkit_web_view_go_to_back_forward_list_item (WEBKIT_WEB_VIEW (self->webview),
|
||
|
back_fw_list_item);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
forward_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
webkit_web_view_go_forward (WEBKIT_WEB_VIEW (self->webview));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
reload_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
webkit_web_view_reload (WEBKIT_WEB_VIEW (self->webview));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
stop_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
webkit_web_view_stop_loading (WEBKIT_WEB_VIEW (self->webview));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
home_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
GtkTreeModel *model;
|
||
|
PikaHelpDomain *domain;
|
||
|
PikaHelpLocale *locale;
|
||
|
|
||
|
model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree_view));
|
||
|
domain = g_object_get_data (G_OBJECT (model), "domain");
|
||
|
locale = g_object_get_data (G_OBJECT (model), "locale");
|
||
|
if (domain && locale)
|
||
|
{
|
||
|
gchar *uri = g_strconcat (domain->help_uri, "/",
|
||
|
locale->locale_id, "/",
|
||
|
pika_help_locale_map (locale,
|
||
|
PIKA_HELP_DEFAULT_ID),
|
||
|
NULL);
|
||
|
pika_help_browser_dialog_load (self, uri);
|
||
|
g_free (uri);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
find_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
gtk_widget_show (self->searchbar);
|
||
|
gtk_widget_grab_focus (self->search_entry);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
find_again_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
gtk_widget_show (self->searchbar);
|
||
|
gtk_widget_grab_focus (self->search_entry);
|
||
|
|
||
|
search (self, gtk_entry_get_text (GTK_ENTRY (self->search_entry)));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
search_next_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
WebKitFindController *find_controller;
|
||
|
|
||
|
find_controller =
|
||
|
webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
|
||
|
webkit_find_controller_search_next (find_controller);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
search_previous_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
WebKitFindController *find_controller;
|
||
|
|
||
|
find_controller =
|
||
|
webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
|
||
|
webkit_find_controller_search_previous (find_controller);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
copy_location_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
const char *uri;
|
||
|
|
||
|
uri = webkit_web_view_get_uri (WEBKIT_WEB_VIEW (self->webview));
|
||
|
if (uri)
|
||
|
{
|
||
|
GtkClipboard *clipboard;
|
||
|
|
||
|
clipboard = gtk_clipboard_get_for_display (gtk_widget_get_display (self->webview),
|
||
|
GDK_SELECTION_CLIPBOARD);
|
||
|
gtk_clipboard_set_text (clipboard, uri, -1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
copy_selection_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
WebKitEditorState *editor_state;
|
||
|
|
||
|
editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (self->webview));
|
||
|
if (webkit_editor_state_is_copy_available (editor_state))
|
||
|
{
|
||
|
webkit_web_view_execute_editing_command (WEBKIT_WEB_VIEW (self->webview),
|
||
|
WEBKIT_EDITING_COMMAND_COPY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
show_index_change_state (GSimpleAction *action,
|
||
|
GVariant *new_state,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
gboolean show_index;
|
||
|
|
||
|
show_index = g_variant_get_boolean (new_state);
|
||
|
g_warning ("NEW STATE %s", show_index? "true" : "false");
|
||
|
gtk_widget_set_visible (self->sidebar, show_index);
|
||
|
g_simple_action_set_state (action, new_state);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
zoom_in_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
double zoom_level;
|
||
|
|
||
|
zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview));
|
||
|
if (zoom_level < 10.0)
|
||
|
webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (self->webview), zoom_level + 0.1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
zoom_out_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
double zoom_level;
|
||
|
|
||
|
zoom_level = webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview));
|
||
|
if (zoom_level > 0.1)
|
||
|
webkit_web_view_set_zoom_level (WEBKIT_WEB_VIEW (self->webview), zoom_level - 0.1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
load_uri_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
const char *uri;
|
||
|
|
||
|
uri = g_variant_get_string (parameter, NULL);
|
||
|
pika_help_browser_dialog_load (self, uri);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
close_action (GSimpleAction *action,
|
||
|
GVariant *parameter,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
gtk_widget_destroy (GTK_WIDGET (self));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
webview_realize (GtkWidget *webview,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
g_return_if_fail (self->busy_cursor == NULL);
|
||
|
|
||
|
self->busy_cursor = gdk_cursor_new_for_display (gtk_widget_get_display (webview),
|
||
|
GDK_WATCH);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
webview_unrealize (GtkWidget *widget,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
g_clear_object (&self->busy_cursor);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
do_popup_menu (PikaHelpBrowserDialog *self,
|
||
|
GtkWidget *webview,
|
||
|
GdkEvent *event)
|
||
|
{
|
||
|
WebKitEditorState *editor_state;
|
||
|
GMenuModel *menu_model;
|
||
|
GtkWidget *menu;
|
||
|
|
||
|
editor_state = webkit_web_view_get_editor_state (WEBKIT_WEB_VIEW (webview));
|
||
|
if (webkit_editor_state_is_copy_available (editor_state))
|
||
|
menu_model = self->copy_popup_menu_model;
|
||
|
else
|
||
|
menu_model = self->popup_menu_model;
|
||
|
|
||
|
menu = gtk_menu_new_from_model (menu_model);
|
||
|
g_signal_connect (menu, "deactivate",
|
||
|
G_CALLBACK (gtk_widget_destroy), NULL);
|
||
|
|
||
|
gtk_menu_attach_to_widget (GTK_MENU (menu), webview, NULL);
|
||
|
gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
webview_popup_menu (GtkWidget *webview,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
do_popup_menu (self, webview, NULL);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
webview_button_press (GtkWidget *webview,
|
||
|
GdkEventButton *event,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||
|
{
|
||
|
do_popup_menu (self, webview, (GdkEvent *) event);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
webview_key_press (GtkWidget *widget,
|
||
|
GdkEventKey *event,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
if (event->keyval == GDK_KEY_slash)
|
||
|
{
|
||
|
g_action_group_activate_action (G_ACTION_GROUP (self),
|
||
|
"find",
|
||
|
NULL);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
webview_title_changed (WebKitWebView *webview,
|
||
|
GParamSpec *pspec,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
const char *title;
|
||
|
char *full_title;
|
||
|
|
||
|
title = webkit_web_view_get_title (webview);
|
||
|
full_title = g_strdup_printf ("%s - %s",
|
||
|
title ? title : _("Untitled"),
|
||
|
_("PIKA Help Browser"));
|
||
|
|
||
|
gtk_window_set_title (GTK_WINDOW (self), full_title);
|
||
|
g_free (full_title);
|
||
|
|
||
|
update_actions (self);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
select_index (PikaHelpBrowserDialog *self,
|
||
|
const char *uri)
|
||
|
{
|
||
|
GtkTreeSelection *selection;
|
||
|
GtkTreeIter *iter = NULL;
|
||
|
|
||
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->tree_view));
|
||
|
|
||
|
if (uri)
|
||
|
iter = g_hash_table_lookup (self->uri_hash_table, uri);
|
||
|
|
||
|
if (iter)
|
||
|
{
|
||
|
GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->tree_view));
|
||
|
GtkTreePath *path;
|
||
|
GtkTreePath *scroll_path;
|
||
|
|
||
|
path = gtk_tree_model_get_path (model, iter);
|
||
|
scroll_path = gtk_tree_path_copy (path);
|
||
|
|
||
|
gtk_tree_path_up (path);
|
||
|
gtk_tree_view_expand_to_path (GTK_TREE_VIEW (self->tree_view), path);
|
||
|
gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (self->tree_view), scroll_path,
|
||
|
NULL, FALSE, 0.0, 0.0);
|
||
|
|
||
|
gtk_tree_path_free (path);
|
||
|
gtk_tree_path_free (scroll_path);
|
||
|
|
||
|
gtk_tree_selection_select_iter (selection, iter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gtk_tree_selection_unselect_all (selection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
webview_decide_policy (WebKitWebView *webview,
|
||
|
WebKitPolicyDecision *decision,
|
||
|
WebKitPolicyDecisionType decision_type,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
/* Some files return mime types like application/x-extension-html,
|
||
|
* which is not supported by default */
|
||
|
webkit_policy_decision_use (decision);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
webview_load_failed (WebKitWebView *webview,
|
||
|
WebKitLoadEvent load_event,
|
||
|
char *failing_uri,
|
||
|
GError *error,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
g_warning ("Failed to load page: %s", error->message);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
webview_load_changed (WebKitWebView *webview,
|
||
|
WebKitLoadEvent event,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
GAction *action;
|
||
|
|
||
|
action = g_action_map_lookup_action (G_ACTION_MAP (self), "back");
|
||
|
switch (event)
|
||
|
{
|
||
|
case WEBKIT_LOAD_STARTED:
|
||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), TRUE);
|
||
|
break;
|
||
|
|
||
|
case WEBKIT_LOAD_FINISHED:
|
||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||
|
update_actions (self);
|
||
|
select_index (self, webkit_web_view_get_uri (webview));
|
||
|
break;
|
||
|
|
||
|
case WEBKIT_LOAD_REDIRECTED:
|
||
|
case WEBKIT_LOAD_COMMITTED:
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
row_activated (GtkTreeView *tree_view,
|
||
|
GtkTreePath *path,
|
||
|
GtkTreeViewColumn *column,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
GtkTreeModel *model;
|
||
|
GtkTreeIter iter;
|
||
|
PikaHelpDomain *domain;
|
||
|
PikaHelpLocale *locale;
|
||
|
PikaHelpItem *item;
|
||
|
char *uri;
|
||
|
|
||
|
model = gtk_tree_view_get_model (tree_view);
|
||
|
gtk_tree_model_get_iter (model, &iter, path);
|
||
|
|
||
|
gtk_tree_model_get (model, &iter,
|
||
|
0, &item,
|
||
|
-1);
|
||
|
|
||
|
domain = g_object_get_data (G_OBJECT (model), "domain");
|
||
|
locale = g_object_get_data (G_OBJECT (model), "locale");
|
||
|
|
||
|
uri = g_strconcat (domain->help_uri, "/",
|
||
|
locale->locale_id, "/",
|
||
|
item->ref,
|
||
|
NULL);
|
||
|
|
||
|
pika_help_browser_dialog_load (self, uri);
|
||
|
|
||
|
g_free (uri);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
search_close_clicked (GtkWidget *button,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
WebKitFindController *find_controller =
|
||
|
webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
|
||
|
|
||
|
gtk_widget_hide (self->searchbar);
|
||
|
|
||
|
webkit_find_controller_search_finish (find_controller);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
search_entry_changed (GtkWidget *search_entry,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
|
||
|
search (self, gtk_entry_get_text (GTK_ENTRY (search_entry)));
|
||
|
}
|
||
|
|
||
|
static gboolean
|
||
|
search_entry_key_press (GtkWidget *search_entry,
|
||
|
GdkEventKey *event,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
WebKitFindController *find_controller;
|
||
|
|
||
|
find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
|
||
|
switch (event->keyval)
|
||
|
{
|
||
|
case GDK_KEY_Escape:
|
||
|
gtk_widget_hide (self->searchbar);
|
||
|
webkit_find_controller_search_finish (find_controller);
|
||
|
return TRUE;
|
||
|
|
||
|
case GDK_KEY_Return:
|
||
|
case GDK_KEY_KP_Enter:
|
||
|
case GDK_KEY_ISO_Enter:
|
||
|
search (self, gtk_entry_get_text (GTK_ENTRY (search_entry)));
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
dialog_unmap (GtkWidget *window,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
PikaHelpBrowserDialog *self = PIKA_HELP_BROWSER_DIALOG (user_data);
|
||
|
DialogData data;
|
||
|
|
||
|
gtk_window_get_size (GTK_WINDOW (window), &data.width, &data.height);
|
||
|
|
||
|
data.paned_position = gtk_paned_get_position (GTK_PANED (self->paned));
|
||
|
data.show_index = gtk_widget_get_visible (self->sidebar);
|
||
|
|
||
|
data.zoom = (self->webview ?
|
||
|
webkit_web_view_get_zoom_level (WEBKIT_WEB_VIEW (self->webview)) : 1.0);
|
||
|
|
||
|
pika_set_data (PIKA_HELP_BROWSER_DIALOG_DATA, &data, sizeof (data));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
search (PikaHelpBrowserDialog *self,
|
||
|
const char *text)
|
||
|
{
|
||
|
WebKitFindController *find_controller;
|
||
|
|
||
|
find_controller = webkit_web_view_get_find_controller (WEBKIT_WEB_VIEW (self->webview));
|
||
|
if (text)
|
||
|
{
|
||
|
const char *prev_text =
|
||
|
webkit_find_controller_get_search_text (find_controller);
|
||
|
|
||
|
/* The previous search, if any, may need to be canceled. */
|
||
|
if (prev_text && strcmp (text, prev_text) != 0)
|
||
|
webkit_find_controller_search_finish (find_controller);
|
||
|
|
||
|
webkit_find_controller_search (find_controller,
|
||
|
text,
|
||
|
WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE |
|
||
|
WEBKIT_FIND_OPTIONS_WRAP_AROUND,
|
||
|
G_MAXUINT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
webkit_find_controller_search_finish (find_controller);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static GtkWidget *
|
||
|
build_menu (const GList *items,
|
||
|
gboolean back)
|
||
|
{
|
||
|
GMenu *menu;
|
||
|
const GList *iter;
|
||
|
int steps;
|
||
|
|
||
|
if (!items)
|
||
|
return NULL;
|
||
|
|
||
|
menu = g_menu_new ();
|
||
|
|
||
|
/* Go over every item in the back_fw list and add it to the menu */
|
||
|
for (iter = items, steps = 1; iter; iter = g_list_next (iter), steps++)
|
||
|
{
|
||
|
WebKitBackForwardListItem *item = iter->data;
|
||
|
const char *title;
|
||
|
char *action;
|
||
|
|
||
|
title = webkit_back_forward_list_item_get_title (item);
|
||
|
if (title == NULL)
|
||
|
continue;
|
||
|
|
||
|
action = g_strdup_printf ("steps(%d)", steps);
|
||
|
g_menu_insert (menu, steps - 1, title, action);
|
||
|
g_free (action);
|
||
|
}
|
||
|
|
||
|
return gtk_menu_new_from_model (G_MENU_MODEL (menu));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
update_actions (PikaHelpBrowserDialog *self)
|
||
|
{
|
||
|
GActionMap *action_map = G_ACTION_MAP (self);
|
||
|
GAction *action;
|
||
|
WebKitBackForwardList *back_forward_list;
|
||
|
|
||
|
back_forward_list =
|
||
|
webkit_web_view_get_back_forward_list (WEBKIT_WEB_VIEW (self->webview));
|
||
|
|
||
|
/* update the back button and its menu */
|
||
|
action = g_action_map_lookup_action (action_map, "back");
|
||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||
|
webkit_web_view_can_go_back (WEBKIT_WEB_VIEW (self->webview)));
|
||
|
|
||
|
if (back_forward_list)
|
||
|
{
|
||
|
const GList *list;
|
||
|
|
||
|
list = webkit_back_forward_list_get_back_list_with_limit (back_forward_list,
|
||
|
12);
|
||
|
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_prev),
|
||
|
build_menu (list, TRUE));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_prev), NULL);
|
||
|
}
|
||
|
|
||
|
/* update the forward button and its menu */
|
||
|
action = g_action_map_lookup_action (action_map, "forward");
|
||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||
|
webkit_web_view_can_go_forward (WEBKIT_WEB_VIEW (self->webview)));
|
||
|
|
||
|
if (back_forward_list)
|
||
|
{
|
||
|
const GList *list;
|
||
|
|
||
|
list = webkit_back_forward_list_get_forward_list_with_limit (back_forward_list,
|
||
|
12);
|
||
|
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_next),
|
||
|
build_menu (list, FALSE));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (self->button_next), NULL);
|
||
|
}
|
||
|
|
||
|
/* update the copy-location action */
|
||
|
action = g_action_map_lookup_action (action_map, "copy-location");
|
||
|
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||
|
webkit_web_view_get_uri (WEBKIT_WEB_VIEW (self->webview)) != NULL);
|
||
|
|
||
|
/* update the show-index action */
|
||
|
action = g_action_map_lookup_action (action_map, "show-index");
|
||
|
g_simple_action_set_state (G_SIMPLE_ACTION (action),
|
||
|
g_variant_new_boolean (gtk_widget_get_visible (self->sidebar)));
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
add_tool_button (GtkWidget *toolbar,
|
||
|
const char *action,
|
||
|
const char *icon,
|
||
|
const char *label,
|
||
|
const char *tooltip)
|
||
|
{
|
||
|
GtkWidget *tool_icon;
|
||
|
GtkToolItem *tool_button;
|
||
|
|
||
|
tool_icon = gtk_image_new_from_icon_name (icon, GTK_ICON_SIZE_BUTTON);
|
||
|
gtk_widget_show (GTK_WIDGET (tool_icon));
|
||
|
tool_button = gtk_tool_button_new (tool_icon, label);
|
||
|
gtk_widget_show (GTK_WIDGET (tool_button));
|
||
|
gtk_tool_item_set_tooltip_text (tool_button, tooltip);
|
||
|
gtk_actionable_set_detailed_action_name (GTK_ACTIONABLE (tool_button), action);
|
||
|
|
||
|
gtk_toolbar_insert (GTK_TOOLBAR (toolbar), tool_button, -1);
|
||
|
}
|
||
|
|
||
|
static GtkWidget *
|
||
|
build_searchbar (PikaHelpBrowserDialog *self)
|
||
|
{
|
||
|
GtkWidget *button;
|
||
|
GtkWidget *hbox;
|
||
|
GtkWidget *label;
|
||
|
|
||
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
|
||
|
|
||
|
label = gtk_label_new (_("Find:"));
|
||
|
gtk_widget_show (label);
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
||
|
|
||
|
self->search_entry = gtk_entry_new ();
|
||
|
gtk_widget_show (self->search_entry);
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), self->search_entry, TRUE, TRUE, 0);
|
||
|
|
||
|
g_signal_connect (self->search_entry, "changed",
|
||
|
G_CALLBACK (search_entry_changed),
|
||
|
self);
|
||
|
|
||
|
g_signal_connect (self->search_entry, "key-press-event",
|
||
|
G_CALLBACK (search_entry_key_press),
|
||
|
self);
|
||
|
|
||
|
button = gtk_button_new_with_mnemonic (C_("search", "_Previous"));
|
||
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
||
|
gtk_button_set_image (GTK_BUTTON (button),
|
||
|
gtk_image_new_from_icon_name (PIKA_ICON_GO_PREVIOUS,
|
||
|
GTK_ICON_SIZE_BUTTON));
|
||
|
gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.search-previous");
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
||
|
gtk_widget_show (button);
|
||
|
|
||
|
button = gtk_button_new_with_mnemonic (C_("search", "_Next"));
|
||
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
||
|
gtk_button_set_image (GTK_BUTTON (button),
|
||
|
gtk_image_new_from_icon_name (PIKA_ICON_GO_NEXT,
|
||
|
GTK_ICON_SIZE_BUTTON));
|
||
|
gtk_actionable_set_action_name (GTK_ACTIONABLE (button), "win.search-next");
|
||
|
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
||
|
gtk_widget_show (button);
|
||
|
|
||
|
button = gtk_button_new_with_mnemonic (C_("search", "_Close"));
|
||
|
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
|
||
|
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
||
|
gtk_widget_show (button);
|
||
|
|
||
|
g_signal_connect (button, "clicked",
|
||
|
G_CALLBACK (search_close_clicked),
|
||
|
self);
|
||
|
|
||
|
return hbox;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
browser_dialog_make_index_foreach (const gchar *help_id,
|
||
|
PikaHelpItem *item,
|
||
|
PikaHelpLocale *locale)
|
||
|
{
|
||
|
gchar *sort_key = item->title;
|
||
|
|
||
|
#if DEBUG_SORT_HELP_ITEMS
|
||
|
g_printerr ("%s: processing %s (parent %s)\n",
|
||
|
G_STRFUNC,
|
||
|
item->title ? item->title : "NULL",
|
||
|
item->parent ? item->parent : "NULL");
|
||
|
#endif
|
||
|
|
||
|
if (item->sort &&
|
||
|
g_regex_match_simple ("^[0-9]+([.][0-9]+)*$", item->sort, 0, 0))
|
||
|
{
|
||
|
sort_key = item->sort;
|
||
|
|
||
|
#if DEBUG_SORT_HELP_ITEMS
|
||
|
g_printerr ("%s: sort key = %s\n", G_STRFUNC, sort_key);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
item->index = 0;
|
||
|
|
||
|
if (sort_key)
|
||
|
{
|
||
|
int max_tokens = PIKA_HELP_BROWSER_INDEX_MAX_DEPTH;
|
||
|
char **indices = g_strsplit (sort_key, ".", max_tokens + 1);
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < max_tokens; i++)
|
||
|
{
|
||
|
gunichar c;
|
||
|
|
||
|
if (! indices[i])
|
||
|
{
|
||
|
/* make sure that all item->index's are comparable */
|
||
|
item->index <<= (8 * (max_tokens - i));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
item->index <<= 8; /* NOP if i = 0 */
|
||
|
c = g_utf8_get_char (indices[i]);
|
||
|
if (g_unichar_isdigit (c))
|
||
|
{
|
||
|
item->index += atoi (indices[i]);
|
||
|
}
|
||
|
else if (g_utf8_strlen (indices[i], -1) == 1)
|
||
|
{
|
||
|
item->index += (c & 0xFF);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
g_strfreev (indices);
|
||
|
|
||
|
#if DEBUG_SORT_HELP_ITEMS
|
||
|
g_printerr ("%s: index = %lu\n", G_STRFUNC, item->index);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
if (item->parent && strlen (item->parent))
|
||
|
{
|
||
|
PikaHelpItem *parent;
|
||
|
|
||
|
parent = g_hash_table_lookup (locale->help_id_mapping, item->parent);
|
||
|
|
||
|
if (parent)
|
||
|
{
|
||
|
parent->children = g_list_prepend (parent->children, item);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
locale->toplevel_items = g_list_prepend (locale->toplevel_items, item);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
help_item_compare (gconstpointer a,
|
||
|
gconstpointer b)
|
||
|
{
|
||
|
const PikaHelpItem *item_a = a;
|
||
|
const PikaHelpItem *item_b = b;
|
||
|
|
||
|
if (item_a->index > item_b->index)
|
||
|
return 1;
|
||
|
else if (item_a->index < item_b->index)
|
||
|
return -1;
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
add_child (PikaHelpBrowserDialog *self,
|
||
|
GtkTreeStore *store,
|
||
|
PikaHelpDomain *domain,
|
||
|
PikaHelpLocale *locale,
|
||
|
GtkTreeIter *parent,
|
||
|
PikaHelpItem *item,
|
||
|
int depth)
|
||
|
{
|
||
|
GtkTreeIter iter;
|
||
|
char *uri;
|
||
|
|
||
|
gtk_tree_store_append (store, &iter, parent);
|
||
|
|
||
|
gtk_tree_store_set (store, &iter,
|
||
|
0, item,
|
||
|
1, item->title,
|
||
|
-1);
|
||
|
|
||
|
uri = g_strconcat (domain->help_uri, "/",
|
||
|
locale->locale_id, "/",
|
||
|
item->ref,
|
||
|
NULL);
|
||
|
|
||
|
g_hash_table_insert (self->uri_hash_table,
|
||
|
uri,
|
||
|
gtk_tree_iter_copy (&iter));
|
||
|
|
||
|
if (depth + 1 == PIKA_HELP_BROWSER_INDEX_MAX_DEPTH)
|
||
|
return;
|
||
|
|
||
|
item->children = g_list_sort (item->children, help_item_compare);
|
||
|
|
||
|
for (GList *list = item->children; list; list = g_list_next (list))
|
||
|
{
|
||
|
PikaHelpItem *item = list->data;
|
||
|
|
||
|
add_child (self, store, domain, locale, &iter, item, depth + 1);
|
||
|
}
|
||
|
}
|