|
|
1.1 root 1: /* Hey EMACS -*- linux-c -*- */
2: /*
3: *
4: * Copyright (C) 2002-2003 Romain Lievin <[email protected]>
5: * Released under the terms of the GNU GPL v2.0.
6: *
7: */
8:
9: #ifdef HAVE_CONFIG_H
10: # include <config.h>
11: #endif
12:
13: #include "lkc.h"
14: #include "images.c"
15:
16: #include <glade/glade.h>
17: #include <gtk/gtk.h>
18: #include <glib.h>
19: #include <gdk/gdkkeysyms.h>
20:
21: #include <stdio.h>
22: #include <string.h>
23: #include <unistd.h>
24: #include <time.h>
25: #include <stdlib.h>
26:
27: //#define DEBUG
28:
29: enum {
30: SINGLE_VIEW, SPLIT_VIEW, FULL_VIEW
31: };
32:
33: enum {
34: OPT_NORMAL, OPT_ALL, OPT_PROMPT
35: };
36:
37: static gint view_mode = FULL_VIEW;
38: static gboolean show_name = TRUE;
39: static gboolean show_range = TRUE;
40: static gboolean show_value = TRUE;
41: static gboolean resizeable = FALSE;
42: static int opt_mode = OPT_NORMAL;
43:
44: GtkWidget *main_wnd = NULL;
45: GtkWidget *tree1_w = NULL; // left frame
46: GtkWidget *tree2_w = NULL; // right frame
47: GtkWidget *text_w = NULL;
48: GtkWidget *hpaned = NULL;
49: GtkWidget *vpaned = NULL;
50: GtkWidget *back_btn = NULL;
51: GtkWidget *save_btn = NULL;
52: GtkWidget *save_menu_item = NULL;
53:
54: GtkTextTag *tag1, *tag2;
55: GdkColor color;
56:
57: GtkTreeStore *tree1, *tree2, *tree;
58: GtkTreeModel *model1, *model2;
59: static GtkTreeIter *parents[256];
60: static gint indent;
61:
62: static struct menu *current; // current node for SINGLE view
63: static struct menu *browsed; // browsed node for SPLIT view
64:
65: enum {
66: COL_OPTION, COL_NAME, COL_NO, COL_MOD, COL_YES, COL_VALUE,
67: COL_MENU, COL_COLOR, COL_EDIT, COL_PIXBUF,
68: COL_PIXVIS, COL_BTNVIS, COL_BTNACT, COL_BTNINC, COL_BTNRAD,
69: COL_NUMBER
70: };
71:
72: static void display_list(void);
73: static void display_tree(struct menu *menu);
74: static void display_tree_part(void);
75: static void update_tree(struct menu *src, GtkTreeIter * dst);
76: static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row);
77: static gchar **fill_row(struct menu *menu);
78: static void conf_changed(void);
79:
80: /* Helping/Debugging Functions */
81:
82: const char *dbg_sym_flags(int val)
83: {
84: static char buf[256];
85:
86: bzero(buf, 256);
87:
88: if (val & SYMBOL_CONST)
89: strcat(buf, "const/");
90: if (val & SYMBOL_CHECK)
91: strcat(buf, "check/");
92: if (val & SYMBOL_CHOICE)
93: strcat(buf, "choice/");
94: if (val & SYMBOL_CHOICEVAL)
95: strcat(buf, "choiceval/");
96: if (val & SYMBOL_VALID)
97: strcat(buf, "valid/");
98: if (val & SYMBOL_OPTIONAL)
99: strcat(buf, "optional/");
100: if (val & SYMBOL_WRITE)
101: strcat(buf, "write/");
102: if (val & SYMBOL_CHANGED)
103: strcat(buf, "changed/");
104: if (val & SYMBOL_AUTO)
105: strcat(buf, "auto/");
106:
107: buf[strlen(buf) - 1] = '\0';
108:
109: return buf;
110: }
111:
112: void replace_button_icon(GladeXML * xml, GdkDrawable * window,
113: GtkStyle * style, gchar * btn_name, gchar ** xpm)
114: {
115: GdkPixmap *pixmap;
116: GdkBitmap *mask;
117: GtkToolButton *button;
118: GtkWidget *image;
119:
120: pixmap = gdk_pixmap_create_from_xpm_d(window, &mask,
121: &style->bg[GTK_STATE_NORMAL],
122: xpm);
123:
124: button = GTK_TOOL_BUTTON(glade_xml_get_widget(xml, btn_name));
125: image = gtk_image_new_from_pixmap(pixmap, mask);
126: gtk_widget_show(image);
127: gtk_tool_button_set_icon_widget(button, image);
128: }
129:
130: /* Main Window Initialization */
131: void init_main_window(const gchar * glade_file)
132: {
133: GladeXML *xml;
134: GtkWidget *widget;
135: GtkTextBuffer *txtbuf;
136: GtkStyle *style;
137:
138: xml = glade_xml_new(glade_file, "window1", NULL);
139: if (!xml)
140: g_error(_("GUI loading failed !\n"));
141: glade_xml_signal_autoconnect(xml);
142:
143: main_wnd = glade_xml_get_widget(xml, "window1");
144: hpaned = glade_xml_get_widget(xml, "hpaned1");
145: vpaned = glade_xml_get_widget(xml, "vpaned1");
146: tree1_w = glade_xml_get_widget(xml, "treeview1");
147: tree2_w = glade_xml_get_widget(xml, "treeview2");
148: text_w = glade_xml_get_widget(xml, "textview3");
149:
150: back_btn = glade_xml_get_widget(xml, "button1");
151: gtk_widget_set_sensitive(back_btn, FALSE);
152:
153: widget = glade_xml_get_widget(xml, "show_name1");
154: gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
155: show_name);
156:
157: widget = glade_xml_get_widget(xml, "show_range1");
158: gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
159: show_range);
160:
161: widget = glade_xml_get_widget(xml, "show_data1");
162: gtk_check_menu_item_set_active((GtkCheckMenuItem *) widget,
163: show_value);
164:
165: save_btn = glade_xml_get_widget(xml, "button3");
166: save_menu_item = glade_xml_get_widget(xml, "save1");
167: conf_set_changed_callback(conf_changed);
168:
169: style = gtk_widget_get_style(main_wnd);
170: widget = glade_xml_get_widget(xml, "toolbar1");
171:
172: #if 0 /* Use stock Gtk icons instead */
173: replace_button_icon(xml, main_wnd->window, style,
174: "button1", (gchar **) xpm_back);
175: replace_button_icon(xml, main_wnd->window, style,
176: "button2", (gchar **) xpm_load);
177: replace_button_icon(xml, main_wnd->window, style,
178: "button3", (gchar **) xpm_save);
179: #endif
180: replace_button_icon(xml, main_wnd->window, style,
181: "button4", (gchar **) xpm_single_view);
182: replace_button_icon(xml, main_wnd->window, style,
183: "button5", (gchar **) xpm_split_view);
184: replace_button_icon(xml, main_wnd->window, style,
185: "button6", (gchar **) xpm_tree_view);
186:
187: #if 0
188: switch (view_mode) {
189: case SINGLE_VIEW:
190: widget = glade_xml_get_widget(xml, "button4");
191: g_signal_emit_by_name(widget, "clicked");
192: break;
193: case SPLIT_VIEW:
194: widget = glade_xml_get_widget(xml, "button5");
195: g_signal_emit_by_name(widget, "clicked");
196: break;
197: case FULL_VIEW:
198: widget = glade_xml_get_widget(xml, "button6");
199: g_signal_emit_by_name(widget, "clicked");
200: break;
201: }
202: #endif
203: txtbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
204: tag1 = gtk_text_buffer_create_tag(txtbuf, "mytag1",
205: "foreground", "red",
206: "weight", PANGO_WEIGHT_BOLD,
207: NULL);
208: tag2 = gtk_text_buffer_create_tag(txtbuf, "mytag2",
209: /*"style", PANGO_STYLE_OBLIQUE, */
210: NULL);
211:
212: gtk_window_set_title(GTK_WINDOW(main_wnd), rootmenu.prompt->text);
213:
214: gtk_widget_show(main_wnd);
215: }
216:
217: void init_tree_model(void)
218: {
219: gint i;
220:
221: tree = tree2 = gtk_tree_store_new(COL_NUMBER,
222: G_TYPE_STRING, G_TYPE_STRING,
223: G_TYPE_STRING, G_TYPE_STRING,
224: G_TYPE_STRING, G_TYPE_STRING,
225: G_TYPE_POINTER, GDK_TYPE_COLOR,
226: G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
227: G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
228: G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
229: G_TYPE_BOOLEAN);
230: model2 = GTK_TREE_MODEL(tree2);
231:
232: for (parents[0] = NULL, i = 1; i < 256; i++)
233: parents[i] = (GtkTreeIter *) g_malloc(sizeof(GtkTreeIter));
234:
235: tree1 = gtk_tree_store_new(COL_NUMBER,
236: G_TYPE_STRING, G_TYPE_STRING,
237: G_TYPE_STRING, G_TYPE_STRING,
238: G_TYPE_STRING, G_TYPE_STRING,
239: G_TYPE_POINTER, GDK_TYPE_COLOR,
240: G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF,
241: G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
242: G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
243: G_TYPE_BOOLEAN);
244: model1 = GTK_TREE_MODEL(tree1);
245: }
246:
247: void init_left_tree(void)
248: {
249: GtkTreeView *view = GTK_TREE_VIEW(tree1_w);
250: GtkCellRenderer *renderer;
251: GtkTreeSelection *sel;
252: GtkTreeViewColumn *column;
253:
254: gtk_tree_view_set_model(view, model1);
255: gtk_tree_view_set_headers_visible(view, TRUE);
256: gtk_tree_view_set_rules_hint(view, FALSE);
257:
258: column = gtk_tree_view_column_new();
259: gtk_tree_view_append_column(view, column);
260: gtk_tree_view_column_set_title(column, _("Options"));
261:
262: renderer = gtk_cell_renderer_toggle_new();
263: gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
264: renderer, FALSE);
265: gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
266: renderer,
267: "active", COL_BTNACT,
268: "inconsistent", COL_BTNINC,
269: "visible", COL_BTNVIS,
270: "radio", COL_BTNRAD, NULL);
271: renderer = gtk_cell_renderer_text_new();
272: gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
273: renderer, FALSE);
274: gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
275: renderer,
276: "text", COL_OPTION,
277: "foreground-gdk",
278: COL_COLOR, NULL);
279:
280: sel = gtk_tree_view_get_selection(view);
281: gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
282: gtk_widget_realize(tree1_w);
283: }
284:
285: static void renderer_edited(GtkCellRendererText * cell,
286: const gchar * path_string,
287: const gchar * new_text, gpointer user_data);
288: static void renderer_toggled(GtkCellRendererToggle * cellrenderertoggle,
289: gchar * arg1, gpointer user_data);
290:
291: void init_right_tree(void)
292: {
293: GtkTreeView *view = GTK_TREE_VIEW(tree2_w);
294: GtkCellRenderer *renderer;
295: GtkTreeSelection *sel;
296: GtkTreeViewColumn *column;
297: gint i;
298:
299: gtk_tree_view_set_model(view, model2);
300: gtk_tree_view_set_headers_visible(view, TRUE);
301: gtk_tree_view_set_rules_hint(view, FALSE);
302:
303: column = gtk_tree_view_column_new();
304: gtk_tree_view_append_column(view, column);
305: gtk_tree_view_column_set_title(column, _("Options"));
306:
307: renderer = gtk_cell_renderer_pixbuf_new();
308: gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
309: renderer, FALSE);
310: gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
311: renderer,
312: "pixbuf", COL_PIXBUF,
313: "visible", COL_PIXVIS, NULL);
314: renderer = gtk_cell_renderer_toggle_new();
315: gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
316: renderer, FALSE);
317: gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
318: renderer,
319: "active", COL_BTNACT,
320: "inconsistent", COL_BTNINC,
321: "visible", COL_BTNVIS,
322: "radio", COL_BTNRAD, NULL);
323: /*g_signal_connect(G_OBJECT(renderer), "toggled",
324: G_CALLBACK(renderer_toggled), NULL); */
325: renderer = gtk_cell_renderer_text_new();
326: gtk_tree_view_column_pack_start(GTK_TREE_VIEW_COLUMN(column),
327: renderer, FALSE);
328: gtk_tree_view_column_set_attributes(GTK_TREE_VIEW_COLUMN(column),
329: renderer,
330: "text", COL_OPTION,
331: "foreground-gdk",
332: COL_COLOR, NULL);
333:
334: renderer = gtk_cell_renderer_text_new();
335: gtk_tree_view_insert_column_with_attributes(view, -1,
336: _("Name"), renderer,
337: "text", COL_NAME,
338: "foreground-gdk",
339: COL_COLOR, NULL);
340: renderer = gtk_cell_renderer_text_new();
341: gtk_tree_view_insert_column_with_attributes(view, -1,
342: "N", renderer,
343: "text", COL_NO,
344: "foreground-gdk",
345: COL_COLOR, NULL);
346: renderer = gtk_cell_renderer_text_new();
347: gtk_tree_view_insert_column_with_attributes(view, -1,
348: "M", renderer,
349: "text", COL_MOD,
350: "foreground-gdk",
351: COL_COLOR, NULL);
352: renderer = gtk_cell_renderer_text_new();
353: gtk_tree_view_insert_column_with_attributes(view, -1,
354: "Y", renderer,
355: "text", COL_YES,
356: "foreground-gdk",
357: COL_COLOR, NULL);
358: renderer = gtk_cell_renderer_text_new();
359: gtk_tree_view_insert_column_with_attributes(view, -1,
360: _("Value"), renderer,
361: "text", COL_VALUE,
362: "editable",
363: COL_EDIT,
364: "foreground-gdk",
365: COL_COLOR, NULL);
366: g_signal_connect(G_OBJECT(renderer), "edited",
367: G_CALLBACK(renderer_edited), NULL);
368:
369: column = gtk_tree_view_get_column(view, COL_NAME);
370: gtk_tree_view_column_set_visible(column, show_name);
371: column = gtk_tree_view_get_column(view, COL_NO);
372: gtk_tree_view_column_set_visible(column, show_range);
373: column = gtk_tree_view_get_column(view, COL_MOD);
374: gtk_tree_view_column_set_visible(column, show_range);
375: column = gtk_tree_view_get_column(view, COL_YES);
376: gtk_tree_view_column_set_visible(column, show_range);
377: column = gtk_tree_view_get_column(view, COL_VALUE);
378: gtk_tree_view_column_set_visible(column, show_value);
379:
380: if (resizeable) {
381: for (i = 0; i < COL_VALUE; i++) {
382: column = gtk_tree_view_get_column(view, i);
383: gtk_tree_view_column_set_resizable(column, TRUE);
384: }
385: }
386:
387: sel = gtk_tree_view_get_selection(view);
388: gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE);
389: }
390:
391:
392: /* Utility Functions */
393:
394:
395: static void text_insert_help(struct menu *menu)
396: {
397: GtkTextBuffer *buffer;
398: GtkTextIter start, end;
399: const char *prompt = _(menu_get_prompt(menu));
400: struct gstr help = str_new();
401:
402: menu_get_ext_help(menu, &help);
403:
404: buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
405: gtk_text_buffer_get_bounds(buffer, &start, &end);
406: gtk_text_buffer_delete(buffer, &start, &end);
407: gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
408:
409: gtk_text_buffer_get_end_iter(buffer, &end);
410: gtk_text_buffer_insert_with_tags(buffer, &end, prompt, -1, tag1,
411: NULL);
412: gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
413: gtk_text_buffer_get_end_iter(buffer, &end);
414: gtk_text_buffer_insert_with_tags(buffer, &end, str_get(&help), -1, tag2,
415: NULL);
416: str_free(&help);
417: }
418:
419:
420: static void text_insert_msg(const char *title, const char *message)
421: {
422: GtkTextBuffer *buffer;
423: GtkTextIter start, end;
424: const char *msg = message;
425:
426: buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_w));
427: gtk_text_buffer_get_bounds(buffer, &start, &end);
428: gtk_text_buffer_delete(buffer, &start, &end);
429: gtk_text_view_set_left_margin(GTK_TEXT_VIEW(text_w), 15);
430:
431: gtk_text_buffer_get_end_iter(buffer, &end);
432: gtk_text_buffer_insert_with_tags(buffer, &end, title, -1, tag1,
433: NULL);
434: gtk_text_buffer_insert_at_cursor(buffer, "\n\n", 2);
435: gtk_text_buffer_get_end_iter(buffer, &end);
436: gtk_text_buffer_insert_with_tags(buffer, &end, msg, -1, tag2,
437: NULL);
438: }
439:
440:
441: /* Main Windows Callbacks */
442:
443: void on_save_activate(GtkMenuItem * menuitem, gpointer user_data);
444: gboolean on_window1_delete_event(GtkWidget * widget, GdkEvent * event,
445: gpointer user_data)
446: {
447: GtkWidget *dialog, *label;
448: gint result;
449:
450: if (!conf_get_changed())
451: return FALSE;
452:
453: dialog = gtk_dialog_new_with_buttons(_("Warning !"),
454: GTK_WINDOW(main_wnd),
455: (GtkDialogFlags)
456: (GTK_DIALOG_MODAL |
457: GTK_DIALOG_DESTROY_WITH_PARENT),
458: GTK_STOCK_OK,
459: GTK_RESPONSE_YES,
460: GTK_STOCK_NO,
461: GTK_RESPONSE_NO,
462: GTK_STOCK_CANCEL,
463: GTK_RESPONSE_CANCEL, NULL);
464: gtk_dialog_set_default_response(GTK_DIALOG(dialog),
465: GTK_RESPONSE_CANCEL);
466:
467: label = gtk_label_new(_("\nSave configuration ?\n"));
468: gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), label);
469: gtk_widget_show(label);
470:
471: result = gtk_dialog_run(GTK_DIALOG(dialog));
472: switch (result) {
473: case GTK_RESPONSE_YES:
474: on_save_activate(NULL, NULL);
475: return FALSE;
476: case GTK_RESPONSE_NO:
477: return FALSE;
478: case GTK_RESPONSE_CANCEL:
479: case GTK_RESPONSE_DELETE_EVENT:
480: default:
481: gtk_widget_destroy(dialog);
482: return TRUE;
483: }
484:
485: return FALSE;
486: }
487:
488:
489: void on_window1_destroy(GtkObject * object, gpointer user_data)
490: {
491: gtk_main_quit();
492: }
493:
494:
495: void
496: on_window1_size_request(GtkWidget * widget,
497: GtkRequisition * requisition, gpointer user_data)
498: {
499: static gint old_h;
500: gint w, h;
501:
502: if (widget->window == NULL)
503: gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
504: else
505: gdk_window_get_size(widget->window, &w, &h);
506:
507: if (h == old_h)
508: return;
509: old_h = h;
510:
511: gtk_paned_set_position(GTK_PANED(vpaned), 2 * h / 3);
512: }
513:
514:
515: /* Menu & Toolbar Callbacks */
516:
517:
518: static void
519: load_filename(GtkFileSelection * file_selector, gpointer user_data)
520: {
521: const gchar *fn;
522:
523: fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
524: (user_data));
525:
526: if (conf_read(fn))
527: text_insert_msg(_("Error"), _("Unable to load configuration !"));
528: else
529: display_tree(&rootmenu);
530: }
531:
532: void on_load1_activate(GtkMenuItem * menuitem, gpointer user_data)
533: {
534: GtkWidget *fs;
535:
536: fs = gtk_file_selection_new(_("Load file..."));
537: g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
538: "clicked",
539: G_CALLBACK(load_filename), (gpointer) fs);
540: g_signal_connect_swapped(GTK_OBJECT
541: (GTK_FILE_SELECTION(fs)->ok_button),
542: "clicked", G_CALLBACK(gtk_widget_destroy),
543: (gpointer) fs);
544: g_signal_connect_swapped(GTK_OBJECT
545: (GTK_FILE_SELECTION(fs)->cancel_button),
546: "clicked", G_CALLBACK(gtk_widget_destroy),
547: (gpointer) fs);
548: gtk_widget_show(fs);
549: }
550:
551:
552: void on_save_activate(GtkMenuItem * menuitem, gpointer user_data)
553: {
554: if (conf_write(NULL))
555: text_insert_msg(_("Error"), _("Unable to save configuration !"));
556: }
557:
558:
559: static void
560: store_filename(GtkFileSelection * file_selector, gpointer user_data)
561: {
562: const gchar *fn;
563:
564: fn = gtk_file_selection_get_filename(GTK_FILE_SELECTION
565: (user_data));
566:
567: if (conf_write(fn))
568: text_insert_msg(_("Error"), _("Unable to save configuration !"));
569:
570: gtk_widget_destroy(GTK_WIDGET(user_data));
571: }
572:
573: void on_save_as1_activate(GtkMenuItem * menuitem, gpointer user_data)
574: {
575: GtkWidget *fs;
576:
577: fs = gtk_file_selection_new(_("Save file as..."));
578: g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(fs)->ok_button),
579: "clicked",
580: G_CALLBACK(store_filename), (gpointer) fs);
581: g_signal_connect_swapped(GTK_OBJECT
582: (GTK_FILE_SELECTION(fs)->ok_button),
583: "clicked", G_CALLBACK(gtk_widget_destroy),
584: (gpointer) fs);
585: g_signal_connect_swapped(GTK_OBJECT
586: (GTK_FILE_SELECTION(fs)->cancel_button),
587: "clicked", G_CALLBACK(gtk_widget_destroy),
588: (gpointer) fs);
589: gtk_widget_show(fs);
590: }
591:
592:
593: void on_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
594: {
595: if (!on_window1_delete_event(NULL, NULL, NULL))
596: gtk_widget_destroy(GTK_WIDGET(main_wnd));
597: }
598:
599:
600: void on_show_name1_activate(GtkMenuItem * menuitem, gpointer user_data)
601: {
602: GtkTreeViewColumn *col;
603:
604: show_name = GTK_CHECK_MENU_ITEM(menuitem)->active;
605: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NAME);
606: if (col)
607: gtk_tree_view_column_set_visible(col, show_name);
608: }
609:
610:
611: void on_show_range1_activate(GtkMenuItem * menuitem, gpointer user_data)
612: {
613: GtkTreeViewColumn *col;
614:
615: show_range = GTK_CHECK_MENU_ITEM(menuitem)->active;
616: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_NO);
617: if (col)
618: gtk_tree_view_column_set_visible(col, show_range);
619: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_MOD);
620: if (col)
621: gtk_tree_view_column_set_visible(col, show_range);
622: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_YES);
623: if (col)
624: gtk_tree_view_column_set_visible(col, show_range);
625:
626: }
627:
628:
629: void on_show_data1_activate(GtkMenuItem * menuitem, gpointer user_data)
630: {
631: GtkTreeViewColumn *col;
632:
633: show_value = GTK_CHECK_MENU_ITEM(menuitem)->active;
634: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), COL_VALUE);
635: if (col)
636: gtk_tree_view_column_set_visible(col, show_value);
637: }
638:
639:
640: void
641: on_set_option_mode1_activate(GtkMenuItem *menuitem, gpointer user_data)
642: {
643: opt_mode = OPT_NORMAL;
644: gtk_tree_store_clear(tree2);
645: display_tree(&rootmenu); /* instead of update_tree to speed-up */
646: }
647:
648:
649: void
650: on_set_option_mode2_activate(GtkMenuItem *menuitem, gpointer user_data)
651: {
652: opt_mode = OPT_ALL;
653: gtk_tree_store_clear(tree2);
654: display_tree(&rootmenu); /* instead of update_tree to speed-up */
655: }
656:
657:
658: void
659: on_set_option_mode3_activate(GtkMenuItem *menuitem, gpointer user_data)
660: {
661: opt_mode = OPT_PROMPT;
662: gtk_tree_store_clear(tree2);
663: display_tree(&rootmenu); /* instead of update_tree to speed-up */
664: }
665:
666:
667: void on_introduction1_activate(GtkMenuItem * menuitem, gpointer user_data)
668: {
669: GtkWidget *dialog;
670: const gchar *intro_text = _(
671: "Welcome to gkc, the GTK+ graphical configuration tool\n"
672: "For each option, a blank box indicates the feature is disabled, a\n"
673: "check indicates it is enabled, and a dot indicates that it is to\n"
674: "be compiled as a module. Clicking on the box will cycle through the three states.\n"
675: "\n"
676: "If you do not see an option (e.g., a device driver) that you\n"
677: "believe should be present, try turning on Show All Options\n"
678: "under the Options menu.\n"
679: "Although there is no cross reference yet to help you figure out\n"
680: "what other options must be enabled to support the option you\n"
681: "are interested in, you can still view the help of a grayed-out\n"
682: "option.\n"
683: "\n"
684: "Toggling Show Debug Info under the Options menu will show \n"
685: "the dependencies, which you can then match by examining other options.");
686:
687: dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
688: GTK_DIALOG_DESTROY_WITH_PARENT,
689: GTK_MESSAGE_INFO,
690: GTK_BUTTONS_CLOSE, intro_text);
691: g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
692: G_CALLBACK(gtk_widget_destroy),
693: GTK_OBJECT(dialog));
694: gtk_widget_show_all(dialog);
695: }
696:
697:
698: void on_about1_activate(GtkMenuItem * menuitem, gpointer user_data)
699: {
700: GtkWidget *dialog;
701: const gchar *about_text =
702: _("gkc is copyright (c) 2002 Romain Lievin <[email protected]>.\n"
703: "Based on the source code from Roman Zippel.\n");
704:
705: dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
706: GTK_DIALOG_DESTROY_WITH_PARENT,
707: GTK_MESSAGE_INFO,
708: GTK_BUTTONS_CLOSE, about_text);
709: g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
710: G_CALLBACK(gtk_widget_destroy),
711: GTK_OBJECT(dialog));
712: gtk_widget_show_all(dialog);
713: }
714:
715:
716: void on_license1_activate(GtkMenuItem * menuitem, gpointer user_data)
717: {
718: GtkWidget *dialog;
719: const gchar *license_text =
720: _("gkc is released under the terms of the GNU GPL v2.\n"
721: "For more information, please see the source code or\n"
722: "visit http://www.fsf.org/licenses/licenses.html\n");
723:
724: dialog = gtk_message_dialog_new(GTK_WINDOW(main_wnd),
725: GTK_DIALOG_DESTROY_WITH_PARENT,
726: GTK_MESSAGE_INFO,
727: GTK_BUTTONS_CLOSE, license_text);
728: g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
729: G_CALLBACK(gtk_widget_destroy),
730: GTK_OBJECT(dialog));
731: gtk_widget_show_all(dialog);
732: }
733:
734:
735: void on_back_clicked(GtkButton * button, gpointer user_data)
736: {
737: enum prop_type ptype;
738:
739: current = current->parent;
740: ptype = current->prompt ? current->prompt->type : P_UNKNOWN;
741: if (ptype != P_MENU)
742: current = current->parent;
743: display_tree_part();
744:
745: if (current == &rootmenu)
746: gtk_widget_set_sensitive(back_btn, FALSE);
747: }
748:
749:
750: void on_load_clicked(GtkButton * button, gpointer user_data)
751: {
752: on_load1_activate(NULL, user_data);
753: }
754:
755:
756: void on_single_clicked(GtkButton * button, gpointer user_data)
757: {
758: view_mode = SINGLE_VIEW;
759: gtk_paned_set_position(GTK_PANED(hpaned), 0);
760: gtk_widget_hide(tree1_w);
761: current = &rootmenu;
762: display_tree_part();
763: }
764:
765:
766: void on_split_clicked(GtkButton * button, gpointer user_data)
767: {
768: gint w, h;
769: view_mode = SPLIT_VIEW;
770: gtk_widget_show(tree1_w);
771: gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h);
772: gtk_paned_set_position(GTK_PANED(hpaned), w / 2);
773: if (tree2)
774: gtk_tree_store_clear(tree2);
775: display_list();
776:
777: /* Disable back btn, like in full mode. */
778: gtk_widget_set_sensitive(back_btn, FALSE);
779: }
780:
781:
782: void on_full_clicked(GtkButton * button, gpointer user_data)
783: {
784: view_mode = FULL_VIEW;
785: gtk_paned_set_position(GTK_PANED(hpaned), 0);
786: gtk_widget_hide(tree1_w);
787: if (tree2)
788: gtk_tree_store_clear(tree2);
789: display_tree(&rootmenu);
790: gtk_widget_set_sensitive(back_btn, FALSE);
791: }
792:
793:
794: void on_collapse_clicked(GtkButton * button, gpointer user_data)
795: {
796: gtk_tree_view_collapse_all(GTK_TREE_VIEW(tree2_w));
797: }
798:
799:
800: void on_expand_clicked(GtkButton * button, gpointer user_data)
801: {
802: gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
803: }
804:
805:
806: /* CTree Callbacks */
807:
808: /* Change hex/int/string value in the cell */
809: static void renderer_edited(GtkCellRendererText * cell,
810: const gchar * path_string,
811: const gchar * new_text, gpointer user_data)
812: {
813: GtkTreePath *path = gtk_tree_path_new_from_string(path_string);
814: GtkTreeIter iter;
815: const char *old_def, *new_def;
816: struct menu *menu;
817: struct symbol *sym;
818:
819: if (!gtk_tree_model_get_iter(model2, &iter, path))
820: return;
821:
822: gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
823: sym = menu->sym;
824:
825: gtk_tree_model_get(model2, &iter, COL_VALUE, &old_def, -1);
826: new_def = new_text;
827:
828: sym_set_string_value(sym, new_def);
829:
830: update_tree(&rootmenu, NULL);
831:
832: gtk_tree_path_free(path);
833: }
834:
835: /* Change the value of a symbol and update the tree */
836: static void change_sym_value(struct menu *menu, gint col)
837: {
838: struct symbol *sym = menu->sym;
839: tristate oldval, newval;
840:
841: if (!sym)
842: return;
843:
844: if (col == COL_NO)
845: newval = no;
846: else if (col == COL_MOD)
847: newval = mod;
848: else if (col == COL_YES)
849: newval = yes;
850: else
851: return;
852:
853: switch (sym_get_type(sym)) {
854: case S_BOOLEAN:
855: case S_TRISTATE:
856: oldval = sym_get_tristate_value(sym);
857: if (!sym_tristate_within_range(sym, newval))
858: newval = yes;
859: sym_set_tristate_value(sym, newval);
860: if (view_mode == FULL_VIEW)
861: update_tree(&rootmenu, NULL);
862: else if (view_mode == SPLIT_VIEW) {
863: update_tree(browsed, NULL);
864: display_list();
865: }
866: else if (view_mode == SINGLE_VIEW)
867: display_tree_part(); //fixme: keep exp/coll
868: break;
869: case S_INT:
870: case S_HEX:
871: case S_STRING:
872: default:
873: break;
874: }
875: }
876:
877: static void toggle_sym_value(struct menu *menu)
878: {
879: if (!menu->sym)
880: return;
881:
882: sym_toggle_tristate_value(menu->sym);
883: if (view_mode == FULL_VIEW)
884: update_tree(&rootmenu, NULL);
885: else if (view_mode == SPLIT_VIEW) {
886: update_tree(browsed, NULL);
887: display_list();
888: }
889: else if (view_mode == SINGLE_VIEW)
890: display_tree_part(); //fixme: keep exp/coll
891: }
892:
893: static void renderer_toggled(GtkCellRendererToggle * cell,
894: gchar * path_string, gpointer user_data)
895: {
896: GtkTreePath *path, *sel_path = NULL;
897: GtkTreeIter iter, sel_iter;
898: GtkTreeSelection *sel;
899: struct menu *menu;
900:
901: path = gtk_tree_path_new_from_string(path_string);
902: if (!gtk_tree_model_get_iter(model2, &iter, path))
903: return;
904:
905: sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree2_w));
906: if (gtk_tree_selection_get_selected(sel, NULL, &sel_iter))
907: sel_path = gtk_tree_model_get_path(model2, &sel_iter);
908: if (!sel_path)
909: goto out1;
910: if (gtk_tree_path_compare(path, sel_path))
911: goto out2;
912:
913: gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
914: toggle_sym_value(menu);
915:
916: out2:
917: gtk_tree_path_free(sel_path);
918: out1:
919: gtk_tree_path_free(path);
920: }
921:
922: static gint column2index(GtkTreeViewColumn * column)
923: {
924: gint i;
925:
926: for (i = 0; i < COL_NUMBER; i++) {
927: GtkTreeViewColumn *col;
928:
929: col = gtk_tree_view_get_column(GTK_TREE_VIEW(tree2_w), i);
930: if (col == column)
931: return i;
932: }
933:
934: return -1;
935: }
936:
937:
938: /* User click: update choice (full) or goes down (single) */
939: gboolean
940: on_treeview2_button_press_event(GtkWidget * widget,
941: GdkEventButton * event, gpointer user_data)
942: {
943: GtkTreeView *view = GTK_TREE_VIEW(widget);
944: GtkTreePath *path;
945: GtkTreeViewColumn *column;
946: GtkTreeIter iter;
947: struct menu *menu;
948: gint col;
949:
950: #if GTK_CHECK_VERSION(2,1,4) // bug in ctree with earlier version of GTK
951: gint tx = (gint) event->x;
952: gint ty = (gint) event->y;
953: gint cx, cy;
954:
955: gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
956: &cy);
957: #else
958: gtk_tree_view_get_cursor(view, &path, &column);
959: #endif
960: if (path == NULL)
961: return FALSE;
962:
963: if (!gtk_tree_model_get_iter(model2, &iter, path))
964: return FALSE;
965: gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
966:
967: col = column2index(column);
968: if (event->type == GDK_2BUTTON_PRESS) {
969: enum prop_type ptype;
970: ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
971:
972: if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) {
973: // goes down into menu
974: current = menu;
975: display_tree_part();
976: gtk_widget_set_sensitive(back_btn, TRUE);
977: } else if ((col == COL_OPTION)) {
978: toggle_sym_value(menu);
979: gtk_tree_view_expand_row(view, path, TRUE);
980: }
981: } else {
982: if (col == COL_VALUE) {
983: toggle_sym_value(menu);
984: gtk_tree_view_expand_row(view, path, TRUE);
985: } else if (col == COL_NO || col == COL_MOD
986: || col == COL_YES) {
987: change_sym_value(menu, col);
988: gtk_tree_view_expand_row(view, path, TRUE);
989: }
990: }
991:
992: return FALSE;
993: }
994:
995: /* Key pressed: update choice */
996: gboolean
997: on_treeview2_key_press_event(GtkWidget * widget,
998: GdkEventKey * event, gpointer user_data)
999: {
1000: GtkTreeView *view = GTK_TREE_VIEW(widget);
1001: GtkTreePath *path;
1002: GtkTreeViewColumn *column;
1003: GtkTreeIter iter;
1004: struct menu *menu;
1005: gint col;
1006:
1007: gtk_tree_view_get_cursor(view, &path, &column);
1008: if (path == NULL)
1009: return FALSE;
1010:
1011: if (event->keyval == GDK_space) {
1012: if (gtk_tree_view_row_expanded(view, path))
1013: gtk_tree_view_collapse_row(view, path);
1014: else
1015: gtk_tree_view_expand_row(view, path, FALSE);
1016: return TRUE;
1017: }
1018: if (event->keyval == GDK_KP_Enter) {
1019: }
1020: if (widget == tree1_w)
1021: return FALSE;
1022:
1023: gtk_tree_model_get_iter(model2, &iter, path);
1024: gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1025:
1026: if (!strcasecmp(event->string, "n"))
1027: col = COL_NO;
1028: else if (!strcasecmp(event->string, "m"))
1029: col = COL_MOD;
1030: else if (!strcasecmp(event->string, "y"))
1031: col = COL_YES;
1032: else
1033: col = -1;
1034: change_sym_value(menu, col);
1035:
1036: return FALSE;
1037: }
1038:
1039:
1040: /* Row selection changed: update help */
1041: void
1042: on_treeview2_cursor_changed(GtkTreeView * treeview, gpointer user_data)
1043: {
1044: GtkTreeSelection *selection;
1045: GtkTreeIter iter;
1046: struct menu *menu;
1047:
1048: selection = gtk_tree_view_get_selection(treeview);
1049: if (gtk_tree_selection_get_selected(selection, &model2, &iter)) {
1050: gtk_tree_model_get(model2, &iter, COL_MENU, &menu, -1);
1051: text_insert_help(menu);
1052: }
1053: }
1054:
1055:
1056: /* User click: display sub-tree in the right frame. */
1057: gboolean
1058: on_treeview1_button_press_event(GtkWidget * widget,
1059: GdkEventButton * event, gpointer user_data)
1060: {
1061: GtkTreeView *view = GTK_TREE_VIEW(widget);
1062: GtkTreePath *path;
1063: GtkTreeViewColumn *column;
1064: GtkTreeIter iter;
1065: struct menu *menu;
1066:
1067: gint tx = (gint) event->x;
1068: gint ty = (gint) event->y;
1069: gint cx, cy;
1070:
1071: gtk_tree_view_get_path_at_pos(view, tx, ty, &path, &column, &cx,
1072: &cy);
1073: if (path == NULL)
1074: return FALSE;
1075:
1076: gtk_tree_model_get_iter(model1, &iter, path);
1077: gtk_tree_model_get(model1, &iter, COL_MENU, &menu, -1);
1078:
1079: if (event->type == GDK_2BUTTON_PRESS) {
1080: toggle_sym_value(menu);
1081: current = menu;
1082: display_tree_part();
1083: } else {
1084: browsed = menu;
1085: display_tree_part();
1086: }
1087:
1088: gtk_widget_realize(tree2_w);
1089: gtk_tree_view_set_cursor(view, path, NULL, FALSE);
1090: gtk_widget_grab_focus(tree2_w);
1091:
1092: return FALSE;
1093: }
1094:
1095:
1096: /* Fill a row of strings */
1097: static gchar **fill_row(struct menu *menu)
1098: {
1099: static gchar *row[COL_NUMBER];
1100: struct symbol *sym = menu->sym;
1101: const char *def;
1102: int stype;
1103: tristate val;
1104: enum prop_type ptype;
1105: int i;
1106:
1107: for (i = COL_OPTION; i <= COL_COLOR; i++)
1108: g_free(row[i]);
1109: bzero(row, sizeof(row));
1110:
1111: row[COL_OPTION] =
1112: g_strdup_printf("%s %s", _(menu_get_prompt(menu)),
1113: sym && !sym_has_value(sym) ? "(NEW)" : "");
1114:
1115: if (opt_mode == OPT_ALL && !menu_is_visible(menu))
1116: row[COL_COLOR] = g_strdup("DarkGray");
1117: else if (opt_mode == OPT_PROMPT &&
1118: menu_has_prompt(menu) && !menu_is_visible(menu))
1119: row[COL_COLOR] = g_strdup("DarkGray");
1120: else
1121: row[COL_COLOR] = g_strdup("Black");
1122:
1123: ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN;
1124: switch (ptype) {
1125: case P_MENU:
1126: row[COL_PIXBUF] = (gchar *) xpm_menu;
1127: if (view_mode == SINGLE_VIEW)
1128: row[COL_PIXVIS] = GINT_TO_POINTER(TRUE);
1129: row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1130: break;
1131: case P_COMMENT:
1132: row[COL_PIXBUF] = (gchar *) xpm_void;
1133: row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1134: row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1135: break;
1136: default:
1137: row[COL_PIXBUF] = (gchar *) xpm_void;
1138: row[COL_PIXVIS] = GINT_TO_POINTER(FALSE);
1139: row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1140: break;
1141: }
1142:
1143: if (!sym)
1144: return row;
1145: row[COL_NAME] = g_strdup(sym->name);
1146:
1147: sym_calc_value(sym);
1148: sym->flags &= ~SYMBOL_CHANGED;
1149:
1150: if (sym_is_choice(sym)) { // parse childs for getting final value
1151: struct menu *child;
1152: struct symbol *def_sym = sym_get_choice_value(sym);
1153: struct menu *def_menu = NULL;
1154:
1155: row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1156:
1157: for (child = menu->list; child; child = child->next) {
1158: if (menu_is_visible(child)
1159: && child->sym == def_sym)
1160: def_menu = child;
1161: }
1162:
1163: if (def_menu)
1164: row[COL_VALUE] =
1165: g_strdup(_(menu_get_prompt(def_menu)));
1166: }
1167: if (sym->flags & SYMBOL_CHOICEVAL)
1168: row[COL_BTNRAD] = GINT_TO_POINTER(TRUE);
1169:
1170: stype = sym_get_type(sym);
1171: switch (stype) {
1172: case S_BOOLEAN:
1173: if (GPOINTER_TO_INT(row[COL_PIXVIS]) == FALSE)
1174: row[COL_BTNVIS] = GINT_TO_POINTER(TRUE);
1175: if (sym_is_choice(sym))
1176: break;
1177: case S_TRISTATE:
1178: val = sym_get_tristate_value(sym);
1179: switch (val) {
1180: case no:
1181: row[COL_NO] = g_strdup("N");
1182: row[COL_VALUE] = g_strdup("N");
1183: row[COL_BTNACT] = GINT_TO_POINTER(FALSE);
1184: row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1185: break;
1186: case mod:
1187: row[COL_MOD] = g_strdup("M");
1188: row[COL_VALUE] = g_strdup("M");
1189: row[COL_BTNINC] = GINT_TO_POINTER(TRUE);
1190: break;
1191: case yes:
1192: row[COL_YES] = g_strdup("Y");
1193: row[COL_VALUE] = g_strdup("Y");
1194: row[COL_BTNACT] = GINT_TO_POINTER(TRUE);
1195: row[COL_BTNINC] = GINT_TO_POINTER(FALSE);
1196: break;
1197: }
1198:
1199: if (val != no && sym_tristate_within_range(sym, no))
1200: row[COL_NO] = g_strdup("_");
1201: if (val != mod && sym_tristate_within_range(sym, mod))
1202: row[COL_MOD] = g_strdup("_");
1203: if (val != yes && sym_tristate_within_range(sym, yes))
1204: row[COL_YES] = g_strdup("_");
1205: break;
1206: case S_INT:
1207: case S_HEX:
1208: case S_STRING:
1209: def = sym_get_string_value(sym);
1210: row[COL_VALUE] = g_strdup(def);
1211: row[COL_EDIT] = GINT_TO_POINTER(TRUE);
1212: row[COL_BTNVIS] = GINT_TO_POINTER(FALSE);
1213: break;
1214: }
1215:
1216: return row;
1217: }
1218:
1219:
1220: /* Set the node content with a row of strings */
1221: static void set_node(GtkTreeIter * node, struct menu *menu, gchar ** row)
1222: {
1223: GdkColor color;
1224: gboolean success;
1225: GdkPixbuf *pix;
1226:
1227: pix = gdk_pixbuf_new_from_xpm_data((const char **)
1228: row[COL_PIXBUF]);
1229:
1230: gdk_color_parse(row[COL_COLOR], &color);
1231: gdk_colormap_alloc_colors(gdk_colormap_get_system(), &color, 1,
1232: FALSE, FALSE, &success);
1233:
1234: gtk_tree_store_set(tree, node,
1235: COL_OPTION, row[COL_OPTION],
1236: COL_NAME, row[COL_NAME],
1237: COL_NO, row[COL_NO],
1238: COL_MOD, row[COL_MOD],
1239: COL_YES, row[COL_YES],
1240: COL_VALUE, row[COL_VALUE],
1241: COL_MENU, (gpointer) menu,
1242: COL_COLOR, &color,
1243: COL_EDIT, GPOINTER_TO_INT(row[COL_EDIT]),
1244: COL_PIXBUF, pix,
1245: COL_PIXVIS, GPOINTER_TO_INT(row[COL_PIXVIS]),
1246: COL_BTNVIS, GPOINTER_TO_INT(row[COL_BTNVIS]),
1247: COL_BTNACT, GPOINTER_TO_INT(row[COL_BTNACT]),
1248: COL_BTNINC, GPOINTER_TO_INT(row[COL_BTNINC]),
1249: COL_BTNRAD, GPOINTER_TO_INT(row[COL_BTNRAD]),
1250: -1);
1251:
1252: g_object_unref(pix);
1253: }
1254:
1255:
1256: /* Add a node to the tree */
1257: static void place_node(struct menu *menu, char **row)
1258: {
1259: GtkTreeIter *parent = parents[indent - 1];
1260: GtkTreeIter *node = parents[indent];
1261:
1262: gtk_tree_store_append(tree, node, parent);
1263: set_node(node, menu, row);
1264: }
1265:
1266:
1267: /* Find a node in the GTK+ tree */
1268: static GtkTreeIter found;
1269:
1270: /*
1271: * Find a menu in the GtkTree starting at parent.
1272: */
1273: GtkTreeIter *gtktree_iter_find_node(GtkTreeIter * parent,
1274: struct menu *tofind)
1275: {
1276: GtkTreeIter iter;
1277: GtkTreeIter *child = &iter;
1278: gboolean valid;
1279: GtkTreeIter *ret;
1280:
1281: valid = gtk_tree_model_iter_children(model2, child, parent);
1282: while (valid) {
1283: struct menu *menu;
1284:
1285: gtk_tree_model_get(model2, child, 6, &menu, -1);
1286:
1287: if (menu == tofind) {
1288: memcpy(&found, child, sizeof(GtkTreeIter));
1289: return &found;
1290: }
1291:
1292: ret = gtktree_iter_find_node(child, tofind);
1293: if (ret)
1294: return ret;
1295:
1296: valid = gtk_tree_model_iter_next(model2, child);
1297: }
1298:
1299: return NULL;
1300: }
1301:
1302:
1303: /*
1304: * Update the tree by adding/removing entries
1305: * Does not change other nodes
1306: */
1307: static void update_tree(struct menu *src, GtkTreeIter * dst)
1308: {
1309: struct menu *child1;
1310: GtkTreeIter iter, tmp;
1311: GtkTreeIter *child2 = &iter;
1312: gboolean valid;
1313: GtkTreeIter *sibling;
1314: struct symbol *sym;
1315: struct property *prop;
1316: struct menu *menu1, *menu2;
1317:
1318: if (src == &rootmenu)
1319: indent = 1;
1320:
1321: valid = gtk_tree_model_iter_children(model2, child2, dst);
1322: for (child1 = src->list; child1; child1 = child1->next) {
1323:
1324: prop = child1->prompt;
1325: sym = child1->sym;
1326:
1327: reparse:
1328: menu1 = child1;
1329: if (valid)
1330: gtk_tree_model_get(model2, child2, COL_MENU,
1331: &menu2, -1);
1332: else
1333: menu2 = NULL; // force adding of a first child
1334:
1335: #ifdef DEBUG
1336: printf("%*c%s | %s\n", indent, ' ',
1337: menu1 ? menu_get_prompt(menu1) : "nil",
1338: menu2 ? menu_get_prompt(menu2) : "nil");
1339: #endif
1340:
1341: if ((opt_mode == OPT_NORMAL && !menu_is_visible(child1)) ||
1342: (opt_mode == OPT_PROMPT && !menu_has_prompt(child1)) ||
1343: (opt_mode == OPT_ALL && !menu_get_prompt(child1))) {
1344:
1345: /* remove node */
1346: if (gtktree_iter_find_node(dst, menu1) != NULL) {
1347: memcpy(&tmp, child2, sizeof(GtkTreeIter));
1348: valid = gtk_tree_model_iter_next(model2,
1349: child2);
1350: gtk_tree_store_remove(tree2, &tmp);
1351: if (!valid)
1352: return; /* next parent */
1353: else
1354: goto reparse; /* next child */
1355: } else
1356: continue;
1357: }
1358:
1359: if (menu1 != menu2) {
1360: if (gtktree_iter_find_node(dst, menu1) == NULL) { // add node
1361: if (!valid && !menu2)
1362: sibling = NULL;
1363: else
1364: sibling = child2;
1365: gtk_tree_store_insert_before(tree2,
1366: child2,
1367: dst, sibling);
1368: set_node(child2, menu1, fill_row(menu1));
1369: if (menu2 == NULL)
1370: valid = TRUE;
1371: } else { // remove node
1372: memcpy(&tmp, child2, sizeof(GtkTreeIter));
1373: valid = gtk_tree_model_iter_next(model2,
1374: child2);
1375: gtk_tree_store_remove(tree2, &tmp);
1376: if (!valid)
1377: return; // next parent
1378: else
1379: goto reparse; // next child
1380: }
1381: } else if (sym && (sym->flags & SYMBOL_CHANGED)) {
1382: set_node(child2, menu1, fill_row(menu1));
1383: }
1384:
1385: indent++;
1386: update_tree(child1, child2);
1387: indent--;
1388:
1389: valid = gtk_tree_model_iter_next(model2, child2);
1390: }
1391: }
1392:
1393:
1394: /* Display the whole tree (single/split/full view) */
1395: static void display_tree(struct menu *menu)
1396: {
1397: struct symbol *sym;
1398: struct property *prop;
1399: struct menu *child;
1400: enum prop_type ptype;
1401:
1402: if (menu == &rootmenu) {
1403: indent = 1;
1404: current = &rootmenu;
1405: }
1406:
1407: for (child = menu->list; child; child = child->next) {
1408: prop = child->prompt;
1409: sym = child->sym;
1410: ptype = prop ? prop->type : P_UNKNOWN;
1411:
1412: if (sym)
1413: sym->flags &= ~SYMBOL_CHANGED;
1414:
1415: if ((view_mode == SPLIT_VIEW)
1416: && !(child->flags & MENU_ROOT) && (tree == tree1))
1417: continue;
1418:
1419: if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT)
1420: && (tree == tree2))
1421: continue;
1422:
1423: if ((opt_mode == OPT_NORMAL && menu_is_visible(child)) ||
1424: (opt_mode == OPT_PROMPT && menu_has_prompt(child)) ||
1425: (opt_mode == OPT_ALL && menu_get_prompt(child)))
1426: place_node(child, fill_row(child));
1427: #ifdef DEBUG
1428: printf("%*c%s: ", indent, ' ', menu_get_prompt(child));
1429: printf("%s", child->flags & MENU_ROOT ? "rootmenu | " : "");
1430: printf("%s", prop_get_type_name(ptype));
1431: printf(" | ");
1432: if (sym) {
1433: printf("%s", sym_type_name(sym->type));
1434: printf(" | ");
1435: printf("%s", dbg_sym_flags(sym->flags));
1436: printf("\n");
1437: } else
1438: printf("\n");
1439: #endif
1440: if ((view_mode != FULL_VIEW) && (ptype == P_MENU)
1441: && (tree == tree2))
1442: continue;
1443: /*
1444: if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT))
1445: || (view_mode == FULL_VIEW)
1446: || (view_mode == SPLIT_VIEW))*/
1447: if (((view_mode == SINGLE_VIEW) && (menu->flags & MENU_ROOT))
1448: || (view_mode == FULL_VIEW)
1449: || (view_mode == SPLIT_VIEW)) {
1450: indent++;
1451: display_tree(child);
1452: indent--;
1453: }
1454: }
1455: }
1456:
1457: /* Display a part of the tree starting at current node (single/split view) */
1458: static void display_tree_part(void)
1459: {
1460: if (tree2)
1461: gtk_tree_store_clear(tree2);
1462: if (view_mode == SINGLE_VIEW)
1463: display_tree(current);
1464: else if (view_mode == SPLIT_VIEW)
1465: display_tree(browsed);
1466: gtk_tree_view_expand_all(GTK_TREE_VIEW(tree2_w));
1467: }
1468:
1469: /* Display the list in the left frame (split view) */
1470: static void display_list(void)
1471: {
1472: if (tree1)
1473: gtk_tree_store_clear(tree1);
1474:
1475: tree = tree1;
1476: display_tree(&rootmenu);
1477: gtk_tree_view_expand_all(GTK_TREE_VIEW(tree1_w));
1478: tree = tree2;
1479: }
1480:
1481: void fixup_rootmenu(struct menu *menu)
1482: {
1483: struct menu *child;
1484: static int menu_cnt = 0;
1485:
1486: menu->flags |= MENU_ROOT;
1487: for (child = menu->list; child; child = child->next) {
1488: if (child->prompt && child->prompt->type == P_MENU) {
1489: menu_cnt++;
1490: fixup_rootmenu(child);
1491: menu_cnt--;
1492: } else if (!menu_cnt)
1493: fixup_rootmenu(child);
1494: }
1495: }
1496:
1497:
1498: /* Main */
1499: int main(int ac, char *av[])
1500: {
1501: const char *name;
1502: char *env;
1503: gchar *glade_file;
1504:
1505: #ifndef LKC_DIRECT_LINK
1506: kconfig_load();
1507: #endif
1508:
1509: bindtextdomain(PACKAGE, LOCALEDIR);
1510: bind_textdomain_codeset(PACKAGE, "UTF-8");
1511: textdomain(PACKAGE);
1512:
1513: /* GTK stuffs */
1514: gtk_set_locale();
1515: gtk_init(&ac, &av);
1516: glade_init();
1517:
1518: //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
1519: //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps");
1520:
1521: /* Determine GUI path */
1522: env = getenv(SRCTREE);
1523: if (env)
1524: glade_file = g_strconcat(env, "/tools/kconfig/gconf.glade", NULL);
1525: else if (av[0][0] == '/')
1526: glade_file = g_strconcat(av[0], ".glade", NULL);
1527: else
1528: glade_file = g_strconcat(g_get_current_dir(), "/", av[0], ".glade", NULL);
1529:
1530: /* Conf stuffs */
1531: if (ac > 1 && av[1][0] == '-') {
1532: switch (av[1][1]) {
1533: case 'a':
1534: //showAll = 1;
1535: break;
1536: case 'h':
1537: case '?':
1538: printf("%s <config>\n", av[0]);
1539: exit(0);
1540: }
1541: name = av[2];
1542: } else
1543: name = av[1];
1544:
1545: conf_parse(name);
1546: fixup_rootmenu(&rootmenu);
1547: conf_read(NULL);
1548:
1549: /* Load the interface and connect signals */
1550: init_main_window(glade_file);
1551: init_tree_model();
1552: init_left_tree();
1553: init_right_tree();
1554:
1555: switch (view_mode) {
1556: case SINGLE_VIEW:
1557: display_tree_part();
1558: break;
1559: case SPLIT_VIEW:
1560: display_list();
1561: break;
1562: case FULL_VIEW:
1563: display_tree(&rootmenu);
1564: break;
1565: }
1566:
1567: gtk_main();
1568:
1569: return 0;
1570: }
1571:
1572: static void conf_changed(void)
1573: {
1574: bool changed = conf_get_changed();
1575: gtk_widget_set_sensitive(save_btn, changed);
1576: gtk_widget_set_sensitive(save_menu_item, changed);
1577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.