Integrate adding files with the file manager
[anjuta-git-plugin.git] / plugins / symbol-db / symbol-db-prefs.c
blob6dcd9325c5d92db96b11026e5bacd8f83b19abcf
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta_trunk
4 * Copyright (C) Massimo Cora' 2008 <maxcvs@email.it>
5 *
6 * anjuta_trunk 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.
11 * anjuta_trunk 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.
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/>.
21 #include <glib.h>
22 #include <config.h>
23 #include <ctype.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <dirent.h>
27 #include <string.h>
28 #include <gtk/gtktreeview.h>
29 #include <gtk/gtkliststore.h>
30 #include <libanjuta/anjuta-debug.h>
31 #include <libanjuta/anjuta-launcher.h>
32 #include <libanjuta/interfaces/ianjuta-language.h>
34 #include "symbol-db-prefs.h"
36 #define GLADE_FILE PACKAGE_DATA_DIR"/glade/anjuta-symbol-db.glade"
37 #define GLADE_ROOT "symbol_prefs"
38 #define ICON_FILE "anjuta-symbol-db-plugin-48.png"
40 #define CTAGS_PREFS_KEY "ctags.executable"
41 #define CHOOSER_WIDGET "preferences_file:text:/usr/bin/ctags:0:symboldb.ctags"
43 enum
45 COLUMN_LOAD,
46 COLUMN_NAME,
47 COLUMN_MAX
50 enum
52 PACKAGE_ADD,
53 PACKAGE_REMOVE,
54 LAST_SIGNAL
57 static unsigned int signals[LAST_SIGNAL] = { 0 };
59 struct _SymbolDBPrefsPriv {
60 GtkListStore *prefs_list_store;
61 GladeXML *prefs_gxml;
62 AnjutaLauncher *pkg_config_launcher;
63 AnjutaPreferences *prefs;
65 SymbolDBSystem *sdbs;
66 SymbolDBEngine *sdbe_project;
67 SymbolDBEngine *sdbe_globals;
69 GList *pkg_list;
70 GHashTable *enabled_packages_hash;
72 gint prefs_notify_id;
76 typedef struct _ParseableData {
77 SymbolDBPrefs *sdbp;
78 gchar *path_str;
80 } ParseableData;
83 static void
84 destroy_parseable_data (ParseableData *pdata)
86 g_free (pdata->path_str);
87 g_free (pdata);
91 G_DEFINE_TYPE (SymbolDBPrefs, sdb_prefs, G_TYPE_OBJECT);
93 static void
94 on_prefs_executable_changed (GtkFileChooser *chooser,
95 gpointer user_data)
97 gchar *new_file;
98 SymbolDBPrefs *sdbp;
99 SymbolDBPrefsPriv *priv;
101 sdbp = SYMBOL_DB_PREFS (user_data);
102 priv = sdbp->priv;
104 new_file = gtk_file_chooser_get_filename (chooser);
105 DEBUG_PRINT ("on_prefs_executable_changed (): new executable selected %s",
106 new_file);
107 if (new_file != NULL)
109 GtkWidget *fchooser;
110 fchooser = glade_xml_get_widget (priv->prefs_gxml, CHOOSER_WIDGET);
111 gtk_widget_set_sensitive (fchooser, TRUE);
113 anjuta_preferences_set (priv->prefs, CTAGS_PREFS_KEY,
114 new_file);
116 /* remember to set the new ctags path into various symbol engines */
117 symbol_db_engine_set_ctags_path (priv->sdbe_project, new_file);
118 symbol_db_engine_set_ctags_path (priv->sdbe_globals, new_file);
121 g_free (new_file);
124 static void
125 on_gconf_notify_prefs (GConfClient *gclient, guint cnxn_id,
126 GConfEntry *entry, gpointer user_data)
128 DEBUG_PRINT ("on_gconf_notify_prefs ()");
131 static gint
132 pkg_list_compare (gconstpointer a, gconstpointer b)
134 return strcmp ((const gchar*)a, (const gchar*)b);
137 static void
138 on_listall_output (AnjutaLauncher * launcher,
139 AnjutaLauncherOutputType output_type,
140 const gchar * chars, gpointer user_data)
142 gchar **lines;
143 const gchar *curr_line;
144 gint i = 0;
145 SymbolDBPrefs *sdbp;
146 SymbolDBPrefsPriv *priv;
147 GtkListStore *store;
149 if (output_type == ANJUTA_LAUNCHER_OUTPUT_STDERR)
151 /* no way. We don't like errors on stderr... */
152 return;
155 sdbp = SYMBOL_DB_PREFS (user_data);
156 priv = sdbp->priv;
158 store = priv->prefs_list_store;
159 lines = g_strsplit (chars, "\n", -1);
161 while ((curr_line = lines[i++]) != NULL)
163 gchar **pkgs;
165 pkgs = g_strsplit (curr_line, " ", -1);
167 /* just take the first token as it's the package-name */
168 if (pkgs == NULL)
169 return;
171 if (pkgs[0] == NULL) {
172 g_strfreev (pkgs);
173 continue;
175 priv->pkg_list = g_list_prepend (priv->pkg_list, g_strdup (pkgs[0]));
176 g_strfreev (pkgs);
179 g_strfreev (lines);
182 static void
183 on_listall_exit (AnjutaLauncher * launcher, int child_pid,
184 int exit_status, gulong time_taken_in_seconds,
185 gpointer user_data)
187 SymbolDBPrefs *sdbp;
188 SymbolDBPrefsPriv *priv;
189 GtkListStore *store;
190 GList *item;
191 GtkWidget *treeview;
193 sdbp = SYMBOL_DB_PREFS (user_data);
194 priv = sdbp->priv;
195 store = priv->prefs_list_store;
197 DEBUG_PRINT ("on_listall_exit ()");
199 g_signal_handlers_disconnect_by_func (launcher, on_listall_exit,
200 user_data);
202 treeview = glade_xml_get_widget (priv->prefs_gxml, "tags_treeview");
203 gtk_widget_set_sensitive (treeview, TRUE);
205 /* we should have pkg_list filled with packages names
206 * It's not enough anyway: we have to sort alphabetically the list.
207 * The implementation done before required the single scan of every package,
208 * for instance 'pkg-config --cflags pkg_name', but this was really
209 * unefficent when a lot of packages were found on /usr/lib/pkg-config.
210 * Let then the user click on the toggle checkbox. We'll notify her whether
211 * there are no good cflags for that package.
213 if (priv->pkg_list == NULL)
215 g_warning ("No packages found");
216 return;
219 priv->pkg_list = g_list_sort (priv->pkg_list, pkg_list_compare);
220 item = priv->pkg_list;
222 while (item != NULL)
224 GtkTreeIter iter;
225 gboolean enabled = FALSE;
226 /* that's good. We can add the package to the GtkListStore */
227 gtk_list_store_append (GTK_LIST_STORE (store), &iter);
229 /* check if we should enable or not the checkbox */
230 if (g_hash_table_lookup (priv->enabled_packages_hash, item->data) == NULL)
231 enabled = FALSE;
232 else
233 enabled = TRUE;
235 gtk_list_store_set (store, &iter, COLUMN_LOAD, enabled,
236 COLUMN_NAME, g_strdup (item->data), -1);
238 item = item->next;
242 static void
243 on_tag_load_toggled_parseable_cb (SymbolDBSystem *sdbs,
244 gboolean is_parseable,
245 gpointer user_data)
247 GtkWidget *treeview, *prefs_progressbar;
248 GtkWindow *prefs_window;
249 ParseableData *pdata;
250 SymbolDBPrefs *sdbp;
251 SymbolDBPrefsPriv *priv;
252 const gchar *path_str;
253 GtkTreeIter iter;
254 GtkTreePath *path;
255 GtkListStore *store;
256 gboolean enabled;
257 gchar *curr_package_name;
259 pdata = (ParseableData *)user_data;
260 path_str = pdata->path_str;
261 sdbp = pdata->sdbp;
262 priv = sdbp->priv;
264 DEBUG_PRINT ("on_tag_load_toggled_parseable_cb %d", is_parseable);
265 prefs_window = GTK_WINDOW (glade_xml_get_widget (priv->prefs_gxml, "symbol_db_pref_window"));
266 treeview = glade_xml_get_widget (priv->prefs_gxml, "tags_treeview");
267 prefs_progressbar = glade_xml_get_widget (priv->prefs_gxml, "prefs_progressbar");
269 store = priv->prefs_list_store;
270 path = gtk_tree_path_new_from_string (path_str);
271 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
272 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
273 COLUMN_LOAD, &enabled,
274 COLUMN_NAME, &curr_package_name,
275 -1);
277 if (is_parseable == FALSE)
279 GtkWidget *wid = gtk_message_dialog_new (prefs_window, GTK_DIALOG_MODAL,
280 GTK_MESSAGE_WARNING,
281 GTK_BUTTONS_OK, _("Package is not parseable"));
282 gtk_dialog_run (GTK_DIALOG (wid));
283 gtk_widget_destroy (wid);
285 /* we for sure don't want this package on list next time */
286 gtk_list_store_set (store, &iter, COLUMN_LOAD, FALSE, -1);
288 /* emit the package-remove signal */
289 g_signal_emit (sdbp, signals[PACKAGE_REMOVE], 0, curr_package_name);
291 else
293 /* we have a good parseable package. Let's mark the check enabled/disabled */
294 enabled = !enabled;
295 gtk_list_store_set (store, &iter, COLUMN_LOAD, enabled, -1);
297 /* good, should we scan the packages? */
298 if (enabled == TRUE)
300 symbol_db_system_scan_package (priv->sdbs, curr_package_name);
302 /* emit the package-add signal */
303 g_signal_emit (sdbp, signals[PACKAGE_ADD], 0, curr_package_name);
305 else
307 /* emit the package-remove signal */
308 g_signal_emit (sdbp, signals[PACKAGE_REMOVE], 0, curr_package_name);
312 gtk_widget_set_sensitive (treeview, TRUE);
313 gtk_widget_hide (prefs_progressbar);
314 gtk_tree_path_free (path);
316 destroy_parseable_data (pdata);
319 static void
320 on_tag_load_toggled (GtkCellRendererToggle *cell, char *path_str,
321 SymbolDBPrefs *sdbp)
323 GtkTreeIter iter;
324 GtkTreePath *path;
325 gchar *curr_package_name;
326 GtkListStore *store;
327 GtkWidget *prefs_progressbar;
328 GtkWidget * treeview;
329 ParseableData *pdata;
330 SymbolDBPrefsPriv *priv;
332 priv = sdbp->priv;
334 DEBUG_PRINT ("on_tag_load_toggled ()");
336 store = priv->prefs_list_store;
337 path = gtk_tree_path_new_from_string (path_str);
338 gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
339 gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
340 COLUMN_NAME, &curr_package_name,
341 -1);
342 gtk_tree_path_free (path);
344 prefs_progressbar = glade_xml_get_widget (priv->prefs_gxml, "prefs_progressbar");
345 gtk_widget_show_all (prefs_progressbar);
347 gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (prefs_progressbar), 1.0);
348 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (prefs_progressbar));
350 treeview = glade_xml_get_widget (priv->prefs_gxml, "tags_treeview");
351 gtk_widget_set_sensitive (treeview, FALSE);
353 pdata = g_new0 (ParseableData, 1);
354 pdata->sdbp = sdbp;
355 pdata->path_str = g_strdup (path_str);
357 symbol_db_system_is_package_parseable (priv->sdbs, curr_package_name,
358 on_tag_load_toggled_parseable_cb,
359 pdata);
362 static void
363 sdb_prefs_init1 (SymbolDBPrefs *sdbp)
365 SymbolDBPrefsPriv *priv;
366 GtkWidget *fchooser;
367 gchar *ctags_value;
369 priv = sdbp->priv;
371 fchooser = glade_xml_get_widget (priv->prefs_gxml, CHOOSER_WIDGET);
372 /* we will reactivate it after the listall has been finished */
373 gtk_widget_set_sensitive (fchooser, FALSE);
375 anjuta_preferences_add_page (priv->prefs,
376 priv->prefs_gxml,
377 GLADE_ROOT,
378 _("Symbol Database"),
379 ICON_FILE);
381 ctags_value = anjuta_preferences_get (priv->prefs, CTAGS_PREFS_KEY);
383 if (ctags_value == NULL || strlen (ctags_value) <= 0)
385 ctags_value = g_strdup (CTAGS_PATH);
388 DEBUG_PRINT ("select ->%s<-", ctags_value);
389 /* FIXME: wtf?! */
390 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (fchooser), ctags_value);
391 gtk_file_chooser_select_filename (GTK_FILE_CHOOSER (fchooser), ctags_value);
393 g_signal_connect (G_OBJECT (fchooser), "selection-changed",
394 G_CALLBACK (on_prefs_executable_changed), sdbp);
396 priv->prefs_notify_id = anjuta_preferences_notify_add (priv->prefs,
397 CTAGS_PREFS_KEY,
398 on_gconf_notify_prefs,
399 priv->prefs, NULL);
401 g_free (ctags_value);
404 static void
405 sdb_prefs_init (SymbolDBPrefs *object)
407 SymbolDBPrefs *sdbp;
408 SymbolDBPrefsPriv *priv;
409 GtkWidget *treeview;
410 GtkCellRenderer *renderer;
411 GtkTreeViewColumn *column;
412 gchar* exe_string = NULL;
413 gboolean require_scan = FALSE; /* scan for packages */
415 sdbp = SYMBOL_DB_PREFS (object);
416 sdbp->priv = g_new0 (SymbolDBPrefsPriv, 1);
417 priv = sdbp->priv;
419 priv->pkg_list = NULL;
421 DEBUG_PRINT ("symbol_db_prefs_init ()");
423 if (priv->prefs_gxml == NULL)
425 /* Create the preferences page */
426 priv->prefs_gxml = glade_xml_new (GLADE_FILE, GLADE_ROOT, NULL);
429 /* init GtkListStore */
430 if (priv->prefs_list_store == NULL)
432 priv->prefs_list_store = gtk_list_store_new (COLUMN_MAX, G_TYPE_BOOLEAN,
433 G_TYPE_STRING);
434 require_scan = TRUE;
437 treeview = glade_xml_get_widget (priv->prefs_gxml, "tags_treeview");
438 /* on_listall_exit will reactivate this */
439 gtk_widget_set_sensitive (treeview, FALSE);
440 gtk_tree_view_set_model (GTK_TREE_VIEW (treeview),
441 GTK_TREE_MODEL (priv->prefs_list_store));
443 /* Add the column for stock treeview */
444 renderer = gtk_cell_renderer_toggle_new ();
445 g_signal_connect (G_OBJECT (renderer), "toggled",
446 G_CALLBACK (on_tag_load_toggled), sdbp);
447 column = gtk_tree_view_column_new_with_attributes (_("Load"),
448 renderer,
449 "active",
450 COLUMN_LOAD,
451 NULL);
452 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
454 renderer = gtk_cell_renderer_text_new ();
455 column = gtk_tree_view_column_new_with_attributes (_("API Tags"),
456 renderer, "text",
457 COLUMN_NAME,
458 NULL);
459 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
460 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
461 gtk_tree_view_set_search_column (GTK_TREE_VIEW (treeview),
462 COLUMN_NAME);
464 /* frame3 show all */
465 GtkWidget *frame3;
466 frame3 = glade_xml_get_widget (priv->prefs_gxml, "frame3");
467 gtk_widget_show_all (frame3);
468 GtkWidget *prefs_progressbar = glade_xml_get_widget (priv->prefs_gxml,
469 "prefs_progressbar");
470 gtk_widget_hide (prefs_progressbar);
472 /* listall launcher thing */
473 if (require_scan == TRUE)
475 priv->pkg_config_launcher = anjuta_launcher_new ();
477 anjuta_launcher_set_check_passwd_prompt (priv->pkg_config_launcher,
478 FALSE);
480 g_signal_connect (G_OBJECT (priv->pkg_config_launcher), "child-exited",
481 G_CALLBACK (on_listall_exit), sdbp);
483 exe_string = g_strdup ("pkg-config --list-all");
485 anjuta_launcher_execute (priv->pkg_config_launcher,
486 exe_string, on_listall_output,
487 sdbp);
490 /* unrefs unused memory objects */
491 g_free (exe_string);
494 static void
495 sdb_prefs_finalize (GObject *object)
497 SymbolDBPrefs *sdbp;
498 SymbolDBPrefsPriv *priv;
500 sdbp = SYMBOL_DB_PREFS (object);
501 priv = sdbp->priv;
503 DEBUG_PRINT ("symbol_db_prefs_finalize ()");
505 anjuta_preferences_notify_remove(priv->prefs, priv->prefs_notify_id);
506 anjuta_preferences_remove_page(priv->prefs, _("Symbol Database"));
508 if (priv->pkg_config_launcher != NULL)
509 g_object_unref (priv->pkg_config_launcher);
510 priv->pkg_config_launcher = NULL;
512 /* free pkg_list */
513 g_list_foreach (priv->pkg_list, (GFunc)g_free, NULL);
514 g_list_free (priv->pkg_list);
515 priv->pkg_list = NULL;
517 if (priv->prefs_gxml != NULL)
518 g_object_unref (priv->prefs_gxml);
520 if (priv->prefs_list_store != NULL)
521 g_object_unref (priv->prefs_list_store);
523 if (priv->enabled_packages_hash)
525 g_hash_table_destroy (priv->enabled_packages_hash);
528 G_OBJECT_CLASS (sdb_prefs_parent_class)->finalize (object);
531 static void
532 sdb_prefs_class_init (SymbolDBPrefsClass *klass)
534 GObjectClass* object_class = G_OBJECT_CLASS (klass);
536 signals[PACKAGE_ADD]
537 = g_signal_new ("package-add",
538 G_OBJECT_CLASS_TYPE (object_class),
539 G_SIGNAL_RUN_FIRST,
540 G_STRUCT_OFFSET (SymbolDBPrefsClass, package_add),
541 NULL, NULL,
542 g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
544 G_TYPE_STRING);
546 signals[PACKAGE_REMOVE]
547 = g_signal_new ("package-remove",
548 G_OBJECT_CLASS_TYPE (object_class),
549 G_SIGNAL_RUN_FIRST,
550 G_STRUCT_OFFSET (SymbolDBPrefsClass, package_remove),
551 NULL, NULL,
552 g_cclosure_marshal_VOID__STRING, G_TYPE_NONE,
554 G_TYPE_STRING);
556 object_class->finalize = sdb_prefs_finalize;
559 SymbolDBPrefs *
560 symbol_db_prefs_new (SymbolDBSystem *sdbs, SymbolDBEngine *sdbe_project,
561 SymbolDBEngine *sdbe_globals, AnjutaPreferences *prefs,
562 GList *enabled_packages)
564 SymbolDBPrefs *sdbp;
565 SymbolDBPrefsPriv *priv;
567 sdbp = g_object_new (SYMBOL_TYPE_DB_PREFS, NULL);
569 priv = sdbp->priv;
571 priv->sdbs = sdbs;
572 priv->prefs = prefs;
573 priv->sdbe_project = sdbe_project;
574 priv->sdbe_globals = sdbe_globals;
575 priv->enabled_packages_hash = g_hash_table_new_full (g_str_hash, g_str_equal,
576 g_free, NULL);
578 /* we'll convert the list of strings in input into an hash table, so that
579 * a lookup there will be done quicker
581 GList *item = enabled_packages;
582 while (item != NULL)
584 g_hash_table_insert (priv->enabled_packages_hash, (gpointer)g_strdup (item->data),
585 (gpointer)TRUE);
586 item = item->next;
589 sdb_prefs_init1 (sdbp);
590 return sdbp;