Revision: 1065 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=1065&view=re... Author: eht16 Date: 2009-11-28 16:54:23 +0000 (Sat, 28 Nov 2009)
Log Message: ----------- Complete rewrite of the Tasks Addon. Changes: - Works on all open documents, not only on the current one - Rescan for tokens only on document open/save/close - Add keybinding to activate the Tasks tab
Modified Paths: -------------- trunk/geany-plugins/addons/ChangeLog trunk/geany-plugins/addons/src/Makefile.am trunk/geany-plugins/addons/src/addons.c trunk/geany-plugins/po/POTFILES.in
Added Paths: ----------- trunk/geany-plugins/addons/src/ao_tasks.c trunk/geany-plugins/addons/src/ao_tasks.h
Removed Paths: ------------- trunk/geany-plugins/addons/src/tasks.c trunk/geany-plugins/addons/src/tasks.h
Modified: trunk/geany-plugins/addons/ChangeLog =================================================================== --- trunk/geany-plugins/addons/ChangeLog 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/addons/ChangeLog 2009-11-28 16:54:23 UTC (rev 1065) @@ -1,3 +1,13 @@ +2009-11-28 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> + + * src/Makefile.am, src/tasks.c, src/tasks.h, src/ao_tasks.h, + src/ao_tasks.c, src/addons.c: + Complete rewrite of the Tasks Addon. Changes: + - Works on all open documents, not only on the current one + - Rescan for tokens only on document open/save/close + - Add keybinding to activate the Tasks tab + + 2009-11-04 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
* src/ao_bookmarklist.c:
Modified: trunk/geany-plugins/addons/src/Makefile.am =================================================================== --- trunk/geany-plugins/addons/src/Makefile.am 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/addons/src/Makefile.am 2009-11-28 16:54:23 UTC (rev 1065) @@ -10,13 +10,13 @@ ao_systray.h \ ao_bookmarklist.h \ ao_markword.h \ - tasks.h \ + ao_tasks.h \ addons.c \ ao_doclist.c \ ao_openuri.c \ ao_systray.c \ ao_bookmarklist.c \ ao_markword.c \ - tasks.c + ao_tasks.c
addons_la_LIBADD = $(COMMONLIBS)
Modified: trunk/geany-plugins/addons/src/addons.c =================================================================== --- trunk/geany-plugins/addons/src/addons.c 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/addons/src/addons.c 2009-11-28 16:54:23 UTC (rev 1065) @@ -29,7 +29,7 @@ #include "ao_systray.h" #include "ao_bookmarklist.h" #include "ao_markword.h" -#include "tasks.h" +#include "ao_tasks.h"
@@ -47,6 +47,7 @@ enum { KB_FOCUS_BOOKMARK_LIST, + KB_FOCUS_TASKS, KB_COUNT };
@@ -69,6 +70,7 @@ AoSystray *systray; AoBookmarkList *bookmarklist; AoMarkWord *markword; + AoTasks *tasks; } AddonsInfo; static AddonsInfo *ao_info = NULL;
@@ -77,6 +79,9 @@ static void ao_update_editor_menu_cb(GObject *obj, const gchar *word, gint pos, GeanyDocument *doc, gpointer data); static void ao_document_activate_cb(GObject *obj, GeanyDocument *doc, gpointer data); +static void ao_document_open_cb(GObject *obj, GeanyDocument *doc, gpointer data); +static void ao_document_save_cb(GObject *obj, GeanyDocument *doc, gpointer data); +static void ao_document_close_cb(GObject *obj, GeanyDocument *doc, gpointer data); gboolean ao_editor_notify_cb(GObject *object, GeanyEditor *editor, SCNotification *nt, gpointer data);
@@ -86,8 +91,9 @@ { "update-editor-menu", (GCallback) &ao_update_editor_menu_cb, FALSE, NULL },
{ "editor-notify", (GCallback) &ao_editor_notify_cb, TRUE, NULL }, - { "document-open", (GCallback) &tasks_on_document_open, TRUE, NULL }, - { "document-close", (GCallback) &tasks_on_document_close, TRUE, NULL }, + { "document-open", (GCallback) &ao_document_open_cb, TRUE, NULL }, + { "document-save", (GCallback) &ao_document_save_cb, TRUE, NULL }, + { "document-close", (GCallback) &ao_document_close_cb, TRUE, NULL }, { "document-activate", (GCallback) &ao_document_activate_cb, TRUE, NULL },
{ NULL, NULL, FALSE, NULL } @@ -100,17 +106,19 @@ }
+static void kb_tasks_activate(guint key_id) +{ + ao_tasks_activate(ao_info->tasks); +} + + gboolean ao_editor_notify_cb(GObject *object, GeanyEditor *editor, SCNotification *nt, gpointer data) { - gboolean ret = FALSE; - ao_bookmark_list_update_marker(ao_info->bookmarklist, editor, nt); ao_mark_word_check(ao_info->markword, editor, nt);
- ret = tasks_on_editor_notify(object, editor, nt, data); - - return ret; + return FALSE; }
@@ -127,11 +135,34 @@ { g_return_if_fail(doc != NULL && doc->is_valid);
- tasks_on_document_activate(obj, doc, data); ao_bookmark_list_update(ao_info->bookmarklist, doc); }
+static void ao_document_open_cb(GObject *obj, GeanyDocument *doc, gpointer data) +{ + g_return_if_fail(doc != NULL && doc->is_valid); + + ao_tasks_update(ao_info->tasks, doc); +} + + +static void ao_document_close_cb(GObject *obj, GeanyDocument *doc, gpointer data) +{ + g_return_if_fail(doc != NULL && doc->is_valid); + + ao_tasks_update(ao_info->tasks, doc); +} + + +static void ao_document_save_cb(GObject *obj, GeanyDocument *doc, gpointer data) +{ + g_return_if_fail(doc != NULL && doc->is_valid); + + ao_tasks_update(ao_info->tasks, doc); +} + + GtkWidget *ao_image_menu_item_new(const gchar *stock_id, const gchar *label) { GtkWidget *item = gtk_image_menu_item_new_with_label(label); @@ -175,13 +206,14 @@ ao_info->systray = ao_systray_new(ao_info->enable_systray); ao_info->bookmarklist = ao_bookmark_list_new(ao_info->enable_bookmarklist); ao_info->markword = ao_mark_word_new(ao_info->enable_markword); + ao_info->tasks = ao_tasks_new(ao_info->enable_tasks);
- tasks_set_enable(ao_info->enable_tasks); - /* setup keybindings */ key_group = plugin_set_key_group(geany_plugin, "addons", KB_COUNT, NULL); keybindings_set_item(key_group, KB_FOCUS_BOOKMARK_LIST, kb_bmlist_activate, 0, 0, "focus_bookmark_list", _("Focus Bookmark List"), NULL); + keybindings_set_item(key_group, KB_FOCUS_TASKS, kb_tasks_activate, + 0, 0, "focus_tasks", _("Focus Tasks List"), NULL); }
@@ -205,6 +237,8 @@ g_object_get_data(G_OBJECT(dialog), "check_bookmarklist")))); ao_info->enable_markword = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( g_object_get_data(G_OBJECT(dialog), "check_markword")))); + ao_info->enable_tasks = (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( + g_object_get_data(G_OBJECT(dialog), "check_tasks"))));
g_key_file_load_from_file(config, ao_info->config_file, G_KEY_FILE_NONE, NULL); g_key_file_set_boolean(config, "addons", @@ -222,7 +256,7 @@ g_object_set(ao_info->bookmarklist, "enable-bookmarklist", ao_info->enable_bookmarklist, NULL); g_object_set(ao_info->markword, "enable-markword", ao_info->enable_markword, NULL); - tasks_set_enable(ao_info->enable_tasks); + g_object_set(ao_info->tasks, "enable-tasks", ao_info->enable_tasks, NULL);
if (! g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0) { @@ -263,7 +297,7 @@ gtk_box_pack_start(GTK_BOX(vbox), check_openuri, FALSE, FALSE, 3);
check_tasks = gtk_check_button_new_with_label( - _("Show available tasks in the Message Window")); + _("Show available Tasks in the Messages Window")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_tasks), ao_info->enable_tasks); gtk_box_pack_start(GTK_BOX(vbox), check_tasks, FALSE, FALSE, 3); @@ -311,9 +345,8 @@ g_object_unref(ao_info->systray); g_object_unref(ao_info->bookmarklist); g_object_unref(ao_info->markword); + g_object_unref(ao_info->tasks);
- tasks_set_enable(FALSE); - g_free(ao_info->config_file); g_free(ao_info); }
Added: trunk/geany-plugins/addons/src/ao_tasks.c =================================================================== --- trunk/geany-plugins/addons/src/ao_tasks.c (rev 0) +++ trunk/geany-plugins/addons/src/ao_tasks.c 2009-11-28 16:54:23 UTC (rev 1065) @@ -0,0 +1,359 @@ +/* + * ao_tasks.c - this file is part of Addons, a Geany plugin + * + * Copyright 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + + +#include <gtk/gtk.h> +#include <glib-object.h> + +#include "geanyplugin.h" + +#include "addons.h" +#include "ao_tasks.h" + +#include <gdk/gdkkeysyms.h> + + +/* Make tokens configurable */ +const gchar *tokens[] = { "TODO", "FIXME", NULL }; + + +typedef struct _AoTasksPrivate AoTasksPrivate; + +#define AO_TASKS_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), \ + AO_TASKS_TYPE, AoTasksPrivate)) + +struct _AoTasks +{ + GObject parent; +}; + +struct _AoTasksClass +{ + GObjectClass parent_class; +}; + +struct _AoTasksPrivate +{ + gboolean enable_tasks; + + GtkListStore *store; + GtkWidget *tree; + + GtkWidget *page; +}; + +enum +{ + PROP_0, + PROP_ENABLE_TASKS +}; + +enum +{ + TLIST_COL_FILENAME, + TLIST_COL_DISPLAY_FILENAME, + TLIST_COL_LINE, + TLIST_COL_NAME, + TLIST_COL_TOOLTIP, + TLIST_COL_MAX +}; + +static void ao_tasks_finalize (GObject *object); +static void ao_tasks_show (AoTasks *t); +static void ao_tasks_hide (AoTasks *t); + +G_DEFINE_TYPE(AoTasks, ao_tasks, G_TYPE_OBJECT); + + +static void ao_tasks_set_property(GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(object); + + switch (prop_id) + { + case PROP_ENABLE_TASKS: + { + gboolean new_val = g_value_get_boolean(value); + if (new_val && ! priv->enable_tasks) + ao_tasks_show(AO_TASKS(object)); + if (! new_val && priv->enable_tasks) + ao_tasks_hide(AO_TASKS(object)); + + priv->enable_tasks = new_val; + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + + +static void ao_tasks_class_init(AoTasksClass *klass) +{ + GObjectClass *g_object_class; + + g_object_class = G_OBJECT_CLASS(klass); + g_object_class->finalize = ao_tasks_finalize; + g_object_class->set_property = ao_tasks_set_property; + g_type_class_add_private(klass, sizeof(AoTasksPrivate)); + + g_object_class_install_property(g_object_class, + PROP_ENABLE_TASKS, + g_param_spec_boolean( + "enable-tasks", + "enable-tasks", + "Whether to show list of defined tasks", + TRUE, + G_PARAM_WRITABLE)); +} + + +static void ao_tasks_finalize(GObject *object) +{ + g_return_if_fail(object != NULL); + g_return_if_fail(IS_AO_TASKS(object)); + + ao_tasks_hide(AO_TASKS(object)); + + G_OBJECT_CLASS(ao_tasks_parent_class)->finalize(object); +} + + +static gboolean ao_tasks_selection_changed_cb(gpointer widget) +{ + GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); + GtkTreeIter iter; + GtkTreeModel *model; + + if (gtk_tree_selection_get_selected(selection, &model, &iter)) + { + gint line; + gchar *filename, *locale_filename; + GeanyDocument *doc; + + gtk_tree_model_get(model, &iter, TLIST_COL_LINE, &line, TLIST_COL_FILENAME, &filename, -1); + locale_filename = utils_get_locale_from_utf8(filename); + doc = document_open_file(locale_filename, FALSE, NULL, NULL); + if (doc != NULL) + { + sci_goto_line(doc->editor->sci, line - 1, TRUE); + gtk_widget_grab_focus(GTK_WIDGET(doc->editor->sci)); + } + g_free(filename); + g_free(locale_filename); + } + return FALSE; +} + + +static gboolean ao_tasks_button_press_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + if (event->button == 1) + { /* allow reclicking of a treeview item */ + g_idle_add(ao_tasks_selection_changed_cb, widget); + } + return FALSE; +} + + +static gboolean ao_tasks_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + if (event->keyval == GDK_Return || + event->keyval == GDK_ISO_Enter || + event->keyval == GDK_KP_Enter || + event->keyval == GDK_space) + { + g_idle_add(ao_tasks_selection_changed_cb, widget); + } + return FALSE; +} + + +static void ao_tasks_hide(AoTasks *t) +{ + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(t); + + if (priv->page) + { + gtk_widget_destroy(priv->page); + priv->page = NULL; + } +} + + +static void ao_tasks_show(AoTasks *t) +{ + GtkCellRenderer *text_renderer; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + GtkTreeSortable *sortable; + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(t); + + priv->store = gtk_list_store_new(TLIST_COL_MAX, + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING); + priv->tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(priv->store)); + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->tree)); + gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); + + /* selection handling */ + g_signal_connect(priv->tree, "button-press-event", G_CALLBACK(ao_tasks_button_press_cb), t); + g_signal_connect(priv->tree, "key-press-event", G_CALLBACK(ao_tasks_key_press_cb), t); + + text_renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("File")); + gtk_tree_view_column_pack_start(column, text_renderer, TRUE); + gtk_tree_view_column_set_attributes(column, text_renderer, "text", + TLIST_COL_DISPLAY_FILENAME, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(priv->tree), column); + + text_renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Line")); + gtk_tree_view_column_pack_start(column, text_renderer, TRUE); + gtk_tree_view_column_set_attributes(column, text_renderer, "text", TLIST_COL_LINE, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(priv->tree), column); + + text_renderer = gtk_cell_renderer_text_new(); + g_object_set(text_renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + column = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(column, _("Task")); + gtk_tree_view_column_pack_start(column, text_renderer, TRUE); + gtk_tree_view_column_set_attributes(column, text_renderer, "text", TLIST_COL_NAME, NULL); + gtk_tree_view_append_column(GTK_TREE_VIEW(priv->tree), column); + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(priv->tree), TRUE); + gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(priv->tree), TRUE); + gtk_tree_view_set_search_column(GTK_TREE_VIEW(priv->tree), TLIST_COL_DISPLAY_FILENAME); + + /* sorting */ + /* TODO improve sorting: sort by filename, then line number; make header clicks sort the data */ + sortable = GTK_TREE_SORTABLE(GTK_TREE_MODEL(priv->store)); + gtk_tree_sortable_set_sort_column_id(sortable, TLIST_COL_DISPLAY_FILENAME, GTK_SORT_ASCENDING); + + ui_widget_modify_font_from_string(priv->tree, geany->interface_prefs->tagbar_font); + + /* GTK 2.12 tooltips */ + if (gtk_check_version(2, 12, 0) == NULL) + g_object_set(priv->tree, "has-tooltip", TRUE, "tooltip-column", TLIST_COL_TOOLTIP, NULL); + + /* scrolled window */ + priv->page = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(priv->page), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + gtk_container_add(GTK_CONTAINER(priv->page), priv->tree); + + gtk_widget_show_all(priv->page); + gtk_notebook_append_page( + GTK_NOTEBOOK(ui_lookup_widget(geany->main_widgets->window, "notebook_info")), + priv->page, + gtk_label_new(_("Tasks"))); + + /* initial update */ + ao_tasks_update(t, NULL); +} + + +void ao_tasks_activate(AoTasks *t) +{ + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(t); + + if (priv->enable_tasks) + { + GtkNotebook *notebook = GTK_NOTEBOOK( + ui_lookup_widget(geany->main_widgets->window, "notebook_info")); + gint page_number = gtk_notebook_page_num(notebook, priv->page); + + gtk_notebook_set_current_page(notebook, page_number); + gtk_widget_grab_focus(priv->tree); + } +} + + +void ao_tasks_update(AoTasks *t, G_GNUC_UNUSED GeanyDocument *cur_doc) +{ + guint i, lines, line; + gchar *line_buf, *context, *display_name, *tooltip; + const gchar **token; + GeanyDocument *doc; + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(t); + + /* TODO this could be improved to only update the currently loaded/saved document instead of + * iterating over all documents. */ + gtk_list_store_clear(priv->store); + + for (i = 0; i < geany->documents_array->len; i++) + { + doc = document_index(i); + if (doc->is_valid) + { + display_name = document_get_basename_for_display(doc, -1); + lines = sci_get_line_count(doc->editor->sci); + for (line = 0; line < lines; line++) + { + line_buf = g_strstrip(sci_get_line(doc->editor->sci, line)); + token = tokens; + while (*token != NULL) + { + if (NZV(*token) && strstr(line_buf, *token) != NULL) + { + context = g_strstrip(sci_get_line(doc->editor->sci, line + 1)); + setptr(context, g_strconcat( + _("Context:"), "\n", line_buf, "\n", context, NULL)); + tooltip = g_markup_escape_text(context, -1); + + gtk_list_store_insert_with_values(priv->store, NULL, -1, + TLIST_COL_FILENAME, DOC_FILENAME(doc), + TLIST_COL_DISPLAY_FILENAME, display_name, + TLIST_COL_LINE, line + 1, + TLIST_COL_NAME, line_buf, + TLIST_COL_TOOLTIP, tooltip, + -1); + g_free(context); + g_free(tooltip); + } + token++; + } + g_free(line_buf); + } + g_free(display_name); + } + } +} + + +static void ao_tasks_init(AoTasks *self) +{ + AoTasksPrivate *priv = AO_TASKS_GET_PRIVATE(self); + + priv->page = NULL; +} + + +AoTasks *ao_tasks_new(gboolean enable) +{ + return g_object_new(AO_TASKS_TYPE, "enable-tasks", enable, NULL); +}
Property changes on: trunk/geany-plugins/addons/src/ao_tasks.c ___________________________________________________________________ Added: svn:mime-type + text/x-csrc Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native
Added: trunk/geany-plugins/addons/src/ao_tasks.h =================================================================== --- trunk/geany-plugins/addons/src/ao_tasks.h (rev 0) +++ trunk/geany-plugins/addons/src/ao_tasks.h 2009-11-28 16:54:23 UTC (rev 1065) @@ -0,0 +1,45 @@ +/* + * ao_tasks.h - this file is part of Addons, a Geany plugin + * + * Copyright 2009 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $Id$ + */ + + +#ifndef __AO_TASKS_H__ +#define __AO_TASKS_H__ + +G_BEGIN_DECLS + +#define AO_TASKS_TYPE (ao_tasks_get_type()) +#define AO_TASKS(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), AO_TASKS_TYPE, AoTasks)) +#define AO_TASKS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), AO_TASKS_TYPE, AoTasksClass)) +#define IS_AO_TASKS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), AO_TASKS_TYPE)) +#define IS_AO_TASKS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), AO_TASKS_TYPE)) + +typedef struct _AoTasks AoTasks; +typedef struct _AoTasksClass AoTasksClass; + +GType ao_tasks_get_type (void); +AoTasks* ao_tasks_new (gboolean enable); +void ao_tasks_update (AoTasks *t, GeanyDocument *cur_doc); +void ao_tasks_activate (AoTasks *t); + +G_END_DECLS + +#endif /* __AO_TASKS_H__ */
Property changes on: trunk/geany-plugins/addons/src/ao_tasks.h ___________________________________________________________________ Added: svn:mime-type + text/x-chdr Added: svn:keywords + Author Date Id Revision Added: svn:eol-style + native
Deleted: trunk/geany-plugins/addons/src/tasks.c =================================================================== --- trunk/geany-plugins/addons/src/tasks.c 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/addons/src/tasks.c 2009-11-28 16:54:23 UTC (rev 1065) @@ -1,515 +0,0 @@ -/* - * tasks - tasks.c - * - * Copyright 2009 Bert Vermeulen bert@biot.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include "geanyplugin.h" - -#include <stdlib.h> -#include <string.h> - -#include <gdk/gdkkeysyms.h> - -#include "addons.h" -#include "tasks.h" - - -#define DEFAULT_TOKENS { "TODO", "FIXME", NULL }; - - -typedef struct { - unsigned int line; - GString *description; -} GeanyTask; - - -static GString *linebuf = NULL; -static char *tokens[] = DEFAULT_TOKENS; -static GHashTable *globaltasks = NULL; -static GtkListStore *taskstore = NULL; -static GtkWidget *notebook_page = NULL; -static gboolean tasks_enabled = FALSE; - - -static gboolean tasks_button_cb(GtkWidget *widget, GdkEventButton *event, gpointer data); -static gboolean tasks_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data); -static void free_editor_tasks(gpointer key, gpointer value, gpointer data); -static void scan_all_documents(void); -static void scan_document_for_tasks(GeanyDocument *doc); -static void create_tasks_tab(void); -static int scan_line_for_tokens(ScintillaObject *sci, unsigned int line); -static int scan_buf_for_tokens(char *buf); -static GeanyTask *create_task(unsigned int line, char *description); -static int find_line(GeanyTask *task, unsigned int *line); -static void found_token(GeanyEditor *editor, unsigned int line, char *d); -static void no_token(GeanyEditor *editor, unsigned int line); -static void lines_moved(GeanyEditor *editor, unsigned int line, int change); -static int keysort(GeanyTask *a, GeanyTask *b); -static void render_taskstore(GeanyEditor *editor); - - -static void tasks_init(void) -{ - globaltasks = g_hash_table_new(NULL, NULL); - linebuf = g_string_sized_new(256); - create_tasks_tab(); - scan_all_documents(); - - tasks_enabled = TRUE; -} - -static void tasks_cleanup(void) -{ - GtkWidget *notebook; - int page; - - g_string_free(linebuf, TRUE); - - g_hash_table_foreach(globaltasks, free_editor_tasks, NULL); - g_hash_table_destroy(globaltasks); - - notebook = ui_lookup_widget(geany->main_widgets->window, "notebook_info"); - page = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), notebook_page); - gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), page); - - tasks_enabled = FALSE; -} - -void tasks_set_enable(gboolean enable) -{ - if (tasks_enabled != enable) - { - if (enable) - tasks_init(); - else - tasks_cleanup(); - } -} - -void tasks_on_document_close(GObject *object, GeanyDocument *doc, gpointer data) -{ - - if(tasks_enabled && doc->is_valid) - free_editor_tasks(doc->editor, NULL, NULL); - -} - - -void tasks_on_document_open(GObject *object, GeanyDocument *doc, gpointer data) -{ - - if(tasks_enabled && doc->is_valid) - scan_document_for_tasks(doc); - -} - - -void tasks_on_document_activate(GObject *object, GeanyDocument *doc, gpointer data) -{ - - if(tasks_enabled && doc->is_valid) - render_taskstore(doc->editor); - -} - - -gboolean tasks_on_editor_notify(GObject *object, GeanyEditor *editor, - SCNotification *nt, gpointer data) -{ - static int mod_line = -1; - int pos, line, offset; - - if (! tasks_enabled) - return FALSE; - - switch (nt->nmhdr.code) - { - case SCN_MODIFIED: - line = sci_get_line_from_position(editor->sci, nt->position); - if(nt->linesAdded != 0) - /* check if existing tasks had their line numbers changed */ - lines_moved(editor, line, nt->linesAdded); - else - /* same-line change: we'll check it later */ - mod_line = line; - break; - case SCN_UPDATEUI: - pos = sci_get_current_position(editor->sci); - line = sci_get_line_from_position(editor->sci, pos); - if(mod_line != -1 && line != mod_line) - { - /* cursor left a line that was changed, scan it for tokens */ - offset = scan_line_for_tokens(editor->sci, mod_line); - if(offset) - found_token(editor, mod_line, linebuf->str + offset); - else - no_token(editor, mod_line); - render_taskstore(editor); - mod_line = -1; - } - break; - } - - return FALSE; -} - - -static gboolean tasks_button_cb(GtkWidget *widget, GdkEventButton *event, gpointer data) -{ - GeanyDocument *doc; - GtkTreeView *tv; - GtkTreeSelection *selection; - GtkTreeIter iter; - GtkTreeModel *model; - gboolean ret = FALSE; - unsigned int line; - - if (event->button == 1) - { - ret = TRUE; - - tv = GTK_TREE_VIEW(ui_lookup_widget(geany->main_widgets->window, "treeview_tasks")); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); - if (gtk_tree_selection_get_selected(selection, &model, &iter)) - { - gtk_tree_model_get(model, &iter, 0, &line, -1); - doc = document_get_current(); - ret = navqueue_goto_line(NULL, doc, line + 1); - } - } - - return ret; -} - - -static gboolean tasks_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) -{ - GtkTreeView *tv; - GdkEventButton button_event; - - if(event->keyval == GDK_Return || - event->keyval == GDK_ISO_Enter || - event->keyval == GDK_KP_Enter || - event->keyval == GDK_space) - { - button_event.button = 1; - button_event.time = event->time; - tv = GTK_TREE_VIEW(ui_lookup_widget(geany->main_widgets->window, "treeview_tasks")); - tasks_button_cb(NULL, &button_event, tv); - - return TRUE; - } - - return FALSE; -} - - -static void free_editor_tasks(gpointer key, gpointer value, gpointer data) -{ - GList *tasklist, *entry; - GeanyTask *task; - - tasklist = (value) ? value : g_hash_table_lookup(globaltasks, key); - if(tasklist) - { - for(entry = g_list_first(tasklist); entry; entry = g_list_next(entry)) - { - task = (GeanyTask *) entry->data; - g_string_free(task->description, TRUE); - g_free(task); - } - g_list_free(tasklist); - } - g_hash_table_remove(globaltasks, key); - -} - - -static void scan_all_documents(void) -{ - unsigned int i; - - for(i = 0; i < geany->documents_array->len; i++) - { - if(document_index(i)->is_valid) - { - scan_document_for_tasks(document_index(i)); - } - } - -} - -/* go through every line of a document and scan it for tasks tokens. add the - * task to the tasklist for that document if found. */ -static void scan_document_for_tasks(GeanyDocument *doc) -{ - unsigned int lines, line, offset; - - lines = sci_get_line_count(doc->editor->sci); - for(line = 0; line < lines; line++) - { - offset = scan_line_for_tokens(doc->editor->sci, line); - if(offset) - found_token(doc->editor, line, linebuf->str + offset); - } - render_taskstore(doc->editor); - -} - - -static void create_tasks_tab(void) -{ - GtkWidget *tv, *notebook; - GtkCellRenderer *renderer; - GtkTreeViewColumn *column; - GtkTreeSelection *selection; - int page; - - taskstore = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING); - tv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(taskstore)); - g_object_set_data(G_OBJECT(geany->main_widgets->window), "treeview_tasks", tv); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), FALSE); - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE); - g_signal_connect(tv, "button-release-event", G_CALLBACK(tasks_button_cb), (gpointer) tv); - g_signal_connect(tv, "key-press-event", G_CALLBACK(tasks_key_cb), (gpointer) tv); - - renderer = gtk_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes(NULL, renderer, "text", 1, NULL); - gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column); - - notebook = ui_lookup_widget(geany->main_widgets->window, "notebook_info"); - page = gtk_notebook_insert_page(GTK_NOTEBOOK(notebook), tv, gtk_label_new(_("Tasks")), -1); - gtk_widget_show_all(tv); - notebook_page = tv; -} - - -/* copy the line into linebuf and scan it for tokens. returns 0 if no tokens - * were found, or the offset to the start of the task in linebuf otherwise. */ -static int scan_line_for_tokens(ScintillaObject *sci, unsigned int line) -{ - unsigned int len, len_done, offset; - - offset = 0; - len = sci_get_line_length(sci, line); - if(len) - { - if(len+1 > linebuf->allocated_len) - { - /* why doesn't GString have this functionality? */ - linebuf->str = g_realloc(linebuf->str, len+1); - if(linebuf->str == NULL) - return 0; - linebuf->allocated_len = len+1; - } - len_done = scintilla_send_message(sci, SCI_GETLINE, line, (sptr_t) linebuf->str); - linebuf->str[len] = 0; - if(len_done) - offset = scan_buf_for_tokens(linebuf->str); - } - - return offset; -} - - -static int scan_buf_for_tokens(char *buf) -{ - unsigned int t, offset, len, i; - char *entry; - - offset = 0; - for(t = 0; tokens[t]; t++) - { - entry = strstr(buf, tokens[t]); - if(entry) - { - entry += strlen(tokens[t]); - while(*entry == ' ' || *entry == ':') - entry++; - for(i = 0; entry[i]; i++) - { - /* strip off line endings */ - if(entry[i] == '\t' || entry[i] == '\r' || entry[i] == '\n') - { - entry[i] = 0; - break; - } - } - /* strip off */ /* no really, I mean */ - len = strlen(entry); - if(len > 1 && entry[len-2] == '*' && entry[len-1] == '/') - entry[len-2] = 0; - offset = entry - buf; - } - } - - return offset; -} - - -static GeanyTask *create_task(unsigned int line, char *description) -{ - GeanyTask *task; - - task = malloc(sizeof(GeanyTask)); - g_return_val_if_fail(task != NULL, NULL); - - task->line = line; - task->description = g_string_new(description); - - return task; -} - - -static int find_line(GeanyTask *task, unsigned int *line) -{ - - if(task->line == *line) - return 0; - - return 1; -} - - -static void found_token(GeanyEditor *editor, unsigned int line, char *description) -{ - GeanyTask *task; - GList *tasklist, *entry; - - tasklist = g_hash_table_lookup(globaltasks, editor); - if(tasklist) - { - entry = g_list_find_custom(tasklist, (gconstpointer) &line, (gconstpointer) find_line); - if(entry) - { - task = (GeanyTask *) entry->data; - if(strcmp(description, task->description->str)) - g_string_assign(task->description, description); - } - else - { - task = create_task(line, description); - tasklist = g_list_append(tasklist, task); - g_hash_table_replace(globaltasks, editor, tasklist); - } - } - else - { - /* this editor doesn't have a tasklist yet */ - task = create_task(line, description); - tasklist = g_list_append(NULL, task); - g_hash_table_insert(globaltasks, editor, tasklist); - } - -} - - -/* no token was found on this line, make sure there's nothing in the tasklist either */ -static void no_token(GeanyEditor *editor, unsigned int line) -{ - GList *tasklist, *entry; - - tasklist = g_hash_table_lookup(globaltasks, editor); - if(tasklist) - { - entry = g_list_find_custom(tasklist, (gconstpointer) &line, (gconstpointer) find_line); - if(entry) - { - tasklist = g_list_remove(tasklist, entry); - g_hash_table_replace(globaltasks, editor, tasklist); - } - } - -} - - -static void lines_moved(GeanyEditor *editor, unsigned int line, int change) -{ - GeanyTask *task; - GList *tasklist, *entry, *to_delete; - - to_delete = NULL; - tasklist = g_hash_table_lookup(globaltasks, editor); - for(entry = g_list_first(tasklist); entry; entry = g_list_next(entry)) - { - task = (GeanyTask *) entry->data; - if(task->line >= line) - { - if(change < 0 && task->line < line - change) - /* the line with this task on it was deleted, so mark the task for deletion */ - to_delete = g_list_append(to_delete, entry->data); - else - /* shift the line number of this task up or down along with the change */ - task->line += change; - } - } - - for(entry = g_list_first(to_delete); entry; entry = g_list_next(entry)) - { - task = (GeanyTask *) entry->data; - tasklist = g_list_remove(tasklist, entry->data); - g_string_free(task->description, TRUE); - g_free(task); - } - g_list_free(to_delete); - - g_hash_table_replace(globaltasks, editor, tasklist); - render_taskstore(editor); - -} - - -static int keysort(GeanyTask *a, GeanyTask *b) -{ - - if(a->line < b->line) - return -1; - else if(a->line > b->line) - return 1; - - return 0; -} - - -static void render_taskstore(GeanyEditor *editor) -{ - GeanyTask *task; - GtkTreeIter iter; - GList *tasklist, *entry; - - gtk_list_store_clear(taskstore); - tasklist = g_hash_table_lookup(globaltasks, editor); - if(!tasklist) - /* empty list */ - return; - tasklist = g_list_sort(tasklist, (GCompareFunc) keysort); - g_hash_table_replace(globaltasks, editor, tasklist); - - for(entry = g_list_first(tasklist); entry; entry = g_list_next(entry)) - { - task = (GeanyTask *) entry->data; - gtk_list_store_append(taskstore, &iter); - gtk_list_store_set(taskstore, &iter, 0, task->line, 1, task->description->str, -1); - } - -} - - -
Deleted: trunk/geany-plugins/addons/src/tasks.h =================================================================== --- trunk/geany-plugins/addons/src/tasks.h 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/addons/src/tasks.h 2009-11-28 16:54:23 UTC (rev 1065) @@ -1,38 +0,0 @@ -/* - * tasks - tasks.h - * - * Copyright 2009 Bert Vermeulen bert@biot.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#ifndef __TASKS_H__ -#define __TASKS_H__ - - -void tasks_set_enable(gboolean enable); - - -gboolean tasks_on_editor_notify(GObject *object, GeanyEditor *editor, - SCNotification *nt, gpointer data); - -void tasks_on_document_open(GObject *object, GeanyDocument *doc, gpointer data); - -void tasks_on_document_activate(GObject *object, GeanyDocument *doc, gpointer data); - -void tasks_on_document_close(GObject *object, GeanyDocument *doc, gpointer data); - -#endif
Modified: trunk/geany-plugins/po/POTFILES.in =================================================================== --- trunk/geany-plugins/po/POTFILES.in 2009-11-28 16:49:09 UTC (rev 1064) +++ trunk/geany-plugins/po/POTFILES.in 2009-11-28 16:54:23 UTC (rev 1065) @@ -2,7 +2,7 @@
# Addons addons/src/ao_systray.c -addons/src/tasks.c +addons/src/ao_tasks.c addons/src/ao_openuri.c addons/src/addons.c addons/src/ao_doclist.c
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.