appmon_lb.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 690 行

ERL
690
字号
%% ``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$%%%%% Due to the fact that the application buttons in the appmon window%%% gets too small to read when the number of applications increases,%%% this listbox window has been created. %%% Because of the limitations of GS a listbox was chosen to keep%%% the nodes and applications. When it's possible to scroll a frame I%%% think one should put in scrollbars in the appmon main window.%%% The listbox solution is too slow with lots of applications.%%%%%% In the listbox the nodes are shown with their applications beneith.%%% By double clicking on an application name, or a single click and%%% then pressing the load button, its application window is started.-module(appmon_lb).-export ([	  start/1, 	  stop/1, 	  add_node/2,	  remove_node/2,	  add_apps/3,	  remove_app/3,	  open_win/2,	  update_status/3	 ]).-export ([init/1]).-define (LB_W, 200).                     % List box width-define (LB_H, 400).                     % List box height-define (BUTT_W, 100).-define (WIN_W, ?LB_W + ?BUTT_W + 25).   % Window width-define (WIN_H, ?LB_H + 20).             % Window height%%% #node{} %%%%%% The record 'node' contains the name of the node, its status and %%% the applications running on that node.%%%%%% node    ==  atom ()%%% status  ==  alive  ||  dead%%% apps    ==  [#app{}]%%%-record (node, {node,             %% Name of the node		status = alive,		apps = []}). %%% #app{}%%%%%% The record 'app' contains the name of the application and its pid%%%%%% app  ==  atom ()%%% pid  ==  pid ()%%%-record (app, {app,		pid}).%%% #win{}%%%%%% The record 'win' contains the pid of the listbox window,%%% its x and y position, its width and height.%%%%%% pid     ==  win_closed  ||  pid ()%%% x       ==  integer ()%%% y       ==  integer ()%%% width   ==  integer ()%%% height  ==  integer ()%%%-record (win, {pid = win_closed,	       x = 50, 	       y = 50,	       width = ?WIN_W,	       height = ?WIN_H}).%%% Every function in the interface is called with the pid %%% of this recieve loop, called 'LbPid'.%%%%%% start  /1%%%%%% start returns the pid of the spawned receive loop or %%% it will call exit/2 after a timeout.%%%%%% Pre:%%%    CallingPid  ==  pid ()%%%%%% Def:%%%    pid ()  ||  exit/2%%%start (CallingPid) ->    PidInit = spawn (?MODULE, init, [CallingPid]),    %% Wait for a initialization completion message from    %% the spawned process before returning its Pid.    receive	{initialization_complete, PidInit} ->	    PidInit    	    %% (Conditional) Failure to start within the time limit 	    %% will result in termination (Timeout may be infinite).    after	60000 ->	    exit (PidInit, kill),	    exit ({startup_timeout, ?MODULE})    end.%%% stop  /1%%%%%% stop exits the receive loop%%%%%% Post:%%%    exiting the receive loop%%%stop (LbPid) ->    call (LbPid, stop).%%% add_node  /2%%%%%% add_node adds the given node to the DB list.%%%%%% Pre:%%%    Node  ==  atom ()%%%%%% Post:%%%    Node is added to the DB list%%%add_node (LbPid, Node) ->    call (LbPid, {add_node, Node}).%%% remove_node  /2%%%%%% remove_node removes the given node from the DB list.%%%%%% Pre:%%%    Node  ==  atom ()%%%%%% Post:%%%    Node is removed from the DB list%%%remove_node (LbPid, Node) ->    call (LbPid, {remove_node, Node}).%%% add_apps  /3%%%%%% add_apps add the given applications to the given %%% node in the DB list.%%%%%% Pre:%%%    Apps  ==  [App]%%%    App   ==  {Name, Pid}%%%    Name  ==  atom ()%%%    Pid   ==  pid ()%%%    Node  ==  atom ()%%%%%% Post:%%%    Node#node{apps = Apps}%%%add_apps (LbPid, Apps, Node) ->    call (LbPid, {add_apps, Apps, Node}).%%% remove_app  /3%%%%%% remove_app remove the given application from the %%% given node in the DB list.%%%%%% Pre:%%%    App   ==  atom ()%%%    Node  ==  atom ()%%%%%% Def:%%%    Node#node{apps = OldApps - App}%%%remove_app (LbPid, App, Node) ->    call (LbPid, {remove_app, App, Node}).%%% open_win  /3%%%%%% open_win opens the listbox window with the given nodes%%% and their applications.%%%%%% Pre:%%%    Nodes_apps  ==  [{Node, Status, Apps}]%%%    Node        ==  atom ()%%%    Status      ==  alive  ||  dead%%%    Apps        ==  [App]%%%    App         ==  {AppName, AppPid}%%%    AppName     ==  atom ()%%%    AppPid      ==  pid ()%%%%%% Post:%%%    Window with listbox%%%open_win (LbPid, Nodes_apps) ->    call (LbPid, {open_win, Nodes_apps}).%%% update_status  /3%%%%%% update_status changes the status for the given node.%%%%%% Pre:%%%    Node    ==  atom ()%%%    Status  ==  alive  ||  dead%%%%%% Def:%%%    Node#node{status = Status}%%%update_status (LbPid, Node, Status) ->    call (LbPid, {update_status, Node, Status}).%%% call  /2%%%%%% call sends the given action to the listbox receive loop.%%%%%% Pre: %%%    Action  ==  atom ()  ||  tuple ()%%%call (LbPid, Action) ->    LbPid ! Action.  %%% init  /1%%%init (CallingPid) ->    CallingPid ! {initialization_complete, self ()},    loop (#win{}, []).%%% loop  /2%%%%%% loop is the recive loop for the listbox window process.%%%%%% Pre:%%%    Win   ==  #win{}%%%    Data  ==  [#node{}]%%%loop (Win, Data) ->    receive	{add_node, Node} ->	    NewData = add_node_1 (Node, Data),	    update (NewData, Win#win.pid),	    loop (Win, NewData);		{remove_node, Node} ->	    NewData = dead_node (Node, Data),	    update (NewData, Win#win.pid),	    loop (Win, NewData);	{add_apps, Apps, Node} ->	    NewData = add_apps_1 (Apps, Node, Data),	    update (NewData, Win#win.pid),	    loop (Win, NewData);		{remove_app, App, Node} ->	    NewData = remove_app_1 (App, Node, Data),	    update (NewData, Win#win.pid),	    loop (Win, NewData);		{open_win, Nodes_apps} ->	    NewData = parse_data ([], Nodes_apps),	    NewWin = Win#win{pid = init_win ({Win#win.x, Win#win.y})},	    update (NewData, NewWin#win.pid),	    loop (NewWin, NewData);	    	{update_status, Node, Status} ->	    NewData = update_status_1 (Node, Status, Data),	    update (NewData, Win#win.pid),	    loop (Win, NewData);		stop ->	    true;	{gs, _Id, destroy, _D, _Arg} -> 	    bye;	{gs, _Id, configure, _D, [W, H | _]} ->	    NewWin = configure (Win#win.pid, W, H),	    loop (NewWin, Data);	{gs, lb, doubleclick, _, _Txt} ->	    load_app (gs:read (lb, selection), Data),	    loop (Win, Data);	    	{gs, lb, click, _, _Txt} ->	    loop (Win, Data);	{gs, close, click, _D, _Arg} -> 	    case Win#win.pid of		win_closed ->		    true;				_opened ->		    gs:destroy (Win#win.pid)	    end,	    loop (#win{}, Data);	{gs, load, click, _D, _Txt} ->	    load_app (gs:read (lb, selection), Data),	    loop (Win, Data);		{gs, clear, click, _D, _Txt} ->	    gs:config (lb, {selection, clear}),	    loop (Win, Data);		_ ->	    loop (Win, Data)    end.%%% init_win  /1%%%init_win ({X, Y}) ->    GS = gs:start (),    Win = gs:window (win, GS, [{x, X},			       {y, Y},			       {width, ?WIN_W},			       {height, ?WIN_H},			       {title,"Appmon: nodes and applications"},			       {configure, true}]),    gs:listbox (lb, Win, [{x, 5},			  {y, 10},			  {width, ?LB_W},			  {height, ?LB_H},			  {vscroll, right},			  {hscroll, bottom},			  {selectmode, single},			  {click, true},			  {doubleclick, true}]),    gs:button (load, Win, [{x, ?WIN_W - ?BUTT_W - 10},			    {y, ?WIN_H - 120},			    {width, ?BUTT_W},			    {label, {text, "Load"}}]),    gs:button (clear, Win, [{x, ?WIN_W - ?BUTT_W - 10},			    {y, ?WIN_H - 80},			    {width, ?BUTT_W},			    {label, {text, "Clear"}}]),    gs:button (close, Win, [{x, ?WIN_W - ?BUTT_W - 10},			   {y, ?WIN_H - 40},			   {width, ?BUTT_W},			   {label, {text, "Close"}}]),    gs:config (Win, {map, true}),    Win.			  			 %%% add_node_1  /2%%%%%% add_node adds the given node in the given window %%% with its appications in a listbox.%%%add_node_1 (Node, []) ->    [new_node (Node)];add_node_1 (Node, [H | T]) ->    T1 = lists:keysort (#node.node, [new_node (Node) | T]),    [H | T1].%%% dead_node  /2%%%%%% dead_node returns a list with the given node's %%% status changed to dead.%%%dead_node (Node, Data) ->    case lists:keysearch (Node, #node.node, Data) of	{value, Node_rec} ->	    L = Node_rec#node.apps,	    lists:keyreplace (Node, #node.node, 			      Data, new_node (Node, dead, L));		_false ->	    Data    end.    %%% add_apps_1  /3%%%%%% add_apps_1 returns a list with the given application %%% into the old list inserted.%%%add_apps_1 (Apps, Node, Data) ->    case lists:keysearch (Node, #node.node, Data) of	{value, _Node_rec} ->	    NewApps = parse_apps (Apps, []),	    lists:keyreplace (Node, #node.node, 			      Data, new_node (Node, NewApps));		_false ->	    Data    end.%%% remove_app_1  /3%%%%%% remove_app_1 returns a list with the given application%%% removed from the old list.%%%remove_app_1 (App, Node, Data) ->        case lists:keysearch (Node, #node.node, Data) of	{value, Node_rec} ->	    L = Node_rec#node.apps,	    L2 = lists:keydelete (App, #app.app, L),	    lists:keyreplace(Node, #node.node, Data, new_node(Node,L2));		_false ->	    Data    end.%%% configure  /3%%%%%% configure returns a win record after the window has been%%% configured.%%%configure (WPid, W, H) ->    X = gs:read (WPid, x),    Y = gs:read (WPid, y),    gs:config (lb, [{width, W - ?BUTT_W - 25}, {height, H - 20}]),    gs:config (load, [{x, W - ?BUTT_W - 10}, {y, H - 120}]),    gs:config (clear, [{x, W - ?BUTT_W - 10}, {y, H - 80}]),    gs:config (close, [{x, W - ?BUTT_W - 10}, {y, H - 40}]),        #win{pid = WPid, x = X, y = Y, width = W, height = H}.    %%% load_app  /2%%%%%% load_app opens the application window by calling %%% the appmon_a module.%%%load_app ([], _Data) ->     %% no application chosen    ok;load_app ([Index], Data) ->    App = gs:read (lb, {get, Index}),        case string:substr (App, 1, 3) of	"   " ->	    AppName = list_to_atom (string:substr (App, 4)),	    	    case get_node (AppName, Index, Data) of		no_node ->		    ok;		NodeName ->		    appmon_a:start (NodeName, AppName)	    end;	_ ->	    ok    end.%%% update_status_1  /3%%%%%% update_status_1 returns a list with the given %%% node's status updated.%%%update_status_1 (Node, Status, Data) ->    case lists:keysearch (Node, #node.node, Data) of	{value, Node_rec} ->	    lists:keyreplace (Node, 			      #node.node, 			      Data, 			      new_node(Node,Status,Node_rec#node.apps));	_not_found ->	    Data    end.%%% update  /2%%%%%% update updates the listbox with new data.%%%update (_Data, win_closed) ->    true;update (Data, _Win) ->    gs:config (lb, clear),    lb_print (Data).%%% lb_print  /1%%%%%% lb_print prints the list into the listbox.%%%lb_print ([]) ->    ok;lb_print ([#node{node = Node, status = Status, apps = Apps} | T]) ->    Str = io_lib:format ("~p (~p)", [Node, Status]),    gs:config (lb, {add, Str}),    case Status of	alive ->	    lb_print_apps (Apps);	_dead ->	    gs:config (lb, {add, ""}),	    ok    end,    lb_print (T).%%% lb_print_apps  /1%%%%%% lb_print_apps prints the applications into the listbox.%%%lb_print_apps ([]) ->    ok;lb_print_apps ([#app{app = App} | T]) ->    Str = io_lib:format ("   ~p", [App]),    gs:config (lb, {add, Str}),    lb_print_apps (T).%%% new_node  /1, 2, 3%%%%%% new_node returna a new node record constructed %%% with the given data%%%new_node (Node) ->    #node{node = Node}.new_node (Node, Apps) ->    #node{node = Node, apps = Apps}.new_node (Node, Status, Apps) ->    #node{node = Node, status = Status, apps = Apps}.%%% new_app  /2%%%%%% new_app returns a new application record %%% constructed with the given data.%%%new_app (App, Pid) ->    #app{app = App, pid = Pid}.%%% parse_apps  /2%%%%%% parse_apps returns a list of application records.%%%parse_apps ([], [H | T]) ->    [H | lists:keysort (#app.app, T)];parse_apps ([App | T], L) ->    Pid = element (1, App),    Name = element (2, App),    parse_apps (T, [new_app (Name, Pid) | L]). %%% get_node  /3%%%%%% get_node returns the node from the given list %%% or else no_node if it doesn't exists.%%%get_node (_App, _Index, []) ->    no_node;get_node (App, Index, [Node | T]) ->    Length = length (Node#node.apps) + 1,    case Length < Index of	true ->	    get_node (App, Index - Length, T);	false ->	    Node#node.node    end.%%% parse_data  /2%%%%%% parse_data returns a list with node records.%%%parse_data (Data, []) ->    Data;parse_data (Data, [{Node, Status, Apps} | T]) ->    Apps_1 = parse_apps (Apps, []),    parse_data ([new_node (Node, Status, Apps_1) | Data], T).    

⌨️ 快捷键说明

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