et_contents_viewer.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 591 行 · 第 1/2 页

ERL
591
字号
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%%%----------------------------------------------------------------------%% Purpose: Displays details of a trace event%%-----------------------------------------------------------------------module(et_contents_viewer).-behaviour(gen_server).%% External exports-export([start_link/1,          stop/1]).%% gen_server callbacks-export([init/1, terminate/2, code_change/3,         handle_call/3, handle_cast/2, handle_info/2]).-include("../include/et.hrl").-include("et_internal.hrl").-record(state, {parent_pid,     % Pid of parent process                viewer_pid,     % Pid of viewer process                event_order,    % Field to be used as primary key                event,          % The original event                filtered_event, % Event processed by active filter                active_filter,  % Name of the active filter                filters,        % List of possible filters                win,            % GUI: Window object                packer,         % GUI: Packer object                width,          % GUI: Window width                height}).       % GUI: Window height%%%----------------------------------------------------------------------%%% Client side%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% start_link(Options) -> {ok, ContentsPid} | {error, Reason}%%%% Start an viewer for the event contents as window in GS%%%% Options = [option()]%% %% option() =%% %%   {parent_pid, pid()}          |  % Pid of parent process%%   {viewer_pid, pid()}          |  % Pid of viewer process%%   {event_order, event_order()} |  % Field to be used as primary key %%   {active_filter, atom()}      |  % Name of the active filter%%   {filter, atom(), fun()}         % A named filter fun%%   %% event_order() = 'trace_ts' | 'event_ts'%% ContentsPid = pid()%% Reason = term()%%----------------------------------------------------------------------start_link(Options) ->    case parse_opt(Options, default_state()) of        {ok, S} ->            case gen_server:start_link(?MODULE, [S], []) of                {ok, ContentsPid} when S#state.parent_pid /= self() ->                    unlink(ContentsPid),                    {ok, ContentsPid};                Other ->                    Other            end;        {error, Reason} ->            {error, Reason}    end.default_state() ->    #state{parent_pid    = self(),           viewer_pid    = undefined,           active_filter = collector,           filters       = [#filter{name = collector, function = fun(E) -> E end}],           width         = 600,           height        = 300}.parse_opt([], S) ->    Name = S#state.active_filter,    Filters = S#state.filters,    if        S#state.event == undefined ->            {error, {badarg, no_event}};        atom(Name) ->            case lists:keysearch(Name, #filter.name, Filters) of                {value, F} when record(F, filter) ->                    {ok, S#state{active_filter = Name}};                false ->                    {error, {badarg, {no_such_filter, Name, Filters}}}            end    end;parse_opt([H | T], S) ->    case H of        {parent_pid, ParentPid} when pid(ParentPid) ->            parse_opt(T, S#state{parent_pid = ParentPid});        {viewer_pid, ViewerPid} when pid(ViewerPid) ->            parse_opt(T, S#state{viewer_pid = ViewerPid});        {event_order, trace_ts} ->            parse_opt(T, S#state{event_order = trace_ts});        {event_order, event_ts} ->            parse_opt(T, S#state{event_order = event_ts});        {event, Event} when record(Event, event) ->            parse_opt(T, S#state{event = Event});        {active_filter, Name} when atom(Name) ->            parse_opt(T, S#state{active_filter = Name});        F when record(F, filter),               atom(F#filter.name),               function(F#filter.function) ->            Filters = lists:keydelete(F#filter.name, #filter.name, S#state.filters),            Filters2 = lists:keysort(#filter.name, [F | Filters]),            parse_opt(T, S#state{filters = Filters2});        {width, Width} when integer(Width), Width > 0 ->            parse_opt(T, S#state{width = Width});        {height, Height} when integer(Height), Height > 0 ->            parse_opt(T, S#state{height = Height});        Bad ->            {error, {bad_option, Bad}}    end;parse_opt(BadList, _S) ->    {error, {bad_option_list, BadList}}.%%----------------------------------------------------------------------%% stop(ContentsPid) -> ok%%%% Stops a contents viewer process%%%% ContentsPid = pid()%%----------------------------------------------------------------------stop(ContentsPid) ->    unlink(ContentsPid),    call(ContentsPid, stop).call(ContentsPid, Request) ->    gen_server:call(ContentsPid, Request, infinity).%%%----------------------------------------------------------------------%%% Callback functions from gen_server%%%----------------------------------------------------------------------%%----------------------------------------------------------------------%% Func: init/1%% Returns: {ok, State}          |%%          {ok, State, Timeout} |%%          ignore               |%%          {stop, Reason}%%----------------------------------------------------------------------init([S]) when record(S, state) ->    process_flag(trap_exit, true),    S2 = create_window(S),    {ok, S2}.%%----------------------------------------------------------------------%% Func: handle_call/3%% Returns: {reply, Reply, State}          |%%          {reply, Reply, State, Timeout} |%%          {noreply, State}               |%%          {noreply, State, Timeout}      |%%          {stop, Reason, Reply, State}   | (terminate/2 is called)%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------handle_call(stop, _From, S) ->    unlink(S#state.parent_pid),    {stop, shutdown, ok, S};handle_call(Request, From, S) ->    ok = error_logger:format("~p(~p): handle_call(~p, ~p, ~p)~n",                             [?MODULE, self(), Request, From, S]),    Reply = {error, {bad_request, Request}},    {reply, Reply, S}.%%----------------------------------------------------------------------%% Func: handle_cast/2%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------handle_cast(Msg, S) ->    ok = error_logger:format("~p(~p): handle_cast(~p, ~p)~n",                             [?MODULE, self(), Msg, S]),    {noreply, S}.%%----------------------------------------------------------------------%% Func: handle_info/2%% Returns: {noreply, State}          |%%          {noreply, State, Timeout} |%%          {stop, Reason, State}            (terminate/2 is called)%%----------------------------------------------------------------------handle_info({gs, Button, click, Data, _Other}, S) ->    case Button of        close ->            gs:destroy(S#state.win),            {stop, normal, S};        save ->            Event = S#state.event,            Bin = list_to_binary(event_to_string(Event, S#state.event_order)),            TimeStamp =                 case S#state.event_order of                    trace_ts -> Event#event.trace_ts;                    event_ts   -> Event#event.event_ts                end,            FileName = ["et_contents_viewer_", now_to_string(TimeStamp), ".save"],            file:write_file(lists:flatten(FileName), Bin),            {noreply, S};        _PopupMenuItem when record(Data, filter) ->            F = Data,            ChildState= S#state{active_filter = F#filter.name},            case gen_server:start_link(?MODULE, [ChildState], []) of                {ok, Pid} when S#state.parent_pid /= self() ->                    unlink(Pid),                    {noreply, S};                _ ->                    {noreply, S}            end;        {hide, Actors} ->            send_viewer_event(S, {delete_actors, Actors}),            {noreply, S};        {show, Actors} ->            send_viewer_event(S, {insert_actors, Actors}),            {noreply, S};        {mode, Mode} ->            send_viewer_event(S, {mode, Mode}),            {noreply, S};        Nyi ->            ok = error_logger:format("~p: click ~p ignored (nyi)~n",                                     [?MODULE, Nyi]),            {noreply, S}    end;handle_info({gs, _Obj, destroy,_, _}, S) ->    unlink(S#state.parent_pid),    gs:destroy(S#state.win),    {stop, normal, S};handle_info({gs, _Obj, keypress, _, [KeySym, _Keycode, _Shift, _Control | _]}, S) ->    case KeySym of        'c' ->            gs:destroy(S#state.win),            {stop, normal, S};        'f' ->            E    = S#state.filtered_event,            From = E#event.from,            send_viewer_event(S, {delete_actors, [From]}),            {noreply, S};        't' ->            E  = S#state.filtered_event,            To = E#event.to,            send_viewer_event(S, {delete_actors, [To]}),            {noreply, S};        'b' ->            E    = S#state.filtered_event,            From = E#event.from,            To   = E#event.to,            send_viewer_event(S, {delete_actors, [From, To]}),            {noreply, S};                'F' ->            E    = S#state.filtered_event,            From = E#event.from,            send_viewer_event(S, {insert_actors, [From]}),            {noreply, S};        'T' ->            E  = S#state.filtered_event,            To = E#event.to,            send_viewer_event(S, {insert_actors, [To]}),            {noreply, S};        'B' ->            E    = S#state.filtered_event,            From = E#event.from,            To   = E#event.to,            send_viewer_event(S, {insert_actors, [From, To]}),            {noreply, S};        's' ->            E     = S#state.filtered_event,            From  = E#event.from,            To    = E#event.to,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?