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