From b65b0c4bf4896021cbd327a4bc1acd426645a5f3 Mon Sep 17 00:00:00 2001 From: Dan Gudmundsson Date: Fri, 11 Nov 2011 15:00:11 +0100 Subject: [observer] Rework tracing part of the gui No tracing is implemented yet. --- lib/observer/src/observer_traceoptions_wx.erl | 1971 +++++++++++++------------ 1 file changed, 1044 insertions(+), 927 deletions(-) (limited to 'lib/observer/src/observer_traceoptions_wx.erl') diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl index 7244efdc50..7570610b97 100644 --- a/lib/observer/src/observer_traceoptions_wx.erl +++ b/lib/observer/src/observer_traceoptions_wx.erl @@ -21,210 +21,420 @@ -include_lib("wx/include/wx.hrl"). -include("observer_defs.hrl"). --export([start/6]). --export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3, - handle_event/2, handle_cast/2]). - --behaviour(wx_object). - --record(traceopts_state, { - parent, - frame, - tree, - boxes, - functionpage_listbox, - matchpage_styled_txtctrl, - matchpage_listbox, - popup_open = false, - module_popup_dialog, - module_popup_checklistbox, - matchspec_popup_dialog, - matchspec_popup_listbox, - matchspec_popup_styled_txtctrl, - match_specs, % [ #match_spec{} ] - checked_funcs = [], - traced_funcs, % Key =:= Module::atom, Value =:= [ #traced_func{} ] - trace_options}). - - --record(boxes, {send, 'receive', functions, events, - on_spawn, on_link, all_spawn, all_link}). - --define(TRACEOPTS_FRAME, 501). - --define(MATCHPAGE_ADDFUN, 502). --define(MATCHPAGE_ADDMS, 503). --define(MATCHPAGE_ADDMS_ALIAS, 504). --define(MATCHPAGE_LISTBOX, 505). - --define(MATCH_POPUP_DIALOG, 506). - --define(MODULEPOPUP_SELECT, 507). --define(MODULEPOPUP_SELALL, 508). --define(MODULEPOPUP_CHECKLISTBOX, 509). --define(MODULEPOPUP_TXTCTRL, 510). --define(MODULEPOPUP_DIALOG, 511). - --define(FUNCTIONPAGE_LISTBOX, 512). --define(FUNCTIONPAGE_TXTCTRL, 513). - - -start(ParentFrame, ParentPid, Node, TraceOpts, TracedFuncs, MatchSpecs) -> - wx_object:start(?MODULE, [ParentFrame, ParentPid, Node, TraceOpts, - TracedFuncs, MatchSpecs], []). - -init([ParentFrame, ParentPid, Node, TraceOpts, TracedFuncs, MatchSpecs]) -> +-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 - {Frame, Tree, Boxes, ModuleListBox, MatchTxtCtrl, MatchListBox} - = setup(ParentFrame, Node, TraceOpts, TracedFuncs, MatchSpecs), - - {Frame, - #traceopts_state{parent = ParentPid, - frame = Frame, - tree = Tree, - functionpage_listbox = ModuleListBox, - matchpage_styled_txtctrl = MatchTxtCtrl, - matchpage_listbox = MatchListBox, - boxes = Boxes, - match_specs = MatchSpecs, - traced_funcs = TracedFuncs, - trace_options = TraceOpts}} - - catch error:{badrpc, _} -> - observer_wx:return_to_localnode(ParentFrame, Node), - {stop, badrpc, #traceopts_state{}} + 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. -setup(ParentFrame, Node, TraceOpts, TracedFuncs, MatchSpecs) -> +function_selector(Parent, Node, Module) -> + Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions", + [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}, + {size, {400, 400}}]), -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Setup main window + 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), + %% Setup Event handling + wxTextCtrl:connect(TxtCtrl, command_text_updated, + [{callback, fun(#wx{event=#wxCommand{cmdString=Input}}, _) -> + filter_listbox_data(Input, ParsedChoices, ListBox) + end}]), + Self = self(), + wxCheckListBox:connect(ListBox, command_checklistbox_toggled, + [{callback, fun(#wx{event=#wxCommand{commandInt=N}}, _) -> + Self ! {ListBox, wxCheckListBox:isChecked(ListBox, N), + wxListBox:getClientData(ListBox, N)} + end}]), + Check = fun(Id, Bool) -> + wxCheckListBox:check(ListBox, Id, [{check, Bool}]), + Self ! {ListBox, Bool, wxListBox: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}}]), - Frame = wxFrame:new(ParentFrame, ?TRACEOPTS_FRAME, "Trace options", - [{style, ?wxRESIZE_BORDER bor ?wxCLOSE_BOX}, - {size, {400, 500}}]), - Panel = wxPanel:new(Frame, []), + Panel = wxPanel:new(Dialog), + PanelSz = wxBoxSizer:new(?wxVERTICAL), MainSz = wxBoxSizer:new(?wxVERTICAL), - Notebook = wxNotebook:new(Panel, ?wxID_ANY), - Modules = get_modules(Node), + TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]), + BtnSz = wxBoxSizer:new(?wxHORIZONTAL), + SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]), -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Setup tracing page - - OptPanel = wxPanel:new(Notebook), - OptMainSz = wxBoxSizer:new(?wxVERTICAL), - TopSz = wxBoxSizer:new(?wxHORIZONTAL), - TopLeftSz = wxStaticBoxSizer:new(?wxVERTICAL, OptPanel, - [{label, "Tracing options"}]), - TopRightSz = wxStaticBoxSizer:new(?wxVERTICAL, OptPanel, - [{label, "Inheritance options:"}]), - - SendBox = wxCheckBox:new(OptPanel, ?wxID_ANY, "Trace send", []), - check_box(SendBox, TraceOpts#trace_options.send), - RecBox = wxCheckBox:new(OptPanel, ?wxID_ANY, "Trace receive", []), - check_box(RecBox, TraceOpts#trace_options.treceive), - FuncBox = wxCheckBox:new(OptPanel, ?wxID_ANY, "Trace functions", []), - check_box(FuncBox, TraceOpts#trace_options.functions), - EventBox = wxCheckBox:new(OptPanel, ?wxID_ANY, "Trace events", []), - check_box(EventBox, TraceOpts#trace_options.events), + TextCtrl = create_styled_txtctrl(Panel), + wxSizer:add(TxtSz, TextCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]), - {SpawnBox, SpwnAllRadio, SpwnFirstRadio} = - optionpage_top_right(OptPanel, TopRightSz, [{flag, ?wxBOTTOM},{border, 5}], "spawn"), - {LinkBox, LinkAllRadio, LinkFirstRadio} = - optionpage_top_right(OptPanel, TopRightSz, [{flag, ?wxBOTTOM},{border, 5}], "link"), - SpawnBool = TraceOpts#trace_options.on_all_spawn or TraceOpts#trace_options.on_1st_spawn, - LinkBool = TraceOpts#trace_options.on_all_link or TraceOpts#trace_options.on_1st_link, - check_box(SpawnBox, SpawnBool), - check_box(LinkBox, LinkBool), - enable({SpawnBox, SpwnAllRadio, SpwnFirstRadio}), - enable({LinkBox, LinkAllRadio, LinkFirstRadio}), - wxRadioButton:setValue(SpwnAllRadio, TraceOpts#trace_options.on_all_spawn), - wxRadioButton:setValue(SpwnFirstRadio, TraceOpts#trace_options.on_1st_spawn), - wxRadioButton:setValue(LinkAllRadio, TraceOpts#trace_options.on_all_link), - wxRadioButton:setValue(LinkFirstRadio, TraceOpts#trace_options.on_1st_link), - - wxSizer:add(TopLeftSz, SendBox, []), - wxSizer:add(TopLeftSz, RecBox, []), - wxSizer:add(TopLeftSz, FuncBox, []), - wxSizer:add(TopLeftSz, EventBox, []), - wxSizer:add(TopLeftSz, 150, -1), - - wxSizer:add(TopSz, TopLeftSz, [{flag, ?wxEXPAND}]), - wxSizer:add(TopSz, TopRightSz,[{flag, ?wxEXPAND}]), - wxSizer:add(OptMainSz, TopSz, []), - wxWindow:setSizer(OptPanel, OptMainSz), - wxNotebook:addPage(Notebook, OptPanel, "Tracing"), - -%%%%%%%%%%%%%%%%%%%%%%%% Setup functions page - - FuncPanel = wxPanel:new(Notebook), - FuncMainSz = wxBoxSizer:new(?wxVERTICAL), - ModuleSz = wxStaticBoxSizer:new(?wxVERTICAL, FuncPanel, [{label, "Select module"}]), - TreeSz = wxStaticBoxSizer:new(?wxVERTICAL, FuncPanel, [{label, "Selected functions"}]), - - AllModules = atomlist_to_stringlist(Modules), - ModuleTxtCtrl = wxTextCtrl:new(FuncPanel, ?FUNCTIONPAGE_TXTCTRL), - ModuleListBox = wxListBox:new(FuncPanel, ?FUNCTIONPAGE_LISTBOX, [{choices, AllModules}, {style, ?wxLB_SINGLE}]), - TreeCtrl = wxTreeCtrl:new(FuncPanel), - wxTreeCtrl:addRoot(TreeCtrl, atom_to_list(Node)), - update_tree(TreeCtrl, TracedFuncs), - - wxTextCtrl:connect(ModuleTxtCtrl, command_text_updated, - [{userData, AllModules}]), - wxListBox:connect(ModuleListBox, command_listbox_doubleclicked), - wxTreeCtrl:connect(TreeCtrl, command_tree_item_activated), - - wxSizer:add(ModuleSz, ModuleTxtCtrl, [{flag, ?wxEXPAND}]), - wxSizer:add(ModuleSz, ModuleListBox, [{flag, ?wxEXPAND}]), - wxSizer:add(TreeSz, TreeCtrl, [{flag, ?wxEXPAND},{proportion, 1}]), - wxSizer:add(FuncMainSz, ModuleSz, [{flag, ?wxEXPAND}]), - wxSizer:add(FuncMainSz, TreeSz, [{flag, ?wxEXPAND}, {proportion, 1}]), - wxWindow:setSizer(FuncPanel, FuncMainSz), - wxNotebook:addPage(Notebook, FuncPanel, "Functions"), - - -%%%%%%%%%%%%%%%%%%% Setup match specification page - - {MatchPanel, _, MatchTxtCtrl, MatchListBox} = create_matchspec_page(Notebook, MatchSpecs, matchpage), - wxNotebook:addPage(Notebook, MatchPanel, "Match Specs"), - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Setup Dialog - - wxSizer:add(MainSz, Notebook, [{proportion, 1}, {flag, ?wxEXPAND}]), - 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(MainSz, DialogBtnSz), - wxWindow:setSizer(Panel, MainSz), - - Boxes = #boxes{send = SendBox, - 'receive' = RecBox, - functions = FuncBox, - events = EventBox, - on_spawn = #on_spawn{checkbox = SpawnBox, - all_spawn = SpwnAllRadio, - first_spawn = SpwnFirstRadio}, - all_spawn = SpwnAllRadio, - on_link = #on_link{checkbox = LinkBox, - all_link = LinkAllRadio, - first_link = LinkFirstRadio}, - all_link = LinkAllRadio}, - - - wxButton:connect(OKBtn, command_button_clicked, [{userData, trace_options}]), - wxButton:connect(CancelBtn, command_button_clicked, [{userData, trace_options}]), - wxFrame:connect(Frame, close_window, []), - wxFrame:show(Frame), - {Frame, TreeCtrl, Boxes, ModuleListBox, MatchTxtCtrl, MatchListBox}. + 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) -> - FilteredData = [X || X <- Data, re:run(X, Input) =/= nomatch], + FilteredData = [X || X = {Str, _} <- Data, re:run(Str, Input) =/= nomatch], wxListBox:clear(ListBox), - wxListBox:appendStrings(ListBox, FilteredData), + wxListBox:appendStrings(ListBox, [Str || {Str,_} <- FilteredData]), + wx:foldl(fun({_, Term}, N) -> + wxListBox:setClientData(ListBox, N, Term), + N+1 + end, 0, FilteredData), FilteredData. get_modules(Node) -> @@ -241,41 +451,11 @@ optionpage_top_right(Panel, TopRightSz, Options, Text) -> wxSizer:add(RadioSz, Radio2, []), wxSizer:add(Sizer, RadioSz, [{flag, ?wxLEFT},{border, 20}]), wxSizer:add(TopRightSz, Sizer, Options), - wxCheckBox:connect(ChkBox, command_checkbox_clicked, [{userData, {ChkBox, Radio1, Radio2}}]), {ChkBox, Radio1, Radio2}. -read_trace_boxes(ChkBoxes = #boxes{on_spawn = OnSpawn, on_link = OnLink}, Options) -> - {On1stSpawn2, OnAllSpawn2} = - case wxCheckBox:isChecked(OnSpawn#on_spawn.checkbox) of - true -> - OnAllSpawn = wxRadioButton:getValue(OnSpawn#on_spawn.all_spawn), - On1stSpawn = wxRadioButton:getValue(OnSpawn#on_spawn.first_spawn), - {On1stSpawn, OnAllSpawn}; - false -> - {false, false} - end, - {On1stLink2, OnAllLink2} = - case wxCheckBox:isChecked(OnLink#on_link.checkbox) of - true -> - OnAllLink = wxRadioButton:getValue(OnLink#on_link.all_link), - On1stLink = wxRadioButton:getValue(OnLink#on_link.first_link), - {On1stLink, OnAllLink}; - false -> - {false, false} - end, - Options#trace_options{send = wxCheckBox:isChecked(ChkBoxes#boxes.send), - treceive = wxCheckBox:isChecked(ChkBoxes#boxes.'receive'), - functions = wxCheckBox:isChecked(ChkBoxes#boxes.functions), - events = wxCheckBox:isChecked(ChkBoxes#boxes.events), - on_all_spawn = OnAllSpawn2, - on_1st_spawn = On1stSpawn2, - on_all_link = OnAllLink2, - on_1st_link = On1stLink2}. - - create_styled_txtctrl(Parent) -> - FixedFont = wxFont:new(12, ?wxFONTFAMILY_TELETYPE, ?wxFONTSTYLE_NORMAL, ?wxNORMAL,[]), + FixedFont = observer_wx:get_attrib({font, modern}), Ed = wxStyledTextCtrl:new(Parent), wxStyledTextCtrl:styleClearAll(Ed), wxStyledTextCtrl:styleSetFont(Ed, ?wxSTC_STYLE_DEFAULT, FixedFont), @@ -314,14 +494,12 @@ keyWords() -> lists:flatten([K ++ " " || K <- L] ++ [0]). -enable({CheckBox, AllRadio, FirstRadio}) -> +enable(CheckBox, Radio) -> case wxCheckBox:isChecked(CheckBox) of false -> - wxWindow:disable(AllRadio), - wxWindow:disable(FirstRadio); + [wxWindow:disable(R) || R <- Radio]; true -> - wxWindow:enable(AllRadio), - wxWindow:enable(FirstRadio) + [wxWindow:enable(R) || R <- Radio] end. @@ -333,18 +511,14 @@ check_box(ChkBox, Bool) -> ignore end. -parse_record_function_names(RecordList) -> - StrList = [atom_to_list(FName) ++ "/" ++ integer_to_list(Arity) - || #traced_func{func_name = FName, arity = Arity} <- RecordList], - parse_function_names(StrList, []). - parse_function_names(Choices) -> - StrList = [atom_to_list(Name) ++ "/" ++ integer_to_list(Arity) || {Name, Arity} <- 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|T], 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*?-"), @@ -355,209 +529,204 @@ parse_function_names([H|T], Acc) -> true -> H end, - parse_function_names(T, [Parsed | Acc]). + parse_function_names(T, [{Parsed, Term} | Acc]). -show_ms_in_savedlistbox(MatchSpecList) -> - MsOrAlias = fun(#match_spec{alias = A, str_ms = M, fun2ms = F}) -> +ms_names(MatchSpecList) -> + MsOrAlias = fun(#match_spec{name = A, str = M}) -> case A of - undefined -> - if - F =:= undefined -> M; - true -> F - end; - _ -> - A + "" -> M; + _ -> A ++ " " ++ M end end, - [MsOrAlias(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]. + [{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([]) -> "."; @@ -569,498 +738,446 @@ ensure_last_is_dot(String) -> String ++ "." end. -check_correct_MS(String) -> - Tokens = try_scan(String), - case try_parse(Tokens) of - {ok, Term} -> - case erlang:match_spec_test([], Term, trace) of - {ok, _, _, _} -> - {true, Term}; - {error, List} -> - Reason = unparse_error_msg(List, []), - {false, Reason} - end; - error -> - {false, "Invalid term"} - end. - -unparse_error_msg([], Acc) -> - lists:reverse(Acc); -unparse_error_msg([{_, Reason} | T], Acc) -> - unparse_error_msg(T, [Reason ++ "\n" | Acc]). - -try_scan(String) -> - try - erl_scan:string(String) of - {ok, T, _} -> - T; - _ -> - error - catch - _:_ -> error - end. - -try_parse(Tokens) -> - try - erl_parse:parse_term(Tokens) of - {ok, Term} -> - {ok, Term}; - _ -> - error - catch - _:_ -> - error - end. - -update_matchspec_listbox(Str, {PopupBox, PageBox}, From) -> - case From of - matchpopup -> - wxControlWithItems:append(PageBox, Str), - wxControlWithItems:append(PopupBox, Str); - matchpage -> - wxControlWithItems:append(PageBox, Str) - 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}. +%% 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}. -- cgit v1.2.3