menuselect_gtk.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <gtk/gtk.h>
  5. #include "menuselect.h"
  6. enum {
  7. /*! The row name */
  8. COLUMN_NAME,
  9. /*! Whether this row is enabled */
  10. COLUMN_SELECTED,
  11. /*! Dependencies */
  12. COLUMN_DEPS,
  13. /*! Optional dependencies */
  14. COLUMN_USES,
  15. /*! Conflicts */
  16. COLUMN_CNFS,
  17. /*! Number of columns, must be the last element in the enum */
  18. NUM_COLUMNS,
  19. };
  20. static void handle_save(GtkWidget *w, gpointer data);
  21. static void handle_about(GtkWidget *w, gpointer data);
  22. static void handle_quit(GtkWidget *w, gpointer data);
  23. static GtkItemFactoryEntry menu_items[] = {
  24. { "/_File", NULL, NULL, 0, "<Branch>" },
  25. { "/File/_Save And Quit", "<control>S", handle_save, 0, "<StockItem>", GTK_STOCK_SAVE },
  26. { "/File/sep1", NULL, NULL, 0, "<Separator>" },
  27. { "/File/_Quit", "<CTRL>Q", handle_quit, 0, "<StockItem>", GTK_STOCK_QUIT },
  28. { "/_Help", NULL, NULL, 0, "<LastBranch>" },
  29. { "/_Help/About", NULL, handle_about, 0, "<Item>" },
  30. };
  31. static gint nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
  32. static GtkTreeView *tree;
  33. static GtkWidget *window;
  34. /* 0, save ... non-zero, don't save */
  35. static int main_res = 1;
  36. static int change_made = 0;
  37. static void handle_save(GtkWidget *w, gpointer data)
  38. {
  39. main_res = 0;
  40. gtk_main_quit();
  41. }
  42. static void handle_about(GtkWidget *w, gpointer data)
  43. {
  44. GtkWidget *dialog;
  45. dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL,
  46. GTK_MESSAGE_INFO, GTK_BUTTONS_OK,
  47. "GMenuselect - http://www.asterisk.org/\n"
  48. "Russell Bryant <russell@digium.com>\n"
  49. "Copyright (C) 2007\n");
  50. gtk_dialog_run(GTK_DIALOG(dialog));
  51. gtk_widget_destroy(dialog);
  52. }
  53. static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
  54. {
  55. return FALSE;
  56. }
  57. static void handle_quit(GtkWidget *widget, gpointer data)
  58. {
  59. gtk_main_quit();
  60. }
  61. static void destroy(GtkWidget *widget, gpointer data)
  62. {
  63. GtkWidget *dialog;
  64. gint response;
  65. if (!main_res || !change_made) {
  66. gtk_main_quit();
  67. return;
  68. }
  69. dialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_MODAL,
  70. GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "Save before quit?");
  71. response = gtk_dialog_run(GTK_DIALOG(dialog));
  72. gtk_widget_destroy(dialog);
  73. if (response == GTK_RESPONSE_YES)
  74. main_res = 0;
  75. gtk_main_quit();
  76. }
  77. static void toggled_handler(GtkCellRendererToggle *renderer, gchar *path, gpointer data)
  78. {
  79. gchar *cat_num_str, *mem_num_str;
  80. int cat_num, mem_num;
  81. int i = 0;
  82. struct category *cat;
  83. struct member *mem;
  84. GtkTreeStore *store = data;
  85. GtkTreeModel *model;
  86. GtkTreeIter cat_iter, mem_iter;
  87. mem_num_str = alloca(strlen(path)) + 1;
  88. strcpy(mem_num_str, path);
  89. cat_num_str = strsep(&mem_num_str, ":");
  90. if (!mem_num_str || !*mem_num_str)
  91. return;
  92. cat_num = atoi(cat_num_str);
  93. mem_num = atoi(mem_num_str);
  94. AST_LIST_TRAVERSE(&categories, cat, list) {
  95. if (i == cat_num)
  96. break;
  97. i++;
  98. }
  99. if (!cat)
  100. return;
  101. i = 0;
  102. AST_LIST_TRAVERSE(&cat->members, mem, list) {
  103. if (i == mem_num)
  104. break;
  105. i++;
  106. }
  107. if (!mem)
  108. return;
  109. toggle_enabled(mem);
  110. model = gtk_tree_view_get_model(tree);
  111. gtk_tree_model_get_iter_first(model, &cat_iter);
  112. for (i = 0; i < cat_num; i++) {
  113. if (!gtk_tree_model_iter_next(model, &cat_iter))
  114. break;
  115. }
  116. if (i != cat_num)
  117. return;
  118. if (!gtk_tree_model_iter_children(model, &mem_iter, &cat_iter))
  119. return;
  120. for (i = 0; i < mem_num; i++) {
  121. if (!gtk_tree_model_iter_next(model, &mem_iter))
  122. break;
  123. }
  124. if (i != mem_num)
  125. return;
  126. gtk_tree_store_set(store, &mem_iter, COLUMN_SELECTED, mem->enabled, -1);
  127. change_made = 1;
  128. }
  129. static void row_activated_handler(GtkTreeView *treeview, GtkTreePath *path,
  130. GtkTreeViewColumn *col, gpointer data)
  131. {
  132. GtkTreeIter iter;
  133. GtkTreeModel *model;
  134. GtkTreeStore *store = data;
  135. gchar *name;
  136. struct category *cat;
  137. struct member *mem;
  138. model = gtk_tree_view_get_model(treeview);
  139. if (!gtk_tree_model_get_iter(model, &iter, path))
  140. return;
  141. gtk_tree_model_get(model, &iter, COLUMN_NAME, &name, -1);
  142. AST_LIST_TRAVERSE(&categories, cat, list) {
  143. AST_LIST_TRAVERSE(&cat->members, mem, list) {
  144. if (strcmp(name, mem->name))
  145. continue;
  146. toggle_enabled(mem);
  147. gtk_tree_store_set(store, &iter, COLUMN_SELECTED, mem->enabled, -1);
  148. change_made = 1;
  149. break;
  150. }
  151. if (mem)
  152. break;
  153. }
  154. g_free(name);
  155. }
  156. static GtkWidget *get_menubar_menu(GtkWidget *window)
  157. {
  158. GtkItemFactory *item_factory;
  159. GtkAccelGroup *accel_group;
  160. /* Make an accelerator group (shortcut keys) */
  161. accel_group = gtk_accel_group_new();
  162. /* Make an ItemFactory (that makes a menubar) */
  163. item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>",
  164. accel_group);
  165. /* This function generates the menu items. Pass the item factory,
  166. the number of items in the array, the array itself, and any
  167. callback data for the the menu items. */
  168. gtk_item_factory_create_items(item_factory, nmenu_items, menu_items, NULL);
  169. /* Attach the new accelerator group to the window. */
  170. gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
  171. /* Finally, return the actual menu bar created by the item factory. */
  172. return gtk_item_factory_get_widget(item_factory, "<main>");
  173. }
  174. int run_menu(void)
  175. {
  176. int argc = 0;
  177. char **argv = NULL;
  178. GtkWidget *s_window;
  179. GtkCellRenderer *renderer;
  180. GtkTreeViewColumn *column;
  181. GtkTreeStore *store;
  182. struct category *cat;
  183. struct member *mem;
  184. GtkWidget *main_vbox;
  185. GtkWidget *menubar;
  186. gtk_init(&argc, &argv);
  187. window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  188. gtk_widget_set_size_request(window, 640, 480);
  189. gtk_window_set_title(GTK_WINDOW(window), "GMenuselect");
  190. main_vbox = gtk_vbox_new(FALSE, 1);
  191. gtk_container_set_border_width(GTK_CONTAINER(main_vbox), 1);
  192. gtk_container_add(GTK_CONTAINER(window), main_vbox);
  193. menubar = get_menubar_menu(window);
  194. gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, FALSE, 0);
  195. s_window = gtk_scrolled_window_new(NULL, NULL);
  196. g_signal_connect(G_OBJECT(window), "delete_event",
  197. G_CALLBACK(delete_event), NULL);
  198. g_signal_connect(G_OBJECT(window), "destroy",
  199. G_CALLBACK(destroy), NULL);
  200. store = gtk_tree_store_new(NUM_COLUMNS,
  201. G_TYPE_STRING, /* COLUMN_NAME */
  202. G_TYPE_BOOLEAN, /* COLUMN_SELECTED */
  203. G_TYPE_STRING, /* COLUMN_DEPS */
  204. G_TYPE_STRING, /* COLUMN_USES */
  205. G_TYPE_STRING); /* COLUMN_CNFS */
  206. AST_LIST_TRAVERSE(&categories, cat, list) {
  207. GtkTreeIter iter, iter2;
  208. gtk_tree_store_append(store, &iter, NULL);
  209. gtk_tree_store_set(store, &iter,
  210. COLUMN_NAME, cat->displayname,
  211. COLUMN_SELECTED, TRUE,
  212. -1);
  213. AST_LIST_TRAVERSE(&cat->members, mem, list) {
  214. char name_buf[64];
  215. char dep_buf[64] = "";
  216. char use_buf[64] = "";
  217. char cnf_buf[64] = "";
  218. struct reference *dep;
  219. struct reference *use;
  220. struct reference *cnf;
  221. AST_LIST_TRAVERSE(&mem->deps, dep, list) {
  222. strncat(dep_buf, dep->displayname, sizeof(dep_buf) - strlen(dep_buf) - 1);
  223. strncat(dep_buf, dep->member ? "(M)" : "(E)", sizeof(dep_buf) - strlen(dep_buf) - 1);
  224. if (AST_LIST_NEXT(dep, list))
  225. strncat(dep_buf, ", ", sizeof(dep_buf) - strlen(dep_buf) - 1);
  226. }
  227. AST_LIST_TRAVERSE(&mem->uses, use, list) {
  228. strncat(use_buf, use->displayname, sizeof(use_buf) - strlen(use_buf) - 1);
  229. if (AST_LIST_NEXT(use, list))
  230. strncat(use_buf, ", ", sizeof(use_buf) - strlen(use_buf) - 1);
  231. }
  232. AST_LIST_TRAVERSE(&mem->conflicts, cnf, list) {
  233. strncat(cnf_buf, cnf->displayname, sizeof(cnf_buf) - strlen(cnf_buf) - 1);
  234. strncat(cnf_buf, cnf->member ? "(M)" : "(E)", sizeof(cnf_buf) - strlen(cnf_buf) - 1);
  235. if (AST_LIST_NEXT(cnf, list))
  236. strncat(cnf_buf, ", ", sizeof(cnf_buf) - strlen(cnf_buf) - 1);
  237. }
  238. if (mem->is_separator) {
  239. snprintf(name_buf, sizeof(name_buf), "--- %s ---", mem->name);
  240. } else {
  241. snprintf(name_buf, sizeof(name_buf), "%s", mem->name);
  242. }
  243. if (mem->depsfailed == HARD_FAILURE)
  244. strncat(name_buf, " (Failed Deps.)", sizeof(name_buf) - strlen(name_buf) - 1);
  245. if (mem->conflictsfailed == HARD_FAILURE)
  246. strncat(name_buf, " (In Conflict)", sizeof(name_buf) - strlen(name_buf) - 1);
  247. gtk_tree_store_append(store, &iter2, &iter);
  248. gtk_tree_store_set(store, &iter2,
  249. COLUMN_NAME, name_buf,
  250. COLUMN_SELECTED, mem->enabled,
  251. COLUMN_DEPS, dep_buf,
  252. COLUMN_USES, use_buf,
  253. COLUMN_CNFS, cnf_buf,
  254. -1);
  255. }
  256. }
  257. tree = (GtkTreeView *) gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
  258. #if GTK_CHECK_VERSION(2,10,0)
  259. gtk_tree_view_set_enable_tree_lines(tree, TRUE);
  260. gtk_tree_view_set_grid_lines(tree, GTK_TREE_VIEW_GRID_LINES_BOTH);
  261. #endif
  262. renderer = gtk_cell_renderer_text_new();
  263. column = gtk_tree_view_column_new_with_attributes("Name",
  264. renderer, "text", COLUMN_NAME, NULL);
  265. gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  266. renderer = gtk_cell_renderer_toggle_new();
  267. column = gtk_tree_view_column_new_with_attributes("Selected",
  268. renderer, "active", COLUMN_SELECTED, NULL);
  269. gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  270. g_signal_connect(renderer, "toggled", (GCallback) toggled_handler, store);
  271. renderer = gtk_cell_renderer_text_new();
  272. column = gtk_tree_view_column_new_with_attributes("Depends On",
  273. renderer, "text", COLUMN_DEPS, NULL);
  274. gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  275. renderer = gtk_cell_renderer_text_new();
  276. column = gtk_tree_view_column_new_with_attributes("Can Use",
  277. renderer, "text", COLUMN_USES, NULL);
  278. gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  279. renderer = gtk_cell_renderer_text_new();
  280. column = gtk_tree_view_column_new_with_attributes("Conflicts With",
  281. renderer, "text", COLUMN_CNFS, NULL);
  282. gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
  283. g_signal_connect(tree, "row-activated", (GCallback) row_activated_handler, store);
  284. gtk_container_add(GTK_CONTAINER(s_window), GTK_WIDGET(tree));
  285. gtk_box_pack_end(GTK_BOX(main_vbox), s_window, TRUE, TRUE, 0);
  286. gtk_widget_show_all(window);
  287. gtk_main();
  288. return main_res;
  289. }