Enable type-ahead find for sidebar symbols and documents tabs

(patch by Thomas Martitz, thanks).



git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@4148 ea778897-0a13-0410-b9d1-a72fbfd435f5
This commit is contained in:
Nick Treleaven 2009-09-03 12:04:27 +00:00
parent a1ca1ed099
commit a4eec38feb
5 changed files with 130 additions and 101 deletions

View File

@ -1,3 +1,10 @@
2009-09-03 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
* src/treeviews.c, src/document.c, src/document.h, THANKS:
Enable type-ahead find for sidebar symbols and documents tabs
(patch by Thomas Martitz, thanks).
2009-09-03 Lex Trotman <elextr(at)gmail(dot)com>
* src/build.c, src/filetypes.h, src/filetypes.c

2
THANKS
View File

@ -59,7 +59,7 @@ Walery Studennikov <despairr(at)gmail(dot)com> - YAML filetype patch
Guillaume de Rorthais <ioguix(at)free(dot)fr> - Auto-close brackets/braces/quotes patch
Tyler Mulligan <tyler(at)doknowevil(dot)net> - Close All toolbar icon
Philipp Gildein <philipp(at)gildein(dot)com> - Ada filetype patch
Thomas Martitz <thomas47(at)arcor(dot)de> - Multiple %cursor% wildcards in Snippets patch
Thomas Martitz <thomas47(at)arcor(dot)de> - Multiple %cursor% in Snippets, typeahead sidebar patch
David Gleich <dgleich(at)stanford(dot)edu> - Send Selection to Terminal patch
Chris Macksey <cmacksey(at)users(dot)sourceforge(dot)net> - ActionScript filetype patch
Simon Treny <simon(dot)treny(at)free(dot)fr> - Documents sidebar stock icons patch

View File

