OSDN Git Service

68ad844b1e8ea36f90fbd4299d912be18f7b6477
[gpet/origin.git] / src / menu.c
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3  * Gui Policy Editor for TOMOYO Linux
4  *
5  * menu.c
6  * Copyright (C) Yoshihiro Kusuno 2010,2011 <yocto@users.sourceforge.jp>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26
27 #include <gtk/gtk.h>
28 #include <glib/gi18n.h>
29
30 #include "gpet.h"
31
32 static void terminate(GtkAction *action, transition_t *transition);
33 static void copy_line(GtkAction *action, transition_t *transition);
34 static void optimize_acl(GtkAction *action, transition_t *transition);
35 static void delete_transition(GtkAction *action, transition_t *transition);
36 static void insert_history_buffer(GtkWidget *view, gchar *entry);
37 static void append_transition(GtkAction *action, transition_t *transition);
38 static void set_transition(GtkAction *action, transition_t *transition);
39 static void manager_transition(GtkAction *action, transition_t *transition);
40 static void memory_transition(GtkAction *action, transition_t *transition);
41 static void show_about_dialog(void);
42 static void Process_state(GtkAction *action, transition_t *transition);
43 static void Detach_acl(GtkAction *action, transition_t *transition);
44
45 static GtkActionEntry entries[] = {
46   {"FileMenu", NULL, N_("_File")},
47   {"EditMenu", NULL, N_("_Edit")},
48   {"ViewMenu", NULL, N_("_View")},
49   {"HelpMenu", NULL, N_("_Help")},
50
51   {"Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q",
52         N_("Quit a program"), G_CALLBACK(terminate)},
53
54   {"Edit", GTK_STOCK_EDIT, N_("S_et"), "<control>E",
55         N_("Set or Edit the selected line"), G_CALLBACK(set_transition)},
56   {"Add", GTK_STOCK_ADD, N_("_Add"), "<control>I",
57         N_("Append line"), G_CALLBACK(append_transition)},
58   {"Delete", GTK_STOCK_DELETE, N_("_Delete"), "<control>D",
59         N_("Delete the selected line"), G_CALLBACK(delete_transition)},
60   {"Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C",
61         N_("Copy an entry at the cursor position to history buffer"),
62         G_CALLBACK(copy_line)},
63   {"OptimizationSupport", GTK_STOCK_CONVERT,
64         N_("_OptimizationSupport"), "<control>O",
65         N_("Extraction of redundant ACL entries"), G_CALLBACK(optimize_acl)},
66
67   {"Search", GTK_STOCK_FIND, N_("_Search"), "<control>F",
68         N_("Search for text"), G_CALLBACK(search_input)},
69   {"SearchBack", GTK_STOCK_GO_BACK, N_("Search_Backwards"), "<control><shift>G",
70         N_("Search backwards for the same text"), G_CALLBACK(search_back)},
71   {"SearchFoward", GTK_STOCK_GO_FORWARD, N_("SearchFor_wards"), "<control>G",
72         N_("Search forwards for the same text"), G_CALLBACK(search_forward)},
73
74   {"Refresh", GTK_STOCK_REFRESH, N_("_Refresh"), "<control>R",
75         N_("Refresh to the latest information"), G_CALLBACK(refresh_transition)},
76   {"Manager", GTK_STOCK_DND, N_("_Manager"), "<control>M",
77         N_("Manager Profile Editor"), G_CALLBACK(manager_transition)},
78   {"Memory", GTK_STOCK_DND, N_("_Statistics"), "<control>S",
79         N_("Statistics"), G_CALLBACK(memory_transition)},
80
81   {"About", GTK_STOCK_ABOUT, N_("_About"), "<alt>A",
82         N_("About a program"), show_about_dialog}
83 };
84 static guint n_entries = G_N_ELEMENTS(entries);
85
86 static GtkToggleActionEntry toggle_entries[] = {
87   { "Process", GTK_STOCK_MEDIA_RECORD, N_("Process"), "<control>at",
88         N_("Process State Viewer"), G_CALLBACK(Process_state), FALSE},
89   { "ACL", "", N_("Detach ACL"), "",
90         N_("Detach ACL window"), G_CALLBACK(Detach_acl), FALSE},
91 };
92 static guint n_toggle_entries = G_N_ELEMENTS(toggle_entries);
93
94 static const gchar *ui_info =
95 "<ui>"
96 "  <menubar name='MenuBar'>"
97 "    <menu action='FileMenu'>"
98 "      <menuitem action='Quit'/>"
99 "    </menu>"
100
101 "    <menu action='EditMenu'>"
102 "      <menuitem action='Edit'/>"
103 "      <menuitem action='Add'/>"
104 "      <menuitem action='Delete'/>"
105 "      <separator/>"
106 "      <menuitem action='Copy'/>"
107 "      <menuitem action='OptimizationSupport'/>"
108 "      <separator/>"
109 "      <menuitem action='Search'/>"
110 "      <menuitem action='SearchBack'/>"
111 "      <menuitem action='SearchFoward'/>"
112 "    </menu>"
113
114 "    <menu action='ViewMenu'>"
115 "      <menuitem action='Refresh'/>"
116 "      <separator/>"
117 "      <menuitem action='Manager'/>"
118 "      <menuitem action='Memory'/>"
119 "      <separator/>"
120 "      <menuitem action='Process'/>"
121 "      <separator/>"
122 "      <menuitem action='ACL'/>"
123 "    </menu>"
124
125 "    <menu action='HelpMenu'>"
126 "      <menuitem action='About'/>"
127 "    </menu>"
128 "  </menubar>"
129
130 "  <toolbar name='ToolBar'>"
131 "    <toolitem action='Quit'/>"
132 "    <separator/>"
133 "    <toolitem action='Edit'/>"
134 "    <toolitem action='Add'/>"
135 "    <toolitem action='Delete'/>"
136 "    <separator/>"
137 "    <toolitem action='Copy'/>"
138 "    <toolitem action='OptimizationSupport'/>"
139 "    <separator/>"
140 "    <toolitem action='Search'/>"
141 "    <toolitem action='SearchBack'/>"
142 "    <toolitem action='SearchFoward'/>"
143 "    <separator/>"
144 "    <toolitem action='Refresh'/>"
145 "    <separator/>"
146 "    <toolitem action='Process'/>"
147 "    <separator/>"
148 "    <toolitem action='About'/>"
149 "  </toolbar>"
150
151 "  <popup name='PopUp'>"
152 "      <menuitem action='Edit'/>"
153 "      <menuitem action='Add'/>"
154 "      <menuitem action='Delete'/>"
155 "      <separator/>"
156 "      <menuitem action='Copy'/>"
157 "      <menuitem action='OptimizationSupport'/>"
158 "  </popup>"
159 "</ui>";
160
161 GtkWidget *create_menu(GtkWidget *parent, transition_t *transition,
162                                 GtkWidget **toolbar)
163 {
164         GtkUIManager            *ui;
165         GtkActionGroup          *actions;
166         GtkAccelGroup           *accel_group;
167         GError                  *error = NULL;
168         GtkWidget               *popup;
169
170         actions = gtk_action_group_new("Actions");
171         gtk_action_group_set_translation_domain(actions, GETTEXT_PACKAGE);
172         gtk_action_group_add_actions(actions,
173                         entries, n_entries, transition);
174         gtk_action_group_add_toggle_actions(actions,
175                         toggle_entries, n_toggle_entries, transition);
176
177         ui = gtk_ui_manager_new();
178         gtk_ui_manager_insert_action_group(ui, actions, 0);
179
180         gtk_action_set_sensitive(
181                 gtk_action_group_get_action(actions, "Search"), TRUE);
182         gtk_action_set_sensitive(
183                 gtk_action_group_get_action(actions, "SearchBack"), FALSE);
184         gtk_action_set_sensitive(
185                 gtk_action_group_get_action(actions, "SearchFoward"), FALSE);
186         gtk_action_set_sensitive(
187                 gtk_action_group_get_action(actions, "Edit"), FALSE);
188         gtk_action_set_sensitive(gtk_action_group_get_action(
189                                 actions, "OptimizationSupport"), FALSE);
190
191         if (is_offline()) {
192                 gtk_action_set_sensitive(
193                         gtk_action_group_get_action(actions, "Process"), FALSE);
194                 gtk_action_set_sensitive(
195                         gtk_action_group_get_action(actions, "Memory"), FALSE);
196         }
197
198         transition->actions = actions;
199
200 //      gtk_ui_manager_set_add_tearoffs(ui, TRUE);
201         accel_group = gtk_ui_manager_get_accel_group(ui);
202         gtk_window_add_accel_group(GTK_WINDOW(parent), accel_group);
203         if (!gtk_ui_manager_add_ui_from_string(ui, ui_info, -1, NULL)) {
204                 g_message ("building menus failed: %s", error->message);
205                 g_error_free (error);
206         }
207
208         *toolbar = gtk_ui_manager_get_widget(ui, "/ToolBar");
209         gtk_toolbar_set_style(GTK_TOOLBAR(*toolbar), GTK_TOOLBAR_ICONS);
210
211         /* to save gpet.c popup_menu() */
212         popup = gtk_ui_manager_get_widget(ui, "/PopUp");
213         g_object_set_data(G_OBJECT(transition->window), "popup", popup);
214
215         /* to save gpet.c gpet_main() */
216         g_object_set_data(G_OBJECT(transition->window),
217                                                 "AccelGroup", accel_group);
218
219         return gtk_ui_manager_get_widget(ui, "/MenuBar");
220 }
221 /*-------+---------+---------+---------+---------+---------+---------+--------*/
222 void disp_statusbar(transition_t *transition, int scr)
223 {
224         gchar   *status_str = NULL;
225
226         switch (scr) {
227         case CCS_SCREEN_EXCEPTION_LIST :
228                 status_str = g_strdup_printf("Entry[%d]",
229                         transition->exp.count);
230                 break;
231         case CCS_SCREEN_PROFILE_LIST :
232                 status_str = g_strdup_printf("Entry[%d]",
233                         transition->prf.count);
234                 break;
235         case CCS_SCREEN_DOMAIN_LIST :
236         case CCS_SCREEN_ACL_LIST :
237                 if (transition->task_flag)
238                         status_str = g_strdup_printf("Process[%d] Policy[%d]",
239                                 transition->tsk.count, transition->acl.count);
240                 else
241                         status_str = g_strdup_printf("Domain[%d] Policy[%d]",
242                                 transition->domain_count, transition->acl.count);
243                 break;
244         case CCS_MAXSCREEN :
245                 status_str = g_strdup_printf("Domain[%d]",
246                         transition->domain_count);
247                 break;
248         default :
249                 g_warning("BUG: screen [%d]  file(%s) line(%d)",
250                                 scr, __FILE__, __LINE__);
251                 break;
252         }
253         gtk_statusbar_pop(GTK_STATUSBAR(transition->statusbar),
254                                 transition->contextid);
255         gtk_statusbar_push(GTK_STATUSBAR(transition->statusbar),
256                                 transition->contextid, status_str);
257         g_free(status_str);
258 }
259 /*-------+---------+---------+---------+---------+---------+---------+--------*/
260 static void terminate(GtkAction *action, transition_t *transition)
261 {
262         write_config(transition);
263         g_object_unref(transition->actions);
264         gtk_main_quit();
265 }
266 /*-------+---------+---------+---------+---------+---------+---------+--------*/
267 static gulong handler_id = 0UL;
268
269 static gboolean cb_destroy_acl(GtkWidget *widget, GdkEvent *event,
270                                         transition_t *transition)
271 {
272         GtkWidget       *acl_container;
273         GtkPaned        *paned;
274
275         if (handler_id == 0UL)
276                 return FALSE;
277
278         /* get gpet.c main()*/
279         acl_container = g_object_get_data(G_OBJECT(transition->window), "acl_container");
280         paned = g_object_get_data(G_OBJECT(transition->window), "pane");
281
282         g_signal_handler_disconnect(
283                         G_OBJECT(transition->acl_window), handler_id);
284         handler_id = 0UL;
285
286         gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(
287                 gtk_action_group_get_action(transition->actions, "ACL")), FALSE);
288         transition->acl_detached = FALSE;
289
290         gtk_widget_reparent(GTK_WIDGET(transition->container),
291                                         GTK_WIDGET(paned));
292
293         gtk_widget_reparent(GTK_WIDGET(acl_container),
294                                         GTK_WIDGET(paned));
295
296         transition->current_page = CCS_SCREEN_DOMAIN_LIST;
297         set_sensitive(transition->actions, transition->task_flag,
298                                                 transition->current_page);
299         refresh_transition(NULL, transition);
300
301         return gtk_widget_hide_on_delete(transition->acl_window);
302 }
303
304 static void Detach_acl(GtkAction *action, transition_t *transition)
305 {
306         GtkWidget       *acl_container;
307         GtkPaned        *paned;
308         /* get gpet.c main()*/
309         acl_container = g_object_get_data(G_OBJECT(transition->window), "acl_container");
310         paned = g_object_get_data(G_OBJECT(transition->window), "pane");
311
312         if (transition->acl_detached) {
313                 cb_destroy_acl(NULL, NULL, transition);
314         } else {
315                 gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(
316                         gtk_action_group_get_action(transition->actions, "ACL")), TRUE);
317                 transition->acl_detached = TRUE;
318                 handler_id = g_signal_connect(
319                         G_OBJECT(transition->acl_window), "delete_event",
320                         G_CALLBACK(cb_destroy_acl), transition);
321                 gtk_widget_reparent(GTK_WIDGET(acl_container),
322                                         transition->acl_window);
323                 gtk_widget_show_all(transition->acl_window);
324
325                 gtk_widget_reparent(GTK_WIDGET(transition->container),
326                                         GTK_WIDGET(paned));
327                 transition->current_page = CCS_SCREEN_ACL_LIST;
328                 set_sensitive(transition->actions, transition->task_flag,
329                                                 transition->current_page);
330                 refresh_transition(NULL, transition);
331         }
332 }
333 /*-------+---------+---------+---------+---------+---------+---------+--------*/
334 static void Process_state(GtkAction *action, transition_t *transition)
335 {
336         GtkWidget       *view;
337         GtkWidget       *notebook;
338         GtkWidget       *tab1;
339         gchar           *label_str;
340
341         view = transition->task_flag ?
342                         transition->tsk.treeview : transition->treeview;
343         gtk_container_remove(transition->container, view);
344         g_object_ref(view);
345
346         transition->task_flag = ~transition->task_flag & 1;
347
348         if (transition->task_flag) {
349                 label_str = _("Process State");
350                 view = transition->tsk.treeview;
351         } else {
352                 label_str = _("Domain Transition");
353                 view = transition->treeview;
354         }
355
356         /* from gpet.c:gpet_main()*/
357         notebook = g_object_get_data(
358                                 G_OBJECT(transition->window), "notebook");
359         tab1 = g_object_get_data(
360                                 G_OBJECT(transition->window), "tab1");
361         gtk_notebook_set_tab_label_text(
362                                 GTK_NOTEBOOK(notebook), tab1, label_str);
363         gtk_notebook_set_menu_label_text(
364                                 GTK_NOTEBOOK(notebook), tab1, label_str);
365
366         gtk_container_add(transition->container, view);
367
368         transition->current_page = CCS_SCREEN_DOMAIN_LIST;
369         set_sensitive(transition->actions, transition->task_flag,
370                                                 transition->current_page);
371         if (transition->acl_detached)
372                 g_object_set(G_OBJECT(notebook), "can-focus", FALSE, NULL);
373         else
374                 g_object_set(G_OBJECT(notebook), "can-focus", TRUE, NULL);
375         refresh_transition(action, transition);
376 }
377 /*-------+---------+---------+---------+---------+---------+---------+--------*/
378 void view_cursor_set(GtkWidget *view,
379                         GtkTreePath *path, GtkTreeViewColumn *column)
380 {
381         if (!path) {
382                 path = gtk_tree_path_new_from_indices(0, -1);
383         }
384
385         {
386                 gchar *path_str = gtk_tree_path_to_string(path);
387                 DEBUG_PRINT("<%s> TreePath[%s]\n",
388                         g_type_name(G_OBJECT_TYPE(view)), path_str);
389                 g_free(path_str);
390         }
391         gtk_tree_view_set_cursor(
392                         GTK_TREE_VIEW(view), path, column, FALSE);
393         gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view), path, NULL,
394                                                 TRUE, 0.5, 0.0);        // ksn
395         gtk_tree_path_free(path);
396 }
397
398 void refresh_transition(GtkAction *action, transition_t *transition)
399 {
400         GtkTreePath             *path = NULL;
401         GtkTreeViewColumn       *column = NULL;
402         GtkWidget               *view = NULL;
403
404         DEBUG_PRINT("In  Refresh Page[%d]\n", (int)transition->current_page);
405         switch((int)transition->current_page) {
406         case CCS_SCREEN_EXCEPTION_LIST :
407                 view = transition->exp.listview;
408                 gtk_tree_view_get_cursor(GTK_TREE_VIEW(view),
409                                                         &path, &column);
410                 if (get_exception_policy(
411                     &(transition->exp.list), &(transition->exp.count)))
412                         break;
413                 add_list_data(&(transition->exp), TRUE);
414                 set_position_addentry(transition, &path);
415                 disp_statusbar(transition, CCS_SCREEN_EXCEPTION_LIST);
416                 view_cursor_set(view, path, column);
417                 gtk_widget_grab_focus(view);
418                 break;
419         case CCS_SCREEN_PROFILE_LIST :
420                 view = transition->prf.listview;
421                 gtk_tree_view_get_cursor(GTK_TREE_VIEW(view),
422                                                         &path, &column);
423                 if (get_profile(
424                     &(transition->prf.list), &(transition->prf.count)))
425                         break;
426                 add_list_data(&(transition->prf), FALSE);
427                 set_position_addentry(transition, &path);
428                 disp_statusbar(transition, CCS_SCREEN_PROFILE_LIST);
429                 view_cursor_set(view, path, column);
430                 gtk_widget_grab_focus(view);
431                 break;
432         case CCS_SCREEN_DOMAIN_LIST :
433         case CCS_MAXSCREEN :
434                 view = transition->task_flag ?
435                         transition->tsk.treeview : transition->treeview;
436                 gtk_tree_view_get_cursor(
437                                 GTK_TREE_VIEW(view), &path, &column);
438
439                 gtk_widget_hide(view);
440                 if (transition->task_flag) {
441                         if (get_task_list(&(transition->tsk.task),
442                                                 &(transition->tsk.count)))
443                                 break;
444                         add_task_tree_data(GTK_TREE_VIEW(view), &(transition->tsk));
445                         gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
446                 } else {
447                         if (get_domain_policy(
448                             transition->dp, &(transition->domain_count)))
449                                 break;
450                         add_tree_data(GTK_TREE_VIEW(view), transition->dp);
451                         gtk_tree_view_expand_all(GTK_TREE_VIEW(view));
452                         set_position_addentry(transition, &path);
453                 }
454
455                 view_cursor_set(view, path, column);
456                 gtk_widget_show(view);
457 #if 0
458                 if (transition->acl_detached) { // get focus
459                         gtk_widget_grab_focus(transition->acl.listview);
460                         DEBUG_PRINT("☆Transition[%d] Acl[%d]\n",
461                                 gtk_window_has_toplevel_focus(GTK_WINDOW(transition->window)),
462                                 gtk_window_has_toplevel_focus(GTK_WINDOW(transition->acl_window)));
463                 } else {
464                         gtk_widget_grab_focus(view);
465                 }
466 #endif
467                 gtk_widget_grab_focus(view);
468                 break;
469         case CCS_SCREEN_ACL_LIST :
470                 view = transition->task_flag ?
471                         transition->tsk.treeview : transition->treeview;
472                 gtk_tree_view_get_cursor(
473                                 GTK_TREE_VIEW(view), &path, &column);
474                 view_cursor_set(view, path, column);
475                 gtk_widget_grab_focus(transition->acl.listview);
476                 break;
477         }
478
479         if (transition->acl_detached) {
480                 DEBUG_PRINT("★Transition[%d] Acl[%d]\n",
481                 gtk_window_has_toplevel_focus(GTK_WINDOW(transition->window)),
482                 gtk_window_has_toplevel_focus(GTK_WINDOW(transition->acl_window)));
483         }
484         DEBUG_PRINT("Out  Refresh Page[%d]\n", (int)transition->current_page);
485 }
486 /*-------+---------+---------+---------+---------+---------+---------+--------*/
487 static void copy_line(GtkAction *action, transition_t *transition)
488 {
489         gint            index;
490         GtkWidget       *view;
491
492         switch((int)transition->current_page) {
493         case CCS_SCREEN_DOMAIN_LIST :
494                 index = get_current_domain_index(transition);
495                 view = transition->treeview;
496                 if (index >= 0)
497                         insert_history_buffer(view, g_strdup(
498                                 ccs_domain_name(transition->dp, index)));
499                 break;
500         case CCS_SCREEN_ACL_LIST :
501                 view = transition->acl.listview;
502                 insert_history_buffer(view, get_alias_and_operand(view));
503                 break;
504         case CCS_SCREEN_EXCEPTION_LIST :
505                 view = transition->exp.listview;
506                 insert_history_buffer(view, get_alias_and_operand(view));
507                 break;
508         default :
509                 break;
510         }
511 }
512 /*-------+---------+---------+---------+---------+---------+---------+--------*/
513 static void optimize_acl(GtkAction *action, transition_t *transition)
514 {
515         GtkTreeSelection        *selection;
516         GtkTreeModel            *model;
517         gint                    count, current;
518
519         if ((int)transition->current_page != CCS_SCREEN_ACL_LIST)
520                 return;
521
522         selection = gtk_tree_view_get_selection(
523                                 GTK_TREE_VIEW(transition->acl.listview));
524         if (!selection || !(count =
525             gtk_tree_selection_count_selected_rows(selection)))
526                 return;
527         DEBUG_PRINT("count[%d]\n", count);
528
529         // current位置を取得:
530         current = select_list_line(&(transition->acl));
531         if (current < 0)
532                 return;
533
534         get_optimize_acl_list(current,
535                         &(transition->acl.list), transition->acl.count);
536
537         model = gtk_tree_view_get_model(GTK_TREE_VIEW(transition->acl.listview));
538         gtk_tree_model_foreach(model,
539                 (GtkTreeModelForeachFunc)disp_acl_line, &(transition->acl));
540
541 #if 0
542         gint                    index;
543         GtkTreePath             *start_path, *end_path;
544         gint                    start_index, end_index;
545         // 表示処理
546         start_path = end_path = gtk_tree_path_new_from_indices(current, -1);
547         gtk_tree_selection_unselect_range(selection, start_path, end_path);
548
549         for (index = 0; index < transition->acl.count; index++) {
550                 if (transition->acl.list[index].selected)
551                         break;
552         }
553         end_path = NULL;
554         start_path = gtk_tree_path_new_from_indices(index, -1);
555         start_index = end_index = index;
556         count = -1;
557         for ( ; index < transition->acl.count; index++) {
558                 count++;
559                 // 対象データ:ccs_gacl_list[index].selected == 1;
560                 if (!transition->acl.list[index].selected)
561                         continue;
562
563                 //パス取得:
564                 if (index == (start_index + count)) {
565                         end_path = gtk_tree_path_new_from_indices(index, -1);
566                         end_index = index;
567                 } else {
568                         if (!end_path)
569                                 end_path = start_path;
570
571                         // カーソルセット:
572 g_print("start[%d] end[%d]\n", start_index, end_index);
573                         gtk_tree_selection_select_range(
574                                         selection, start_path, end_path);
575
576                         start_path = gtk_tree_path_new_from_indices(index, -1);
577                         start_index = index;
578                         count = 0;
579                         end_path = NULL;
580                 }
581         }
582
583         if (end_path) {
584 g_print("start[%d] end[%d]\n", start_index, end_index);
585                 gtk_tree_selection_select_range(selection, start_path, end_path);
586         }
587 #endif
588 }
589 /*-------+---------+---------+---------+---------+---------+---------+--------*/
590 static gint message_dialog(GtkWidget *parent, gchar *message)
591 {
592         GtkWidget       *dialog;
593         gint            result;
594
595         dialog = gtk_message_dialog_new_with_markup(GTK_WINDOW(parent) ,
596                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
597                         GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
598                         NULL);
599         gtk_message_dialog_set_markup(GTK_MESSAGE_DIALOG(dialog), message);
600
601         result = gtk_dialog_run(GTK_DIALOG(dialog));
602         gtk_widget_destroy(dialog);
603
604         return result;
605 }
606
607 static void delete_transition(GtkAction *action, transition_t *transition)
608 {
609         GtkTreeSelection        *selection;
610         gint                    count;
611         GtkWidget               *parent;
612         gchar                   *message = NULL;
613         gint                    ret = 1;
614
615         DEBUG_PRINT("delete : current page[%d]\n", transition->current_page);
616
617         switch((int)transition->current_page) {
618         case CCS_SCREEN_EXCEPTION_LIST :
619                 selection = gtk_tree_view_get_selection(
620                                 GTK_TREE_VIEW(transition->exp.listview));
621                 if (!selection || !(count =
622                     gtk_tree_selection_count_selected_rows(selection)))
623                         break;
624                 DEBUG_PRINT("count[%d]\n", count);
625                 message = count > 1 ?
626                  g_strdup_printf(_(
627                         "<span foreground='red' size='x-large'>"
628                         "<b>Delete</b> the %d selected exception policies?</span>"), count) :
629                  g_strdup_printf(_(
630                         "<span foreground='red' size='x-large'>"
631                         "<b>Delete</b> the selected exception policy?</span>"));
632                 if (GTK_RESPONSE_YES ==
633                     message_dialog(transition->window, message)) {
634                         ret = delete_exp(transition, selection, count);
635                 }
636                 break;
637         case CCS_SCREEN_DOMAIN_LIST :
638         case CCS_MAXSCREEN :
639                 selection = gtk_tree_view_get_selection(
640                                 GTK_TREE_VIEW(transition->treeview));
641                 if (!selection || !(count =
642                     gtk_tree_selection_count_selected_rows(selection)))
643                         break;
644                 DEBUG_PRINT("count[%d]\n", count);
645                 message = count > 1 ?
646                  g_strdup_printf(_(
647                         "<span foreground='red' size='x-large'>"
648                         "<b>Delete</b> the %d selected domains?</span>"), count) :
649                  g_strdup_printf(_(
650                         "<span foreground='red' size='x-large'>"
651                         "<b>Delete</b> the selected domain?</span>"));
652                 if (GTK_RESPONSE_YES ==
653                     message_dialog(transition->window, message)) {
654                         ret = delete_domain(transition, selection, count);
655                 }
656                 break;
657         case CCS_SCREEN_ACL_LIST :
658                 DEBUG_PRINT("Delete ACL\n");
659                 selection = gtk_tree_view_get_selection(
660                                 GTK_TREE_VIEW(transition->acl.listview));
661                 if (!selection || !(count =
662                     gtk_tree_selection_count_selected_rows(selection)))
663                         break;
664                 DEBUG_PRINT("count[%d]\n", count);
665                 parent = transition->acl_detached ?
666                         transition->acl_window : transition->window;
667                 message = count > 1 ?
668                  g_strdup_printf(_(
669                         "<span foreground='blue' size='x-large'>"
670                         "<b>Delete</b> the %d selected policies?</span>"), count) :
671                  g_strdup_printf(_(
672                         "<span foreground='blue' size='x-large'>"
673                         "<b>Delete</b> the selected policy?</span>"));
674                 if (GTK_RESPONSE_YES ==
675                     message_dialog(parent, message)) {
676                         ret = delete_acl(transition, selection, count);
677                 }
678                 break;
679         case CCS_SCREEN_MANAGER_LIST :
680                 DEBUG_PRINT("Delete manager\n");
681                 break;
682         }
683
684         g_free(message);
685
686         if (!ret)
687                 refresh_transition(NULL, transition);
688 }
689 /*-------+---------+---------+---------+---------+---------+---------+--------*/
690 #define COMBO_LIST_LIMIT        20
691 static GList    *combolist = NULL;
692 static gchar    *Last_entry_string = NULL;
693
694 gchar *get_combo_entry_last(void)
695 {
696         return Last_entry_string;
697 }
698
699 static void insert_history_buffer(GtkWidget *view, gchar *entry)
700 {
701         GtkClipboard    *clipboard;
702         GList           *list;
703         guint           len;
704
705         if (!entry)
706                 return;
707
708         /* to system clipboard */
709         clipboard = gtk_widget_get_clipboard(view, GDK_SELECTION_CLIPBOARD);
710         gtk_clipboard_set_text(clipboard, entry, -1);
711
712         for (list = combolist; list; list = g_list_next(list)) {
713                 if (strcmp(entry, (gchar *)list->data) == 0)
714                         return;
715         }
716
717         combolist = g_list_insert(combolist, entry, 0);
718         len = g_list_length(combolist);
719         if (len > COMBO_LIST_LIMIT) {
720                 g_free(g_list_nth_data(combolist, len - 1));
721                 combolist = g_list_delete_link(combolist,
722                                         g_list_nth(combolist, len - 1));
723         }
724 }
725
726 static gint combo_entry_activate(GtkWidget *combo, gchar **new_text)
727 {
728         GtkComboBox     *combobox;
729         GList           *list;
730         gboolean        exist_flag = FALSE;
731
732         combobox = GTK_COMBO_BOX(combo);
733         (*new_text) = gtk_combo_box_get_active_text(combobox);
734         if(!(*new_text) || strcmp(*new_text, "") == 0)
735                 return 1;
736
737         g_free(Last_entry_string);
738         Last_entry_string = g_strdup(*new_text);
739
740         for (list = combolist; list; list = g_list_next(list)) {
741                 if (strcmp(*new_text, (gchar *)list->data) == 0) {
742                         exist_flag = TRUE;
743                         break;
744                 }
745         }
746
747         if (!exist_flag) {
748                 guint len;
749                 combolist = insert_item(combobox, combolist, *new_text, 0);
750                 len = g_list_length(combolist);
751                 if (len > COMBO_LIST_LIMIT) {
752                         combolist = remove_item(combobox, combolist, len - 1);
753                 }
754                 DEBUG_PRINT("Append '%s'.\n", *new_text);
755         }
756
757         return exist_flag ? 1 : 0;
758 }
759
760 static gint append_dialog(transition_t *transition,
761                                 gchar *title, gchar **input)
762 {
763         GtkWidget               *dialog, *parent;
764         GtkWidget               *combo;
765         GList                   *list;
766         gint                    response, result = 1;
767
768         parent = (transition->acl_detached &&
769                 (int)transition->current_page == CCS_SCREEN_ACL_LIST) ?
770                         transition->acl_window : transition->window;
771
772         dialog = gtk_dialog_new_with_buttons(title,
773                         GTK_WINDOW(parent),
774                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
775                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
776                         GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
777                         NULL);
778
779         combo = gtk_combo_box_entry_new_text();
780         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
781
782         for (list = combolist; list; list = g_list_next(list)) {
783                 gtk_combo_box_append_text(
784                         GTK_COMBO_BOX(combo), (gchar *)list->data);
785         }
786
787         gtk_container_add(
788                 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), combo);
789         gtk_widget_set_size_request(dialog, 600, -1);
790         gtk_widget_show_all(dialog);
791
792         response = gtk_dialog_run(GTK_DIALOG(dialog));
793         if (response == GTK_RESPONSE_APPLY) {
794                 combo_entry_activate(combo, input);
795                 result = 0;
796         }
797         gtk_widget_destroy(dialog);
798
799         return result;
800 }
801
802 static void append_transition(GtkAction *action, transition_t *transition)
803 {
804         gchar           *input = NULL;
805         gint            index, result = 1;
806         enum addentry_type      type = ADDENTRY_NON;
807         char            *err_buff = NULL;
808
809         switch((int)transition->current_page) {
810         case CCS_SCREEN_DOMAIN_LIST :
811                 DEBUG_PRINT("append domain\n");
812                 result = append_dialog(transition,
813                                  _("Add Domain"), &input);
814                 if (!result)
815                         result = add_domain(input, &err_buff);
816                 type = ADDENTRY_DOMAIN_LIST;
817                 break;
818         case CCS_SCREEN_ACL_LIST :
819                 DEBUG_PRINT("append acl\n");
820                 result = append_dialog(transition, _("Add Acl"), &input);
821                 if (!result) {
822                         index = get_current_domain_index(transition);
823                         if (index >= 0)
824                                 result = add_acl_list(transition->dp,
825                                                 index, input, &err_buff);
826                 }
827                 type = ADDENTRY_ACL_LIST;
828                 break;
829         case CCS_SCREEN_EXCEPTION_LIST :
830                 DEBUG_PRINT("append exception\n");
831                 result = append_dialog(transition,
832                                  _("Add Exception"), &input);
833                 if (!result)
834                         result = add_exception_policy(input, &err_buff);
835                 type = ADDENTRY_EXCEPTION_LIST;
836                 break;
837         case CCS_SCREEN_PROFILE_LIST :
838                 DEBUG_PRINT("append profile\n");
839                 result = append_dialog(transition,
840                                  _("Add Profile (0 - 255)"), &input);
841                 if (!result)
842                         result = add_profile(input, &err_buff);
843                 type = ADDENTRY_PROFILE_LIST;
844                 break;
845         default :
846                 DEBUG_PRINT("append ???\n");
847                 break;
848         }
849
850         if (result) {
851                 if(err_buff) {
852                         g_warning("%s", err_buff);
853                         free(err_buff);
854                 }
855                 transition->addentry = ADDENTRY_NON;
856         } else {
857                 transition->addentry = type;
858                 refresh_transition(NULL, transition);
859         }
860 }
861 /*-------+---------+---------+---------+---------+---------+---------+--------*/
862 enum list_column_pos {
863         LIST_PROFILE,           // display
864         PROFILE_NO,             // hidden
865         N_COLUMNS_LIST
866 };
867 static GtkWidget *create_list_profile(void)
868 {
869         GtkWidget               *treeview;
870         GtkListStore            *liststore;
871         GtkCellRenderer *renderer;
872         GtkTreeViewColumn       *column;
873
874         liststore = gtk_list_store_new(N_COLUMNS_LIST,
875                                         G_TYPE_STRING, G_TYPE_UINT);
876         treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(liststore));
877         g_object_unref(liststore);
878
879         renderer = gtk_cell_renderer_text_new();
880         column = gtk_tree_view_column_new();
881         gtk_tree_view_column_pack_start(column, renderer, FALSE);
882         column = gtk_tree_view_column_new_with_attributes("operand",
883                                 renderer, "text", LIST_PROFILE, NULL);
884         gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column);
885
886         // ヘッダ表示
887         gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
888
889         return treeview;
890 }
891
892 static void add_list_profile(GtkWidget *listview,
893                                  generic_list_t *generic)
894 {
895         GtkListStore    *store;
896         GtkTreeIter     iter;
897         int             i;
898         gchar           *profile;
899
900         store = GTK_LIST_STORE(gtk_tree_view_get_model(
901                                         GTK_TREE_VIEW(listview)));
902         gtk_list_store_clear(store);
903
904         DEBUG_PRINT("Count[%d]\n", generic->count);
905         for(i = 0; i < generic->count; i++){
906                 if (generic->list[i].directive > 255 ||
907                         !strstr(generic->list[i].operand, "COMMENT="))
908                         continue;
909
910                 DEBUG_PRINT("[%3d]:%3u-%s\n", i,
911                         generic->list[i].directive, generic->list[i].operand);
912
913                 gtk_list_store_append(store, &iter);
914                 profile = g_strdup_printf("%3u-%s",
915                                         generic->list[i].directive,
916                                         generic->list[i].operand);
917                 gtk_list_store_set(store, &iter,
918                                 LIST_PROFILE, profile,
919                                 PROFILE_NO, generic->list[i].directive,
920                                 -1);
921                 g_free(profile);
922         }
923 }
924
925 static gboolean apply_profile(transition_t *transition,
926                                 GtkTreeSelection *domain_selection,
927                                 GtkWidget *listview)
928 {
929         GtkTreeSelection        *selection;
930         GtkTreeIter             iter;
931         GtkTreeModel            *model;
932         GList                   *list;
933         guint                   profile_no;
934         gint                    result;
935
936         selection = gtk_tree_view_get_selection(
937                                                 GTK_TREE_VIEW(listview));
938         if (selection &&
939             gtk_tree_selection_count_selected_rows(selection) == 1) {
940                 list = gtk_tree_selection_get_selected_rows(
941                                                         selection, NULL);
942                 model = gtk_tree_view_get_model(GTK_TREE_VIEW(listview));
943                 gtk_tree_model_get_iter(model, &iter,
944                                         g_list_first(list)->data);
945                 gtk_tree_model_get(model, &iter,
946                                         PROFILE_NO, &profile_no, -1);
947                 DEBUG_PRINT("Selct Profile [%u]\n", profile_no);
948                 result = set_domain_profile(transition,
949                                         domain_selection, profile_no);
950                 if (!result)
951                         refresh_transition(NULL, transition);
952                 return TRUE;
953         } else {
954                 return FALSE;
955         }
956 }
957
958 static void set_domain(transition_t *transition)
959 {
960         GtkTreeSelection        *domain_selection;
961         GtkWidget               *dialog;
962         GtkWidget               *listview;
963         gint                    count, response;
964
965         if (transition->task_flag)
966                 domain_selection = gtk_tree_view_get_selection(
967                                 GTK_TREE_VIEW(transition->tsk.treeview));
968         else
969                 domain_selection = gtk_tree_view_get_selection(
970                                 GTK_TREE_VIEW(transition->treeview));
971
972         if (!domain_selection || !(count =
973             gtk_tree_selection_count_selected_rows(domain_selection)))
974                 return;
975
976         dialog = gtk_dialog_new_with_buttons(_("Profile list"),
977                         GTK_WINDOW(transition->window),
978                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
979                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
980                         GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
981                         NULL);
982
983         listview = create_list_profile();
984         add_list_profile(listview, &(transition->prf));
985         view_cursor_set(listview, NULL, NULL);
986         gtk_container_add(
987                 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), listview);
988         gtk_widget_set_size_request(dialog, 400, 300);
989         gtk_widget_set_name(dialog, "GpetProfileSelectDialog"); // .gpetrc
990         gtk_widget_show_all(dialog);
991
992 retry_profile:
993         response = gtk_dialog_run(GTK_DIALOG(dialog));
994         if (response == GTK_RESPONSE_APPLY) {
995                 DEBUG_PRINT("Apply button was pressed.\n");
996                 if (!apply_profile(transition,
997                                         domain_selection, listview))
998                         goto retry_profile;
999         } else if (response == GTK_RESPONSE_CANCEL) {
1000                 DEBUG_PRINT("Cancel button was pressed.\n");
1001         } else {
1002                 DEBUG_PRINT("Another response was recieved.\n");
1003         }
1004         gtk_widget_destroy(dialog);
1005 }
1006
1007 static void edit_profile(transition_t *transition)
1008 {
1009         GtkWidget               *dialog;
1010         GtkWidget               *hbox;
1011         GtkWidget               *label;
1012         GtkWidget               *entry;
1013         gchar                   *profile, *label_str, *ptr;
1014         gint                    index, response;
1015
1016         if ((index = select_list_line(&(transition->prf))) < 0)
1017                 return;
1018
1019         entry = gtk_entry_new();
1020
1021         profile = g_strdup(transition->prf.list[index].operand);
1022         ptr = strchr(profile, '=');
1023         if (ptr)
1024                 ptr++;
1025         if (ptr) {
1026                 gtk_entry_set_text(GTK_ENTRY(entry), ptr);
1027                 *ptr = '\0';
1028         }
1029
1030         if (transition->prf.list[index].directive < 256)
1031                 label_str = g_strdup_printf("%3u-%s",
1032                         transition->prf.list[index].directive, profile);
1033         else
1034                 label_str = g_strdup_printf("%s", profile);
1035         label = gtk_label_new(label_str);
1036         g_free(profile);
1037         g_free(label_str);
1038
1039         dialog = gtk_dialog_new_with_buttons(_("Profile Edit"),
1040                         GTK_WINDOW(transition->window),
1041                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1042                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1043                         GTK_STOCK_APPLY, GTK_RESPONSE_APPLY,
1044                         NULL);
1045
1046         hbox = gtk_hbox_new(FALSE, 5);
1047         gtk_container_add(
1048                 GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), hbox);
1049
1050         gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1051         gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
1052
1053         gtk_widget_set_size_request(dialog, 600, -1);
1054         gtk_widget_show_all(dialog);
1055
1056         response = gtk_dialog_run(GTK_DIALOG(dialog));
1057         if (response == GTK_RESPONSE_APPLY) {
1058                 const gchar     *input;
1059                 char            *err_buff = NULL;
1060 //              transition->prf.list[index].selected = 1;
1061                 input = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
1062                 DEBUG_PRINT("Edit profile [%s] index[%d]\n", input, index);
1063                 if (set_profile_level(index, input, &err_buff)) {
1064                         g_warning("%s", err_buff);
1065                         free(err_buff);
1066                 } else {
1067                         refresh_transition(NULL, transition);
1068                 }
1069         }
1070         gtk_widget_destroy(dialog);
1071 }
1072
1073 static void set_transition(GtkAction *action, transition_t *transition)
1074 {
1075         switch((int)transition->current_page) {
1076         case CCS_SCREEN_DOMAIN_LIST :
1077                 DEBUG_PRINT("set profile\n");
1078                 set_domain(transition);
1079                 break;
1080         case CCS_SCREEN_PROFILE_LIST :
1081                 DEBUG_PRINT("edit profile\n");
1082                 edit_profile(transition);
1083                 break;
1084         default :
1085                 DEBUG_PRINT("edit ???\n");
1086                 break;
1087         }
1088 }
1089 /*-------+---------+---------+---------+---------+---------+---------+--------*/
1090 static void manager_transition(GtkAction *action, transition_t *transition)
1091 {
1092         manager_main(transition);
1093 }
1094
1095 static void memory_transition(GtkAction *action, transition_t *transition)
1096 {
1097         memory_main(transition);
1098 }
1099 /*-------+---------+---------+---------+---------+---------+---------+--------*/
1100 GdkPixbuf *get_png_file(void)
1101 {
1102         GdkPixbuf       *pixbuf;
1103         GError          *err = NULL;
1104
1105         pixbuf = gdk_pixbuf_new_from_file(PACKAGE_ICON_DIR "/tomoyo.png", &err);
1106         if (!pixbuf) {
1107                 g_warning("%s", err->message);
1108                 g_error_free(err);
1109         }
1110         return pixbuf;
1111 }
1112
1113 static void show_about_dialog(void)
1114 {
1115         GtkWidget               *dialog;
1116         GtkAboutDialog  *about;
1117         GdkPixbuf               *pixbuf;
1118
1119         const gchar     *authors[] = {
1120                 _("Yoshihiro Kusuno <yocto@users.sourceforge.jp>"),
1121                 _("ccstools --- kumaneko san"),
1122                 NULL};
1123         const gchar     *documenters[] = {_("Yoshihiro Kusuno"), NULL};
1124 //      const gchar     *translators = "none";
1125
1126         dialog = gtk_about_dialog_new();
1127         about = GTK_ABOUT_DIALOG(dialog);
1128         gtk_about_dialog_set_name(about, "gpet");
1129         gtk_about_dialog_set_authors(about, authors);
1130         gtk_about_dialog_set_documenters(about, documenters);
1131 //      gtk_about_dialog_set_translator_credits(about, translators);
1132         gtk_about_dialog_set_version(about, VERSION);
1133         gtk_about_dialog_set_copyright(about,
1134                                 "Copyright(C) 2010,2011 TOMOYO Linux Project");
1135         gtk_about_dialog_set_comments(about,
1136                                 "Gui Policy Editor for TOMOYO Linux 1.8"
1137                                 " or AKARI 1.0"
1138                                 "\n(based on ccs-editpolicy:ccstools)");
1139         gtk_about_dialog_set_website(about, "http://sourceforge.jp/projects/gpet/");
1140 //      gtk_about_dialog_set_website_label(about, "http://tomoyo.sourceforge.jp/");
1141
1142         pixbuf = get_png_file();
1143         if (pixbuf) {
1144                 gtk_about_dialog_set_logo(about, pixbuf);
1145                 g_object_unref(pixbuf);
1146         }
1147         gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
1148
1149         gtk_dialog_run(GTK_DIALOG(about));
1150         gtk_widget_destroy(GTK_WIDGET(about));
1151 }