~ubuntu-branches/debian/sid/frama-c/sid

« back to all changes in this revision

Viewing changes to src/slicing/register_gui.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-06-03 08:19:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090603081925-kihvxvt0wy3zc4ar
Tags: upstream-20081201.dfsg
ImportĀ upstreamĀ versionĀ 20081201.dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
(**************************************************************************)
 
2
(*                                                                        *)
 
3
(*  This file is part of Frama-C.                                         *)
 
4
(*                                                                        *)
 
5
(*  Copyright (C) 2007-2008                                               *)
 
6
(*    CEA   (Commissariat ļæ½ l'ļæ½nergie Atomique)                           *)
 
7
(*    INRIA (Institut National de Recherche en Informatique et en         *)
 
8
(*           Automatique)                                                 *)
 
9
(*                                                                        *)
 
10
(*  you can redistribute it and/or modify it under the terms of the GNU   *)
 
11
(*  Lesser General Public License as published by the Free Software       *)
 
12
(*  Foundation, version 2.1.                                              *)
 
13
(*                                                                        *)
 
14
(*  It is distributed in the hope that it will be useful,                 *)
 
15
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of        *)
 
16
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *)
 
17
(*  GNU Lesser General Public License for more details.                   *)
 
18
(*                                                                        *)
 
19
(*  See the GNU Lesser General Public License version v2.1                *)
 
20
(*  for more details (enclosed in the file licenses/LGPLv2.1).            *)
 
21
(*                                                                        *)
 
22
(**************************************************************************)
 
23
 
 
24
(*i $Id: register_gui.ml,v 1.35 2008/12/16 10:02:59 uid526 Exp $ i*)
 
25
open Cil_types
 
26
open Cilutil 
 
27
 
 
28
module Enable = 
 
29
  Computation.Ref
 
30
    (struct include Datatype.Bool
 
31
            let default () = false 
 
32
     end)
 
33
    (struct 
 
34
       let name = "Slicing_gui.State"
 
35
       let dependencies = []
 
36
     end)
 
37
    
 
38
   
 
39
(* for slicing callback *)
 
40
let mk_selection fselect = fselect (!Db.Slicing.Select.empty_selects ())
 
41
  
 
42
(* for slicing callback *)
 
43
let mk_selection_cad fselect =
 
44
  mk_selection fselect (!Db.Slicing.Mark.make ~ctrl:true ~addr:true ~data:true)
 
45
    
 
46
(* for slicing callback *)
 
47
let mk_selection_all fselect =
 
48
  mk_selection fselect ~spare:false
 
49
    
 
50
(* for slicing callback *)
 
51
let mk_slice selection =
 
52
  let n = string_of_int (1 + List.length (!Db.Slicing.Project.get_all ())) in
 
53
  let project = !Db.Slicing.Project.mk_project ("Slicing "^ n) in
 
54
    !Db.Slicing.Request.add_persistent_selection project selection ;
 
55
    !Db.Slicing.Request.apply_all_internal project;          
 
56
    if Cmdline.Slicing.Mode.Callers.get () then
 
57
      !Db.Slicing.Slice.remove_uncalled project;
 
58
    let new_project = !Db.Slicing.Project.extract ((!Db.Slicing.Project.get_name project)^ " export") project in
 
59
      !Db.Slicing.Project.set_project (Some (project)) ;
 
60
      new_project
 
61
 
 
62
(* To add a sensitive/unsensitive menu item to a [factory] *)
 
63
let add_item (factory:GMenu.menu GMenu.factory) ~callback name arg_opt =
 
64
    match arg_opt with
 
