PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/anjuta-3.5.4/plugins/gdb/preferences.c

#
C | 474 lines | 343 code | 86 blank | 45 comment | 35 complexity | 18613e3f7ecfcd56c09b1e2fea40c229 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, GPL-3.0, LGPL-3.0
  1. /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
  2. /* preferences.c
  3. *
  4. * Copyright (C) 2010 S?Šbastien Granjoux
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of the
  9. * License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public
  17. * License along with this program; if not, write to the
  18. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. * Boston, MA 02111-1307, USA.
  20. *
  21. */
  22. #ifdef HAVE_CONFIG_H
  23. #include <config.h>
  24. #endif
  25. #include "preferences.h"
  26. #include <libanjuta/anjuta-utils.h>
  27. #define BUILDER_FILE PACKAGE_DATA_DIR"/glade/anjuta-gdb.ui"
  28. #define BUILD_PREFS_DIALOG "preferences_dialog_build"
  29. #define GDB_PREFS_ROOT "gdb_preferences_container"
  30. #define GDB_PRINTER_TREEVIEW "printers_treeview"
  31. #define GDB_PRINTER_REMOVE_BUTTON "remove_button"
  32. #define ICON_FILE "anjuta-gdb.plugin.png"
  33. #define GDB_SECTION "Gdb"
  34. #define GDB_PRINTER_KEY "PrettyPrinter"
  35. /* column of the printer list view */
  36. enum {
  37. GDB_PP_ACTIVE_COLUMN,
  38. GDB_PP_FILENAME_COLUMN,
  39. GDB_PP_REGISTER_COLUMN,
  40. GDB_PP_N_COLUMNS
  41. };
  42. /* Node types
  43. *---------------------------------------------------------------------------*/
  44. typedef struct
  45. {
  46. GtkTreeView *treeview;
  47. GtkListStore *model;
  48. GtkWidget *remove_button;
  49. GList **list;
  50. } PreferenceDialog;
  51. /* Private functions
  52. *---------------------------------------------------------------------------*/
  53. static gboolean
  54. gdb_append_missing_register_function (GString *msg, GtkTreeModel *model, GtkTreeIter *iter)
  55. {
  56. gboolean active;
  57. gchar *path;
  58. gchar *function;
  59. gboolean missing;
  60. gtk_tree_model_get (model, iter,
  61. GDB_PP_ACTIVE_COLUMN, &active,
  62. GDB_PP_FILENAME_COLUMN, &path,
  63. GDB_PP_REGISTER_COLUMN, &function, -1);
  64. if (function != NULL) function = g_strstrip (function);
  65. missing = active && ((function == NULL) || (*function == '\0'));
  66. if (missing)
  67. {
  68. g_string_append (msg, path);
  69. g_string_append (msg, "\n");
  70. gtk_list_store_set (GTK_LIST_STORE (model), iter, GDB_PP_ACTIVE_COLUMN, FALSE, -1);
  71. }
  72. g_free (path);
  73. g_free (function);
  74. return missing;
  75. }
  76. static void
  77. gdb_check_register_function (PreferenceDialog *dlg, GtkTreeIter *iter)
  78. {
  79. GString *list;
  80. list = g_string_new (NULL);
  81. if (iter == NULL)
  82. {
  83. GtkTreeIter iter;
  84. gboolean valid;
  85. for (valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (dlg->model), &iter);
  86. valid; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (dlg->model), &iter))
  87. {
  88. gdb_append_missing_register_function (list, GTK_TREE_MODEL (dlg->model), &iter);
  89. }
  90. }
  91. else
  92. {
  93. gdb_append_missing_register_function (list, GTK_TREE_MODEL (dlg->model), iter);
  94. }
  95. if (list->len > 0)
  96. {
  97. gchar *msg;
  98. /* Translators: pretty printer file is a script containing functions allowing gdb
  99. * to display variable content in a simpler way, typically removing
  100. * implementation details.
  101. * The register function is an additional function in the script. It defines
  102. * which function is used for each type of variables. */
  103. msg = g_strdup_printf(_("The register function hasn't been found automatically in the following pretty printer files:\n"
  104. "%s\nYou need to fill yourself the register function columns before enabling the rows. "
  105. "Most of the time the register function name contains the word \"register\"."), list->str);
  106. anjuta_util_dialog_warning (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (dlg->treeview))), msg);
  107. g_free (msg);
  108. g_string_free (list, TRUE);
  109. }
  110. }
  111. static gchar *
  112. gdb_find_register_function (const gchar *path)
  113. {
  114. GFile *file;
  115. gchar *function = NULL;
  116. gchar *content = NULL;
  117. file = g_file_new_for_path (path);
  118. if (g_file_load_contents (file, NULL, &content, NULL, NULL, NULL))
  119. {
  120. GRegex *regex;
  121. GMatchInfo *match;
  122. regex = g_regex_new ("^def\\s+(register\\w*)\\s*\\(\\w+\\)\\s*:", G_REGEX_CASELESS | G_REGEX_MULTILINE, 0, NULL);
  123. if (g_regex_match (regex, content, 0, &match))
  124. {
  125. function = g_match_info_fetch (match, 1);
  126. g_match_info_free (match);
  127. }
  128. g_regex_unref (regex);
  129. g_free (content);
  130. }
  131. g_object_unref (file);
  132. return function;
  133. }
  134. static gboolean
  135. on_add_printer_in_list (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data)
  136. {
  137. GList** list = (GList **)user_data;
  138. gchar *filepath;
  139. gchar *function;
  140. gboolean active;
  141. GdbPrettyPrinter *printer;
  142. gtk_tree_model_get (model, iter, GDB_PP_ACTIVE_COLUMN, &active,
  143. GDB_PP_FILENAME_COLUMN, &filepath,
  144. GDB_PP_REGISTER_COLUMN, &function,
  145. -1);
  146. printer = g_slice_new0 (GdbPrettyPrinter);
  147. printer->enable = active;
  148. printer->path = filepath;
  149. printer->function = function;
  150. *list = g_list_prepend (*list, printer);
  151. return FALSE;
  152. }
  153. /* Call backs
  154. *---------------------------------------------------------------------------*/
  155. /* Gtk builder callbacks */
  156. void gdb_on_printer_add (GtkButton *button, gpointer user_data);
  157. void gdb_on_printer_remove (GtkButton *button, gpointer user_data);
  158. void gdb_on_destroy_preferences (GtkWidget *object, gpointer user_data);
  159. void
  160. gdb_on_destroy_preferences (GtkWidget *object, gpointer user_data)
  161. {
  162. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  163. GList *new_list;
  164. /* Free previous list and replace with new one */
  165. g_list_foreach (*(dlg->list), (GFunc)gdb_pretty_printer_free, NULL);
  166. g_list_free (*(dlg->list));
  167. *(dlg->list) = NULL;
  168. /* Replace with new one */
  169. new_list = NULL;
  170. gtk_tree_model_foreach (GTK_TREE_MODEL (dlg->model), on_add_printer_in_list, &new_list);
  171. new_list = g_list_reverse (new_list);
  172. *(dlg->list) = new_list;
  173. g_free (dlg);
  174. }
  175. void
  176. gdb_on_printer_add (GtkButton *button, gpointer user_data)
  177. {
  178. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  179. GtkWidget *chooser;
  180. GtkFileFilter *filter;
  181. chooser = gtk_file_chooser_dialog_new (_("Select a pretty printer file"),
  182. GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
  183. GTK_FILE_CHOOSER_ACTION_OPEN,
  184. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
  185. GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
  186. NULL);
  187. filter = gtk_file_filter_new ();
  188. gtk_file_filter_add_mime_type (filter, "text/x-python");
  189. gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser), TRUE);
  190. gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser),filter);
  191. if (gtk_dialog_run (GTK_DIALOG (chooser)) == GTK_RESPONSE_ACCEPT)
  192. {
  193. GSList *filenames;
  194. GSList *item;
  195. filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
  196. for (item = filenames; item != NULL; item = g_slist_next (item))
  197. {
  198. GtkTreeIter iter;
  199. gchar *path = (gchar *)item->data;
  200. gchar *function;
  201. function = gdb_find_register_function (path);
  202. gtk_list_store_append (dlg->model, &iter);
  203. gtk_list_store_set (dlg->model, &iter, GDB_PP_ACTIVE_COLUMN, TRUE,
  204. GDB_PP_FILENAME_COLUMN, path,
  205. GDB_PP_REGISTER_COLUMN, function,
  206. -1);
  207. g_free (path);
  208. g_free (function);
  209. gdb_check_register_function (dlg, &iter);
  210. }
  211. g_slist_free (filenames);
  212. }
  213. gtk_widget_destroy (chooser);
  214. }
  215. void
  216. gdb_on_printer_remove (GtkButton *button, gpointer user_data)
  217. {
  218. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  219. GtkTreeIter iter;
  220. GtkTreeSelection* sel;
  221. sel = gtk_tree_view_get_selection (dlg->treeview);
  222. if (gtk_tree_selection_get_selected (sel, NULL, &iter))
  223. {
  224. gtk_list_store_remove (dlg->model, &iter);
  225. }
  226. }
  227. static void
  228. gdb_on_printer_activate (GtkCellRendererToggle *cell_renderer, const gchar *path, gpointer user_data)
  229. {
  230. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  231. GtkTreeIter iter;
  232. if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dlg->model), &iter, path))
  233. {
  234. gboolean enable;
  235. gtk_tree_model_get (GTK_TREE_MODEL (dlg->model), &iter, GDB_PP_ACTIVE_COLUMN, &enable, -1);
  236. enable = !enable;
  237. gtk_list_store_set (dlg->model, &iter, GDB_PP_ACTIVE_COLUMN, enable, -1);
  238. }
  239. }
  240. static void
  241. gdb_on_printer_function_changed (GtkCellRendererText *renderer,
  242. gchar *path,
  243. gchar *new_text,
  244. gpointer user_data)
  245. {
  246. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  247. GtkTreeIter iter;
  248. if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (dlg->model), &iter, path))
  249. {
  250. gchar *function = g_strstrip (new_text);
  251. gtk_list_store_set (dlg->model, &iter, GDB_PP_REGISTER_COLUMN, function, -1);
  252. }
  253. }
  254. static void
  255. gdb_on_printer_selection_changed (GtkTreeSelection *selection, gpointer user_data)
  256. {
  257. PreferenceDialog *dlg = (PreferenceDialog *)user_data;
  258. GtkTreeIter iter;
  259. GtkTreeSelection* sel;
  260. gboolean selected;
  261. sel = gtk_tree_view_get_selection (dlg->treeview);
  262. selected = gtk_tree_selection_get_selected (sel, NULL, &iter);
  263. gtk_widget_set_sensitive(dlg->remove_button, selected);
  264. }
  265. /* Public functions
  266. *---------------------------------------------------------------------------*/
  267. void
  268. gdb_merge_preferences (AnjutaPreferences* prefs, GList **list)
  269. {
  270. GtkBuilder *bxml;
  271. GtkCellRenderer *renderer;
  272. GtkTreeViewColumn *column;
  273. GtkTreeSelection *selection;
  274. PreferenceDialog *dlg;
  275. GList *item;
  276. g_return_if_fail (list != NULL);
  277. /* Create the preferences page */
  278. bxml = anjuta_util_builder_new (BUILDER_FILE, NULL);
  279. if (!bxml) return;
  280. dlg = g_new0 (PreferenceDialog, 1);
  281. /* Get widgets */
  282. anjuta_util_builder_get_objects (bxml,
  283. GDB_PRINTER_TREEVIEW, &dlg->treeview,
  284. GDB_PRINTER_REMOVE_BUTTON, &dlg->remove_button,
  285. NULL);
  286. /* Create tree view */
  287. dlg->model = gtk_list_store_new (GDB_PP_N_COLUMNS,
  288. G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING);
  289. gtk_tree_view_set_model (dlg->treeview, GTK_TREE_MODEL (dlg->model));
  290. g_object_unref (dlg->model);
  291. renderer = gtk_cell_renderer_toggle_new ();
  292. g_signal_connect (G_OBJECT (renderer), "toggled", G_CALLBACK (gdb_on_printer_activate), dlg);
  293. column = gtk_tree_view_column_new_with_attributes (_("Activate"), renderer,
  294. "active", GDB_PP_ACTIVE_COLUMN, NULL);
  295. gtk_tree_view_append_column (dlg->treeview, column);
  296. renderer = gtk_cell_renderer_text_new ();
  297. column = gtk_tree_view_column_new_with_attributes (_("File"), renderer,
  298. "text", GDB_PP_FILENAME_COLUMN, NULL);
  299. gtk_tree_view_append_column (dlg->treeview, column);
  300. renderer = gtk_cell_renderer_text_new ();
  301. g_object_set(renderer, "editable", TRUE, NULL);
  302. g_signal_connect(renderer, "edited", G_CALLBACK (gdb_on_printer_function_changed), dlg);
  303. /* Translators: The "Register Function" column contains the name of a
  304. * function used to register pretty printers in gdb. */
  305. column = gtk_tree_view_column_new_with_attributes (_("Register Function"), renderer,
  306. "text", GDB_PP_REGISTER_COLUMN, NULL);
  307. gtk_tree_view_append_column (dlg->treeview, column);
  308. /* Connect all signals */
  309. gtk_builder_connect_signals (bxml, dlg);
  310. selection = gtk_tree_view_get_selection (dlg->treeview);
  311. g_signal_connect (G_OBJECT (selection), "changed", G_CALLBACK (gdb_on_printer_selection_changed), dlg);
  312. /* Fill tree view */
  313. dlg->list = list;
  314. for (item = g_list_first (*list); item != NULL; item = g_list_next (item))
  315. {
  316. GdbPrettyPrinter *printer = (GdbPrettyPrinter *)item->data;
  317. GtkTreeIter iter;
  318. gtk_list_store_append (dlg->model, &iter);
  319. gtk_list_store_set (dlg->model, &iter, GDB_PP_ACTIVE_COLUMN, printer->enable ? TRUE : FALSE,
  320. GDB_PP_FILENAME_COLUMN, printer->path,
  321. GDB_PP_REGISTER_COLUMN, printer->function,
  322. -1);
  323. }
  324. anjuta_preferences_add_from_builder (prefs, bxml, NULL, GDB_PREFS_ROOT, _("Gdb Debugger"), ICON_FILE);
  325. g_object_unref (bxml);
  326. }
  327. void
  328. gdb_unmerge_preferences (AnjutaPreferences* prefs)
  329. {
  330. anjuta_preferences_remove_page(prefs, _("Gdb Debugger"));
  331. }
  332. GList *
  333. gdb_load_pretty_printers (AnjutaSession *session)
  334. {
  335. GList *session_list;
  336. GList *list = NULL;
  337. GList *item;
  338. session_list = anjuta_session_get_string_list (session, GDB_SECTION, GDB_PRINTER_KEY);
  339. for (item = g_list_first (session_list); item != NULL; item = g_list_next (item))
  340. {
  341. GdbPrettyPrinter *printer;
  342. gchar *name = (gchar *)item->data;
  343. gchar *ptr;
  344. printer = g_slice_new0 (GdbPrettyPrinter);
  345. ptr = strchr (name, ':');
  346. if (ptr != NULL)
  347. {
  348. if (*name == 'E') printer->enable = TRUE;
  349. name = ptr + 1;
  350. }
  351. ptr = strrchr (name, ':');
  352. if (ptr != NULL)
  353. {
  354. *ptr = '\0';
  355. printer->function = g_strdup (ptr + 1);
  356. }
  357. printer->path = g_strdup (name);
  358. list = g_list_prepend (list, printer);
  359. }
  360. g_list_foreach (session_list, (GFunc)g_free, NULL);
  361. g_list_free (session_list);
  362. return list;
  363. }
  364. gboolean
  365. gdb_save_pretty_printers (AnjutaSession *session, GList *list)
  366. {
  367. GList *session_list = NULL;
  368. GList *item;
  369. for (item = g_list_first (list); item != NULL; item = g_list_next (item))
  370. {
  371. GdbPrettyPrinter *printer = (GdbPrettyPrinter *)item->data;
  372. gchar *name;
  373. name = g_strconcat (printer->enable ? "E:" : "D:", printer->path, ":", printer->function == NULL ? "" : printer->function, NULL);
  374. session_list = g_list_prepend (session_list, name);
  375. }
  376. session_list = g_list_reverse (session_list);
  377. anjuta_session_set_string_list (session, GDB_SECTION, GDB_PRINTER_KEY, session_list);
  378. g_list_foreach (session_list, (GFunc)g_free, NULL);
  379. g_list_free (session_list);
  380. return FALSE;
  381. }
  382. void
  383. gdb_pretty_printer_free (GdbPrettyPrinter *printer)
  384. {
  385. g_free (printer->path);
  386. g_free (printer->function);
  387. g_slice_free (GdbPrettyPrinter, printer);
  388. }