%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
-module(observer_traceoptions_wx).
-include_lib("wx/include/wx.hrl").
-include("observer_defs.hrl").
-export([process_trace/2, trace_pattern/4]).
-compile(export_all).
process_trace(Parent, Default) ->
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Process Options",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}]),
Panel = wxPanel:new(Dialog),
MainSz = wxBoxSizer:new(?wxVERTICAL),
PanelSz = wxBoxSizer:new(?wxHORIZONTAL),
LeftSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Tracing options"}]),
RightSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Inheritance options:"}]),
FuncBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace function call", []),
check_box(FuncBox, lists:member(functions, Default)),
SendBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace send message", []),
check_box(SendBox, lists:member(send, Default)),
RecBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace receive message", []),
check_box(RecBox, lists:member('receive', Default)),
EventBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace process events", []),
check_box(EventBox, lists:member(events, Default)),
{SpawnBox, SpwnAllRadio, SpwnFirstRadio} =
optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "spawn"),
{LinkBox, LinkAllRadio, LinkFirstRadio} =
optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "link"),
SpawnBool = lists:member(on_spawn, Default) orelse lists:member(on_first_spawn, Default),
LinkBool = lists:member(on_link, Default) orelse lists:member(on_first_link, Default),
check_box(SpawnBox, SpawnBool),
check_box(LinkBox, LinkBool),
enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio]),
enable(LinkBox, [LinkAllRadio, LinkFirstRadio]),
wxRadioButton:setValue(SpwnAllRadio, lists:member(on_spawn, Default)),
wxRadioButton:setValue(SpwnFirstRadio, lists:member(on_first_spawn, Default)),
wxRadioButton:setValue(LinkAllRadio, lists:member(on_link, Default)),
wxRadioButton:setValue(LinkFirstRadio, lists:member(on_first_link, Default)),
wxSizer:add(LeftSz, FuncBox, []),
wxSizer:add(LeftSz, SendBox, []),
wxSizer:add(LeftSz, RecBox, []),
wxSizer:add(LeftSz, EventBox, []),
wxSizer:add(LeftSz, 150, -1),
wxSizer:add(PanelSz, LeftSz, [{flag, ?wxEXPAND}]),
wxSizer:add(PanelSz, RightSz,[{flag, ?wxEXPAND}]),
wxPanel:setSizer(Panel, PanelSz),
wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND}, {proportion,1}]),
Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}]),
wxWindow:setSizerAndFit(Dialog, MainSz),
wxSizer:setSizeHints(MainSz, Dialog),
wxCheckBox:connect(SpawnBox, command_checkbox_clicked,
[{callback, fun(#wx{event=#wxCommand{}},_) ->
enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio])
end}]),
wxCheckBox:connect(LinkBox, command_checkbox_clicked,
[{callback, fun(#wx{event=#wxCommand{}},_) ->
enable(LinkBox, [LinkAllRadio, LinkFirstRadio])
end}]),
Res = case wxDialog:showModal(Dialog) of
?wxID_OK ->
All = [{SendBox, send}, {RecBox, 'receive'},
{FuncBox, functions}, {EventBox, events},
{{SpawnBox, SpwnAllRadio}, on_spawn},
{{SpawnBox,SpwnFirstRadio}, on_first_spawn},
{{LinkBox, LinkAllRadio}, on_link},
{{LinkBox, LinkFirstRadio}, on_first_link}],
Check = fun({Box, Radio}) ->
wxCheckBox:getValue(Box) andalso wxRadioButton:getValue(Radio);
(Box) ->
wxCheckBox:getValue(Box)
end,
Opts = [Id || {Tick, Id} <- All, Check(Tick)],
{ok, lists:reverse(Opts)};
?wxID_CANCEL ->
cancel
end,
wxDialog:destroy(Dialog),
Res.
trace_pattern(ParentPid, Parent, Node, MatchSpecs) ->
try
Module = module_selector(Parent, Node),
MFAs = function_selector(Parent, Node, Module),
MatchSpec = select_matchspec(ParentPid, Parent, MatchSpecs),
{Module, [#tpattern{m=M,fa={F,A},ms=MatchSpec} || {M,F,A} <- MFAs]}
catch cancel -> cancel
end.
module_selector(Parent, Node) ->
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
{size, {400, 400}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
MainSz = wxBoxSizer:new(?wxVERTICAL),
TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY),
ListBox = wxListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_SINGLE}]),
wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]),
wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxPanel:setSizer(Panel, PanelSz),
wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 1}]),
Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 0}]),
wxWindow:setSizer(Dialog, MainSz),
OkId = wxDialog:getAffirmativeId(Dialog),
OkButt = wxWindow:findWindowById(OkId),
wxWindow:disable(OkButt),
wxWindow:setFocus(TxtCtrl),
%% init data
Modules = get_modules(Node),
AllModules = [{atom_to_list(X), X} || X <- Modules],
filter_listbox_data("", AllModules, ListBox),
wxTextCtrl:connect(TxtCtrl, command_text_updated,
[{callback, fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
filter_listbox_data(Input, AllModules, ListBox)
end}]),
wxListBox:connect(ListBox, command_listbox_doubleclicked,
[{callback, fun(_, _) -> wxDialog:endModal(Dialog, ?wxID_OK) end}]),
wxListBox:connect(ListBox, command_listbox_selected,
[{callback, fun(_, _) -> wxWindow:enable(OkButt) end}]),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
SelId = wxListBox:getSelection(ListBox),
Module = wxListBox:getClientData(ListBox, SelId),
wxDialog:destroy(Dialog),
Module;
?wxID_CANCEL ->
wxDialog:destroy(Dialog),
throw(cancel)
end.
function_selector(Parent, Node, Module) ->
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
{size, {400, 400}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
MainSz = wxBoxSizer:new(?wxVERTICAL),
TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY),
ListBox = wxCheckListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_EXTENDED}]),
wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]),
wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
SelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Check Visible"}]),
DeSelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Uncheck Visible"}]),
ButtonSz = wxBoxSizer:new(?wxHORIZONTAL),
[wxSizer:add(ButtonSz, Button, []) || Button <- [SelAllBtn, DeSelAllBtn]],
wxSizer:add(PanelSz, ButtonSz, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 0}]),
wxPanel:setSizer(Panel, PanelSz),
wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 1}]),
Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 0}]),
wxWindow:setSizer(Dialog, MainSz),
wxWindow:setFocus(TxtCtrl),
%% Init
Functions = observer_wx:try_rpc(Node, Module, module_info, [functions]),
Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions,
not(erl_internal:guard_bif(Name, Arity))]),
ParsedChoices = parse_function_names(Choices),
filter_listbox_data("", ParsedChoices, ListBox, false),
%% Setup Event handling
wxTextCtrl:connect(TxtCtrl, command_text_updated,
[{callback,
fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
filter_listbox_data(Input, ParsedChoices, ListBox, false)
end}]),
Self = self(),
%% Sigh clientdata in checklistbox crashes on windows, wx-bug I presume.
%% Don't have time to investigate now, workaround file bug report later
GetClientData = fun(LB, N) ->
String = wxListBox:getString(LB, N),
{_, Data} = lists:keyfind(String, 1, ParsedChoices),
Data
end,
wxCheckListBox:connect(ListBox, command_checklistbox_toggled,
[{callback,
fun(#wx{event=#wxCommand{commandInt=N}}, _) ->
Self ! {ListBox, wxCheckListBox:isChecked(ListBox, N),
GetClientData(ListBox, N)}
end}]),
Check = fun(Id, Bool) ->
wxCheckListBox:check(ListBox, Id, [{check, Bool}]),
Self ! {ListBox, Bool, GetClientData(ListBox, Id)}
end,
wxButton:connect(SelAllBtn, command_button_clicked,
[{callback, fun(#wx{}, _) ->
Count = wxListBox:getCount(ListBox),
[Check(SelId, true) ||
SelId <- lists:seq(0, Count-1),
not wxCheckListBox:isChecked(ListBox, SelId)]
end}]),
wxButton:connect(DeSelAllBtn, command_button_clicked,
[{callback, fun(#wx{}, _) ->
Count = wxListBox:getCount(ListBox),
[Check(SelId, false) ||
SelId <- lists:seq(0, Count-1),
wxCheckListBox:isChecked(ListBox, SelId)]
end}]),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
wxDialog:destroy(Dialog),
case get_checked_funcs(ListBox, []) of
[] -> [{Module, '_', '_'}];
FAs ->
[{Module, F, A} || {F,A} <- FAs]
end;
?wxID_CANCEL ->
wxDialog:destroy(Dialog),
throw(cancel)
end.
get_checked_funcs(ListBox, Acc) ->
receive
{ListBox, true, FA} ->
get_checked_funcs(ListBox, [FA|lists:delete(FA,Acc)]);
{ListBox, false, FA} ->
get_checked_funcs(ListBox, lists:delete(FA,Acc))
after 0 ->
lists:reverse(Acc)
end.
select_matchspec(Pid, Parent, MatchSpecs) ->
Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications",
[{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
{size, {400, 400}}]),
Panel = wxPanel:new(Dialog),
PanelSz = wxBoxSizer:new(?wxVERTICAL),
MainSz = wxBoxSizer:new(?wxVERTICAL),
TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]),
BtnSz = wxBoxSizer:new(?wxHORIZONTAL),
SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]),
TextCtrl = create_styled_txtctrl(Panel),
wxSizer:add(TxtSz, TextCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]),
AddMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "New"}]),
EditMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Edit"}]),
DelMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Delete"}]),
wxSizer:add(BtnSz, AddMsBtn),
wxSizer:add(BtnSz, EditMsBtn),
wxSizer:add(BtnSz, DelMsBtn),
ListBox = wxListBox:new(Panel, ?wxID_ANY, []),
wxSizer:add(SavedSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(PanelSz, TxtSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(PanelSz, BtnSz),
wxSizer:add(PanelSz, SavedSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxWindow:setSizer(Panel, PanelSz),
wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 1}]),
Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
{border, 5}, {proportion, 0}]),
wxWindow:setSizer(Dialog, MainSz),
OkId = wxDialog:getAffirmativeId(Dialog),
OkButt = wxWindow:findWindowById(OkId),
wxWindow:disable(OkButt),
wxWindow:disable(EditMsBtn),
wxWindow:disable(DelMsBtn),
Choices = ms_names(MatchSpecs),
filter_listbox_data("", Choices, ListBox),
Add = fun(_,_) ->
case edit_ms(TextCtrl, new, Parent) of
Ms = #match_spec{} -> add_and_select(-1, Ms, ListBox);
Else -> Else
end
end,
Edit = fun(_,_) ->
SelId = wxListBox:getSelection(ListBox),
case SelId >= 0 of
true ->
#match_spec{name=Name} = wxListBox:getClientData(ListBox,SelId),
case edit_ms(TextCtrl, Name, Parent) of
Ms = #match_spec{} -> add_and_select(SelId, Ms, ListBox);
Else -> Else
end;
false ->
ok
end
end,
Del = fun(_,_) ->
SelId = wxListBox:getSelection(ListBox),
case SelId >= 0 of
true ->
wxListBox:delete(ListBox, SelId);
false ->
ok
end
end,
Sel = fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
case Id >= 0 of
true ->
wxWindow:enable(OkButt),
wxWindow:enable(EditMsBtn),
wxWindow:enable(DelMsBtn),
#match_spec{func=Str} = wxListBox:getClientData(ListBox,Id),
wxStyledTextCtrl:setText(TextCtrl, Str);
false ->
try
wxWindow:disable(OkButt),
wxWindow:disable(EditMsBtn),
wxWindow:disable(DelMsBtn)
catch _:_ -> ok
end
end
end,
wxButton:connect(AddMsBtn, command_button_clicked, [{callback,Add}]),
wxButton:connect(EditMsBtn, command_button_clicked, [{callback,Edit}]),
wxButton:connect(DelMsBtn, command_button_clicked, [{callback,Del}]),
wxListBox:connect(ListBox, command_listbox_selected, [{callback, Sel}]),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
SelId = wxListBox:getSelection(ListBox),
Count = wxListBox:getCount(ListBox),
MSs = [wxListBox:getClientData(ListBox, Id) ||
Id <- lists:seq(0, Count-1)],
Pid ! {update_ms, MSs},
MS = lists:nth(SelId+1, MSs),
wxDialog:destroy(Dialog),
MS;
?wxID_CANCEL ->
wxDialog:destroy(Dialog),
throw(cancel)
end.
edit_ms(TextCtrl, Label0, Parent) ->
Str = ensure_last_is_dot(wxStyledTextCtrl:getText(TextCtrl)),
try
MatchSpec = ms_from_string(Str),
Label = case Label0 == new of
true -> get_label(Parent);
_ -> Label0
end,
#match_spec{name=Label, term=MatchSpec,
str=io_lib:format("~w",[MatchSpec]),
func=Str}
catch
throw:cancel ->
ok;
throw:Error ->
observer_wx:create_txt_dialog(Parent, Error, "Error", ?wxICON_ERROR),
ok
end.
get_label(Frame) ->
Dialog = wxTextEntryDialog:new(Frame, "Enter alias: "),
case wxDialog:showModal(Dialog) of
?wxID_OK ->
wxTextEntryDialog:getValue(Dialog);
?wxID_CANCEL ->
throw(cancel)
end.
ms_from_string(Str) ->
try
Tokens = case erl_scan:string(Str) of
{ok, Ts, _} -> Ts;
{error, {SLine, SMod, SError}, _} ->
throw(io_lib:format("~w: ~s", [SLine,SMod:format_error(SError)]))
end,
Exprs = case erl_parse:parse_exprs(Tokens) of
{ok, T} -> T;
{error, {PLine, PMod, PError}} ->
throw(io_lib:format("~w: ~s", [PLine,PMod:format_error(PError)]))
end,
Term = case Exprs of
[{'fun', _, {clauses, Clauses}}|_] ->
case ms_transform:transform_from_shell(dbg,Clauses,orddict:new()) of
{error, [{_,[{MSLine,Mod,MSInfo}]}],_} ->
throw(io_lib:format("~w: ~p", [MSLine,Mod:format_error(MSInfo)]));
{error, _} ->
throw("Could not convert fun() to match spec");
Ms ->
Ms
end;
[Expr|_] ->
erl_parse:normalise(Expr)
end,
case erlang:match_spec_test([], Term, trace) of
{ok, _, _, _} -> Term;
{error, List} -> throw([[Error, $\n] || {_, Error} <- List])
end
catch error:_Reason ->
%% io:format("Bad term: ~s~n ~p in ~p~n", [Str, _Reason, erlang:get_stacktrace()]),
throw("Invalid term")
end.
add_and_select(Id, MS0, ListBox) ->
[{Str,User}] = ms_names([MS0]),
Sel = case Id >= 0 of
true ->
wxListBox:setString(ListBox, Id, Str),
wxListBox:setClientData(ListBox, Id, User),
Id;
false ->
wxListBox:append(ListBox, Str, User)
end,
wxListBox:setSelection(ListBox, Sel).
filter_listbox_data(Input, Data, ListBox) ->
filter_listbox_data(Input, Data, ListBox, true).
filter_listbox_data(Input, Data, ListBox, AddClientData) ->
FilteredData = [X || X = {Str, _} <- Data, re:run(Str, Input) =/= nomatch],
wxListBox:clear(ListBox),
wxListBox:appendStrings(ListBox, [Str || {Str,_} <- FilteredData]),
AddClientData andalso
wx:foldl(fun({_, Term}, N) ->
wxListBox:setClientData(ListBox, N, Term),
N+1
end, 0, FilteredData),
FilteredData.
get_modules(Node) ->
lists:sort([Module || {Module, _} <- observer_wx:try_rpc(Node, code, all_loaded, [])]).
optionpage_top_right(Panel, TopRightSz, Options, Text) ->
Sizer = wxBoxSizer:new(?wxVERTICAL),
ChkBox = wxCheckBox:new(Panel, ?wxID_ANY, "Inherit on " ++ Text, []),
RadioSz = wxBoxSizer:new(?wxVERTICAL),
Radio1 = wxRadioButton:new(Panel, ?wxID_ANY, "All " ++ Text, [{style, ?wxRB_GROUP}]),
Radio2 = wxRadioButton:new(Panel, ?wxID_ANY, "First " ++ Text ++ " only", []),
wxSizer:add(Sizer, ChkBox, []),
wxSizer:add(RadioSz, Radio1, []),
wxSizer:add(RadioSz, Radio2, []),
wxSizer:add(Sizer, RadioSz, [{flag, ?wxLEFT},{border, 20}]),
wxSizer:add(TopRightSz, Sizer, Options),
{ChkBox, Radio1, Radio2}.
create_styled_txtctrl(Parent) ->
FixedFont = observer_wx:get_attrib({font, modern}),
Ed = wxStyledTextCtrl:new(Parent),
wxStyledTextCtrl:styleClearAll(Ed),
wxStyledTextCtrl:styleSetFont(Ed, ?wxSTC_STYLE_DEFAULT, FixedFont),
wxStyledTextCtrl:setLexer(Ed, ?wxSTC_LEX_ERLANG),
wxStyledTextCtrl:setMarginType(Ed, 1, ?wxSTC_MARGIN_NUMBER),
wxStyledTextCtrl:setSelectionMode(Ed, ?wxSTC_SEL_LINES),
wxStyledTextCtrl:setUseHorizontalScrollBar(Ed, false),
Styles = [{?wxSTC_ERLANG_DEFAULT, {0,0,0}},
{?wxSTC_ERLANG_COMMENT, {160,53,35}},
{?wxSTC_ERLANG_VARIABLE, {150,100,40}},
{?wxSTC_ERLANG_NUMBER, {5,5,100}},
{?wxSTC_ERLANG_KEYWORD, {130,40,172}},
{?wxSTC_ERLANG_STRING, {170,45,132}},
{?wxSTC_ERLANG_OPERATOR, {30,0,0}},
{?wxSTC_ERLANG_ATOM, {0,0,0}},
{?wxSTC_ERLANG_FUNCTION_NAME, {64,102,244}},
{?wxSTC_ERLANG_CHARACTER,{236,155,172}},
{?wxSTC_ERLANG_MACRO, {40,144,170}},
{?wxSTC_ERLANG_RECORD, {40,100,20}},
{?wxSTC_ERLANG_SEPARATOR,{0,0,0}},
{?wxSTC_ERLANG_NODE_NAME,{0,0,0}}],
SetStyle = fun({Style, Color}) ->
wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont),
wxStyledTextCtrl:styleSetForeground(Ed, Style, Color)
end,
[SetStyle(Style) || Style <- Styles],
wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()),
Ed.
keyWords() ->
L = ["after","begin","case","try","cond","catch","andalso","orelse",
"end","fun","if","let","of","query","receive","when","bnot","not",
"div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
lists:flatten([K ++ " " || K <- L] ++ [0]).
enable(CheckBox, Radio) ->
case wxCheckBox:isChecked(CheckBox) of
false ->
[wxWindow:disable(R) || R <- Radio];
true ->
[wxWindow:enable(R) || R <- Radio]
end.
check_box(ChkBox, Bool) ->
case Bool of
true ->
wxCheckBox:set3StateValue(ChkBox, ?wxCHK_CHECKED);
false ->
ignore
end.
parse_function_names(Choices) ->
StrList = [{atom_to_list(Name) ++ "/" ++ integer_to_list(Arity), Term}
|| Term = {Name, Arity} <- Choices],
parse_function_names(StrList, []).
parse_function_names([], Acc) ->
lists:reverse(Acc);
parse_function_names([{H, Term}|T], Acc) ->
IsFun = re:run(H, ".*-fun-\\d*?-"),
IsLc = re:run(H, ".*-lc\\$\\^\\d*?/\\d*?-\\d*?-"),
IsLbc = re:run(H, ".*-lbc\\$\\^\\d*?/\\d*?-\\d*?-"),
Parsed =
if IsFun =/= nomatch -> "Fun: " ++ H;
IsLc =/= nomatch -> "List comprehension: " ++ H;
IsLbc =/= nomatch -> "Bit comprehension: " ++ H;
true ->
H
end,
parse_function_names(T, [{Parsed, Term} | Acc]).
ms_names(MatchSpecList) ->
MsOrAlias = fun(#match_spec{name = A, str = M}) ->
case A of
"" -> M;
_ -> A ++ " " ++ M
end
end,
[{MsOrAlias(X), X} || X <- MatchSpecList].
%% find_and_format_ms(Selection, [ #match_spec{str_ms = Spec, alias = Alias, fun2ms = Fun} | T ]) ->
%% case ((Selection =:= Spec) or (Selection =:= Alias)) or (Selection =:= Fun) of
%% true ->
%% if Selection =:= Alias ->
%% Spec;
%% true ->
%% Selection
%% end;
%% false ->
%% find_and_format_ms(Selection, T)
%% end.
%% find_ms(_, []) ->
%% {nomatch, #match_spec{}};
%% find_ms(Str, [ #match_spec{str_ms = Spec, alias = Alias, fun2ms = Fun} = MS | T ]) ->
%% case ((Str =:= Spec) or (Str =:= Alias)) or (Str =:= Fun) of
%% true ->
%% {match, MS};
%% false ->
%% find_ms(Str, T)
%% end.
%% apply_matchspec(MatchSpec, TracedDict, root) ->
%% UpdateMS = fun(_Key, RecordList) ->
%% [X#traced_func{match_spec = MatchSpec} || X <- RecordList]
%% end,
%% {ok, dict:map(UpdateMS, TracedDict)};
%% apply_matchspec(MatchSpec, TracedDict, {module, Module}) ->
%% RecordList = dict:fetch(Module, TracedDict),
%% RecordList2 = [X#traced_func{match_spec = MatchSpec} || X <- RecordList],
%% {ok, dict:store(Module, RecordList2, TracedDict)};
%% apply_matchspec(MatchSpec, TracedDict, {function, Module, TracedFuncRec}) ->
%% RecordList = dict:fetch(Module, TracedDict),
%% NewFunc = TracedFuncRec#traced_func{match_spec = MatchSpec},
%% RecordList2 = [NewFunc | [X || X <- RecordList, X =/= TracedFuncRec]],
%% {NewFunc, dict:store(Module, RecordList2, TracedDict)}.
%% create_matchspec_page(Parent, MatchSpecs, UserData) ->
%% Panel = wxPanel:new(Parent),
%% MainSz = wxBoxSizer:new(?wxVERTICAL),
%% TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]),
%% BtnSz = wxBoxSizer:new(?wxHORIZONTAL),
%% SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]),
%% TxtCtrl = create_styled_txtctrl(Panel),
%% wxSizer:add(TxtSz, TxtCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]),
%% AddMsBtn = wxButton:new(Panel, ?MATCHPAGE_ADDMS, [{label, "Add"}]),
%% AddMsAliasBtn = wxButton:new(Panel, ?MATCHPAGE_ADDMS_ALIAS, [{label, "Add with alias"}]),
%% Fun2MSBtn = wxButton:new(Panel, ?MATCHPAGE_ADDFUN, [{label, "Add fun"}]),
%% wxSizer:add(BtnSz, AddMsBtn),
%% wxSizer:add(BtnSz, AddMsAliasBtn),
%% wxSizer:add(BtnSz, Fun2MSBtn),
%% Choices = show_ms_in_savedlistbox(MatchSpecs),
%% SavedMSListBox = wxListBox:new(Panel, ?MATCHPAGE_LISTBOX, [{choices, Choices}]),
%% wxSizer:add(SavedSz, SavedMSListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
%% wxButton:connect(AddMsBtn, command_button_clicked, [{userData, UserData}]),
%% wxButton:connect(AddMsAliasBtn, command_button_clicked, [{userData, UserData}] ),
%% wxButton:connect(Fun2MSBtn, command_button_clicked, [{userData, UserData}] ),
%% wxListBox:connect(SavedMSListBox, command_listbox_selected, [{userData, UserData}] ),
%% wxSizer:add(MainSz, TxtSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
%% wxSizer:add(MainSz, BtnSz),
%% wxSizer:add(MainSz, SavedSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
%% wxWindow:setSizer(Panel, MainSz),
%% {Panel, MainSz, TxtCtrl, SavedMSListBox}.
%% update_tree(Tree, Dict) ->
%% RootId = wxTreeCtrl:getRootItem(Tree),
%% wxTreeCtrl:deleteChildren(Tree, RootId),
%% FillTree = fun(KeyAtom, RecordList, acc_in) ->
%% ParsedList = parse_record_function_names(RecordList),
%% Module = wxTreeCtrl:appendItem(Tree, RootId, atom_to_list(KeyAtom)),
%% lists:foldl(fun(TracedFuncRecord, N) ->
%% FNameStr = lists:nth(N, ParsedList),
%% wxTreeCtrl:appendItem(Tree, Module, FNameStr,
%% [{data, TracedFuncRecord}]),
%% N+1
%% end,
%% 1, RecordList),
%% wxTreeCtrl:sortChildren(Tree, Module),
%% acc_in
%% end,
%% dict:fold(FillTree, acc_in, Dict),
%% wxTreeCtrl:sortChildren(Tree, RootId),
%% wxTreeCtrl:expand(Tree, RootId).
%% create_module_popup(Parent, ModuleName, TracedDict) ->
%% Module = list_to_atom(ModuleName),
%% Value = dict:find(Module, TracedDict),
%% TracedModRecs =
%% case Value of
%% {ok, V} ->
%% V;
%% error ->
%% []
%% end,
%% Functions = Module:module_info(functions),
%% Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions, not(erl_internal:guard_bif(Name, Arity))]),
%% ParsedChoices = parse_function_names(Choices),
%% Dialog = wxDialog:new(Parent, ?MODULEPOPUP_DIALOG, ModuleName,
%% [{style, ?wxDEFAULT_FRAME_STYLE}]),
%% Panel = wxPanel:new(Dialog),
%% MainSz = wxBoxSizer:new(?wxVERTICAL),
%% SelBtnSz = wxBoxSizer:new(?wxHORIZONTAL),
%% TxtCtrl = wxTextCtrl:new(Panel, ?MODULEPOPUP_TXTCTRL),
%% SelBtn = wxButton:new(Panel, ?MODULEPOPUP_SELECT, [{label, "Select"}]),
%% DeSelBtn = wxButton:new(Panel, ?MODULEPOPUP_SELECT, [{label, "Deselect"}]),
%% SelAllBtn = wxButton:new(Panel, ?MODULEPOPUP_SELALL, [{label, "Select all"}]),
%% DeSelAllBtn = wxButton:new(Panel, ?MODULEPOPUP_SELALL, [{label, "Deselect all"}]),
%% CheckListBox = wxCheckListBox:new(Panel, ?MODULEPOPUP_CHECKLISTBOX, [{choices, ParsedChoices}, {style, ?wxLB_EXTENDED}]),
%% Indices = find_index(TracedModRecs, Choices),
%% lists:foreach(fun(X) -> wxCheckListBox:check(CheckListBox, X) end, Indices),
%% Selections = [wxControlWithItems:getString(CheckListBox, I) || I <- Indices],
%% OKBtn = wxButton:new(Panel, ?wxID_OK, []),
%% CancelBtn = wxButton:new(Panel, ?wxID_CANCEL, []),
%% DialogBtnSz = wxStdDialogButtonSizer:new(),
%% wxStdDialogButtonSizer:addButton(DialogBtnSz, OKBtn),
%% wxStdDialogButtonSizer:addButton(DialogBtnSz, CancelBtn),
%% wxStdDialogButtonSizer:realize(DialogBtnSz),
%% wxSizer:add(SelBtnSz, SelBtn),
%% wxSizer:add(SelBtnSz, DeSelBtn),
%% wxSizer:add(SelBtnSz, SelAllBtn),
%% wxSizer:add(SelBtnSz, DeSelAllBtn),
%% wxSizer:add(MainSz, TxtCtrl, [{flag, ?wxEXPAND}]),
%% wxSizer:add(MainSz, CheckListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
%% wxSizer:add(MainSz, SelBtnSz, [{flag, ?wxEXPAND}]),
%% wxSizer:add(MainSz, DialogBtnSz),
%% wxWindow:setSizer(Panel, MainSz),
%% wxButton:connect(SelBtn, command_button_clicked, [{userData, true}]),
%% wxButton:connect(DeSelBtn, command_button_clicked, [{userData, false}]),
%% wxButton:connect(SelAllBtn, command_button_clicked, [{userData, true}]),
%% wxButton:connect(DeSelAllBtn, command_button_clicked, [{userData, false}]),
%% wxButton:connect(OKBtn, command_button_clicked, [{userData, {module_popup, Module, ParsedChoices, Choices}}]),
%% wxButton:connect(CancelBtn, command_button_clicked, [{userData, module_popup}]),
%% wxTextCtrl:connect(TxtCtrl, command_text_updated, [{userData, ParsedChoices}]),
%% wxCheckListBox:connect(CheckListBox, command_checklistbox_toggled),
%% wxDialog:connect(Dialog, close_window),
%% wxDialog:show(Dialog),
%% {Dialog, CheckListBox, Selections}.
%% get_selections(Selections, FunctionList) ->
%% get_selections(Selections, FunctionList, []).
%% get_selections([], _, Acc) ->
%% Acc;
%% get_selections([Int|T], FuncList, Acc) ->
%% get_selections(T, FuncList, [lists:nth(Int, FuncList) | Acc]).
%% find_index(Selections, FunctionList) ->
%% find_index(Selections, FunctionList, 1, []).
%% find_index(Selections, FunctionList, N, Acc) when N > length(FunctionList); Selections =:= [] ->
%% Acc;
%% find_index([#traced_func{func_name = Name, arity = Arity} |STail] = Selections,
%% FunctionList, N, Acc) ->
%% {Fname, A} = lists:nth(N, FunctionList),
%% case (Fname =:= Name) and (A =:= Arity) of
%% true ->
%% find_index(STail, FunctionList, 1, [N-1|Acc]);
%% false ->
%% find_index(Selections, FunctionList, N+1, Acc)
%% end;
%% find_index([Sel|STail] = Selections, FunctionList, N, Acc) when is_list(Sel) ->
%% case lists:nth(N, FunctionList) =:= Sel of
%% true ->
%% find_index(STail, FunctionList, 1, [N-1|Acc]);
%% false ->
%% find_index(Selections, FunctionList, N+1, Acc)
%% end.
%% atomlist_to_stringlist(Modules) ->
%% [atom_to_list(X) || X <- Modules].
ensure_last_is_dot([]) ->
".";
ensure_last_is_dot(String) ->
case lists:last(String) =:= $. of
true ->
String;
false ->
String ++ "."
end.
%% dbg_from_string(Str0) ->
%% Str = unicode:characters_to_list(Str0),
%% case erl_scan:string(Str) of
%% {ok, Tokens,_} ->
%% case erl_parse:parse_exprs(Tokens) of
%% {ok,[{'fun',_,{clauses, Cl}}]} ->
%% case ms_transform:
%% transform_from_shell(dbg,Cl,orddict:new()) of
%% {error, [{_,[{Line,ms_transform,Info}]}],_} ->
%% {error,{Line,ms_transform,Info}};
%% {error, _} = ET1 ->
%% ET1;
%% Else ->
%% {ok, Else, "[" ++ lists:flatten(io_lib:format("~p", Else)) ++ "]"}
%% end;
%% {ok,_} ->
%% {error, {1,ms_transform,1}};
%% {error,Reason} ->
%% {error,Reason}
%% end;
%% {error,Reason2,_} ->
%% {error,Reason2}
%% end.
%% get_correct_matchspec_components(From, State) ->
%% case From of
%% matchpage ->
%% {State#traceopts_state.matchpage_styled_txtctrl,
%% State#traceopts_state.frame};
%% matchpopup ->
%% {State#traceopts_state.matchspec_popup_styled_txtctrl,
%% State#traceopts_state.matchspec_popup_dialog}
%% end.
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %Trace option window
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% All pages
%% handle_event(#wx{id = ?wxID_OK,
%% event = #wxCommand{type = command_button_clicked},
%% userData = trace_options},
%% #traceopts_state{boxes = Boxes,
%% trace_options = TraceOpts,
%% match_specs = MatchSpecs,
%% traced_funcs = TracedFuncs,
%% parent = Parent} = State) ->
%% UpdTraceOpts = wx:batch(fun() ->
%% read_trace_boxes(Boxes, TraceOpts)
%% end),
%% Parent ! {updated_traceopts,
%% UpdTraceOpts,
%% MatchSpecs,
%% TracedFuncs},
%% {stop, shutdown, State};
%% handle_event(#wx{id = ?wxID_CANCEL,
%% event = #wxCommand{type = command_button_clicked},
%% userData = trace_options},
%% #traceopts_state{parent = Parent} = State) ->
%% Parent ! traceopts_closed,
%% {stop, shutdown, State};
%% handle_event(#wx{id = ?TRACEOPTS_FRAME,
%% event = #wxClose{type = close_window}},
%% #traceopts_state{parent = Parent} = State) ->
%% Parent ! traceopts_closed,
%% {stop, shutdown, State};
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Tracing
%% handle_event(#wx{event = #wxCommand{type = command_checkbox_clicked}, userData = Boxgroup},
%% State) ->
%% enable(Boxgroup),
%% {noreply, State};
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Functions
%% handle_event(#wx{id = ?FUNCTIONPAGE_LISTBOX,
%% event = #wxCommand{type = command_listbox_doubleclicked,
%% cmdString = ChosenModule}},
%% #traceopts_state{frame = Frame,
%% traced_funcs = TracedDict,
%% popup_open = false} = State) ->
%% {Dialog, CheckListBox, CheckedFuncs} = create_module_popup(Frame, ChosenModule, TracedDict),
%% {noreply, State#traceopts_state{popup_open = true,
%% module_popup_dialog = Dialog,
%% module_popup_checklistbox = CheckListBox,
%% checked_funcs = CheckedFuncs}};
%% handle_event(#wx{id = ?FUNCTIONPAGE_TXTCTRL,
%% event = #wxCommand{type = command_text_updated,
%% cmdString = Input},
%% userData = Data},
%% #traceopts_state{functionpage_listbox = ListBox} = State) ->
%% filter_listbox_data(Input, Data, ListBox),
%% {noreply, State};
%% handle_event(#wx{event = #wxTree{type = command_tree_item_activated,
%% item = Item}},
%% #traceopts_state{frame = Frame,
%% match_specs = MatchSpecs,
%% popup_open = false} = State) ->
%% Dialog = wxDialog:new(Frame, ?MATCH_POPUP_DIALOG, "Match specification",
%% [{style, ?wxDEFAULT_FRAME_STYLE}]),
%% {MatchPanel, MatchSz, StyledTxtCtrl, ListBox} = create_matchspec_page(Dialog, MatchSpecs, matchpopup),
%% ApplyBtn = wxButton:new(MatchPanel, ?wxID_APPLY),
%% CancelBtn = wxButton:new(MatchPanel, ?wxID_CANCEL, []),
%% wxButton:connect(ApplyBtn, command_button_clicked, [{userData, Item}]),
%% wxButton:connect(CancelBtn, command_button_clicked, [{userData, matchspec_popup}]),
%% DialogBtnSz = wxStdDialogButtonSizer:new(),
%% wxStdDialogButtonSizer:addButton(DialogBtnSz, ApplyBtn),
%% wxStdDialogButtonSizer:addButton(DialogBtnSz, CancelBtn),
%% wxStdDialogButtonSizer:realize(DialogBtnSz),
%% wxSizer:add(MatchSz, DialogBtnSz),
%% wxDialog:connect(Dialog, close_window),
%% wxDialog:show(Dialog),
%% {noreply, State#traceopts_state{matchspec_popup_dialog = Dialog,
%% matchspec_popup_listbox = ListBox,
%% matchspec_popup_styled_txtctrl = StyledTxtCtrl,
%% popup_open = true}};
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Page - Match specs
%% handle_event(#wx{event = #wxCommand{type = command_listbox_selected,
%% cmdString = Txt}},
%% State) when Txt =:= [] ->
%% {noreply, State};
%% handle_event(#wx{id = ?MATCHPAGE_LISTBOX,
%% event = #wxCommand{type = command_listbox_selected,
%% cmdString = SavedTxt},
%% userData = From},
%% #traceopts_state{match_specs = MatchSpecs} = State) ->
%% {StyledTxtCtrl, _} = get_correct_matchspec_components(From, State),
%% MsOrFun = find_and_format_ms(SavedTxt, MatchSpecs),
%% wxStyledTextCtrl:setText(StyledTxtCtrl, MsOrFun),
%% {noreply, State};
%% handle_event(#wx{id = ?MATCHPAGE_ADDFUN,
%% event = #wxCommand{type = command_button_clicked},
%% userData = From},
%% #traceopts_state{match_specs = MatchSpecs,
%% matchpage_listbox = PageListBox,
%% matchspec_popup_listbox = PopupListBox} = State) ->
%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
%% StrFun = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
%% MatchSpecs2 = case dbg_from_string(StrFun) of
%% {ok, TermMS, StrMS} ->
%% FunMS = #match_spec{str_ms = StrMS, term_ms = TermMS, fun2ms = StrFun},
%% case lists:member(FunMS, MatchSpecs) of
%% true ->
%% observer_wx:create_txt_dialog(Frame, StrFun ++ "\nalready exists",
%% "Error", ?wxICON_ERROR),
%% MatchSpecs;
%% false ->
%% wxStyledTextCtrl:setText(StyledTxtCtrl, StrMS),
%% update_matchspec_listbox(StrFun, {PopupListBox, PageListBox}, From),
%% lists:reverse([FunMS | MatchSpecs])
%% end;
%% {error, {_, Module, What}} ->
%% FailMsg = Module:format_error(What),
%% observer_wx:create_txt_dialog(Frame, FailMsg, "Error", ?wxICON_ERROR),
%% MatchSpecs
%% end,
%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
%% handle_event(#wx{id = ?MATCHPAGE_ADDMS,
%% event = #wxCommand{type = command_button_clicked},
%% userData = From},
%% #traceopts_state{match_specs = MatchSpecs,
%% matchpage_listbox = PageListBox,
%% matchspec_popup_listbox = PopupListBox} = State) ->
%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
%% StrMS = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
%% MatchSpecs2 = case check_correct_MS(StrMS) of
%% {true, TermMS} ->
%% MS = #match_spec{str_ms = StrMS, term_ms = TermMS},
%% case lists:member(MS, MatchSpecs) of
%% true ->
%% observer_wx:create_txt_dialog(Frame, StrMS ++ "\nalready exists",
%% "Error", ?wxICON_ERROR),
%% MatchSpecs;
%% false ->
%% update_matchspec_listbox(StrMS, {PopupListBox, PageListBox}, From),
%% lists:reverse([MS | MatchSpecs])
%% end;
%% {false, Reason} ->
%% observer_wx:create_txt_dialog(Frame, Reason, "Error", ?wxICON_ERROR),
%% MatchSpecs
%% end,
%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
%% handle_event(#wx{id = ?MATCHPAGE_ADDMS_ALIAS,
%% event = #wxCommand{type = command_button_clicked},
%% userData = From},
%% #traceopts_state{match_specs = MatchSpecs,
%% matchpage_listbox = PageListBox,
%% matchspec_popup_listbox = PopupListBox} = State) ->
%% {StyledTxtCtrl, Frame} = get_correct_matchspec_components(From, State),
%% StrMS = ensure_last_is_dot(wxStyledTextCtrl:getText(StyledTxtCtrl)),
%% MatchSpecs2 = case check_correct_MS(StrMS) of
%% {true, TermMS} ->
%% Dialog = wxTextEntryDialog:new(Frame, "Enter ms alias: "),
%% Alias = case wxDialog:showModal(Dialog) of
%% ?wxID_OK ->
%% wxTextEntryDialog:getValue(Dialog);
%% ?wxID_CANCEL ->
%% ""
%% end,
%% wxDialog:destroy(Dialog),
%% case Alias of
%% "" ->
%% observer_wx:create_txt_dialog(Frame, "Bad alias", "Syntax error",
%% ?wxICON_ERROR),
%% MatchSpecs;
%% _ ->
%% MS = #match_spec{alias = Alias, str_ms = StrMS,
%% term_ms = TermMS},
%% {OccupiedAlias, _} = find_ms(Alias, MatchSpecs),
%% if
%% OccupiedAlias =:= match ->
%% observer_wx:create_txt_dialog(Frame, "Alias " ++ Alias ++ " already exists",
%% "Error", ?wxICON_ERROR),
%% MatchSpecs;
%% true ->
%% update_matchspec_listbox(Alias, {PopupListBox, PageListBox}, From),
%% lists:reverse([MS | MatchSpecs])
%% end
%% end;
%% {false, Reason} ->
%% observer_wx:create_txt_dialog(Frame, Reason, "Error", ?wxICON_ERROR),
%% MatchSpecs
%% end,
%% {noreply, State#traceopts_state{match_specs = MatchSpecs2}};
%% handle_event(#wx{id = ?wxID_APPLY,
%% event = #wxCommand{type = command_button_clicked},
%% userData = Item},
%% #traceopts_state{matchspec_popup_dialog = Dialog,
%% matchspec_popup_listbox = ListBox,
%% tree = Tree,
%% match_specs = MatchSpecs,
%% traced_funcs = TracedDict} = State) ->
%% IntSelection = wxListBox:getSelection(ListBox),
%% StrSelection =
%% case IntSelection >= 0 of
%% true ->
%% wxControlWithItems:getString(ListBox, IntSelection);
%% false ->
%% []
%% end,
%% {_, MS} = find_ms(StrSelection, MatchSpecs),
%% RootId = wxTreeCtrl:getRootItem(Tree),
%% ItemParent = wxTreeCtrl:getItemParent(Tree, Item),
%% TracedDict2 =
%% if (Item =:= RootId) ->
%% {ok, NewDict} = apply_matchspec(MS, TracedDict, root),
%% NewDict;
%% (ItemParent =:= RootId) ->
%% Module = list_to_atom(wxTreeCtrl:getItemText(Tree, Item)),
%% {ok, NewDict} = apply_matchspec(MS, TracedDict, {module, Module}),
%% NewDict;
%% true ->
%% TracedFuncRec = wxTreeCtrl:getItemData(Tree, Item),
%% Module = list_to_atom(wxTreeCtrl:getItemText(Tree, ItemParent)),
%% {NewTracedFuncRecord, NewDict} =
%% apply_matchspec(MS,
%% TracedDict,
%% {function,
%% Module,
%% TracedFuncRec}),
%% wxTreeCtrl:setItemData(Tree, Item, NewTracedFuncRecord),
%% NewDict
%% end,
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{traced_funcs = TracedDict2,
%% popup_open = false}};
%% handle_event(#wx{id = ?wxID_CANCEL,
%% event = #wxCommand{type = command_button_clicked},
%% userData = matchspec_popup},
%% #traceopts_state{matchspec_popup_dialog = Dialog} = State) ->
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{popup_open = false}};
%% handle_event(#wx{id = ?MATCH_POPUP_DIALOG,
%% event = #wxClose{type = close_window}},
%% #traceopts_state{matchspec_popup_dialog = Dialog} = State) ->
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{popup_open = false}};
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %Module Popup
%% handle_event(#wx{id = ?wxID_OK,
%% event = #wxCommand{type = command_button_clicked},
%% userData = {module_popup, Module,
%% ParsedChoices, Choices}},
%% #traceopts_state{
%% module_popup_dialog = Dialog,
%% traced_funcs = TracedDict,
%% tree = Tree,
%% checked_funcs = CheckedFuncs} = State) ->
%% Indices = [I+1 || I <- find_index(CheckedFuncs, ParsedChoices)],
%% Selections = get_selections(Indices, Choices),
%% TracedDict2 = case Selections of
%% [] ->
%% dict:erase(Module, TracedDict);
%% _ ->
%% Traced = [#traced_func{arity = Arity,
%% func_name = Function}
%% || {Function, Arity} <- Selections],
%% dict:store(Module, Traced, TracedDict)
%% end,
%% update_tree(Tree, TracedDict2),
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{traced_funcs = TracedDict2,
%% checked_funcs = [],
%% popup_open = false}};
%% handle_event(#wx{id = ?wxID_CANCEL,
%% event = #wxCommand{type = command_button_clicked},
%% userData = module_popup},
%% #traceopts_state{module_popup_dialog = Dialog} = State) ->
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{popup_open = false,
%% checked_funcs = []}};
%% handle_event(#wx{id = ?MODULEPOPUP_SELECT,
%% event = #wxCommand{type = command_button_clicked},
%% userData = Bool},
%% #traceopts_state{module_popup_checklistbox = CheckListBox,
%% checked_funcs = CheckedFuncs} = State) ->
%% {_, Selections} = wxListBox:getSelections(CheckListBox),
%% lists:foreach(fun(Index) -> wxCheckListBox:check(CheckListBox, Index, [{check, Bool}]) end, Selections),
%% StrSelections = [wxControlWithItems:getString(CheckListBox, N) || N <- Selections],
%% CheckedFuncs2 = case Bool of
%% true ->
%% [X || X <- StrSelections,
%% not(lists:member(X, CheckedFuncs))] ++ CheckedFuncs;
%% false ->
%% CheckedFuncs -- StrSelections
%% end,
%% {noreply, State#traceopts_state{checked_funcs = CheckedFuncs2}};
%% handle_event(#wx{id = ?MODULEPOPUP_SELALL,
%% event = #wxCommand{type = command_button_clicked},
%% userData = Bool},
%% #traceopts_state{module_popup_checklistbox = CheckListBox} = State) ->
%% lists:foreach(fun(Index) ->
%% wxCheckListBox:check(CheckListBox, Index, [{check, Bool}])
%% end,
%% lists:seq(0, wxControlWithItems:getCount(CheckListBox))),
%% CheckedFuncs = case Bool of
%% true ->
%% [wxControlWithItems:getString(CheckListBox, N)
%% || N <- lists:seq(0, wxControlWithItems:getCount(CheckListBox))];
%% false ->
%% []
%% end,
%% {noreply, State#traceopts_state{checked_funcs = CheckedFuncs}};
%% handle_event(#wx{id = ?MODULEPOPUP_CHECKLISTBOX,
%% obj = CheckListBox,
%% event = #wxCommand{type = command_checklistbox_toggled,
%% commandInt = Index}},
%% #traceopts_state{checked_funcs = CheckedFuncs} = State) ->
%% UpdCheckedFuncs = case
%% wxCheckListBox:isChecked(CheckListBox, Index) of
%% true ->
%% [wxControlWithItems:getString(CheckListBox, Index) | CheckedFuncs];
%% false ->
%% lists:delete(wxControlWithItems:getString(CheckListBox, Index), CheckedFuncs)
%% end,
%% {noreply, State#traceopts_state{checked_funcs = UpdCheckedFuncs}};
%% handle_event(#wx{id = ?MODULEPOPUP_TXTCTRL,
%% event = #wxCommand{type = command_text_updated,
%% cmdString = Input},
%% userData = Data},
%% #traceopts_state{module_popup_checklistbox = CListBox,
%% checked_funcs = CheckedFuncs} = State) ->
%% FilteredData = filter_listbox_data(Input, Data, CListBox),
%% lists:foreach(fun(Index) ->
%% wxCheckListBox:check(CListBox, Index, [{check, true}])
%% end,
%% [wxControlWithItems:findString(CListBox, X) || X <- CheckedFuncs, lists:member(X, FilteredData)]),
%% {noreply, State};
%% handle_event(#wx{id = ?MODULEPOPUP_DIALOG,
%% event = #wxClose{type = close_window}},
%% #traceopts_state{module_popup_dialog = Dialog} = State) ->
%% wxDialog:destroy(Dialog),
%% {noreply, State#traceopts_state{popup_open = false,
%% checked_funcs = []}};
%% handle_event(#wx{event = What}, State) ->
%% io:format("~p~p: Unhandled event: ~p ~n", [?MODULE, self(), What]),
%% {noreply, State}.
%% terminate(Reason, #traceopts_state{frame = Frame}) ->
%% io:format("~p terminating traceopts. Reason: ~p~n", [?MODULE, Reason]),
%% wxFrame:destroy(Frame),
%% ok.
%% code_change(_, _, State) ->
%% {stop, not_yet_implemented, State}.
%% handle_info(Any, State) ->
%% io:format("~p~p: received unexpected message: ~p\n", [?MODULE, self(), Any]),
%% {noreply, State}.
%% handle_call(Msg, _From, State) ->
%% io:format("~p~p: Got Call ~p~n",[?MODULE, ?LINE, Msg]),
%% {reply, ok, State}.
%% handle_cast(Msg, State) ->
%% io:format("~p ~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]),
%% {noreply, State}.