65
      | None -> (* add the menu item, but it isn't sensitive *)
 
66
          let item = factory#add_item name ~callback:(fun () -> ())
 
67
          in item#misc#set_sensitive false
 
68
      | Some arg -> (* add the menu item with its callback *)
 
69
          ignore (factory#add_item name ~callback:(fun () -> callback arg))
 
70
 
 
71
(* To inform the user about a status. *)       
 
72
let gui_annot_info (main_ui:Design.main_window_extension_points) ~level txt =
 
73
  if (Cmdline.Slicing.Mode.Verbose.get () >= level) then
 
74
    begin
 
75
      main_ui#annot_window#buffer#insert ((txt ()) ^ ".\n")
 
76
    end
 
77
      
 
78
(* To inform the user about an action. *)       
 
79
let gui_annot_action (main_ui:Design.main_window_extension_points) txt =
 
80
  if (Cmdline.Slicing.Mode.Verbose.get () >= 0) then
 
81
    begin
 
82
      let tag_style_italic = Gtk_helper.make_tag main_ui#annot_window#buffer ~name:"slicing:style italic" [`STYLE `ITALIC] in
 
83
        main_ui#annot_window#buffer#insert ~tags:[tag_style_italic] ((txt ()) ^ "\n")
 
84
    end
 
85
      
 
86
(* To inform the user about an error. *)       
 
87
let gui_annot_error (main_ui:Design.main_window_extension_points) txt =
 
88
  let tag_style_italic = Gtk_helper.make_tag main_ui#annot_window#buffer ~name:"slicing:style italic" [`STYLE `OBLIQUE  ; ] in
 
89
    main_ui#annot_window#buffer#insert ~tags:[tag_style_italic] (txt ^ ".\n")
 
90
      
 
91
let gui_mk_slice main_ui selection ~info =
 
92
  let already_locked =
 
93
    gui_annot_action main_ui info;
 
94
    main_ui#lock () in (* lock the gui while ... *)
 
95
  let new_project = mk_slice selection in (* ... slicing computation *)
 
96
    main_ui#unlock already_locked ;
 
97
    gui_annot_action main_ui (fun () -> "Slice exported to project: " ^ (Project.name new_project));
 
98
    main_ui#rehighlight ()
 
99
        
 
100
let gui_compute_values (main_ui:Design.main_window_extension_points) =
 
101
  if not (Db.Value.is_computed ()) then
 
102
    begin
 
103
      gui_annot_action main_ui (fun () -> "Activating slicing plugin by running value analysis first");
 
104
      let already_locked = main_ui#lock () in
 
105
        (try !Db.Value.compute ();
 
106
         with Globals.No_such_entry_point msg -> gui_annot_error main_ui msg);
 
107
        main_ui#unlock already_locked
 
108
    end
 
109
 
 
110
(* To do an action and inform the user. *)
 
111
let gui_apply_action (main_ui:Design.main_window_extension_points) f x ~info =
 
112
  f x ;
 
113
  gui_annot_action main_ui info
 
114
 
 
115
let get_setting_option_text txt = "Setting option " ^ txt ^ " for the current project"
 
116
  
 
117
let gui_toggle_slice_undef (main_ui:Design.main_window_extension_points) =
 
118
  let slice_undef = not (Cmdline.Slicing.Mode.SliceUndef.get ()) in
 
119
    gui_apply_action main_ui Cmdline.Slicing.Mode.SliceUndef.set slice_undef
 
120
      ~info:(fun () ->
 
121
               
 
122
               if slice_undef then (get_setting_option_text "-slice-undef-functions" )^
 
123
                 ". Allow the use of the slicing level for calls to undefined functions"
 
124
               else (get_setting_option_text "-no-slice-undef-functions") ^
 
125
                 ". Forbid the slicing of prototypes of undefined functions")
 
126
    
 
127
let gui_set_project (main_ui:Design.main_window_extension_points) proj_opt =
 
128
  gui_apply_action main_ui !Db.Slicing.Project.set_project proj_opt
 
129
    ~info:(fun () ->
 
130
             Extlib.may_map ~dft:"Clear slicing highlighting"
 
131
               (fun project -> ("Highlighting for " ^ (!Db.Slicing.Project.get_name project)))
 
132
               proj_opt) ;
 
133
  main_ui#rehighlight ()
 
134
      
 
135
let slicing_selector (popup_factory:GMenu.menu GMenu.factory)
 
136
    (main_ui:Design.main_window_extension_points) ~button localizable = 
 
137
  if not (Db.Value.is_computed ()) then
 
138
    ignore (popup_factory#add_item "Activate _Slicing"
 
139
              ~callback:(fun () -> gui_compute_values main_ui ))
 
140
  else if not (Enable.get ()) then
 
141
    ignore (popup_factory#add_item "Enable _Slicing menu"
 
142
              ~callback:(fun () -> Enable.set true))
 
143
  else
 
144
    let slicing_project = !Db.Slicing.Project.get_project () in
 
145
      if button = 1 then
 
146
        begin let level = 0 in
 
147
        let slicing_view project =
 
148
          gui_annot_info main_ui ~level (fun () -> "Highlighting for " ^ (!Db.Slicing.Project.get_name project))
 
149
        in 
 
150
          Extlib.may slicing_view slicing_project;
 
151
          if Cmdline.Slicing.Mode.Verbose.get () > level then begin
 
152
            let slicing_mark project =
 
153
              let slicing_mark kf get_mark =
 
154
                (* use -slicing-debug -verbose to get slicing mark information *)
 
155
                let add_mark_info txt = gui_annot_info ~level main_ui (fun () -> "Tag: " ^ (txt ())) in
 
156
                let slices = !Db.Slicing.Slice.get_all project kf in
 
157
                  match slices with
 
158
                    | [] -> (* No slice for this kf *)
 
159
                        add_mark_info (fun () ->
 
160
                                         if !Db.Slicing.Project.is_called project kf
 
161
                                         then (* but the source function is called *)
 
162
                                           (Cil.fprintf_to_string "<src>%a"
 
163
                                              !Db.Slicing.Mark.pretty (!Db.Slicing.Mark.get_from_src_func project kf))
 
164
                                         else
 
165
                                           "<   ><   >")
 
166
                    | slices ->
 
167
                        if !Db.Slicing.Project.is_called project kf
 
168
                        then begin (* The source function is also called *)
 
169
                          assert (not (kf == fst (Globals.entry_point ()))) ;
 
170
                          add_mark_info (fun () ->
 
171
                                           Cil.fprintf_to_string "<src>%a"
 
172
                                             !Db.Slicing.Mark.pretty (!Db.Slicing.Mark.get_from_src_func project kf))
 
173
                        end ;
 
174
                        let mark_slice slice =
 
175
                          add_mark_info (fun () -> Cil.fprintf_to_string "%a" !Db.Slicing.Mark.pretty (get_mark slice))
 
176
                        in List.iter mark_slice slices
 
177
              in match localizable with
 
178
                | Pretty_source.PTermLval(Some kf,(Kstmt ki),_) (* as for the statement *)
 
179
                | Pretty_source.PLval (Some kf,(Kstmt ki),_) (* as for the statement *)
 
180
                | Pretty_source.PStmt (kf,ki) -> slicing_mark kf (fun slice -> !Db.Slicing.Slice.get_mark_from_stmt slice ki)
 
181
                | Pretty_source.PVDecl (Some kf,vi) -> slicing_mark kf (fun slice -> !Db.Slicing.Slice.get_mark_from_local_var slice vi)
 
182
                | _ -> ()
 
183
            in Extlib.may slicing_mark slicing_project
 
184
          end 
 
185
        end 
 
186
      else if button = 3 then begin
 
187
        let submenu = popup_factory#add_submenu "Slicing" in
 
188
        let slicing_factory = new GMenu.factory submenu in
 
189
          (* definitions for slicing plug-in *)        
 
190
        let add_slicing_item name = add_item slicing_factory name in
 
191
        let mk_slice = gui_mk_slice main_ui in
 
192
        let add_slice_menu kf_opt kf_ki_opt =
 
193
          
 
194
          add_slicing_item "Slice calls to"
 
195
            kf_opt
 
196
            ~callback:(fun kf ->
 
197
                         mk_slice
 
198
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing effects of function %a"
 
199
                                    Kernel_function.pretty_name kf)
 
200
                           ((mk_selection_all !Db.Slicing.Select.select_func_calls_to) kf));
 
201
          add_slicing_item "Slice calls into"
 
202
            kf_opt
 
203
            ~callback:(fun kf -> 
 
204
                         mk_slice
 
205
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing entrance into function %a"
 
206
                                    Kernel_function.pretty_name kf)
 
207
                           ((mk_selection_all !Db.Slicing.Select.select_func_calls_into) kf));
 
