1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) 2001-2003 CodeFactory AB
5 * Copyright (C) 2001-2003 Mikael Hallendal <micke@imendio.com>
6 * Copyright (C) 2005-2007 Massimo CorĂ <maxcvs@email.it>
8 * anjuta is free software.
10 * You may redistribute it and/or modify it under the terms of the
11 * GNU General Public License, as published by the Free Software
12 * Foundation; either version 2 of the License, or (at your option)
15 * anjuta is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 * See the GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with anjuta. If not, write to:
22 * The Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor
24 * Boston, MA 02110-1301, USA.
30 #include <glib-object.h>
31 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtkaccessible.h>
34 #include <gtk/gtkcellrenderertext.h>
35 #include <gtk/gtkentry.h>
36 #include <gtk/gtkframe.h>
37 #include <gtk/gtkhbox.h>
38 #include <gtk/gtkvbox.h>
39 #include <gtk/gtklabel.h>
40 #include <gtk/gtkscrolledwindow.h>
41 #include <gtk/gtktreeview.h>
42 #include <gtk/gtktreeselection.h>
43 #include <libgnome/gnome-i18n.h>
44 #include <libanjuta/anjuta-debug.h>
46 #include "symbol-db-view-search.h"
47 #include "symbol-db-engine.h"
48 #include "symbol-db-engine-iterator.h"
49 #include "symbol-db-engine-iterator-node.h"
50 #include "symbol-db-view.h"
53 struct _SymbolDBViewSearchPriv
58 GtkWidget
*entry
; /* entrybox */
59 GtkWidget
*hitlist
; /* treeview */
61 GCompletion
*completion
;
82 /* max hits to display on the search tab */
85 static GtkVBox
*parent_class
;
86 static gint signals
[LAST_SIGNAL
] = { 0 };
89 sdb_view_search_model_filter (SymbolDBViewSearch
* search
,
92 SymbolDBViewSearchPriv
*priv
;
95 SymbolDBEngineIterator
*iterator
;
98 g_return_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
));
99 g_return_if_fail (string
!= NULL
);
103 /* get the tree store model */
104 store
= GTK_TREE_STORE (gtk_tree_view_get_model
105 (GTK_TREE_VIEW (priv
->hitlist
)));
107 /* let's clean up rows from store model */
108 g_list_foreach (priv
->completion
->items
, (GFunc
)g_free
, NULL
);
109 g_completion_clear_items (priv
->completion
);
111 gtk_tree_store_clear (GTK_TREE_STORE (store
));
115 iterator
= symbol_db_engine_find_symbol_by_name_pattern (priv
->sdbe
,
116 string
, SYMINFO_SIMPLE
| SYMINFO_FILE_PATH
|
117 SYMINFO_ACCESS
| SYMINFO_KIND
);
120 GList
*completion_list
;
122 SymbolDBEngineIteratorNode
*iter_node
;
124 /* max number of hits to take care of */
125 hits
= symbol_db_engine_iterator_get_n_items (iterator
);
126 max_hits
= (hits
< MAX_HITS
)? hits
: MAX_HITS
;
128 completion_list
= NULL
;
130 for (i
= 0; i
< max_hits
; ++i
)
134 iter_node
= SYMBOL_DB_ENGINE_ITERATOR_NODE (iterator
);
136 const gchar
*sym_name
=
137 symbol_db_engine_iterator_node_get_symbol_name (iter_node
);
141 /* get the full file path instead of a database-oriented one. */
143 symbol_db_engine_get_full_local_path (priv
->sdbe
,
144 symbol_db_engine_iterator_node_get_symbol_extra_string (
145 iter_node
, SYMINFO_FILE_PATH
));
148 gtk_tree_store_append (GTK_TREE_STORE (store
), &iter
, NULL
);
150 gtk_tree_store_set (GTK_TREE_STORE (store
), &iter
,
151 COLUMN_PIXBUF
, symbol_db_view_get_pixbuf (
152 symbol_db_engine_iterator_node_get_symbol_extra_string (
153 iter_node
, SYMINFO_KIND
),
154 symbol_db_engine_iterator_node_get_symbol_extra_string (
155 iter_node
, SYMINFO_ACCESS
)
157 COLUMN_NAME
, sym_name
,
159 symbol_db_engine_iterator_node_get_symbol_file_pos (
161 COLUMN_FILE
, file_path
,
163 symbol_db_engine_iterator_node_get_symbol_id (iter_node
),
166 completion_list
= g_list_prepend (completion_list
,
167 g_strdup (sym_name
));
171 symbol_db_engine_iterator_move_next (iterator
);
175 completion_list
= g_list_reverse (completion_list
);
176 g_completion_add_items (priv
->completion
, completion_list
);
177 g_list_free (completion_list
);
182 g_object_unref (iterator
);
187 sdb_view_search_filter_idle (SymbolDBViewSearch
* search
)
189 SymbolDBViewSearchPriv
*priv
;
192 g_return_val_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
), FALSE
);
196 str
= (gchar
*) gtk_entry_get_text (GTK_ENTRY (priv
->entry
));
197 sdb_view_search_model_filter (search
, str
);
199 priv
->idle_filter
= 0;
205 sdb_view_search_on_entry_changed (GtkEntry
* entry
,
206 SymbolDBViewSearch
* search
)
208 SymbolDBViewSearchPriv
*priv
;
210 g_return_if_fail (GTK_IS_ENTRY (entry
));
211 g_return_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
));
215 DEBUG_PRINT("Entry changed");
217 if (!priv
->idle_filter
)
220 g_idle_add ((GSourceFunc
)
221 sdb_view_search_filter_idle
, search
);
226 sdb_view_search_on_entry_activated (GtkEntry
* entry
,
227 SymbolDBViewSearch
* search
)
229 SymbolDBViewSearchPriv
*priv
;
232 g_return_if_fail (GTK_IS_ENTRY (entry
));
233 g_return_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
));
237 str
= (gchar
*) gtk_entry_get_text (GTK_ENTRY (priv
->entry
));
239 /* parse the string typed in the entry */
240 sdb_view_search_model_filter (search
, str
);
246 sdb_view_search_on_tree_row_activate (GtkTreeView
* view
,
248 GtkTreeViewColumn
* arg2
,
249 SymbolDBViewSearch
* search
)
253 SymbolDBViewSearchPriv
*priv
;
256 GtkTreeSelection
*selection
;
260 selection
= gtk_tree_view_get_selection (view
);
262 if (!gtk_tree_selection_get_selected (selection
, NULL
, &iter
))
265 ("sdb_view_search_on_tree_row_activate: error getting selected row");
269 gtk_tree_model_get (GTK_TREE_MODEL (priv
->model
),
275 DEBUG_PRINT ("sdb_view_search_on_tree_row_activate: file %s", file
);
277 g_signal_emit (search
, signals
[SYM_SELECTED
], 0, line
, file
);
281 /* Always return FALSE so the tree view gets the event and can update
290 sdb_view_search_on_entry_key_press_event (GtkEntry
* entry
,
292 SymbolDBViewSearch
* search
)
294 SymbolDBViewSearchPriv
*priv
;
298 DEBUG_PRINT ("key_press event");
299 if (event
->keyval
== GDK_Tab
)
301 DEBUG_PRINT ("tab key pressed");
302 if (event
->state
& GDK_CONTROL_MASK
)
304 gtk_widget_grab_focus (priv
->hitlist
);
308 gtk_editable_set_position (GTK_EDITABLE (entry
), -1);
309 gtk_editable_select_region (GTK_EDITABLE (entry
), -1,
315 if (event
->keyval
== GDK_Return
|| event
->keyval
== GDK_KP_Enter
)
322 DEBUG_PRINT("enter key pressed: getting the first entry found");
324 /* Get the first entry found. */
325 if (gtk_tree_model_get_iter_first
326 (GTK_TREE_MODEL (priv
->model
), &iter
))
329 gtk_tree_model_get (GTK_TREE_MODEL (priv
->model
),
336 g_return_val_if_fail (&iter
!= NULL
, FALSE
);
338 gtk_entry_set_text (GTK_ENTRY (entry
), name
);
340 gtk_editable_set_position (GTK_EDITABLE (entry
), -1);
341 gtk_editable_select_region (GTK_EDITABLE (entry
), -1, -1);
343 g_signal_emit (search
, signals
[SYM_SELECTED
], 0, line
, file
);
355 sdb_view_search_complete_idle (SymbolDBViewSearch
* search
)
357 SymbolDBViewSearchPriv
*priv
;
359 gchar
*completed
= NULL
;
363 g_return_val_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
), FALSE
);
367 text
= gtk_entry_get_text (GTK_ENTRY (priv
->entry
));
369 list
= g_completion_complete (priv
->completion
, (gchar
*) text
,
374 text_length
= strlen (text
);
375 gtk_entry_set_text (GTK_ENTRY (priv
->entry
), completed
);
377 gtk_editable_set_position (GTK_EDITABLE (priv
->entry
),
380 gtk_editable_select_region (GTK_EDITABLE (priv
->entry
),
384 priv
->idle_complete
= 0;
389 sdb_view_search_on_entry_text_inserted (GtkEntry
* entry
,
393 SymbolDBViewSearch
* search
)
395 SymbolDBViewSearchPriv
*priv
;
396 g_return_if_fail (SYMBOL_IS_DB_VIEW_SEARCH (search
));
400 if (!priv
->idle_complete
)
402 priv
->idle_complete
=
403 g_idle_add ((GSourceFunc
)
404 sdb_view_search_complete_idle
, search
);
409 sdb_view_search_init (SymbolDBViewSearch
* search
)
412 SymbolDBViewSearchPriv
*priv
;
413 GtkTreeViewColumn
*column
;
414 GtkCellRenderer
*renderer
;
415 GtkWidget
*frame
, *list_sw
;
418 /* allocate space for a SymbolDBViewSearchPriv class. */
419 priv
= g_new0 (SymbolDBViewSearchPriv
, 1);
422 priv
->idle_complete
= 0;
423 priv
->idle_filter
= 0;
425 priv
->completion
= g_completion_new (NULL
);
427 priv
->hitlist
= gtk_tree_view_new ();
430 priv
->model
= GTK_TREE_MODEL (gtk_tree_store_new (COLUMN_MAX
, GDK_TYPE_PIXBUF
,
431 G_TYPE_STRING
, G_TYPE_INT
, G_TYPE_STRING
, G_TYPE_INT
));
433 gtk_tree_view_set_model (GTK_TREE_VIEW (priv
->hitlist
), GTK_TREE_MODEL (priv
->model
));
434 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv
->hitlist
), FALSE
);
436 gtk_tree_view_set_model (GTK_TREE_VIEW (priv
->hitlist
),
437 GTK_TREE_MODEL (priv
->model
));
438 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (priv
->hitlist
), TRUE
);
440 /* column initialization */
441 column
= gtk_tree_view_column_new ();
442 gtk_tree_view_column_set_sizing (column
,
443 GTK_TREE_VIEW_COLUMN_AUTOSIZE
);
445 renderer
= gtk_cell_renderer_pixbuf_new ();
446 gtk_tree_view_column_pack_start (column
, renderer
, FALSE
);
447 gtk_tree_view_column_add_attribute (column
, renderer
, "pixbuf",
450 renderer
= gtk_cell_renderer_text_new ();
451 gtk_tree_view_column_pack_start (column
, renderer
, TRUE
);
452 gtk_tree_view_column_add_attribute (column
, renderer
, "text",
455 gtk_tree_view_append_column (GTK_TREE_VIEW (priv
->hitlist
), column
);
456 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (priv
->hitlist
),
459 gtk_box_set_spacing (GTK_BOX (search
), 2);
461 gtk_container_set_border_width (GTK_CONTAINER (search
), 2);
463 /* creating entry box, where we'll type the keyword to look for */
464 priv
->entry
= gtk_entry_new ();
466 /* set up some signals */
467 g_signal_connect (priv
->entry
, "key_press_event",
468 G_CALLBACK (sdb_view_search_on_entry_key_press_event
),
471 g_signal_connect (priv
->hitlist
, "row_activated",
472 G_CALLBACK (sdb_view_search_on_tree_row_activate
),
475 g_signal_connect (priv
->entry
, "changed",
476 G_CALLBACK (sdb_view_search_on_entry_changed
),
479 g_signal_connect (priv
->entry
, "activate",
480 G_CALLBACK (sdb_view_search_on_entry_activated
),
483 g_signal_connect (priv
->entry
, "insert_text",
484 G_CALLBACK (sdb_view_search_on_entry_text_inserted
), search
);
486 gtk_box_pack_start (GTK_BOX (search
), priv
->entry
, FALSE
, FALSE
, 0);
488 frame
= gtk_frame_new (NULL
);
489 gtk_frame_set_shadow_type (GTK_FRAME (frame
), GTK_SHADOW_IN
);
491 list_sw
= gtk_scrolled_window_new (NULL
, NULL
);
492 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (list_sw
),
493 GTK_POLICY_AUTOMATIC
,
494 GTK_POLICY_AUTOMATIC
);
496 gtk_container_add (GTK_CONTAINER (frame
), list_sw
);
497 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv
->hitlist
), FALSE
);
499 gtk_container_add (GTK_CONTAINER (list_sw
), priv
->hitlist
);
500 gtk_box_pack_end_defaults (GTK_BOX (search
), frame
);
502 gtk_widget_show_all (GTK_WIDGET (search
));
506 sdb_view_search_dispose (GObject
* obj
)
508 SymbolDBViewSearch
*search
= SYMBOL_DB_VIEW_SEARCH (obj
);
509 SymbolDBViewSearchPriv
*priv
= search
->priv
;
511 DEBUG_PRINT("Destroying symbolsearch");
513 /* anjuta_symbol_view's dispose should manage it's freeing */
516 symbol_db_view_search_clear(search
);
517 g_object_unref (priv
->model
);
525 priv
->hitlist
= NULL
;
527 G_OBJECT_CLASS (parent_class
)->dispose (obj
);
532 sdb_view_search_finalize (GObject
* obj
)
534 SymbolDBViewSearch
*search
= SYMBOL_DB_VIEW_SEARCH (obj
);
535 SymbolDBViewSearchPriv
*priv
= search
->priv
;
537 DEBUG_PRINT ("Finalizing symbolsearch widget");
539 g_list_foreach (priv
->completion
->items
, (GFunc
)g_free
, NULL
);
540 g_completion_free (priv
->completion
);
543 G_OBJECT_CLASS (parent_class
)->finalize (obj
);
548 sdb_view_search_class_init (SymbolDBViewSearchClass
* klass
)
550 GObjectClass
*object_class
;
552 object_class
= G_OBJECT_CLASS (klass
);
553 parent_class
= g_type_class_peek_parent (klass
);
555 object_class
->finalize
= sdb_view_search_finalize
;
556 object_class
->dispose
= sdb_view_search_dispose
;
558 signals
[SYM_SELECTED
] =
559 g_signal_new ("symbol-selected",
560 G_TYPE_FROM_CLASS (klass
),
562 G_STRUCT_OFFSET (SymbolDBViewSearchClass
,
563 symbol_selected
), NULL
, NULL
,
564 g_cclosure_marshal_VOID__UINT_POINTER
, G_TYPE_NONE
,
565 2, G_TYPE_INT
, G_TYPE_STRING
);
569 * Cleaning issues. This function must be called when a project is removed.
572 symbol_db_view_search_clear (SymbolDBViewSearch
*search
)
574 SymbolDBViewSearchPriv
*priv
;
577 /* set entry text to a NULL string */
578 gtk_entry_set_text (GTK_ENTRY (priv
->entry
), "");
580 /* thrown away the g_completion words */
581 g_list_foreach (priv
->completion
->items
, (GFunc
)g_free
, NULL
);
582 g_completion_clear_items (priv
->completion
);
584 /* clean the gtk_tree_store */
585 gtk_tree_store_clear (GTK_TREE_STORE(gtk_tree_view_get_model
586 (GTK_TREE_VIEW (priv
->hitlist
))));
590 sdb_view_search_get_type (void)
592 static GType type
= 0;
596 static const GTypeInfo info
= {
597 sizeof (SymbolDBViewSearchClass
),
600 (GClassInitFunc
) sdb_view_search_class_init
,
603 sizeof (SymbolDBViewSearch
),
605 (GInstanceInitFunc
) sdb_view_search_init
,
608 type
= g_type_register_static (GTK_TYPE_VBOX
,
609 "SymbolDBViewSearch", &info
, 0);
615 symbol_db_view_search_new (SymbolDBEngine
*dbe
)
617 SymbolDBViewSearch
*search
;
618 SymbolDBViewSearchPriv
*priv
;
620 /* create a new object */
621 search
= g_object_new (SYMBOL_TYPE_DB_VIEW_SEARCH
, NULL
);
623 /* store the engine pointer */
627 return GTK_WIDGET (search
);