@ -513,19 +513,40 @@ static void monitor_file_setup(GeanyDocument *doc)
}
void document_try_focus(GeanyDocument *doc)
{
/* doc might not be valid e.g. if user closed a tab whilst Geany is opening files */
if (DOC_VALID(doc))
{
GtkWidget *sci = GTK_WIDGET(doc->editor->sci);
GtkWidget *focusw = gtk_window_get_focus(GTK_WINDOW(main_widgets.window));
if (focusw == doc->priv->tag_tree)
gtk_widget_grab_focus(sci);
}
}
static gboolean on_idle_focus(gpointer doc)
{
document_try_focus(doc);
return FALSE;
}
/* Creates a new document and editor, adding a tab in the notebook.
* @return The created document */
static GeanyDocument *document_create(const gchar *utf8_filename)
{
GeanyDocument *this;
GeanyDocument *doc;
gint new_idx;
gint cur_pages = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
if (cur_pages == 1)
{
GeanyDocument *doc = document_get_current();
GeanyDocument *cur = document_get_current();
/* remove the empty document and open a new one */
if (doc != NULL && doc->file_name == NULL && ! doc->changed)
if (cur != NULL && cur->file_name == NULL && ! cur->changed)
document_remove_page(0);
}
@ -537,36 +558,35 @@ static GeanyDocument *document_create(const gchar *utf8_filename)
new_idx = documents_array->len;
g_ptr_array_add(documents_array, new_doc);
}
this = documents[new_idx];
init_doc_struct(this); /* initialize default document settings */
this->index = new_idx;
doc = documents[new_idx];
init_doc_struct(doc); /* initialize default document settings */
doc->index = new_idx;
this->file_name = g_strdup(utf8_filename);
doc->file_name = g_strdup(utf8_filename);
this->editor = editor_create(this);
doc->editor = editor_create(doc);
editor_apply_update_prefs(this->editor);
editor_apply_update_prefs(doc->editor);
treeviews_openfiles_add(this); /* sets this->iter */
treeviews_openfiles_add(doc); /* sets doc->iter */
notebook_new_tab(this);
notebook_new_tab(doc);
/* select document in sidebar */
{
GtkTreeSelection *sel;
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv.tree_openfiles));
gtk_tree_selection_select_iter(sel, &this->priv->iter);
gtk_tree_selection_select_iter(sel, &doc->priv->iter);
}
ui_document_buttons_update();
gtk_widget_grab_focus(GTK_WIDGET(this->editor->sci));
this->is_valid = TRUE; /* do this last to prevent UI updating with NULL items. */
return this;
doc->is_valid = TRUE; /* do this last to prevent UI updating with NULL items. */
return doc;
}
/**
* Close the given document.
*
@ -729,7 +749,9 @@ GeanyDocument *document_new_file(const gchar *utf8_filename, GeanyFiletype *ft,
ui_document_show_hide(doc); /* update the document menu */
sci_set_line_numbers(doc->editor->sci, editor_prefs.show_linenumber_margin, 0);
sci_goto_pos(doc->editor->sci, 0, TRUE);
/* bring it in front, jump to the start and grab the focus */
editor_goto_pos(doc->editor, 0, FALSE);
document_try_focus(doc);
#if USE_GIO_FILEMON
monitor_file_setup(doc);
@ -996,8 +1018,10 @@ static gboolean load_text_file(const gchar *locale_filename, const gchar *displa
/* Sets the cursor position on opening a file. First it sets the line when cl_options.goto_line
* is set, otherwise it sets the line when pos is greater than zero and finally it sets the column
* if cl_options.goto_column is set. */
static void set_cursor_position(GeanyEditor *editor, gint pos)
* if cl_options.goto_column is set.
*
* returns the new position which may have changed */
static int set_cursor_position(GeanyEditor *editor, gint pos)
{
if (cl_options.goto_line >= 0)
{ /* goto line which was specified on command line and then undefine the line */
@ -1013,11 +1037,14 @@ static void set_cursor_position(GeanyEditor *editor, gint pos)
if (cl_options.goto_column >= 0)
{ /* goto column which was specified on command line and then undefine the column */
gint cur_pos = sci_get_current_position(editor->sci);
sci_set_current_position(editor->sci, cur_pos + cl_options.goto_column, FALSE);
gint new_pos = sci_get_current_position(editor->sci) + cl_options.goto_column;
sci_set_current_position(editor->sci, new_pos, FALSE);
editor->scroll_percent = 0.5F;
cl_options.goto_column = -1;
return new_pos;
}
return sci_get_current_position(editor->sci);
}
@ -1204,14 +1231,10 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
if (doc != NULL)
{
ui_add_recent_file(utf8_filename); /* either add or reorder recent item */
gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook),
gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook),
(GtkWidget*) doc->editor->sci));
g_free(utf8_filename);
g_free(locale_filename);
document_check_disk_status(doc, TRUE); /* force a file changed check */
set_cursor_position(doc->editor, pos);
return doc;
goto end;
}
}
display_filename = utils_str_middle_truncate(utf8_filename, 100);
@ -1269,7 +1292,7 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
sci_set_line_numbers(doc->editor->sci, editor_prefs.show_linenumber_margin, 0);
/* set the cursor position according to pos, cl_options.goto_line and cl_options.goto_column */
set_cursor_position(doc->editor, pos);
pos = set_cursor_position(doc->editor, pos);
if (! reload)
{
@ -1323,6 +1346,13 @@ GeanyDocument *document_open_file_full(GeanyDocument *doc, const gchar *filename
* based on a configurable interval */
/*g_timeout_add(10000, auto_update_tag_list, doc);*/
end:
/* now bring the file in front */
editor_goto_pos(doc->editor, pos, FALSE);
/* finally, let the editor widget grab the focus so you can start coding
* right away */
g_idle_add(on_idle_focus, doc);
return doc;
}

View File

@ -184,6 +184,8 @@ void document_finalize(void);
gboolean document_remove_page(guint page_num);
void document_try_focus(GeanyDocument *doc);
gboolean document_close(GeanyDocument *doc);
gboolean document_account_for_unsaved(void);

View File

@ -42,10 +42,13 @@
#include "project.h"
#include "stash.h"
#include "keyfile.h"
#include "sciwrappers.h"
#include <gdk/gdkkeysyms.h>
SidebarTreeviews tv = {NULL, NULL, NULL};
/* while typeahead searching, editor should not get focus */
static gboolean may_steal_focus = FALSE;
static struct
{
@ -85,17 +88,16 @@ static gboolean documents_show_paths;
static GtkWidget *tag_window; /* scrolled window that holds the symbol list GtkTreeView */
/* callback prototypes */
static void on_openfiles_tree_selection_changed(GtkTreeSelection *selection, gpointer data);
static gboolean on_openfiles_tree_selection_changed(GtkTreeSelection *selection);
static void on_openfiles_document_action(GtkMenuItem *menuitem, gpointer user_data);
static gboolean on_taglist_tree_selection_changed(GtkTreeSelection *selection);
static gboolean on_symbols_button_press_event(GtkWidget *widget, GdkEventButton *event,
static gboolean treeviews_button_press_cb(GtkWidget *widget, GdkEventButton *event,
gpointer user_data);
static gboolean on_documents_button_release_event(GtkWidget *widget, GdkEventButton *event,
gpointer user_data);
static gboolean on_treeviews_key_press_event(GtkWidget *widget, GdkEventKey *event,
static gboolean treeviews_key_press_cb(GtkWidget *widget, GdkEventKey *event,
gpointer user_data);
static void on_list_document_activate(GtkCheckMenuItem *item, gpointer user_data);
static void on_list_symbol_activate(GtkCheckMenuItem *item, gpointer user_data);
static void documents_menu_update(GtkTreeSelection *selection);
/* the prepare_* functions are document-related, but I think they fit better here than in document.c */
@ -107,9 +109,9 @@ static void prepare_taglist(GtkWidget *tree, GtkTreeStore *store)
text_renderer = gtk_cell_renderer_text_new();
icon_renderer = gtk_cell_renderer_pixbuf_new();
column = gtk_tree_view_column_new();
column = gtk_tree_view_column_new();
gtk_tree_view_column_pack_start(column, icon_renderer, FALSE);
gtk_tree_view_column_pack_start(column, icon_renderer, FALSE);
gtk_tree_view_column_set_attributes(column, icon_renderer, "pixbuf", SYMBOLS_COLUMN_ICON, NULL);
g_object_set(icon_renderer, "xalign", 0.0, NULL);
@ -127,11 +129,9 @@ static void prepare_taglist(GtkWidget *tree, GtkTreeStore *store)
g_object_unref(store);
g_signal_connect(tree, "button-press-event",
G_CALLBACK(on_symbols_button_press_event), NULL);
G_CALLBACK(treeviews_button_press_cb), NULL);
g_signal_connect(tree, "key-press-event",
G_CALLBACK(on_treeviews_key_press_event), GINT_TO_POINTER(TREEVIEW_SYMBOL));
gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree), FALSE);
G_CALLBACK(treeviews_key_press_cb), NULL);
if (gtk_check_version(2, 12, 0) == NULL)
{
@ -242,13 +242,12 @@ static void prepare_openfiles(void)
store_openfiles = gtk_tree_store_new(5, G_TYPE_STRING, G_TYPE_STRING,
G_TYPE_POINTER, GDK_TYPE_COLOR, G_TYPE_STRING);
gtk_tree_view_set_model(GTK_TREE_VIEW(tv.tree_openfiles), GTK_TREE_MODEL(store_openfiles));
g_object_unref(store_openfiles);
/* set policy settings for the scolledwindow around the treeview again, because glade
* doesn't keep the settings */
gtk_scrolled_window_set_policy(
GTK_SCROLLED_WINDOW(ui_lookup_widget(main_widgets.window, "scrolledwindow7")),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
GTK_SCROLLED_WINDOW(ui_lookup_widget(main_widgets.window, "scrolledwindow7")),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
icon_renderer = gtk_cell_renderer_pixbuf_new();
text_renderer = gtk_cell_renderer_text_new();
@ -262,7 +261,8 @@ static void prepare_openfiles(void)
gtk_tree_view_append_column(GTK_TREE_VIEW(tv.tree_openfiles), column);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv.tree_openfiles), FALSE);
gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tv.tree_openfiles), FALSE);
gtk_tree_view_set_search_column(GTK_TREE_VIEW(tv.tree_openfiles),
DOCUMENTS_SHORTNAME);
/* sort opened filenames in the store_openfiles treeview */
sortable = GTK_TREE_SORTABLE(GTK_TREE_MODEL(store_openfiles));
@ -274,13 +274,15 @@ static void prepare_openfiles(void)
if (gtk_check_version(2, 12, 0) == NULL)
g_object_set(tv.tree_openfiles, "has-tooltip", TRUE, "tooltip-column", DOCUMENTS_FILENAME, NULL);
g_signal_connect(tv.tree_openfiles, "button-release-event",
G_CALLBACK(on_documents_button_release_event), NULL);
/* selection handling */
select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv.tree_openfiles));
gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
g_signal_connect(select, "changed", G_CALLBACK(on_openfiles_tree_selection_changed), NULL);
g_object_unref(store_openfiles);
g_signal_connect(GTK_TREE_VIEW(tv.tree_openfiles), "button-press-event",
G_CALLBACK(treeviews_button_press_cb), NULL);
g_signal_connect(GTK_TREE_VIEW(tv.tree_openfiles), "key-press-event",
G_CALLBACK(treeviews_key_press_cb), NULL);
}
@ -702,30 +704,15 @@ static void on_openfiles_document_action(GtkMenuItem *menuitem, gpointer user_da
}
static gboolean change_focus_to_editor(GeanyDocument *doc, GtkWidget *focus_widget)
static void change_focus_to_editor(GeanyDocument *doc)
{
/* idx might not be valid e.g. if user closed a tab whilst Geany is opening files */
if (DOC_VALID(doc))
{
GtkWidget *focusw = gtk_window_get_focus(GTK_WINDOW(main_widgets.window));
GtkWidget *sci = GTK_WIDGET(doc->editor->sci);
if (focusw == focus_widget)
gtk_widget_grab_focus(sci);
}
return FALSE;
if (may_steal_focus)
document_try_focus(doc);
may_steal_focus = FALSE;
}
static gboolean change_focus_cb(gpointer data)
{
change_focus_to_editor(data, tv.tree_openfiles);
return FALSE;
}
static void on_openfiles_tree_selection_changed(GtkTreeSelection *selection, gpointer data)
static gboolean on_openfiles_tree_selection_changed(GtkTreeSelection *selection)
{
GtkTreeIter iter;
GtkTreeModel *model;
@ -734,14 +721,18 @@ static void on_openfiles_tree_selection_changed(GtkTreeSelection *selection, gpo
/* use switch_notebook_page to ignore changing the notebook page because it is already done */
if (gtk_tree_selection_get_selected(selection, &model, &iter) && ! ignore_callback)
{
gint pos;
gtk_tree_model_get(model, &iter, DOCUMENTS_DOCUMENT, &doc, -1);
if (! doc)
return; /* parent */
gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.notebook),
gtk_notebook_page_num(GTK_NOTEBOOK(main_widgets.notebook),
(GtkWidget*) doc->editor->sci));
g_idle_add((GSourceFunc) change_focus_cb, doc);
return FALSE; /* parent */
pos = sci_get_current_position(doc->editor->sci);
/* we could just reload, but that would destroy the notification about
* the file being modified if it was externally, so fill in all required fields */
document_open_file_full(NULL, doc->file_name, pos,
doc->readonly, doc->file_type, doc->encoding);
}
return FALSE;
}
@ -767,7 +758,7 @@ static gboolean on_taglist_tree_selection_changed(GtkTreeSelection *selection)
if (doc != NULL)
{
navqueue_goto_line(doc, doc, line);
change_focus_to_editor(doc, doc->priv->tag_tree);
change_focus_to_editor(doc);
}
}
}
@ -775,29 +766,35 @@ static gboolean on_taglist_tree_selection_changed(GtkTreeSelection *selection)
}
static gboolean on_treeviews_key_press_event(GtkWidget *widget, GdkEventKey *event,
static gboolean treeviews_key_press_cb(GtkWidget *widget, GdkEventKey *event,
gpointer user_data)
{
may_steal_focus = FALSE;
if (event->keyval == GDK_Return ||
event->keyval == GDK_ISO_Enter ||
event->keyval == GDK_KP_Enter ||
event->keyval == GDK_space)
{
may_steal_focus = TRUE;
GtkTreeSelection *select = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
/* delay the query of selection state because this callback is executed before GTK
* changes the selection (g_signal_connect_after would be better but it doesn't work) */
g_idle_add((GSourceFunc) on_taglist_tree_selection_changed, select);
if (widget == tv.tree_openfiles) /* tag and doc list have separate handlers */
g_idle_add((GSourceFunc) on_openfiles_tree_selection_changed, select);
else
g_idle_add((GSourceFunc) on_taglist_tree_selection_changed, select);
}
return FALSE;
}
static gboolean on_symbols_button_press_event(GtkWidget *widget, GdkEventButton *event,
static gboolean treeviews_button_press_cb(GtkWidget *widget, GdkEventButton *event,
G_GNUC_UNUSED gpointer user_data)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
may_steal_focus = TRUE;
if (event->type == GDK_2BUTTON_PRESS)
{ /* double click on parent node(section) expands/collapses it */
@ -824,18 +821,31 @@ static gboolean on_symbols_button_press_event(GtkWidget *widget, GdkEventButton
{ /* allow reclicking of taglist treeview item */
/* delay the query of selection state because this callback is executed before GTK
* changes the selection (g_signal_connect_after would be better but it doesn't work) */
g_idle_add((GSourceFunc) on_taglist_tree_selection_changed, selection);
if (widget == tv.tree_openfiles)
g_idle_add((GSourceFunc) on_openfiles_tree_selection_changed, selection);
else
g_idle_add((GSourceFunc) on_taglist_tree_selection_changed, selection);
}
else if (event->button == 3)
{
gtk_menu_popup(GTK_MENU(tv.popup_taglist), NULL, NULL, NULL, NULL,
event->button, event->time);
return TRUE; /* prevent selection changed signal for symbol tags */
documents_menu_update(selection);
if (widget == tv.tree_openfiles)
{
if (!openfiles_popup_menu)
create_openfiles_popup_menu();
gtk_menu_popup(GTK_MENU(openfiles_popup_menu), NULL, NULL, NULL, NULL,
event->button, event->time);
}
else
{
gtk_menu_popup(GTK_MENU(tv.popup_taglist), NULL, NULL, NULL, NULL,
event->button, event->time);
}
}
return FALSE;
}
static void documents_menu_update(GtkTreeSelection *selection)
{
GtkTreeModel *model;
@ -866,26 +876,6 @@ static void documents_menu_update(GtkTreeSelection *selection)
}
static gboolean on_documents_button_release_event(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
if (event->button == 3)
{
if (!openfiles_popup_menu)
create_openfiles_popup_menu();
documents_menu_update(selection);
gtk_menu_popup(GTK_MENU(openfiles_popup_menu), NULL, NULL, NULL, NULL,
event->button, event->time);
}
return FALSE;
}
GeanyPrefGroup *stash_group = NULL;
static void on_load_settings(void)