208
          add_slicing_item "Slice result"
 
209
            (Extlib.opt_filter (fun kf ->
 
210
                                  let is_not_void_kf x =
 
211
                                    match x.Cil_types.vtype with
 
212
                                      | Cil_types.TFun (Cil_types.TVoid (_),_,_,_) -> false
 
213
                                      | _ -> true
 
214
                                  in is_not_void_kf (Kernel_function.get_vi kf))
 
215
               kf_opt)
 
216
            ~callback:(fun kf ->
 
217
                         mk_slice
 
218
                           ~info:(fun () -> Cil.fprintf_to_string "Request for returned value of function %a"
 
219
                                    Kernel_function.pretty_name kf)
 
220
                           ((mk_selection_all !Db.Slicing.Select.select_func_return) kf));
 
221
          add_slicing_item "Slice stmt"
 
222
            kf_ki_opt
 
223
            ~callback:(fun (kf, ki) ->
 
224
                         mk_slice
 
225
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing effects of statement %d"
 
226
                                    ki.sid)
 
227
                           ((mk_selection_all !Db.Slicing.Select.select_stmt) ki kf));
 
228
          add_slicing_item "Slice lval"
 
229
            kf_ki_opt
 
230
            ~callback:(fun (kf, ki) ->
 
231
                         let do_with_txt txt =
 
232
                           try
 
233
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
234
                               mk_slice
 
235
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing Lvalue %s before statement %d"
 
236
                                          txt
 
237
                                          ki.sid)
 
