Redesign the goto line popup dialog
This commit is contained in:
parent
7a06a119b5
commit
5d62c0c452
|
@ -64,6 +64,7 @@ NOINST_H_FILES = \
|
||||||
xed-tab-label.h \
|
xed-tab-label.h \
|
||||||
xedtextregion.h \
|
xedtextregion.h \
|
||||||
xed-ui.h \
|
xed-ui.h \
|
||||||
|
xed-view-frame.h \
|
||||||
xed-window-private.h
|
xed-window-private.h
|
||||||
|
|
||||||
INST_H_FILES = \
|
INST_H_FILES = \
|
||||||
|
@ -149,6 +150,7 @@ libxed_c_files = \
|
||||||
xed-utils.c \
|
xed-utils.c \
|
||||||
xed-view.c \
|
xed-view.c \
|
||||||
xed-view-activatable.c \
|
xed-view-activatable.c \
|
||||||
|
xed-view-frame.c \
|
||||||
xed-window.c \
|
xed-window.c \
|
||||||
xed-window-activatable.c \
|
xed-window-activatable.c \
|
||||||
xedtextregion.c
|
xedtextregion.c
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "xed-window.h"
|
#include "xed-window.h"
|
||||||
#include "xed-utils.h"
|
#include "xed-utils.h"
|
||||||
#include "xed-searchbar.h"
|
#include "xed-searchbar.h"
|
||||||
|
#include "xed-view-frame.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
_xed_cmd_search_find (GtkAction *action,
|
_xed_cmd_search_find (GtkAction *action,
|
||||||
|
@ -47,7 +48,9 @@ void
|
||||||
_xed_cmd_search_clear_highlight (XedWindow *window)
|
_xed_cmd_search_clear_highlight (XedWindow *window)
|
||||||
{
|
{
|
||||||
XedDocument *doc;
|
XedDocument *doc;
|
||||||
|
|
||||||
xed_debug (DEBUG_COMMANDS);
|
xed_debug (DEBUG_COMMANDS);
|
||||||
|
|
||||||
doc = xed_window_get_active_document (window);
|
doc = xed_window_get_active_document (window);
|
||||||
if (doc != NULL)
|
if (doc != NULL)
|
||||||
{
|
{
|
||||||
|
@ -59,19 +62,22 @@ void
|
||||||
_xed_cmd_search_goto_line (GtkAction *action,
|
_xed_cmd_search_goto_line (GtkAction *action,
|
||||||
XedWindow *window)
|
XedWindow *window)
|
||||||
{
|
{
|
||||||
XedView *active_view;
|
XedTab *active_tab;
|
||||||
|
XedViewFrame *frame;
|
||||||
|
|
||||||
xed_debug (DEBUG_COMMANDS);
|
xed_debug (DEBUG_COMMANDS);
|
||||||
|
|
||||||
active_view = xed_window_get_active_view (window);
|
active_tab = xed_window_get_active_tab (window);
|
||||||
if (active_view == NULL)
|
if (active_tab == NULL)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Focus the view if needed: we need to focus the view otherwise
|
/* Focus the view if needed: we need to focus the view otherwise
|
||||||
activating the binding for goto line has no effect */
|
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. */
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -727,11 +727,13 @@ xed_searchbar_show (XedSearchbar *searchbar,
|
||||||
void
|
void
|
||||||
xed_searchbar_hide (XedSearchbar *searchbar)
|
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_transition_type (GTK_REVEALER (searchbar->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
|
||||||
gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), FALSE);
|
gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), FALSE);
|
||||||
|
|
||||||
// focus document
|
// 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)
|
if (active_view != NULL)
|
||||||
{
|
{
|
||||||
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
gtk_widget_grab_focus (GTK_WIDGET (active_view));
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "xed-debug.h"
|
#include "xed-debug.h"
|
||||||
#include "xed-enum-types.h"
|
#include "xed-enum-types.h"
|
||||||
#include "xed-settings.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))
|
#define XED_TAB_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_TAB, XedTabPrivate))
|
||||||
|
|
||||||
|
@ -55,8 +56,7 @@ struct _XedTabPrivate
|
||||||
|
|
||||||
XedTabState state;
|
XedTabState state;
|
||||||
|
|
||||||
GtkWidget *view;
|
XedViewFrame *frame;
|
||||||
GtkWidget *view_scrolled_window;
|
|
||||||
|
|
||||||
GtkWidget *message_area;
|
GtkWidget *message_area;
|
||||||
GtkWidget *print_preview;
|
GtkWidget *print_preview;
|
||||||
|
@ -375,20 +375,22 @@ static void
|
||||||
set_view_properties_according_to_state (XedTab *tab,
|
set_view_properties_according_to_state (XedTab *tab,
|
||||||
XedTabState state)
|
XedTabState state)
|
||||||
{
|
{
|
||||||
|
XedView *view;
|
||||||
gboolean val;
|
gboolean val;
|
||||||
gboolean hl_current_line;
|
gboolean hl_current_line;
|
||||||
|
|
||||||
hl_current_line = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_HIGHLIGHT_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);
|
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));
|
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) &&
|
val = ((state != XED_TAB_STATE_LOADING) &&
|
||||||
(state != XED_TAB_STATE_CLOSING) &&
|
(state != XED_TAB_STATE_CLOSING) &&
|
||||||
(hl_current_line));
|
(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
|
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 */
|
if ((state == XED_TAB_STATE_LOADING_ERROR) || /* FIXME: add other states if needed */
|
||||||
(state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW))
|
(state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW))
|
||||||
{
|
{
|
||||||
gtk_widget_hide (tab->priv->view_scrolled_window);
|
gtk_widget_hide (GTK_WIDGET (tab->priv->frame));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tab->priv->print_preview == NULL)
|
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");
|
g_object_notify (G_OBJECT (tab), "state");
|
||||||
}
|
}
|
||||||
|
@ -969,7 +971,7 @@ document_loaded (XedDocument *document,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scroll to the cursor when the document is loaded */
|
/* 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 ());
|
all_documents = xed_app_get_documents (xed_app_get_default ());
|
||||||
|
|
||||||
|
@ -1408,24 +1410,13 @@ view_focused_in (GtkWidget *widget,
|
||||||
return FALSE;
|
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
|
static void
|
||||||
xed_tab_init (XedTab *tab)
|
xed_tab_init (XedTab *tab)
|
||||||
{
|
{
|
||||||
GtkWidget *sw;
|
|
||||||
XedDocument *doc;
|
|
||||||
gboolean auto_save;
|
gboolean auto_save;
|
||||||
guint auto_save_interval;
|
guint auto_save_interval;
|
||||||
|
XedDocument *doc;
|
||||||
|
XedView *view;
|
||||||
|
|
||||||
tab->priv = XED_TAB_GET_PRIVATE (tab);
|
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);
|
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 */
|
/* Manage auto save data */
|
||||||
auto_save = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_AUTO_SAVE);
|
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);
|
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 = (tab->priv->auto_save != FALSE);
|
||||||
|
|
||||||
tab->priv->auto_save_interval = auto_save_interval;
|
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 */
|
/* Create the frame */
|
||||||
doc = xed_document_new ();
|
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);
|
g_object_set_data (G_OBJECT (doc), XED_TAB_KEY, tab);
|
||||||
|
|
||||||
_xed_document_set_mount_operation_factory (doc, tab_mount_operation_factory, tab);
|
view = xed_view_frame_get_view (tab->priv->frame);
|
||||||
|
g_object_set_data (G_OBJECT (view), XED_TAB_KEY, 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);
|
|
||||||
|
|
||||||
g_signal_connect (doc, "notify::location",
|
g_signal_connect (doc, "notify::location",
|
||||||
G_CALLBACK (document_location_notify_handler), tab);
|
G_CALLBACK (document_location_notify_handler), tab);
|
||||||
|
@ -1486,9 +1463,9 @@ xed_tab_init (XedTab *tab)
|
||||||
g_signal_connect (doc, "saved",
|
g_signal_connect (doc, "saved",
|
||||||
G_CALLBACK (document_saved), tab);
|
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_CALLBACK (view_focused_in), tab);
|
||||||
g_signal_connect_after (tab->priv->view, "realize",
|
g_signal_connect_after (view, "realize",
|
||||||
G_CALLBACK (view_realized), tab);
|
G_CALLBACK (view_realized), tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1528,7 +1505,9 @@ _xed_tab_new_from_location (GFile *location,
|
||||||
XedView *
|
XedView *
|
||||||
xed_tab_get_view (XedTab *tab)
|
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 *
|
XedDocument *
|
||||||
xed_tab_get_document (XedTab *tab)
|
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
|
#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 */
|
/* FIXME: this can cause problems with the tab state machine */
|
||||||
set_message_area (tab, info_bar);
|
set_message_area (tab, info_bar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GtkWidget *
|
||||||
|
_xed_tab_get_view_frame (XedTab *tab)
|
||||||
|
{
|
||||||
|
return GTK_WIDGET (tab->priv->frame);
|
||||||
|
}
|
||||||
|
|
|
@ -132,6 +132,7 @@ void _xed_tab_print (XedTab *tab);
|
||||||
void _xed_tab_print_preview (XedTab *tab);
|
void _xed_tab_print_preview (XedTab *tab);
|
||||||
void _xed_tab_mark_for_closing (XedTab *tab);
|
void _xed_tab_mark_for_closing (XedTab *tab);
|
||||||
gboolean _xed_tab_can_close (XedTab *tab);
|
gboolean _xed_tab_can_close (XedTab *tab);
|
||||||
|
GtkWidget *_xed_tab_get_view_frame (XedTab *tab);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -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 <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "xed-view-frame.h"
|
||||||
|
#include "xed-marshal.h"
|
||||||
|
#include "xed-debug.h"
|
||||||
|
#include "xed-utils.h"
|
||||||
|
|
||||||
|
#include <gdk/gdkkeysyms.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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));
|
||||||
|
}
|
|
@ -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 <gtk/gtk.h>
|
||||||
|
#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__ */
|
549
xed/xed-view.c
549
xed/xed-view.c
|
@ -19,7 +19,6 @@
|
||||||
#include "xed-app.h"
|
#include "xed-app.h"
|
||||||
|
|
||||||
#define XED_VIEW_SCROLL_MARGIN 0.02
|
#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))
|
#define XED_VIEW_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_VIEW, XedViewPrivate))
|
||||||
|
|
||||||
|
@ -31,36 +30,22 @@ enum
|
||||||
struct _XedViewPrivate
|
struct _XedViewPrivate
|
||||||
{
|
{
|
||||||
GSettings *editor_settings;
|
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;
|
GtkTextBuffer *current_buffer;
|
||||||
PeasExtensionSet *extensions;
|
PeasExtensionSet *extensions;
|
||||||
guint view_realized : 1;
|
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 */
|
/* Signals */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
START_INTERACTIVE_GOTO_LINE, DROP_URIS, LAST_SIGNAL
|
DROP_URIS,
|
||||||
|
LAST_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
static guint view_signals[LAST_SIGNAL] = { 0 };
|
static guint view_signals[LAST_SIGNAL] = { 0 };
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
XED_SEARCH_ENTRY_NORMAL, XED_SEARCH_ENTRY_NOT_FOUND
|
|
||||||
} XedSearchEntryState;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
document_read_only_notify_handler (XedDocument *document,
|
document_read_only_notify_handler (XedDocument *document,
|
||||||
GParamSpec *pspec,
|
GParamSpec *pspec,
|
||||||
|
@ -177,8 +162,6 @@ xed_view_init (XedView *view)
|
||||||
|
|
||||||
view->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
|
view->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
|
||||||
|
|
||||||
view->priv->typeselect_flush_timeout = 0;
|
|
||||||
|
|
||||||
/* Drag and drop support */
|
/* Drag and drop support */
|
||||||
tl = gtk_drag_dest_get_target_list (GTK_WIDGET(view));
|
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->extensions);
|
||||||
g_clear_object (&view->priv->editor_settings);
|
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);
|
current_buffer_removed (view);
|
||||||
|
|
||||||
/* Disconnect notify buffer because the destroy of the textview will set
|
/* Disconnect notify buffer because the destroy of the textview will set
|
||||||
|
@ -328,16 +299,8 @@ static gint
|
||||||
xed_view_focus_out (GtkWidget *widget,
|
xed_view_focus_out (GtkWidget *widget,
|
||||||
GdkEventFocus *event)
|
GdkEventFocus *event)
|
||||||
{
|
{
|
||||||
XedView *view = XED_VIEW (widget);
|
|
||||||
|
|
||||||
gtk_widget_queue_draw (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);
|
GTK_WIDGET_CLASS (xed_view_parent_class)->focus_out_event (widget, event);
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -508,13 +471,11 @@ static gboolean
|
||||||
xed_view_button_press_event (GtkWidget *widget,
|
xed_view_button_press_event (GtkWidget *widget,
|
||||||
GdkEventButton *event)
|
GdkEventButton *event)
|
||||||
{
|
{
|
||||||
if ((event->type == GDK_BUTTON_PRESS)
|
if ((event->type == GDK_BUTTON_PRESS) &&
|
||||||
&& (event->button == 3)
|
(event->button == 3) &&
|
||||||
&& (event->window == gtk_text_view_get_window (GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_LEFT)))
|
(event->window == gtk_text_view_get_window (GTK_TEXT_VIEW(widget), GTK_TEXT_WINDOW_LEFT)))
|
||||||
{
|
{
|
||||||
|
|
||||||
show_line_numbers_menu (widget, event);
|
show_line_numbers_menu (widget, event);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,19 +636,9 @@ xed_view_class_init (XedViewClass *klass)
|
||||||
widget_class->drag_drop = xed_view_drag_drop;
|
widget_class->drag_drop = xed_view_drag_drop;
|
||||||
widget_class->button_press_event = xed_view_button_press_event;
|
widget_class->button_press_event = xed_view_button_press_event;
|
||||||
widget_class->realize = xed_view_realize;
|
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;
|
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
|
/* A new signal DROP_URIS has been added to allow plugins to intercept
|
||||||
* the default dnd behaviour of 'text/uri-list'. XedView now handles
|
* the default dnd behaviour of 'text/uri-list'. XedView now handles
|
||||||
* dnd in the default handlers of drag_drop, drag_motion and
|
* 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);
|
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_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);
|
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);
|
gtk_widget_modify_font (GTK_WIDGET (view), font_desc);
|
||||||
pango_font_description_free (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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -46,9 +46,6 @@ struct _XedViewClass
|
||||||
/* FIXME: Do we need placeholders ? */
|
/* FIXME: Do we need placeholders ? */
|
||||||
|
|
||||||
/* Key bindings */
|
/* 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);
|
void (* drop_uris) (XedView *view, gchar **uri_list);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "xed-notebook.h"
|
#include "xed-notebook.h"
|
||||||
#include "xed-statusbar.h"
|
#include "xed-statusbar.h"
|
||||||
#include "xed-searchbar.h"
|
#include "xed-searchbar.h"
|
||||||
|
#include "xed-view-frame.h"
|
||||||
#include "xed-utils.h"
|
#include "xed-utils.h"
|
||||||
#include "xed-commands.h"
|
#include "xed-commands.h"
|
||||||
#include "xed-debug.h"
|
#include "xed-debug.h"
|
||||||
|
@ -127,13 +128,26 @@ on_key_pressed (GtkWidget *widget,
|
||||||
GdkEventKey *event,
|
GdkEventKey *event,
|
||||||
XedWindow *window)
|
XedWindow *window)
|
||||||
{
|
{
|
||||||
gint handled = FALSE;
|
|
||||||
if (event->keyval == GDK_KEY_Escape)
|
if (event->keyval == GDK_KEY_Escape)
|
||||||
{
|
{
|
||||||
xed_searchbar_hide (XED_SEARCHBAR (window->priv->searchbar));
|
XedTab *tab;
|
||||||
handled = TRUE;
|
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;
|
||||||
}
|
}
|
||||||
return handled;
|
else
|
||||||
|
{
|
||||||
|
xed_searchbar_hide (XED_SEARCHBAR (window->priv->searchbar));
|
||||||
|
return GDK_EVENT_STOP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GDK_EVENT_PROPAGATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
Loading…
Reference in New Issue