From 5d62c0c452c7496563509f6149601bfbd7bd8c00 Mon Sep 17 00:00:00 2001 From: JosephMcc Date: Thu, 19 Jan 2017 00:00:59 -0800 Subject: [PATCH] Redesign the goto line popup dialog --- xed/Makefile.am | 2 + xed/xed-commands-search.c | 16 +- xed/xed-searchbar.c | 4 +- xed/xed-tab.c | 85 +++--- xed/xed-tab.h | 1 + xed/xed-view-frame.c | 612 ++++++++++++++++++++++++++++++++++++++ xed/xed-view-frame.h | 70 +++++ xed/xed-view.c | 553 +--------------------------------- xed/xed-view.h | 3 - xed/xed-window.c | 22 +- 10 files changed, 760 insertions(+), 608 deletions(-) create mode 100644 xed/xed-view-frame.c create mode 100644 xed/xed-view-frame.h diff --git a/xed/Makefile.am b/xed/Makefile.am index 2bb2c57..7bca45b 100644 --- a/xed/Makefile.am +++ b/xed/Makefile.am @@ -64,6 +64,7 @@ NOINST_H_FILES = \ xed-tab-label.h \ xedtextregion.h \ xed-ui.h \ + xed-view-frame.h \ xed-window-private.h INST_H_FILES = \ @@ -149,6 +150,7 @@ libxed_c_files = \ xed-utils.c \ xed-view.c \ xed-view-activatable.c \ + xed-view-frame.c \ xed-window.c \ xed-window-activatable.c \ xedtextregion.c diff --git a/xed/xed-commands-search.c b/xed/xed-commands-search.c index 9050525..d5570ed 100644 --- a/xed/xed-commands-search.c +++ b/xed/xed-commands-search.c @@ -12,6 +12,7 @@ #include "xed-window.h" #include "xed-utils.h" #include "xed-searchbar.h" +#include "xed-view-frame.h" void _xed_cmd_search_find (GtkAction *action, @@ -47,7 +48,9 @@ void _xed_cmd_search_clear_highlight (XedWindow *window) { XedDocument *doc; + xed_debug (DEBUG_COMMANDS); + doc = xed_window_get_active_document (window); if (doc != NULL) { @@ -59,19 +62,22 @@ void _xed_cmd_search_goto_line (GtkAction *action, XedWindow *window) { - XedView *active_view; + XedTab *active_tab; + XedViewFrame *frame; + xed_debug (DEBUG_COMMANDS); - active_view = xed_window_get_active_view (window); - if (active_view == NULL) + active_tab = xed_window_get_active_tab (window); + if (active_tab == NULL) { return; } /* Focus the view if needed: we need to focus the view otherwise activating the binding for goto line has no effect */ - gtk_widget_grab_focus (GTK_WIDGET(active_view)); + // gtk_widget_grab_focus (GTK_WIDGET(active_view)); /* Goto line is builtin in XedView, just activate the corresponding binding. */ - gtk_bindings_activate (G_OBJECT(active_view), GDK_KEY_i, GDK_CONTROL_MASK); + frame = XED_VIEW_FRAME (_xed_tab_get_view_frame (active_tab)); + xed_view_frame_popup_goto_line (frame); } diff --git a/xed/xed-searchbar.c b/xed/xed-searchbar.c index 1dbb842..1cd1e2e 100755 --- a/xed/xed-searchbar.c +++ b/xed/xed-searchbar.c @@ -727,11 +727,13 @@ xed_searchbar_show (XedSearchbar *searchbar, void xed_searchbar_hide (XedSearchbar *searchbar) { + XedView *active_view; + gtk_revealer_set_transition_type (GTK_REVEALER (searchbar->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN); gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), FALSE); // focus document - XedView *active_view = xed_window_get_active_view (searchbar->window); + active_view = xed_window_get_active_view (searchbar->window); if (active_view != NULL) { gtk_widget_grab_focus (GTK_WIDGET (active_view)); diff --git a/xed/xed-tab.c b/xed/xed-tab.c index c090289..196ba7e 100644 --- a/xed/xed-tab.c +++ b/xed/xed-tab.c @@ -44,6 +44,7 @@ #include "xed-debug.h" #include "xed-enum-types.h" #include "xed-settings.h" +#include "xed-view-frame.h" #define XED_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_TAB, XedTabPrivate)) @@ -55,8 +56,7 @@ struct _XedTabPrivate XedTabState state; - GtkWidget *view; - GtkWidget *view_scrolled_window; + XedViewFrame *frame; GtkWidget *message_area; GtkWidget *print_preview; @@ -375,20 +375,22 @@ static void set_view_properties_according_to_state (XedTab *tab, XedTabState state) { + XedView *view; gboolean val; gboolean hl_current_line; hl_current_line = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_HIGHLIGHT_CURRENT_LINE); + view = xed_view_frame_get_view (tab->priv->frame); val = ((state == XED_TAB_STATE_NORMAL) && (tab->priv->print_preview == NULL) && !tab->priv->not_editable); - gtk_text_view_set_editable (GTK_TEXT_VIEW (tab->priv->view), val); + gtk_text_view_set_editable (GTK_TEXT_VIEW (view), val); val = ((state != XED_TAB_STATE_LOADING) && (state != XED_TAB_STATE_CLOSING)); - gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (tab->priv->view), val); + gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), val); val = ((state != XED_TAB_STATE_LOADING) && (state != XED_TAB_STATE_CLOSING) && (hl_current_line)); - gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (tab->priv->view), val); + gtk_source_view_set_highlight_current_line (GTK_SOURCE_VIEW (view), val); } static void @@ -410,17 +412,17 @@ xed_tab_set_state (XedTab *tab, if ((state == XED_TAB_STATE_LOADING_ERROR) || /* FIXME: add other states if needed */ (state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW)) { - gtk_widget_hide (tab->priv->view_scrolled_window); + gtk_widget_hide (GTK_WIDGET (tab->priv->frame)); } else { if (tab->priv->print_preview == NULL) { - gtk_widget_show (tab->priv->view_scrolled_window); + gtk_widget_show (GTK_WIDGET (tab->priv->frame)); } } - set_cursor_according_to_state (GTK_TEXT_VIEW (tab->priv->view), state); + set_cursor_according_to_state (GTK_TEXT_VIEW (xed_view_frame_get_view (tab->priv->frame)), state); g_object_notify (G_OBJECT (tab), "state"); } @@ -969,7 +971,7 @@ document_loaded (XedDocument *document, } /* Scroll to the cursor when the document is loaded */ - xed_view_scroll_to_cursor (XED_VIEW (tab->priv->view)); + xed_view_scroll_to_cursor (xed_view_frame_get_view (tab->priv->frame)); all_documents = xed_app_get_documents (xed_app_get_default ()); @@ -1408,24 +1410,13 @@ view_focused_in (GtkWidget *widget, return FALSE; } -static GMountOperation * -tab_mount_operation_factory (XedDocument *doc, - gpointer userdata) -{ - XedTab *tab = XED_TAB (userdata); - GtkWidget *window; - - window = gtk_widget_get_toplevel (GTK_WIDGET (tab)); - return gtk_mount_operation_new (GTK_WINDOW (window)); -} - static void xed_tab_init (XedTab *tab) { - GtkWidget *sw; - XedDocument *doc; gboolean auto_save; guint auto_save_interval; + XedDocument *doc; + XedView *view; tab->priv = XED_TAB_GET_PRIVATE (tab); @@ -1437,12 +1428,6 @@ xed_tab_init (XedTab *tab) gtk_orientable_set_orientation (GTK_ORIENTABLE (tab), GTK_ORIENTATION_VERTICAL); - /* Create the scrolled window */ - sw = gtk_scrolled_window_new (NULL, NULL); - tab->priv->view_scrolled_window = sw; - - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - /* Manage auto save data */ auto_save = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_AUTO_SAVE); auto_save_interval = g_settings_get_uint (tab->priv->editor, XED_SETTINGS_AUTO_SAVE_INTERVAL); @@ -1450,26 +1435,18 @@ xed_tab_init (XedTab *tab) tab->priv->auto_save = (tab->priv->auto_save != FALSE); tab->priv->auto_save_interval = auto_save_interval; - /*FIXME - if (tab->priv->auto_save_interval <= 0) - { - tab->priv->auto_save_interval = GPM_DEFAULT_AUTO_SAVE_INTERVAL; - }*/ - /* Create the view */ - doc = xed_document_new (); + /* Create the frame */ + tab->priv->frame = xed_view_frame_new (); + gtk_widget_show (GTK_WIDGET (tab->priv->frame)); + + gtk_box_pack_end (GTK_BOX (tab), GTK_WIDGET (tab->priv->frame), TRUE, TRUE, 0); + + doc = xed_view_frame_get_document (tab->priv->frame); g_object_set_data (G_OBJECT (doc), XED_TAB_KEY, tab); - _xed_document_set_mount_operation_factory (doc, tab_mount_operation_factory, tab); - - tab->priv->view = xed_view_new (doc); - g_object_unref (doc); - gtk_widget_show (tab->priv->view); - g_object_set_data (G_OBJECT (tab->priv->view), XED_TAB_KEY, tab); - - gtk_box_pack_end (GTK_BOX (tab), sw, TRUE, TRUE, 0); - gtk_container_add (GTK_CONTAINER (sw), tab->priv->view); - gtk_widget_show (sw); + view = xed_view_frame_get_view (tab->priv->frame); + g_object_set_data (G_OBJECT (view), XED_TAB_KEY, tab); g_signal_connect (doc, "notify::location", G_CALLBACK (document_location_notify_handler), tab); @@ -1486,9 +1463,9 @@ xed_tab_init (XedTab *tab) g_signal_connect (doc, "saved", G_CALLBACK (document_saved), tab); - g_signal_connect_after (tab->priv->view, "focus-in-event", + g_signal_connect_after (view, "focus-in-event", G_CALLBACK (view_focused_in), tab); - g_signal_connect_after (tab->priv->view, "realize", + g_signal_connect_after (view, "realize", G_CALLBACK (view_realized), tab); } @@ -1528,7 +1505,9 @@ _xed_tab_new_from_location (GFile *location, XedView * xed_tab_get_view (XedTab *tab) { - return XED_VIEW (tab->priv->view); + g_return_val_if_fail (XED_IS_TAB (tab), NULL); + + return xed_view_frame_get_view (tab->priv->frame); } /** @@ -1542,7 +1521,9 @@ xed_tab_get_view (XedTab *tab) XedDocument * xed_tab_get_document (XedTab *tab) { - return XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (tab->priv->view))); + g_return_val_if_fail (XED_IS_TAB (tab), NULL); + + return xed_view_frame_get_document (tab->priv->frame); } #define MAX_DOC_NAME_LENGTH 40 @@ -2631,3 +2612,9 @@ xed_tab_set_info_bar (XedTab *tab, /* FIXME: this can cause problems with the tab state machine */ set_message_area (tab, info_bar); } + +GtkWidget * +_xed_tab_get_view_frame (XedTab *tab) +{ + return GTK_WIDGET (tab->priv->frame); +} diff --git a/xed/xed-tab.h b/xed/xed-tab.h index 80f2972..885f996 100644 --- a/xed/xed-tab.h +++ b/xed/xed-tab.h @@ -132,6 +132,7 @@ void _xed_tab_print (XedTab *tab); void _xed_tab_print_preview (XedTab *tab); void _xed_tab_mark_for_closing (XedTab *tab); gboolean _xed_tab_can_close (XedTab *tab); +GtkWidget *_xed_tab_get_view_frame (XedTab *tab); G_END_DECLS diff --git a/xed/xed-view-frame.c b/xed/xed-view-frame.c new file mode 100644 index 0000000..981b0cb --- /dev/null +++ b/xed/xed-view-frame.c @@ -0,0 +1,612 @@ +/* + * xed-view-frame.c + * This file is part of xed + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * xed is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xed 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 xed; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "xed-view-frame.h" +#include "xed-marshal.h" +#include "xed-debug.h" +#include "xed-utils.h" + +#include +#include +#include + +#define XED_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */ + +#define SEARCH_POPUP_MARGIN 12 + +#define XED_VIEW_FRAME_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE((object), XED_TYPE_VIEW_FRAME, XedViewFramePrivate)) + +struct _XedViewFramePrivate +{ + GtkWidget *view; + GtkWidget *overlay; + + GtkTextMark *start_mark; + + GtkWidget *revealer; + GtkWidget *search_entry; + + guint flush_timeout_id; + glong search_entry_focus_out_id; + glong search_entry_changed_id; + gboolean disable_popdown; +}; + +enum +{ + PROP_0, + PROP_DOCUMENT, + PROP_VIEW +}; + +typedef enum +{ + SEARCH_STATE_NORMAL, + SEARCH_STATE_NOT_FOUND +} SearchState; + +G_DEFINE_TYPE (XedViewFrame, xed_view_frame, GTK_TYPE_BOX) + +static void +xed_view_frame_finalize (GObject *object) +{ + G_OBJECT_CLASS (xed_view_frame_parent_class)->finalize (object); +} + +static void +xed_view_frame_dispose (GObject *object) +{ + XedViewFrame *frame = XED_VIEW_FRAME (object); + + if (frame->priv->flush_timeout_id != 0) + { + g_source_remove (frame->priv->flush_timeout_id); + frame->priv->flush_timeout_id = 0; + } + + G_OBJECT_CLASS (xed_view_frame_parent_class)->dispose (object); +} + +static void +xed_view_frame_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + XedViewFrame *frame = XED_VIEW_FRAME (object); + + switch (prop_id) + { + case PROP_DOCUMENT: + g_value_set_object (value, xed_view_frame_get_document (frame)); + break; + case PROP_VIEW: + g_value_set_object (value, xed_view_frame_get_view (frame)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +hide_search_widget (XedViewFrame *frame, + gboolean cancel) +{ + GtkTextBuffer *buffer; + + g_signal_handler_block (frame->priv->search_entry, frame->priv->search_entry_focus_out_id); + + if (frame->priv->flush_timeout_id != 0) + { + g_source_remove (frame->priv->flush_timeout_id); + frame->priv->flush_timeout_id = 0; + } + + gtk_revealer_set_reveal_child (GTK_REVEALER (frame->priv->revealer), FALSE); + + if (cancel) + { + GtkTextBuffer *buffer; + GtkTextIter iter; + + buffer = GTK_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view))); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, frame->priv->start_mark); + gtk_text_buffer_place_cursor (buffer, &iter); + + xed_view_scroll_to_cursor (XED_VIEW (frame->priv->view)); + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view)); + gtk_text_buffer_delete_mark (buffer, frame->priv->start_mark); + + /* Make sure the view is the one who has the focus when we destroy + the search widget */ + gtk_widget_grab_focus (frame->priv->view); + + g_signal_handler_unblock (frame->priv->search_entry, frame->priv->search_entry_focus_out_id); +} + +static gboolean +search_entry_flush_timeout (XedViewFrame *frame) +{ + frame->priv->flush_timeout_id = 0; + hide_search_widget (frame, FALSE); + + return FALSE; +} + +static void +set_search_state (XedViewFrame *frame, + SearchState state) +{ + GtkStyleContext *context; + + context = gtk_widget_get_style_context (GTK_WIDGET (frame->priv->search_entry)); + + if (state == SEARCH_STATE_NOT_FOUND) + { + gtk_style_context_add_class (context, GTK_STYLE_CLASS_ERROR); + } + else + { + gtk_style_context_remove_class (context, GTK_STYLE_CLASS_ERROR); + } +} + +static gboolean +search_widget_key_press_event (GtkWidget *widget, + GdkEventKey *event, + XedViewFrame *frame) +{ + if (event->keyval == GDK_KEY_Escape) + { + + hide_search_widget (frame, TRUE); + return GDK_EVENT_STOP; + } + + return GDK_EVENT_PROPAGATE; +} + +static void +search_entry_activate (GtkEntry *entry, + XedViewFrame *frame) +{ + hide_search_widget (frame, FALSE); +} + +static void +search_entry_insert_text (GtkEditable *editable, + const gchar *text, + gint length, + gint *position, + XedViewFrame *frame) +{ + gunichar c; + const gchar *p; + const gchar *end; + const gchar *next; + + p = text; + end = text + length; + + if (p == end) + return; + + c = g_utf8_get_char (p); + + if (((c == '-' || c == '+') && *position == 0) || + (c == ':' && *position != 0)) + { + gchar *s = NULL; + + if (c == ':') + { + s = gtk_editable_get_chars (editable, 0, -1); + s = g_utf8_strchr (s, -1, ':'); + } + + if (s == NULL || s == p) + { + next = g_utf8_next_char (p); + p = next; + } + + g_free (s); + } + + while (p != end) + { + next = g_utf8_next_char (p); + + c = g_utf8_get_char (p); + + if (!g_unichar_isdigit (c)) + { + g_signal_stop_emission_by_name (editable, "insert_text"); + gtk_widget_error_bell (frame->priv->search_entry); + break; + } + + p = next; + } +} + +static void +search_init (GtkWidget *entry, + XedViewFrame *frame) +{ + const gchar *entry_text; + + /* renew the flush timeout */ + if (frame->priv->flush_timeout_id != 0) + { + g_source_remove (frame->priv->flush_timeout_id); + frame->priv->flush_timeout_id = g_timeout_add (XED_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT, + (GSourceFunc)search_entry_flush_timeout, frame); + } + + entry_text = gtk_entry_get_text (GTK_ENTRY (entry)); + + if (*entry_text != '\0') + { + gboolean moved, moved_offset; + gint line; + gint offset_line = 0; + gint line_offset = 0; + gchar **split_text = NULL; + const gchar *text; + GtkTextIter iter; + XedDocument *doc; + + doc = xed_view_frame_get_document (frame); + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (doc), &iter, frame->priv->start_mark); + split_text = g_strsplit (entry_text, ":", -1); + + if (g_strv_length (split_text) > 1) + { + text = split_text[0]; + } + else + { + text = entry_text; + } + + if (*text == '-') + { + gint cur_line = gtk_text_iter_get_line (&iter); + + if (*(text + 1) != '\0') + { + offset_line = MAX (atoi (text + 1), 0); + } + + line = MAX (cur_line - offset_line, 0); + } + else if (*entry_text == '+') + { + gint cur_line = gtk_text_iter_get_line (&iter); + + if (*(text + 1) != '\0') + { + offset_line = MAX (atoi (text + 1), 0); + } + + line = cur_line + offset_line; + } + else + { + line = MAX (atoi (text) - 1, 0); + } + + if (split_text[1] != NULL) + { + line_offset = atoi (split_text[1]); + } + + g_strfreev (split_text); + + moved = xed_document_goto_line (doc, line); + moved_offset = xed_document_goto_line_offset (doc, line, line_offset); + + xed_view_scroll_to_cursor (XED_VIEW (frame->priv->view)); + + if (!moved || !moved_offset) + { + set_search_state (frame, SEARCH_STATE_NOT_FOUND); + } + else + { + set_search_state (frame, SEARCH_STATE_NORMAL); + } + } +} + +static gboolean +search_entry_focus_out_event (GtkWidget *widget, + GdkEventFocus *event, + XedViewFrame *frame) +{ + if (frame->priv->disable_popdown) + { + return GDK_EVENT_STOP; + } + + hide_search_widget (frame, FALSE); + return GDK_EVENT_PROPAGATE; +} + +static void +search_enable_popdown (GtkWidget *widget, + XedViewFrame *frame) +{ + frame->priv->disable_popdown = FALSE; +} + +static void +search_entry_populate_popup (GtkEntry *entry, + GtkMenu *menu, + XedViewFrame *frame) +{ + frame->priv->disable_popdown = TRUE; + g_signal_connect (menu, "hide", + G_CALLBACK (search_enable_popdown), frame); +} + +static GtkWidget * +create_search_widget (XedViewFrame *frame) +{ + GtkWidget *search_widget; + GtkWidget *hbox; + GtkStyleContext *context; + + /* wrap it in a frame, so we can specify borders etc */ + search_widget = gtk_frame_new (NULL); + context = gtk_widget_get_style_context (search_widget); + gtk_style_context_add_class (context, "xed-goto-line-box"); + gtk_widget_show (search_widget); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_container_add (GTK_CONTAINER (search_widget), hbox); + gtk_widget_show (hbox); + + g_signal_connect (hbox, "key-press-event", + G_CALLBACK (search_widget_key_press_event), frame); + + /* add entry */ + frame->priv->search_entry = gtk_entry_new (); + gtk_widget_set_tooltip_text (frame->priv->search_entry, _("Line you want to move the cursor to")); + gtk_entry_set_icon_from_icon_name (GTK_ENTRY (frame->priv->search_entry), + GTK_ENTRY_ICON_PRIMARY, "go-jump-symbolic"); + gtk_widget_show (frame->priv->search_entry); + + g_signal_connect (frame->priv->search_entry, "activate", + G_CALLBACK (search_entry_activate), frame); + g_signal_connect (frame->priv->search_entry, "insert_text", + G_CALLBACK (search_entry_insert_text), frame); + g_signal_connect (frame->priv->search_entry, "populate-popup", + G_CALLBACK (search_entry_populate_popup), frame); + frame->priv->search_entry_changed_id = g_signal_connect (frame->priv->search_entry, "changed", + G_CALLBACK (search_init), frame); + frame->priv->search_entry_focus_out_id = g_signal_connect (frame->priv->search_entry, "focus-out-event", + G_CALLBACK (search_entry_focus_out_event), frame); + + gtk_container_add (GTK_CONTAINER (hbox), frame->priv->search_entry); + + return search_widget; +} + +static void +init_search_entry (XedViewFrame *frame) +{ + GtkTextBuffer *buffer; + gint line; + gchar *line_str; + GtkTextIter iter; + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view)); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, frame->priv->start_mark); + line = gtk_text_iter_get_line (&iter); + line_str = g_strdup_printf ("%d", line + 1); + + gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry), line_str); + gtk_editable_select_region (GTK_EDITABLE (frame->priv->search_entry), 0, -1); + + g_free (line_str); + + return; +} + +static void +start_interactive_search_real (XedViewFrame *frame) +{ + GtkTextBuffer *buffer; + GtkTextIter iter; + GtkTextMark *mark; + + if (gtk_revealer_get_reveal_child (GTK_REVEALER (frame->priv->revealer))) + { + gtk_editable_select_region (GTK_EDITABLE (frame->priv->search_entry), 0, -1); + return; + } + + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view)); + + mark = gtk_text_buffer_get_insert (buffer); + gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark); + + frame->priv->start_mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, FALSE); + + gtk_revealer_set_reveal_child (GTK_REVEALER (frame->priv->revealer), TRUE); + + /* NOTE: we must be very careful here to not have any text before + focusing the entry because when the entry is focused the text is + selected, and gtk+ doesn't allow us to have more than one selection + active */ + g_signal_handler_block (frame->priv->search_entry, frame->priv->search_entry_changed_id); + gtk_entry_set_text (GTK_ENTRY (frame->priv->search_entry), ""); + g_signal_handler_unblock (frame->priv->search_entry, frame->priv->search_entry_changed_id); + + /* We need to grab the focus after the widget has been added */ + gtk_widget_grab_focus (frame->priv->search_entry); + + init_search_entry (frame); + + frame->priv->flush_timeout_id = g_timeout_add (XED_VIEW_FRAME_SEARCH_DIALOG_TIMEOUT, + (GSourceFunc) search_entry_flush_timeout, frame); +} + +static void +xed_view_frame_class_init (XedViewFrameClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = xed_view_frame_finalize; + object_class->dispose = xed_view_frame_dispose; + object_class->get_property = xed_view_frame_get_property; + + g_object_class_install_property (object_class, PROP_DOCUMENT, + g_param_spec_object ("document", + "Document", + "The Document", + XED_TYPE_DOCUMENT, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (object_class, PROP_VIEW, + g_param_spec_object ("view", + "View", + "The View", + XED_TYPE_VIEW, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private (object_class, sizeof (XedViewFramePrivate)); +} + +static GMountOperation * +view_frame_mount_operation_factory (XedDocument *doc, + gpointer user_data) +{ + XedViewFrame *frame = XED_VIEW_FRAME (user_data); + GtkWidget *window; + + window = gtk_widget_get_toplevel (GTK_WIDGET (frame)); + + return gtk_mount_operation_new (GTK_WINDOW (window)); +} + +static void +xed_view_frame_init (XedViewFrame *frame) +{ + XedDocument *doc; + GtkWidget *sw; + GdkRGBA transparent = {0, 0, 0, 0}; + + frame->priv = XED_VIEW_FRAME_GET_PRIVATE (frame); + + gtk_orientable_set_orientation (GTK_ORIENTABLE (frame), GTK_ORIENTATION_VERTICAL); + + doc = xed_document_new (); + + _xed_document_set_mount_operation_factory (doc, view_frame_mount_operation_factory, frame); + + frame->priv->view = xed_view_new (doc); + gtk_widget_set_vexpand (frame->priv->view, TRUE); + gtk_widget_show (frame->priv->view); + + g_object_unref (doc); + + /* Create the scrolled window */ + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_container_add (GTK_CONTAINER (sw), frame->priv->view); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_show (sw); + + frame->priv->overlay = gtk_overlay_new (); + gtk_container_add (GTK_CONTAINER (frame->priv->overlay), sw); + gtk_widget_override_background_color (frame->priv->overlay, 0, &transparent); + gtk_widget_show (frame->priv->overlay); + + gtk_box_pack_start (GTK_BOX (frame), frame->priv->overlay, TRUE, TRUE, 0); + + /* Add revealer */ + frame->priv->revealer = gtk_revealer_new (); + gtk_container_add (GTK_CONTAINER (frame->priv->revealer), create_search_widget (frame)); + gtk_widget_show (frame->priv->revealer); + gtk_widget_set_halign (frame->priv->revealer, GTK_ALIGN_END); + gtk_widget_set_valign (frame->priv->revealer, GTK_ALIGN_START); + + if (gtk_widget_get_direction (frame->priv->revealer) == GTK_TEXT_DIR_LTR) + { + gtk_widget_set_margin_right (frame->priv->revealer, SEARCH_POPUP_MARGIN); + } + else + { + gtk_widget_set_margin_left (frame->priv->revealer, SEARCH_POPUP_MARGIN); + } + + gtk_overlay_add_overlay (GTK_OVERLAY (frame->priv->overlay), frame->priv->revealer); +} + +XedViewFrame * +xed_view_frame_new () +{ + return g_object_new (XED_TYPE_VIEW_FRAME, NULL); +} + +XedDocument * +xed_view_frame_get_document (XedViewFrame *frame) +{ + g_return_val_if_fail (XED_IS_VIEW_FRAME (frame), NULL); + + return XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (frame->priv->view))); +} + +XedView * +xed_view_frame_get_view (XedViewFrame *frame) +{ + g_return_val_if_fail (XED_IS_VIEW_FRAME (frame), NULL); + + return XED_VIEW (frame->priv->view); +} + +void +xed_view_frame_popup_goto_line (XedViewFrame *frame) +{ + g_return_if_fail (XED_IS_VIEW_FRAME (frame)); + + start_interactive_search_real (frame); +} + +gboolean +xed_view_frame_get_search_popup_visible (XedViewFrame *frame) +{ + g_return_val_if_fail (XED_IS_VIEW_FRAME (frame), FALSE); + + return gtk_revealer_get_child_revealed (GTK_REVEALER (frame->priv->revealer)); +} diff --git a/xed/xed-view-frame.h b/xed/xed-view-frame.h new file mode 100644 index 0000000..1383fbe --- /dev/null +++ b/xed/xed-view-frame.h @@ -0,0 +1,70 @@ +/* + * xed-view-frame.h + * This file is part of xed + * + * Copyright (C) 2010 - Ignacio Casal Quinteiro + * + * xed is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * xed 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 xed; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __XED_VIEW_FRAME_H__ +#define __XED_VIEW_FRAME_H__ + +#include +#include "xed-document.h" +#include "xed-view.h" + +G_BEGIN_DECLS + +#define XED_TYPE_VIEW_FRAME (xed_view_frame_get_type ()) +#define XED_VIEW_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_VIEW_FRAME, XedViewFrame)) +#define XED_VIEW_FRAME_CONST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XED_TYPE_VIEW_FRAME, XedViewFrame const)) +#define XED_VIEW_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XED_TYPE_VIEW_FRAME, XedViewFrameClass)) +#define XED_IS_VIEW_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XED_TYPE_VIEW_FRAME)) +#define XED_IS_VIEW_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XED_TYPE_VIEW_FRAME)) +#define XED_VIEW_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XED_TYPE_VIEW_FRAME, XedViewFrameClass)) + +typedef struct _XedViewFrame XedViewFrame; +typedef struct _XedViewFrameClass XedViewFrameClass; +typedef struct _XedViewFramePrivate XedViewFramePrivate; + +struct _XedViewFrame +{ + GtkBox parent; + + XedViewFramePrivate *priv; +}; + +struct _XedViewFrameClass +{ + GtkBoxClass parent_class; +}; + +GType xed_view_frame_get_type (void) G_GNUC_CONST; + +XedViewFrame *xed_view_frame_new (void); + +XedDocument *xed_view_frame_get_document (XedViewFrame *frame); + +XedView *xed_view_frame_get_view (XedViewFrame *frame); + +void xed_view_frame_popup_goto_line (XedViewFrame *frame); + +gboolean xed_view_frame_get_search_popup_visible (XedViewFrame *frame); + +G_END_DECLS + +#endif /* __XED_VIEW_FRAME_H__ */ diff --git a/xed/xed-view.c b/xed/xed-view.c index 76998a1..74022bd 100644 --- a/xed/xed-view.c +++ b/xed/xed-view.c @@ -19,7 +19,6 @@ #include "xed-app.h" #define XED_VIEW_SCROLL_MARGIN 0.02 -#define XED_VIEW_SEARCH_DIALOG_TIMEOUT (30*1000) /* 30 seconds */ #define XED_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_VIEW, XedViewPrivate)) @@ -31,43 +30,29 @@ enum struct _XedViewPrivate { GSettings *editor_settings; - GtkTextIter start_search_iter; - GtkWidget *search_window; - GtkWidget *search_entry; - guint typeselect_flush_timeout; - guint search_entry_changed_id; - gboolean disable_popdown; GtkTextBuffer *current_buffer; PeasExtensionSet *extensions; guint view_realized : 1; }; - -static gboolean start_interactive_goto_line (XedView *view); -static void hide_search_window (XedView *view, gboolean cancel); - -G_DEFINE_TYPE(XedView, xed_view, GTK_SOURCE_TYPE_VIEW) +G_DEFINE_TYPE (XedView, xed_view, GTK_SOURCE_TYPE_VIEW) /* Signals */ enum { - START_INTERACTIVE_GOTO_LINE, DROP_URIS, LAST_SIGNAL + DROP_URIS, + LAST_SIGNAL }; static guint view_signals[LAST_SIGNAL] = { 0 }; -typedef enum -{ - XED_SEARCH_ENTRY_NORMAL, XED_SEARCH_ENTRY_NOT_FOUND -} XedSearchEntryState; - static void document_read_only_notify_handler (XedDocument *document, GParamSpec *pspec, XedView *view) { xed_debug (DEBUG_VIEW); - gtk_text_view_set_editable (GTK_TEXT_VIEW(view), !xed_document_get_readonly (document)); + gtk_text_view_set_editable (GTK_TEXT_VIEW (view), !xed_document_get_readonly (document)); } static void @@ -177,8 +162,6 @@ xed_view_init (XedView *view) view->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor"); - view->priv->typeselect_flush_timeout = 0; - /* Drag and drop support */ tl = gtk_drag_dest_get_target_list (GTK_WIDGET(view)); @@ -207,18 +190,6 @@ xed_view_dispose (GObject *object) g_clear_object (&view->priv->extensions); g_clear_object (&view->priv->editor_settings); - if (view->priv->search_window != NULL) - { - gtk_widget_destroy (view->priv->search_window); - view->priv->search_window = NULL; - view->priv->search_entry = NULL; - if (view->priv->typeselect_flush_timeout != 0) - { - g_source_remove (view->priv->typeselect_flush_timeout); - view->priv->typeselect_flush_timeout = 0; - } - } - current_buffer_removed (view); /* Disconnect notify buffer because the destroy of the textview will set @@ -328,16 +299,8 @@ static gint xed_view_focus_out (GtkWidget *widget, GdkEventFocus *event) { - XedView *view = XED_VIEW (widget); - gtk_widget_queue_draw (widget); - /* hide interactive search dialog */ - if (view->priv->search_window != NULL) - { - hide_search_window (view, FALSE); - } - GTK_WIDGET_CLASS (xed_view_parent_class)->focus_out_event (widget, event); return FALSE; @@ -508,13 +471,11 @@ static gboolean xed_view_button_press_event (GtkWidget *widget, GdkEventButton *event) { - if ((event->type == GDK_BUTTON_PRESS) - && (event->button == 3) - && (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_LEFT))) + if ((event->type == GDK_BUTTON_PRESS) && + (event->button == 3) && + (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_LEFT))) { - show_line_numbers_menu (widget, event); - return TRUE; } @@ -675,19 +636,9 @@ xed_view_class_init (XedViewClass *klass) widget_class->drag_drop = xed_view_drag_drop; widget_class->button_press_event = xed_view_button_press_event; widget_class->realize = xed_view_realize; - klass->start_interactive_goto_line = start_interactive_goto_line; text_view_class->delete_from_cursor = xed_view_delete_from_cursor; - view_signals[START_INTERACTIVE_GOTO_LINE] = - g_signal_new ("start_interactive_goto_line", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (XedViewClass, start_interactive_goto_line), - NULL, NULL, - xed_marshal_BOOLEAN__NONE, - G_TYPE_BOOLEAN, 0); - /* A new signal DROP_URIS has been added to allow plugins to intercept * the default dnd behaviour of 'text/uri-list'. XedView now handles * dnd in the default handlers of drag_drop, drag_motion and @@ -710,8 +661,6 @@ xed_view_class_init (XedViewClass *klass) binding_set = gtk_binding_set_by_class (klass); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_i, GDK_CONTROL_MASK, "start_interactive_goto_line", 0); - gtk_binding_entry_add_signal (binding_set, GDK_KEY_d, GDK_CONTROL_MASK, "delete_from_cursor", 2, G_TYPE_ENUM, GTK_DELETE_PARAGRAPHS, G_TYPE_INT, 1); } @@ -914,491 +863,3 @@ xed_view_set_font (XedView *view, gtk_widget_modify_font (GTK_WIDGET (view), font_desc); pango_font_description_free (font_desc); } - -static void -set_entry_state (GtkWidget *entry, - XedSearchEntryState state) -{ - GtkStyleContext *context = gtk_widget_get_style_context (GTK_WIDGET(entry)); - - if (state == XED_SEARCH_ENTRY_NOT_FOUND) - { - gtk_style_context_add_class (context, GTK_STYLE_CLASS_ERROR); - } - else - { - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_ERROR); - } -} - -/* Cut and paste from gtkwindow.c */ -static void -send_focus_change (GtkWidget *widget, - gboolean in) -{ - GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE); - - g_object_ref (widget); - - fevent->focus_change.type = GDK_FOCUS_CHANGE; - fevent->focus_change.window = g_object_ref (gtk_widget_get_window (widget)); - fevent->focus_change.in = in; - - gtk_widget_event (widget, fevent); - - g_object_notify (G_OBJECT(widget), "has-focus"); - - g_object_unref (widget); - gdk_event_free (fevent); -} - -static void -hide_search_window (XedView *view, - gboolean cancel) -{ - if (view->priv->disable_popdown) - { - return; - } - - if (view->priv->search_entry_changed_id != 0) - { - g_signal_handler_disconnect (view->priv->search_entry, view->priv->search_entry_changed_id); - view->priv->search_entry_changed_id = 0; - } - - if (view->priv->typeselect_flush_timeout != 0) - { - g_source_remove (view->priv->typeselect_flush_timeout); - view->priv->typeselect_flush_timeout = 0; - } - - /* send focus-in event */ - send_focus_change (GTK_WIDGET(view->priv->search_entry), FALSE); - gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW(view), TRUE); - gtk_widget_hide (view->priv->search_window); - - if (cancel) - { - GtkTextBuffer *buffer; - buffer = GTK_TEXT_BUFFER(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - gtk_text_buffer_place_cursor (buffer, &view->priv->start_search_iter); - xed_view_scroll_to_cursor (view); - } - - /* make sure a focus event is sent for the edit area */ - send_focus_change (GTK_WIDGET(view), TRUE); -} - -static gboolean -search_entry_flush_timeout (XedView *view) -{ - view->priv->typeselect_flush_timeout = 0; - hide_search_window (view, FALSE); - - return FALSE; -} - -static void -update_search_window_position (XedView *view) -{ - gint x, y; - gint view_x, view_y; - GdkWindow *view_window = gtk_widget_get_window (GTK_WIDGET(view)); - - gtk_widget_realize (view->priv->search_window); - gdk_window_get_origin (view_window, &view_x, &view_y); - - x = MAX(12, view_x + 12); - y = MAX(12, view_y - 12); - - gtk_window_move (GTK_WINDOW(view->priv->search_window), x, y); -} - -static gboolean -search_window_deleted (GtkWidget *widget, - GdkEventAny *event, - XedView *view) -{ - hide_search_window (view, FALSE); - return TRUE; -} - -static gboolean -search_window_button_pressed (GtkWidget *widget, - GdkEventButton *event, - XedView *view) -{ - hide_search_window (view, FALSE); - gtk_propagate_event (GTK_WIDGET(view), (GdkEvent *) event); - return FALSE; -} - -static gboolean -search_window_key_pressed (GtkWidget *widget, - GdkEventKey *event, - XedView *view) -{ - gboolean retval = FALSE; - guint modifiers; - - modifiers = gtk_accelerator_get_default_mod_mask (); - - /* Close window */ - if (event->keyval == GDK_KEY_Tab) - { - hide_search_window (view, FALSE); - retval = TRUE; - } - - /* Close window and cancel the search */ - if (event->keyval == GDK_KEY_Escape) - { - hide_search_window (view, TRUE); - retval = TRUE; - } - - return retval; -} - -static void -search_entry_activate (GtkEntry *entry, - XedView *view) -{ - hide_search_window (view, FALSE); -} - -static gboolean -real_search_enable_popdown (gpointer data) -{ - XedView *view = (XedView *) data; - view->priv->disable_popdown = FALSE; - return FALSE; -} - -static void -search_enable_popdown (GtkWidget *widget, - XedView *view) -{ - g_timeout_add (200, real_search_enable_popdown, view); - - /* renew the flush timeout */ - if (view->priv->typeselect_flush_timeout != 0) - { - g_source_remove (view->priv->typeselect_flush_timeout); - } - - view->priv->typeselect_flush_timeout = g_timeout_add (XED_VIEW_SEARCH_DIALOG_TIMEOUT, - (GSourceFunc) search_entry_flush_timeout, view); -} - -static void -search_entry_populate_popup (GtkEntry *entry, - GtkMenu *menu, - XedView *view) -{ - GtkWidget *menu_item; - view->priv->disable_popdown = TRUE; - g_signal_connect(menu, "hide", G_CALLBACK (search_enable_popdown), view); -} - -static void -search_entry_insert_text (GtkEditable *editable, - const gchar *text, - gint length, - gint *position, - XedView *view) -{ - gunichar c; - const gchar *p; - const gchar *end; - const gchar *next; - - p = text; - end = text + length; - - if (p == end) - { - return; - } - - c = g_utf8_get_char (p); - - if (((c == '-' || c == '+') && *position == 0) || (c == ':' && *position != 0)) - { - gchar *s = NULL; - if (c == ':') - { - s = gtk_editable_get_chars (editable, 0, -1); - s = g_utf8_strchr (s, -1, ':'); - } - if (s == NULL || s == p) - { - next = g_utf8_next_char(p); - p = next; - } - g_free (s); - } - - while (p != end) - { - next = g_utf8_next_char(p); - c = g_utf8_get_char (p); - if (!g_unichar_isdigit (c)) - { - g_signal_stop_emission_by_name (editable, "insert_text"); - gtk_widget_error_bell (view->priv->search_entry); - break; - } - p = next; - } -} - -static void -customize_for_search_mode (XedView *view) -{ - gtk_entry_set_icon_from_stock (GTK_ENTRY(view->priv->search_entry), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_JUMP_TO); - gtk_widget_set_tooltip_text (view->priv->search_entry, _("Line you want to move the cursor to")); -} - -static void -ensure_search_window (XedView *view) -{ - GtkWidget *frame; - GtkWidget *vbox; - GtkWidget *toplevel; - GtkWindowGroup *group; - GtkWindowGroup *search_group; - - toplevel = gtk_widget_get_toplevel (GTK_WIDGET(view)); - group = gtk_window_get_group (GTK_WINDOW(toplevel)); - if (view->priv->search_window != NULL) - { - search_group = gtk_window_get_group (GTK_WINDOW(view->priv->search_window)); - } - - if (view->priv->search_window != NULL) - { - if (group) - { - gtk_window_group_add_window (group, GTK_WINDOW(view->priv->search_window)); - } - else if (search_group) - { - gtk_window_group_remove_window (search_group, GTK_WINDOW(view->priv->search_window)); - } - customize_for_search_mode (view); - return; - } - - view->priv->search_window = gtk_window_new (GTK_WINDOW_POPUP); - - if (group) - { - gtk_window_group_add_window (group, GTK_WINDOW(view->priv->search_window)); - } - - gtk_window_set_modal (GTK_WINDOW(view->priv->search_window), TRUE); - - g_signal_connect(view->priv->search_window, "delete_event", G_CALLBACK (search_window_deleted), view); - g_signal_connect(view->priv->search_window, "key_press_event", G_CALLBACK (search_window_key_pressed), view); - g_signal_connect(view->priv->search_window, "button_press_event", G_CALLBACK (search_window_button_pressed), view); - - frame = gtk_frame_new (NULL); - gtk_frame_set_shadow_type (GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); - gtk_widget_show (frame); - gtk_container_add (GTK_CONTAINER(view->priv->search_window), frame); - - vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); - gtk_widget_show (vbox); - gtk_container_add (GTK_CONTAINER(frame), vbox); - gtk_container_set_border_width (GTK_CONTAINER(vbox), 3); - - /* add entry */ - view->priv->search_entry = gtk_entry_new (); - gtk_widget_show (view->priv->search_entry); - - g_signal_connect(view->priv->search_entry, "populate_popup", G_CALLBACK (search_entry_populate_popup), view); - g_signal_connect(view->priv->search_entry, "activate", G_CALLBACK (search_entry_activate), view); - g_signal_connect(view->priv->search_entry, "insert_text", G_CALLBACK (search_entry_insert_text), view); - - gtk_container_add (GTK_CONTAINER(vbox), view->priv->search_entry); - gtk_widget_realize (view->priv->search_entry); - - customize_for_search_mode (view); -} - -static gboolean -get_selected_text (GtkTextBuffer *doc, - gchar **selected_text, - gint *len) -{ - GtkTextIter start, end; - - g_return_val_if_fail(selected_text != NULL, FALSE); - g_return_val_if_fail(*selected_text == NULL, FALSE); - - if (!gtk_text_buffer_get_selection_bounds (doc, &start, &end)) - { - if (len != NULL) - { - len = 0; - } - return FALSE; - } - - *selected_text = gtk_text_buffer_get_slice (doc, &start, &end, TRUE); - - if (len != NULL) - { - *len = g_utf8_strlen (*selected_text, -1); - } - - return TRUE; -} - -static void -init_search_entry (XedView *view) -{ - gint line; - gchar *line_str; - - line = gtk_text_iter_get_line (&view->priv->start_search_iter); - line_str = g_strdup_printf ("%d", line + 1); - gtk_entry_set_text (GTK_ENTRY(view->priv->search_entry), line_str); - - g_free (line_str); - return; -} - -static void -search_init (GtkWidget *entry, - XedView *view) -{ - XedDocument *doc; - const gchar *entry_text; - - /* renew the flush timeout */ - if (view->priv->typeselect_flush_timeout != 0) - { - g_source_remove (view->priv->typeselect_flush_timeout); - view->priv->typeselect_flush_timeout = g_timeout_add (XED_VIEW_SEARCH_DIALOG_TIMEOUT, - (GSourceFunc) search_entry_flush_timeout, view); - } - doc = XED_DOCUMENT(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); - - entry_text = gtk_entry_get_text (GTK_ENTRY(entry)); - - if (*entry_text != '\0') - { - gboolean moved, moved_offset; - gint line; - gint offset_line = 0; - gint line_offset = 0; - gchar **split_text = NULL; - const gchar *text; - - split_text = g_strsplit (entry_text, ":", -1); - - if (g_strv_length (split_text) > 1) - { - text = split_text[0]; - } - else - { - text = entry_text; - } - - if (*text == '-') - { - gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter); - - if (*(text + 1) != '\0') - { - offset_line = MAX(atoi (text + 1), 0); - } - - line = MAX(cur_line - offset_line, 0); - } - else if (*entry_text == '+') - { - gint cur_line = gtk_text_iter_get_line (&view->priv->start_search_iter); - - if (*(text + 1) != '\0') - { - offset_line = MAX(atoi (text + 1), 0); - } - - line = cur_line + offset_line; - } - else - { - line = MAX(atoi (text) - 1, 0); - } - - if (split_text[1] != NULL) - { - line_offset = atoi (split_text[1]); - } - - g_strfreev (split_text); - - moved = xed_document_goto_line (doc, line); - moved_offset = xed_document_goto_line_offset (doc, line, line_offset); - - xed_view_scroll_to_cursor (view); - - if (!moved || !moved_offset) - { - set_entry_state (view->priv->search_entry, XED_SEARCH_ENTRY_NOT_FOUND); - } - else - { - set_entry_state (view->priv->search_entry, XED_SEARCH_ENTRY_NORMAL); - } - } -} - -static gboolean -start_interactive_goto_line (XedView *view) -{ - GtkTextBuffer *buffer; - - if ((view->priv->search_window != NULL) && gtk_widget_get_visible (view->priv->search_window)) - { - return TRUE; - } - - if (!gtk_widget_has_focus (GTK_WIDGET(view))) - { - return FALSE; - } - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW(view)); - - gtk_text_buffer_get_iter_at_mark (buffer, &view->priv->start_search_iter, gtk_text_buffer_get_insert (buffer)); - - ensure_search_window (view); - - /* done, show it */ - update_search_window_position (view); - gtk_widget_show (view->priv->search_window); - - if (view->priv->search_entry_changed_id == 0) - { - view->priv->search_entry_changed_id = g_signal_connect(view->priv->search_entry, "changed", - G_CALLBACK (search_init), view); - } - - init_search_entry (view); - - view->priv->typeselect_flush_timeout = g_timeout_add (XED_VIEW_SEARCH_DIALOG_TIMEOUT, - (GSourceFunc) search_entry_flush_timeout, view); - - gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW(view), FALSE); - gtk_widget_grab_focus (view->priv->search_entry); - - send_focus_change (view->priv->search_entry, TRUE); - - return TRUE; -} diff --git a/xed/xed-view.h b/xed/xed-view.h index 368be30..eab7295 100644 --- a/xed/xed-view.h +++ b/xed/xed-view.h @@ -46,9 +46,6 @@ struct _XedViewClass /* FIXME: Do we need placeholders ? */ /* Key bindings */ - gboolean (* start_interactive_search) (XedView *view); - gboolean (* start_interactive_goto_line)(XedView *view); - gboolean (* reset_searched_text) (XedView *view); void (* drop_uris) (XedView *view, gchar **uri_list); }; diff --git a/xed/xed-window.c b/xed/xed-window.c index 4a10c77..5b75854 100644 --- a/xed/xed-window.c +++ b/xed/xed-window.c @@ -18,6 +18,7 @@ #include "xed-notebook.h" #include "xed-statusbar.h" #include "xed-searchbar.h" +#include "xed-view-frame.h" #include "xed-utils.h" #include "xed-commands.h" #include "xed-debug.h" @@ -127,13 +128,26 @@ on_key_pressed (GtkWidget *widget, GdkEventKey *event, XedWindow *window) { - gint handled = FALSE; if (event->keyval == GDK_KEY_Escape) { - xed_searchbar_hide (XED_SEARCHBAR (window->priv->searchbar)); - handled = TRUE; + XedTab *tab; + XedViewFrame *frame; + + tab = xed_window_get_active_tab (window); + frame = XED_VIEW_FRAME (_xed_tab_get_view_frame (tab)); + + if (xed_view_frame_get_search_popup_visible (frame)) + { + return GDK_EVENT_PROPAGATE; + } + else + { + xed_searchbar_hide (XED_SEARCHBAR (window->priv->searchbar)); + return GDK_EVENT_STOP; + } } - return handled; + + return GDK_EVENT_PROPAGATE; } static void