238
                                 ((mk_selection_cad !Db.Slicing.Select.select_stmt_lval)
 
239
                                    lval_str ~before:true ki ~scope:ki ~eval:ki kf)
 
240
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
241
                         in
 
242
                         let txt =
 
243
                           GToolbox.input_string
 
244
                             ~title:"Input a pure Lvalue expression to slice before current statement"
 
245
                             ""
 
246
                         in Extlib.may do_with_txt txt);
 
247
          add_slicing_item "Slice rd"
 
248
            kf_ki_opt
 
249
            ~callback:(fun (kf, ki) ->
 
250
                         let do_with_txt txt =
 
251
                           try
 
252
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
253
                               mk_slice
 
254
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing read accesses to Lvalue %s"
 
255
                                          txt)
 
256
                                 ((mk_selection_cad !Db.Slicing.Select.select_func_lval_rw)
 
257
                                    ~rd:lval_str ~wr:Cilutil.StringSet.empty ~scope:ki ~eval:ki kf)
 
258
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
259
                         in
 
260
                         let txt =
 
261
                           GToolbox.input_string
 
262
                             ~title:"Input a pure Lvalue expression to slice read accesses"
 
263
                             ""
 
264
                         in Extlib.may do_with_txt txt);
 
265
          add_slicing_item "Slice wr"
 
266
            kf_ki_opt
 
267
            ~callback:(fun (kf, ki) ->
 
268
                         let do_with_txt txt =
 
269
                           try
 
270
                             let lval_str = Cilutil.StringSet.add txt Cilutil.StringSet.empty in
 
271
                               mk_slice
 
272
                                 ~info:(fun () -> Cil.fprintf_to_string "Request for slicing writen accesses to Lvalue %s"
 
273
                                          txt)
 
274
                                 ((mk_selection_cad !Db.Slicing.Select.select_func_lval_rw)
 
275
                                    ~rd:Cilutil.StringSet.empty ~wr:lval_str ~scope:ki ~eval:ki kf)
 
276
                           with e -> main_ui#error "Invalid expression: %s" (Printexc.to_string e)
 
277
                         in
 
278
                         let txt =
 
279
                           GToolbox.input_string
 
280
                             ~title:"Input a pure Lvalue expression to slice read accesses"
 
281
                             ""
 
282
                         in Extlib.may do_with_txt txt);
 
283
          add_slicing_item "Slice ctrl"
 
284
            kf_ki_opt
 
285
            ~callback:(fun (kf, ki) ->
 
286
                         mk_slice
 
287
                           ~info:(fun () -> Cil.fprintf_to_string "Request for slicing accessibility to statement %d"
 
288
                                    ki.sid)
 
289
                           ((mk_selection_all !Db.Slicing.Select.select_stmt_ctrl) ki kf))
 
290
        in
 
291
        let some_kf_from_vi vi = 
 
292
          try let kf = Globals.Functions.get vi in
 
293
          if Enable.get () && !Db.Value.is_called kf then Some kf else None
 
