1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * symbol-db-views.c
4  * Copyright (C) Naba Kumar 2010 <naba@gnome.org>
5  *
6  * anjuta is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * anjuta is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <gtk/gtk.h>
20 #include <libanjuta/interfaces/ianjuta-document-manager.h>
21 #include <libanjuta/interfaces/ianjuta-markable.h>
22 #include "symbol-db-model-project.h"
23 #include "symbol-db-model-file.h"
24 #include "symbol-db-model-search.h"
25 #include "symbol-db-engine.h"
26 #include "symbol-db-views.h"
27 #include "plugin.h"
28 
29 static void
on_treeview_row_activated(GtkTreeView * view,GtkTreePath * arg1,GtkTreeViewColumn * arg2,SymbolDBPlugin * plugin)30 on_treeview_row_activated (GtkTreeView *view, GtkTreePath *arg1,
31                            GtkTreeViewColumn *arg2,
32                            SymbolDBPlugin *plugin)
33 {
34 	GtkTreeModel *model;
35 	GtkTreeSelection *selection;
36 	GtkTreeIter iter;
37 	IAnjutaDocumentManager *docman;
38 	GFile* file;
39 	gchar *filename, *full_path;
40 	gint line;
41 
42 	AnjutaShell *shell = ANJUTA_PLUGIN (plugin)->shell;
43 	selection = gtk_tree_view_get_selection (view);
44 	if (!gtk_tree_selection_get_selected (selection, &model, &iter))
45 	    return;
46 
47 	gtk_tree_model_get (model, &iter,
48 	                    SYMBOL_DB_MODEL_PROJECT_COL_FILE, &filename,
49 	                    SYMBOL_DB_MODEL_PROJECT_COL_LINE, &line,
50 	                    -1);
51 	g_return_if_fail (filename != NULL);
52 
53 	docman = anjuta_shell_get_interface (shell, IAnjutaDocumentManager,
54 	                                     NULL);
55 	g_return_if_fail (docman != NULL);
56 
57 	full_path = g_build_filename (plugin->project_root_dir, filename, NULL);
58 	file = g_file_new_for_path (full_path);
59 	ianjuta_document_manager_goto_file_line (docman, file, line, NULL);
60 	g_free (full_path);
61 	g_free (filename);
62 	g_object_unref (file);
63 
64 	if (IANJUTA_IS_MARKABLE (plugin->current_editor))
65 	{
66 		ianjuta_markable_delete_all_markers (IANJUTA_MARKABLE (plugin->current_editor),
67 		                                     IANJUTA_MARKABLE_LINEMARKER,
68 		                                     NULL);
69 
70 		ianjuta_markable_mark (IANJUTA_MARKABLE (plugin->current_editor),
71 		                       line, IANJUTA_MARKABLE_LINEMARKER, NULL, NULL);
72 	}
73 }
74 
75 static void
on_treeview_row_expanded(GtkTreeView * view,GtkTreeIter * iter,GtkTreePath * path,SymbolDBPlugin * plugin)76 on_treeview_row_expanded (GtkTreeView *view, GtkTreeIter *iter,
77                           GtkTreePath *path, SymbolDBPlugin *plugin)
78 {
79 	gchar* symbol_name;
80 	GtkTreeModel *model;
81 	GHashTable *expanded_nodes =
82 		g_object_get_data (G_OBJECT (view), "__expanded_nodes__");
83 
84 	model = gtk_tree_view_get_model (view);
85 	gtk_tree_model_get (model, iter, SYMBOL_DB_MODEL_PROJECT_COL_LABEL,
86 	                    &symbol_name, -1);
87 	g_hash_table_insert (expanded_nodes, symbol_name, GINT_TO_POINTER (1));
88 }
89 
90 static void
on_treeview_row_collapsed(GtkTreeView * view,GtkTreeIter * iter,GtkTreePath * path,SymbolDBPlugin * plugin)91 on_treeview_row_collapsed (GtkTreeView *view, GtkTreeIter *iter,
92                            GtkTreePath *path, SymbolDBPlugin *plugin)
93 {
94 	gchar* symbol_name;
95 	GtkTreeModel *model;
96 
97 	GHashTable *expanded_nodes =
98 		g_object_get_data (G_OBJECT (view), "__expanded_nodes__");
99 
100 	model = gtk_tree_view_get_model (view);
101 	gtk_tree_model_get (model, iter, SYMBOL_DB_MODEL_PROJECT_COL_LABEL,
102 	                    &symbol_name, -1);
103 	g_hash_table_remove (expanded_nodes, symbol_name);
104 	g_free (symbol_name);
105 }
106 
107 static void
on_treeview_has_child_toggled(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,GtkTreeView * view)108 on_treeview_has_child_toggled (GtkTreeModel *model,
109                                GtkTreePath  *path,
110                                GtkTreeIter  *iter,
111                                GtkTreeView  *view)
112 {
113 	gchar* symbol_name;
114 
115 	GHashTable *expanded_nodes =
116 		g_object_get_data (G_OBJECT (view), "__expanded_nodes__");
117 
118 	gtk_tree_model_get (model, iter, SYMBOL_DB_MODEL_PROJECT_COL_LABEL,
119 	                    &symbol_name, -1);
120 	if (g_hash_table_lookup (expanded_nodes, symbol_name))
121 		gtk_tree_view_expand_row (view, path, FALSE);
122 	g_free (symbol_name);
123 }
124 
125 static gboolean
symbol_db_view_search_equal_func(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)126 symbol_db_view_search_equal_func (GtkTreeModel *model, gint column,
127                                   const gchar *key, GtkTreeIter *iter,
128                                   gpointer search_data)
129 {
130 	gchar *pattern, *str;
131 	gboolean res;
132 
133 	gtk_tree_model_get (model, iter, column, &str, -1);
134 
135 	pattern = g_strdup_printf (".*%s.*", key);
136 	res = g_regex_match_simple (pattern, str, G_REGEX_CASELESS, 0);
137 
138 	g_free (pattern);
139 	g_free (str);
140 
141 	return !res;
142 }
143 
144 
145 static void
on_search_entry_changed(GtkEntry * entry,SymbolDBModelSearch * model)146 on_search_entry_changed (GtkEntry *entry, SymbolDBModelSearch *model)
147 {
148 	g_object_set (model, "search-pattern", gtk_entry_get_text (entry), NULL);
149 }
150 
151 GtkWidget*
symbol_db_view_new(SymbolViewType view_type,SymbolDBEngine * dbe,SymbolDBPlugin * plugin)152 symbol_db_view_new (SymbolViewType view_type,
153                     SymbolDBEngine *dbe, SymbolDBPlugin *plugin)
154 {
155 	GtkWidget *sw;
156 	GtkTreeModel *model;
157 	GtkWidget *dbv;
158 	GtkTreeViewColumn *column;
159 	GtkCellRenderer *renderer;
160 	GtkWidget *vbox = NULL;
161 	GtkWidget *entry;
162 
163 	switch (view_type)
164 	{
165 		case SYMBOL_DB_VIEW_FILE:
166 			model = symbol_db_model_file_new (dbe);
167 			break;
168 		case SYMBOL_DB_VIEW_SEARCH:
169 			model = symbol_db_model_search_new (dbe);
170 			g_object_set (model, "show-file-line", TRUE, NULL);
171 			break;
172 		default:
173 			model = symbol_db_model_project_new (dbe);
174 	}
175 
176 	dbv = gtk_tree_view_new_with_model (model);
177 	g_object_unref (model);
178 
179 	g_signal_connect (G_OBJECT (dbv), "row-activated",
180 					  G_CALLBACK (on_treeview_row_activated), plugin);
181 	g_signal_connect (G_OBJECT (dbv), "row-expanded",
182 					  G_CALLBACK (on_treeview_row_expanded), plugin);
183 	g_signal_connect (G_OBJECT (dbv), "row-collapsed",
184 					  G_CALLBACK (on_treeview_row_collapsed), plugin);
185 	g_signal_connect (G_OBJECT (model), "row-has-child-toggled",
186 					  G_CALLBACK (on_treeview_has_child_toggled), dbv);
187 
188 	g_object_set_data_full (G_OBJECT (dbv), "__expanded_nodes__",
189 	                        g_hash_table_new_full (g_str_hash, g_str_equal,
190 	                                               g_free, NULL),
191 	                        (GDestroyNotify)g_hash_table_destroy);
192 
193 	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (dbv), FALSE);
194 	gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (dbv), TRUE);
195 	gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (dbv),
196 	                                  SYMBOL_DB_MODEL_PROJECT_COL_ARGS);
197 	/* Columns */
198 	/* Note: Fixed sized columns are mandatory for high performance */
199 	column = gtk_tree_view_column_new ();
200 
201 	gtk_tree_view_column_set_fixed_width (column, 400);
202 	gtk_tree_view_column_set_title (column, _("Symbol"));
203 	gtk_tree_view_column_set_sizing (column,
204 	                                 GTK_TREE_VIEW_COLUMN_FIXED);
205 
206 	renderer = gtk_cell_renderer_pixbuf_new ();
207 	gtk_cell_renderer_set_fixed_size (renderer, 16, -1);
208 	gtk_tree_view_column_pack_start (column, renderer, FALSE);
209 	gtk_tree_view_column_add_attribute (column, renderer, "pixbuf",
210 	                                    SYMBOL_DB_MODEL_PROJECT_COL_PIXBUF);
211 
212 	renderer = gtk_cell_renderer_text_new ();
213 	gtk_tree_view_column_pack_start (column, renderer, TRUE);
214 	gtk_tree_view_column_add_attribute (column, renderer, "markup",
215 	                                    SYMBOL_DB_MODEL_PROJECT_COL_LABEL);
216 
217 	gtk_tree_view_append_column (GTK_TREE_VIEW (dbv), column);
218 	gtk_tree_view_set_expander_column (GTK_TREE_VIEW (dbv), column);
219 
220 	sw = gtk_scrolled_window_new (NULL, NULL);
221 	gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
222 	                                     GTK_SHADOW_IN);
223 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
224 	                                GTK_POLICY_AUTOMATIC,
225 	                                GTK_POLICY_AUTOMATIC);
226 	gtk_widget_show (dbv);
227 	gtk_container_add (GTK_CONTAINER (sw), dbv);
228 	gtk_widget_show (sw);
229 
230 	/* Search */
231 	gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (dbv),
232 	                                     symbol_db_view_search_equal_func,
233 	                                     NULL, NULL);
234 	gtk_tree_view_set_search_column (GTK_TREE_VIEW (dbv),
235 	                                 SYMBOL_DB_MODEL_PROJECT_COL_LABEL);
236 
237 	if (view_type == SYMBOL_DB_VIEW_SEARCH)
238 	{
239 		entry = gtk_search_entry_new ();
240 		g_signal_connect (entry, "changed",
241 		                  G_CALLBACK (on_search_entry_changed), model);
242 		gtk_widget_show (entry);
243 		vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3);
244 		gtk_widget_show (vbox);
245 		gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
246 		gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
247 		g_object_set_data (G_OBJECT (vbox), "search_entry", entry);
248 		gtk_tree_view_set_show_expanders (GTK_TREE_VIEW (dbv), FALSE);
249 		return vbox;
250 	}
251 	return sw;
252 }
253 
254 GtkWidget*
symbol_db_view_get_search_entry(GtkWidget * search_view)255 symbol_db_view_get_search_entry (GtkWidget *search_view)
256 {
257 	return g_object_get_data (G_OBJECT (search_view), "search_entry");
258 }
259