
Some coding style fixes, also one warning fix, and a lot of shuffling around to reorganize the code. Basically removing the prototype listing at the file start is a big error. This file is huge and without a minimum of organization, it's a huge mess to understand what's what. Basically a class file must always start by the class_init(), then the init(), then the various object methods (constructed() or finalize() if any, etc.), and possibly other parent classes' implementations. These are the entry points, it's normal to start here (not from leaf functions!). Then we get the public functions which are other entry points (calls from other parts of the code). And only after, private functions such as signal or action callbacks, and utilities at the very end. This requires a well organized prototype listing, which works as a menu, and prevents the implementation order to depend on call order (this gets us completely random order and imply usually that top functions are the less important ones, such as utilities, just how it was before this commit). Anyway I'm not sure why I spent time on this because we deprecated this plug-in, but if we still want to push nice updates (like MR !519), we should at least do it well and clean. Also it's a good first example for plug-in rewrite in modern no-GtkAction code.
1415 lines
51 KiB
C
1415 lines
51 KiB
C
/* GIMP - The GNU Image Manipulation Program
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
*
|
|
* GIMP 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 "libgimp/gimp.h"
|
|
#include "libgimp/gimpui.h"
|
|
|
|
#include "plug-ins/help/gimphelp.h"
|
|
|
|
#include "dialog.h"
|
|
#include "uri.h"
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
|
#define GIMP_HELP_BROWSER_DIALOG_DATA "gimp-help-browser-dialog"
|
|
#define GIMP_HELP_BROWSER_INDEX_MAX_DEPTH 4
|
|
|
|
|
|
typedef struct
|
|
{
|
|
int width;
|
|
int height;
|
|
int paned_position;
|
|
gboolean show_index;
|
|
double zoom;
|
|
} DialogData;
|
|
|
|
struct _GimpHelpBrowserDialog
|
|
{
|
|
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 (GimpHelpBrowserDialog, gimp_help_browser_dialog, GTK_TYPE_APPLICATION_WINDOW)
|
|
|
|
|
|
static void gimp_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 (GimpHelpBrowserDialog *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 (GimpHelpBrowserDialog *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 (GimpHelpBrowserDialog *self,
|
|
const char *text);
|
|
|
|
static GtkWidget * build_menu (const GList *items,
|
|
gboolean back);
|
|
|
|
static void update_actions (GimpHelpBrowserDialog *self);
|
|
|
|
static void add_tool_button (GtkWidget *toolbar,
|
|
const char *action,
|
|
const char *icon,
|
|
const char *label,
|
|
const char *tooltip);
|
|
static GtkWidget * build_searchbar (GimpHelpBrowserDialog *self);
|
|
|
|
static void browser_dialog_make_index_foreach (const gchar *help_id,
|
|
GimpHelpItem *item,
|
|
GimpHelpLocale *locale);
|
|
static gint help_item_compare (gconstpointer a,
|
|
gconstpointer b);
|
|
static void add_child (GimpHelpBrowserDialog *self,
|
|
GtkTreeStore *store,
|
|
GimpHelpDomain *domain,
|
|
GimpHelpLocale *locale,
|
|
GtkTreeIter *parent,
|
|
GimpHelpItem *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
|
|
gimp_help_browser_dialog_class_init (GimpHelpBrowserDialogClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = gimp_help_browser_dialog_finalize;
|
|
}
|
|
|
|
static void
|
|
gimp_help_browser_dialog_init (GimpHelpBrowserDialog *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), _("GIMP Help Browser"));
|
|
gtk_window_set_icon_name (GTK_WINDOW (window), GIMP_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", GIMP_ICON_VIEW_REFRESH, _("_Reload"), _("Reload current page"));
|
|
add_tool_button (toolbar, "win.stop", GIMP_ICON_PROCESS_STOP, _("_Stop"), _("Stop loading this page"));
|
|
add_tool_button (toolbar, "win.home", GIMP_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.gimp.org')", GIMP_ICON_HELP_USER_MANUAL, "docs.gimp.org", _("Visit the GIMP documentation website"));
|
|
|
|
item = gtk_menu_tool_button_new (gtk_image_new_from_icon_name (GIMP_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 (GIMP_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_string (
|
|
"<interface>"
|
|
"<menu id=\"help_browser_popup_menu\">"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">_Back</attribute>"
|
|
"<attribute name=\"action\">win.back</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">_Previous</attribute>"
|
|
"<attribute name=\"action\">win.forward</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">_Reload</attribute>"
|
|
"<attribute name=\"action\">win.reload</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">_Stop</attribute>"
|
|
"<attribute name=\"action\">win.stop</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">_Home</attribute>"
|
|
"<attribute name=\"action\">win.home</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">C_opy location</attribute>"
|
|
"<attribute name=\"action\">win.copy-location</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">S_how index</attribute>"
|
|
"<attribute name=\"action\">win.show-index</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Find</attribute>"
|
|
"<attribute name=\"action\">win.find</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Find _Again</attribute>"
|
|
"<attribute name=\"action\">win.find-again</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Zoom in</attribute>"
|
|
"<attribute name=\"action\">win.zoom-in</attribute>"
|
|
"</item>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Zoom out</attribute>"
|
|
"<attribute name=\"action\">win.zoom-out</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Close</attribute>"
|
|
"<attribute name=\"action\">win.close</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"</menu>"
|
|
"<menu id=\"help_browser_copy_popup_menu\">"
|
|
"<section>"
|
|
"<item>"
|
|
"<attribute name=\"label\" translatable=\"yes\">Copy selection</attribute>"
|
|
"<attribute name=\"action\">win.copy-selection</attribute>"
|
|
"</item>"
|
|
"</section>"
|
|
"</menu>"
|
|
"</interface>",
|
|
-1);
|
|
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
|
|
gimp_help_browser_dialog_finalize (GObject *object)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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 (gimp_help_browser_dialog_parent_class)->finalize (object);
|
|
}
|
|
|
|
/* Public functions. */
|
|
|
|
GimpHelpBrowserDialog *
|
|
gimp_help_browser_dialog_new (const gchar *plug_in_binary, GApplication *app)
|
|
{
|
|
GimpHelpBrowserDialog *window;
|
|
DialogData data = { 720, 560, 240, TRUE, 1.0 };
|
|
|
|
gimp_ui_init (plug_in_binary);
|
|
|
|
gimp_get_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data);
|
|
|
|
window = g_object_new (GIMP_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
|
|
gimp_help_browser_dialog_load (GimpHelpBrowserDialog *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
|
|
gimp_help_browser_dialog_make_index (GimpHelpBrowserDialog *self,
|
|
GimpHelpDomain *domain,
|
|
GimpHelpLocale *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))
|
|
{
|
|
GimpHelpItem *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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
|
|
GtkTreeModel *model;
|
|
GimpHelpDomain *domain;
|
|
GimpHelpLocale *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, "/",
|
|
gimp_help_locale_map (locale,
|
|
GIMP_HELP_DEFAULT_ID),
|
|
NULL);
|
|
gimp_help_browser_dialog_load (self, uri);
|
|
g_free (uri);
|
|
}
|
|
}
|
|
|
|
static void
|
|
find_action (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
|
|
const char *uri;
|
|
|
|
uri = g_variant_get_string (parameter, NULL);
|
|
gimp_help_browser_dialog_load (self, uri);
|
|
}
|
|
|
|
static void
|
|
close_action (GSimpleAction *action,
|
|
GVariant *parameter,
|
|
gpointer user_data)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (self));
|
|
}
|
|
|
|
static void
|
|
webview_realize (GtkWidget *webview,
|
|
gpointer user_data)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
|
|
|
|
g_clear_object (&self->busy_cursor);
|
|
}
|
|
|
|
static void
|
|
do_popup_menu (GimpHelpBrowserDialog *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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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"),
|
|
_("GIMP Help Browser"));
|
|
|
|
gtk_window_set_title (GTK_WINDOW (self), full_title);
|
|
g_free (full_title);
|
|
|
|
update_actions (self);
|
|
}
|
|
|
|
static void
|
|
select_index (GimpHelpBrowserDialog *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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_HELP_BROWSER_DIALOG (user_data);
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GimpHelpDomain *domain;
|
|
GimpHelpLocale *locale;
|
|
GimpHelpItem *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);
|
|
|
|
gimp_help_browser_dialog_load (self, uri);
|
|
|
|
g_free (uri);
|
|
}
|
|
|
|
static void
|
|
search_close_clicked (GtkWidget *button,
|
|
gpointer user_data)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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)
|
|
{
|
|
GimpHelpBrowserDialog *self = GIMP_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);
|
|
|
|
gimp_set_data (GIMP_HELP_BROWSER_DIALOG_DATA, &data, sizeof (data));
|
|
}
|
|
|
|
static void
|
|
search (GimpHelpBrowserDialog *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 (GimpHelpBrowserDialog *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 (GimpHelpBrowserDialog *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 (GIMP_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 (GIMP_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,
|
|
GimpHelpItem *item,
|
|
GimpHelpLocale *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 = GIMP_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))
|
|
{
|
|
GimpHelpItem *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 GimpHelpItem *item_a = a;
|
|
const GimpHelpItem *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 (GimpHelpBrowserDialog *self,
|
|
GtkTreeStore *store,
|
|
GimpHelpDomain *domain,
|
|
GimpHelpLocale *locale,
|
|
GtkTreeIter *parent,
|
|
GimpHelpItem *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 == GIMP_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))
|
|
{
|
|
GimpHelpItem *item = list->data;
|
|
|
|
add_child (self, store, domain, locale, &iter, item, depth + 1);
|
|
}
|
|
}
|