294
          with Not_found -> None in
 
295
        let some_kf_from_lv  lv = 
 
296
          match lv with
 
297
            | Var vi,_ -> some_kf_from_vi vi
 
298
            | _ -> None in
 
299
        let some_kf_ki kf ki = 
 
300
          if Enable.get ()
 
301
            && !Db.Value.is_called kf
 
302
            && Db.Value.is_accessible (Cil_types.Kstmt ki)
 
303
          then Some (kf, ki) else None in
 
304
          begin  (* add menu for slicing and scope plug-in *)
 
305
            match localizable with
 
306
              | Pretty_source.PLval (Some kf,(Kstmt stmt),lv) ->
 
307
                  add_slice_menu (some_kf_from_lv lv) (some_kf_ki kf stmt)
 
308
              | Pretty_source.PTermLval(Some kf,(Kstmt ki),_) (* as for the statement *)
 
309
              | Pretty_source.PStmt (kf,ki) ->
 
310
                  add_slice_menu None (some_kf_ki kf ki)
 
311
              | Pretty_source.PVDecl (_,vi) ->
 
312
                  add_slice_menu (some_kf_from_vi vi) None
 
313
              | _  ->
 
314
                  add_slice_menu None None
 
315
          end;
 
316
          let projects = !Db.Slicing.Project.get_all() in
 
317
            ignore (slicing_factory#add_separator ());
 
318
            add_slicing_item "_Disable"
 
319
              (Some ())
 
320
              ~callback:(fun () -> Enable.set false);
 
321
            add_slicing_item "_Clear"
 
322
              (if slicing_project = None then None else Some ())
 
323
              ~callback:(fun () -> gui_set_project main_ui None) ;
 
324
            List.iter
 
325
              (fun proj ->
 
326
                 let add_highlight_menu sensitive =
 
327
                   add_slicing_item
 
328
                     ("Highlight " ^ (Pretty_utils.escape_underscores (!Db.Slicing.Project.get_name proj)))
 
329
                     sensitive
 
330
                     ~callback:(fun () -> gui_set_project main_ui (Some proj))
 
331
                 in match slicing_project with
 
332
                   | Some project -> add_highlight_menu (if (proj == project) then None else Some ())
 
333
                   | None -> add_highlight_menu (Some()))
 
334
              projects;
 
335
      end
 
336
        
 
337
let slicing_highlighter 
 
338
    (buffer:GSourceView.source_buffer) localizable ~start ~stop =
 
339
  if Enable.get () then begin
 
340
    (* Definition for highlight 'Slicing' *)
 
341
    let highlight project =
 
342
      let ki = match localizable with 
 
343
        | Pretty_source.PStmt (_,stmt) -> Kstmt stmt
 
344
        | Pretty_source.PLval (_,ki,_) | Pretty_source.PTermLval(_,ki,_) -> ki
 
345
        | Pretty_source.PVDecl _ -> Kglobal
 
346
      in
 
347
      if Db.Value.is_accessible ki then 
 
348
        let unused_code_area = 
 
349
          Gtk_helper.make_tag buffer ~name:"slicing_unused" [`STRIKETHROUGH true ] in
 
350
        let spare_code_area = 
 
351
          Gtk_helper.make_tag buffer ~name:"slicing_spare" [`UNDERLINE `LOW] in
 
352
        let necessary_code_area = 
 
353
          Gtk_helper.make_tag buffer ~name:"slicing_necessary" [`BACKGROUND "green"] in
 
354
        let apply_on_one_project_and_merge_slices kf pb pe mark_of_slice =
 
355
          let apply_mark mark =
 
356
            if Cmdline.Debug.get () > 0 then
 
357
              Format.printf "Got mark: %a@." !Db.Slicing.Mark.pretty mark;
 
358
            if !Db.Slicing.Mark.is_bottom mark then
 
359
              Gtk_helper.apply_tag buffer unused_code_area pb pe;
 
360
            if !Db.Slicing.Mark.is_spare mark then
 
361
              Gtk_helper.apply_tag buffer spare_code_area pb pe;
 
362
            if (!Db.Slicing.Mark.is_ctrl mark
 
363
                || !Db.Slicing.Mark.is_data mark
 
364
                || !Db.Slicing.Mark.is_addr mark)
 
365
            then
 
366
              Gtk_helper.apply_tag buffer necessary_code_area pb pe
 
367
          in
 
368
          let slices = !Db.Slicing.Slice.get_all project kf in
 
369
          begin
 
370
            match slices with
 
371
            | [] ->
 
372
                (* No slice for this kf *)
 
373
                if !Db.Slicing.Project.is_called project kf
 
374
                then begin
 
375
                  if Cmdline.Debug.get () > 0 then 
 
376
                    Format.printf "Got source code@." ;
 
377
                  apply_mark (!Db.Slicing.Mark.get_from_src_func project kf)
 
378
                end
 
379
                else
 
380
                  Gtk_helper.apply_tag buffer unused_code_area pb pe
 
381
            | slices ->
 
382
                if !Db.Slicing.Project.is_called project kf
 
383
                then begin
 
384
                  assert (not (kf == fst (Globals.entry_point ()))) ;
 
385
                  if Cmdline.Debug.get () > 0 then 
 
386
                    Format.printf "Got source code@." ;
 
387
                  apply_mark (!Db.Slicing.Mark.get_from_src_func project kf)
 
388
                end ;
 
389
                if Cmdline.Debug.get () > 0 then begin
 
390
                  let l = List.length slices in
 
391
                  if l >=2 then
 
392
                    Format.printf "Got %d slices@."
 
393
                      (List.length slices)
 
394
                end;
 
395
                let mark_slice slice =
 
396
                  let mark = mark_of_slice project slice in
 
397
                  apply_mark mark
 
398
                in List.iter mark_slice slices
 
399
          end
 
400
        in
 
401
        let tag_stmt kf stmt pb pe =
 
402
          assert (Db.Value.is_accessible (Kstmt stmt)) ;
 
403
          apply_on_one_project_and_merge_slices
 
404
            kf
 
405
            pb
 
406
            pe
 
407
            (fun _ slice -> !Db.Slicing.Slice.get_mark_from_stmt slice stmt)
 
408
        in
 
409
        let tag_vdecl kf vi pb pe =
 
410
          if not vi.vglob then
 
411
            apply_on_one_project_and_merge_slices
 
412
              kf
 
413
              pb
 
414
              pe
 
415
              (fun _ slice -> !Db.Slicing.Slice.get_mark_from_local_var slice vi)
 
416
        in
 
417
        match localizable with 
 
418
        | Pretty_source.PStmt (kf,stmt) -> tag_stmt kf stmt start stop
 
419
        | Pretty_source.PVDecl (Some kf,vi) -> tag_vdecl kf vi start stop 
 
420
        | Pretty_source.PVDecl (None,_)
 
421
        | Pretty_source.PLval _
 
422
        | Pretty_source.PTermLval _ -> ()
 
423
    in 
 
424
    let slicing_project = !Db.Slicing.Project.get_project () in
 
425
    (* 2. Highlights the 'Slicing' *)
 
426
    Extlib.may highlight slicing_project         
 
427
  end
 
428
 
 
429
let none_text = "<i>None</i>"
 
430
 
 
431
let rebuild_model ((_, (model, _column)) as combo_box_text) = 
 
432
  model#clear ();
 
433
  GEdit.text_combo_add combo_box_text none_text;
 
434
  List.iter 
 
435
    (fun p -> GEdit.text_combo_add combo_box_text (!Db.Slicing.Project.get_name p)) 
 
436
    (List.rev (!Db.Slicing.Project.get_all()))
 
437
 
 
438
let refresh_combo_box ((combo_box, (model, _column)) as combo_box_text) 
 
439
    slicing_project sensitive =
 
440
  let nb_combo_elts = model#iter_n_children None in
 
441
  let projects = List.rev (!Db.Slicing.Project.get_all()) in
 
442
  if nb_combo_elts<>(1+(List.length projects))
 
443
  then rebuild_model combo_box_text;
 
444
  (* Reset the active project as active in the combo box *)
 
445
  let nth_proj = ref 0 in
 
446
  let i = ref 1 in
 
447
  List.iter (fun proj ->
 
448
                 Extlib.may (fun slicing_proj ->
 
449
                               if proj == slicing_proj then nth_proj := !i)
 
450
                   slicing_project;
 
451
                 incr i)
 
452
      projects;
 
453
  combo_box#set_active !nth_proj;
 
454
  combo_box#misc#set_sensitive sensitive
 
455
 
 
456
    
 
457
let gui_set_slicing_debug (main_ui:Design.main_window_extension_points) v =
 
458
  let old = Cmdline.Slicing.Mode.Verbose.get () in
 
459
    if v != old then (* Otherwise set is done at every refreshing *)
 
460
      gui_apply_action main_ui Cmdline.Slicing.Mode.Verbose.set v
 
461
        ~info:(fun () -> get_setting_option_text ("-slicing-debug \"-debug " ^ (string_of_int v) ^ "\""))
 
462
    
 
463
let gui_set_slicing_level (main_ui:Design.main_window_extension_points) v =
 
464
  let old = Cmdline.Slicing.Mode.Calls.get () in
 
465
    if v != old then (* Otherwise set is done at every refreshing *)
 
466
      gui_apply_action main_ui Cmdline.Slicing.Mode.Calls.set v
 
467
        ~info:(fun () -> get_setting_option_text ("-slicing-level " ^ (string_of_int v)))
 
468
        
 
469
let gui_set_slicing_undef_functions (main_ui:Design.main_window_extension_points) v =
 
470
  let old = Cmdline.Slicing.Mode.SliceUndef.get () in
 
471
    if v != old then (* Otherwise set is done at every refreshing *)
 
472
      gui_apply_action main_ui Cmdline.Slicing.Mode.SliceUndef.set v
 
473
        ~info:(fun () -> get_setting_option_text (if v then "-slicing-undef-functions" else "-no-slice-undef-functions"))
 
474
        
 
475
let slicing_panel main_ui =
 
476
  let w = GPack.vbox  () in
 
477
  let hbox1 = GPack.hbox
 
478
    ~packing:w#pack () in
 
479
  let activate_button = GButton.button ~label:"Activate"
 
480
    ~packing:hbox1#pack () in
 
481
  let ((combo_box, (_model, column)) as combo_box_text) =
 
482
    GEdit.combo_box_text ~strings:[ none_text ] ~wrap_width:3 ~use_markup:true
 
483
      ~packing:(hbox1#pack ~expand:true ~fill:true) () in
 
484
 
 
485
  let table = GPack.table ~columns:2 ~rows:2 ~homogeneous:true ~packing:w#pack () in
 
486
 
 
487
  let hbox2 = GPack.hbox ~packing:(table#attach ~left:1 ~top:0) () in
 
488
 
 
489
    (* [enabled_button] to give slicing menu available *)    
 
490
  let enable_refresh () = 
 
491
    gui_compute_values main_ui ;
 
492
    main_ui#rehighlight ()
 
493
  in 
 
494
  let enabled_button =
 
495
    GButton.check_button 
 
496
      ~label:"Enable"
 
497
      ~active:(Enable.get ())
 
498
      ~packing:(table#attach ~left:0 ~top:0) () in
 
499
 
 
500
  ignore (enabled_button#connect#toggled 
 
501
            ~callback:(fun () -> 
 
502
                         Enable.set enabled_button#active;
 
503
                         enable_refresh ()));
 
504
 
 
505
  let verbose_refresh = Gtk_helper.on_int ~lower:0 ~upper:3 
 
506
    hbox2
 
507
    "Verbosity"
 
508
        ~sensitive:Enable.get
 
509
        Cmdline.Slicing.Mode.Verbose.get
 
510
        (gui_set_slicing_debug main_ui)
 
511
  in
 
512
 
 
513
  let hbox3 = GPack.hbox ~packing:(table#attach ~left:1 ~top:1) () in
 
514
    (* [slice_undef_button] related to -slice-undef option *)    
 
515
  let slice_undef_button =
 
516
    GButton.check_button 
 
517
      ~label:"Libraries"
 
518
      ~active:(Enable.get ())
 
519
      ~packing:(table#attach ~left:0 ~top:1) () in
 
520
 
 
521
   let level_refresh = Gtk_helper.on_int ~lower:0 ~upper:3
 
522
    hbox3 
 
523
    "Level"
 
524
    ~sensitive:Enable.get
 
525
    Cmdline.Slicing.Mode.Calls.get 
 
526
    (gui_set_slicing_level main_ui)
 
527
   in
 
528
 
 
529
    combo_box#set_active 0 ;
 
530
    ignore (combo_box#connect#changed
 
531
              (fun () ->
 
532
                 match combo_box#active_iter with
 
533
                   | None -> ()
 
534
                   | Some row -> 
 
535
                       let slicing_project_name =
 
536
                         (* get the text entry related to the current slicing project *)
 
537
                         Extlib.may_map !Db.Slicing.Project.get_name ~dft:none_text (!Db.Slicing.Project.get_project ())
 
538
                       and selected_name = combo_box#model#get ~row ~column in
 
539
                         if (selected_name != slicing_project_name) then
 
540
                           let proj_opt =
 
541
                             try Some (List.find (fun proj -> selected_name = !Db.Slicing.Project.get_name proj) (!Db.Slicing.Project.get_all ()))
 
542
                             with Not_found -> None
 
543
                           in
 
544
                             gui_set_project main_ui proj_opt));
 
545
    ignore (activate_button#connect#pressed
 
546
              (fun () -> gui_compute_values main_ui ));
 
547
 
 
548
    ignore (slice_undef_button#connect#toggled
 
549
              (fun () ->
 
550
                 gui_set_slicing_undef_functions main_ui slice_undef_button#active));
 
551
    
 
552
    Project.register_after_set_current_hook
 
553
      ~user_only:true
 
554
      (fun () -> rebuild_model combo_box_text);
 
555
 
 
556
    let refresh () =
 
557
      let value_is_computed = Db.Value.is_computed () in
 
558
      let slicing_project = !Db.Slicing.Project.get_project () in
 
559
      let enabled = Enable.get () in
 
560
      activate_button#misc#set_sensitive (not value_is_computed) ;
 
561
      enabled_button#misc#set_sensitive value_is_computed ;
 
562
      slice_undef_button#misc#set_sensitive enabled ;
 
563
      
 
564
      verbose_refresh ();
 
565
      level_refresh ();
 
566
 
 
567
      if enabled_button#active <> enabled then 
 
568
        begin
 
569
          enabled_button#set_active enabled ;
 
570
          enable_refresh ();
 
571
        end;
 
572
 
 
573
      slice_undef_button#set_active (Cmdline.Slicing.Mode.SliceUndef.get());
 
574
  
 
575
      ignore (refresh_combo_box combo_box_text slicing_project (enabled && value_is_computed))
 
576
    in 
 
577
    refresh () ;
 
578
    "Slicing",w#coerce,Some refresh
 
579
        
 
580
let file_tree_decorate (file_tree:Filetree.t) = 
 
581
  file_tree#append_pixbuf_column 
 
582
    "Slicing"  
 
583
    (fun globs -> 
 
584
       Extlib.may_map
 
585
         (fun project ->
 
586
            if (List.exists
 
587
                  (fun glob -> match glob with 
 
588
                     | GFun ({svar = vi},_ ) ->
 
589
                         begin
 
590
                           try
 
591
                             let kf = Globals.Functions.get vi
 
592
                             in (!Db.Slicing.Project.is_called project kf)
 
593
                                || ( [] != (!Db.Slicing.Slice.get_all project kf))
 
594
                           with Not_found -> false
 
595
                         end
 
596
                     |  _ -> false) 
 
597
                  globs) then
 
598
              [`STOCK_ID "gtk-yes"]
 
599
            else
 
600
              [`STOCK_ID ""])
 
601
         ~dft:[`STOCK_ID ""]
 
602
         (!Db.Slicing.Project.get_project ()))
 
603
 
 
604
let main (main_ui:Design.main_window_extension_points) =
 
605
  main_ui#register_source_selector slicing_selector;
 
606
  main_ui#register_source_highlighter slicing_highlighter;
 
607
  main_ui#register_panel slicing_panel;
 
608
  file_tree_decorate main_ui#file_tree
 
609
 
 
610
let () = Design.register_extension main
 
611
 
 
612
(*
 
613
Local Variables:
 
614
compile-command: "LC_ALL=C make -C ../.. -j"
 
615
End:
 
616
*)
 
617
 
 
618