tv_nodewin.erl

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

ERL
406
字号
%% ``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$%%-module(tv_nodewin).-export([start/2, init/3]).-include("tv_int_msg.hrl").-define(WINDOW_WIDTH, 230).-define(WINDOW_HEIGHT, 260).-define(DEFAULT_BG_COLOR, {217,217,217}).-define(POLL_INTERVAL, 5000).%%%*********************************************************************%%% EXTERNAL FUNCTIONS%%%*********************************************************************start(CurrNode, ErrMsgMode) ->    spawn_link(?MODULE, init, [self(), CurrNode, ErrMsgMode]).init(Pid, CurrNode, ErrMsgMode) ->    process_flag(trap_exit, true),    net_kernel:monitor_nodes(true),    put(error_msg_mode, ErrMsgMode),    gs:start(),    NewCurrNode = update_node_listbox(CurrNode, false),    tell_master(NewCurrNode, CurrNode, Pid),    loop(Pid, NewCurrNode, node(), false).%%%*********************************************************************%%% INTERNAL FUNCTIONS%%%*********************************************************************init_window(CurrNode, Pid) ->    create_window(),    NewCurrNode = update_node_listbox(CurrNode, true),    tell_master(NewCurrNode, CurrNode, Pid),    gs:config(win, [{map,true}]),    NewCurrNode.handle_error(nodedown) ->    gs:window(errorwin, gs:start(), []),    gs:config(errorwin, [beep]),    case get(error_msg_mode) of	normal ->	    tv_utils:notify(errorwin, "TV Notification", ["The selected node is down!"]);	haiku ->	    Msg = ["With searching comes loss",		   "And the presence of absence:",		   "Node is down."],	    tv_utils:notify(errorwin, "TV Notification", Msg)    end,    gs:destroy(errorwin);handle_error(distributed) ->    gs:window(errorwin, gs:start(), []),    gs:config(errorwin, [beep]),    case get(error_msg_mode) of	normal ->	    tv_utils:notify(errorwin, "TV Notification", 			    ["The system has become distributed!"]);	haiku ->	    Msg = [],	    tv_utils:notify(errorwin, "TV Notification", Msg)    end,    gs:destroy(errorwin);handle_error(undistributed) ->    gs:window(errorwin, gs:start(), []),    gs:config(errorwin, [beep]),    case get(error_msg_mode) of	normal ->	    tv_utils:notify(errorwin, "TV Notification", 			    ["The system is no longer distributed!"]);	haiku ->	    Msg = ["The system you see",		   "Is not a distributed",		   "system anymore."],	    tv_utils:notify(errorwin, "TV Notification", Msg)    end,    gs:destroy(errorwin).get_node_lists(CurrNode) ->    NodeDataList = lists:sort([node() | nodes()]),    NodeTextList = lists:map(fun(Item) ->					 " " ++ atom_to_list(Item)				 end, 				 NodeDataList),    %% It *may* be possible that CurrNode has disappeared!    %% If this is the case, use the node where TV resides    %% as new current node.    %% This also covers the case when our own node (or some    %% other node) suddenly goes distributed.    NewCurrNode = case lists:member(CurrNode, NodeDataList) of		      true ->			  CurrNode;		      false ->			  node()		  end,           %% Now get the index that shall be marked in the node listbox.       %% Remember that the first item has number 0 (zero)!    NodeMarkIndex = get_node_mark_index(NewCurrNode, NodeDataList, 0),        {NewCurrNode, NodeDataList, NodeTextList, NodeMarkIndex}.    %% We know that CurrNode is *somewhere* in the list, since we have checked.%% If the original CurrNode wasn't there, then we are using node() instead,%% which definitely is in the list. (node() may have gone distributed in the %% meantime, but it *IS* in the list!)  :-)get_node_mark_index(CurrNode, [H | T], Acc) when CurrNode =/= H ->    get_node_mark_index(CurrNode, T, Acc + 1);get_node_mark_index(CurrNode, [CurrNode | _], Acc) ->    Acc.  %% Acc tells the index of the current head.  :-)    check_selected_node('nonode@nohost', _OldNode, _WinCreated) when node() =:= 'nonode@nohost' ->       %% Not distributed, OK!    'nonode@nohost';check_selected_node(_Node, _OldNode, WinCreated) when node() =:= 'nonode@nohost' ->       %% No longer distributed, but previously was!    handle_error(undistributed),    update_node_listbox('nonode@nohost', WinCreated);check_selected_node(Node, _OldNode, _WinCreated) when Node =:= node() ->       %% We are distributed, but on        %% our own node! Since we        % still are running, the node        %% is up.    Node;check_selected_node(Node, 'nonode@nohost', WinCreated) ->       %% The system has been distributed!    net_kernel:monitor_nodes(true),    handle_error(distributed),    update_node_listbox(Node, WinCreated);check_selected_node(Node, _OldNode, WinCreated) ->       %% We are distributed, and a new node has been chosen!       %% We better check this node!    case net_adm:ping(Node) of	pong ->	    Node;	_Other ->	    handle_error(nodedown),	    update_node_listbox(Node, WinCreated)    end.available_nodes() ->    lists:sort([node() | nodes()]).loop(Pid, CurrNode, HomeNode, WinCreated) ->    receive	{nodedown, _Node} ->	    flush_nodedown_messages(),	    flush_nodeup_messages(),	    case lists:member(CurrNode, available_nodes()) of		true ->		    done;		false when node() =:= 'nonode@nohost', CurrNode =/= 'nonode@nohost' ->		    handle_error(undistributed);		false ->		    handle_error(nodedown)	    end,	    NewCurrNode = update_node_listbox(CurrNode, WinCreated),	    tell_master(NewCurrNode, CurrNode, Pid),	    loop(Pid, NewCurrNode, node(), WinCreated);	{nodeup, _Node} ->	    flush_nodeup_messages(),	    flush_nodedown_messages(),	    case lists:member(CurrNode, available_nodes()) of		true ->		    done;		false when node() =:= 'nonode@nohost', CurrNode =/= 'nonode@nohost' ->		    handle_error(undistributed);		false when CurrNode =:= 'nonode@nohost' ->		    net_kernel:monitor_nodes(true),		    handle_error(distributed);		false ->		    handle_error(nodedown)	    end,	    NewCurrNode = update_node_listbox(CurrNode, WinCreated),	    tell_master(NewCurrNode, CurrNode, Pid),	    loop(Pid, NewCurrNode, node(), WinCreated);	{gs, node_listbox, click, Data, [Idx, _Txt | _]} ->	    NewCurrNode = check_selected_node(lists:nth(Idx + 1, Data), CurrNode, WinCreated),	    tell_master(NewCurrNode, CurrNode, Pid),	    loop(Pid, NewCurrNode, node(), WinCreated);	{gs, win, configure, _, _} ->	    gs:config(win, [{width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),	    loop(Pid, CurrNode, HomeNode, WinCreated);	show_window when WinCreated->	    gs:config(win, [raise]),	    loop(Pid, CurrNode, HomeNode, WinCreated);		show_window when not WinCreated ->	    init_window(CurrNode, Pid),	    loop(Pid, CurrNode, HomeNode, true);	{gs, _Id, click, close_menu, _Args} ->	    gs:destroy(win),	    loop(Pid, CurrNode, HomeNode, false);	{gs, _Id, keypress, _Data, [c, _, 0, 1 | _]} ->	    gs:destroy(win),	    loop(Pid, CurrNode, HomeNode, false);		{gs, _Id, keypress, _Data, ['C', _, 1, 1 | _]} ->	    gs:destroy(win),	    loop(Pid, CurrNode, HomeNode, false);	{gs, _Id, keypress, _Data, _Args} ->	    loop(Pid, CurrNode, HomeNode, WinCreated);    		{gs, _, destroy, _, _} ->	    loop(Pid, CurrNode, HomeNode, false);    	{error_msg_mode, Mode} ->	    put(error_msg_mode, Mode),	    loop(Pid, CurrNode, HomeNode, WinCreated);	{'EXIT', Pid, _Reason} ->	    net_kernel:monitor_nodes(false),	    exit(normal);	{'EXIT', _OtherPid, _Reason} ->	    loop(Pid, CurrNode, HomeNode, WinCreated);		_Other ->	    io:format("Node window received message ~p ~n", [_Other]),	    loop(Pid, CurrNode, HomeNode, WinCreated)    after 	1000 ->	    NewHomeNode = case node() of			      HomeNode ->				  HomeNode;			      Other ->				  self() ! {nodeup, Other}			  end,	    loop(Pid, CurrNode, NewHomeNode, WinCreated)    end.			      tell_master(NewNode, NewNode, _Pid) ->    done;tell_master(NewNode, _OldNode, Pid) ->    Pid ! {tv_new_node, self(), NewNode}.flush_nodedown_messages() ->    receive	{nodedown,_Node} ->	    flush_nodedown_messages()    after	0 ->	    done    end.flush_nodeup_messages() ->    receive	{nodeup,_Node} ->	    flush_nodeup_messages()    after	0 ->	    done    end.update_node_listbox(Node, WinCreated) ->    {NewNode, NodeDataList, NodeTextList, MarkIndex} = get_node_lists(Node),    case WinCreated of	false ->	    done;	true ->	    catch gs:config(node_listbox, [{data, NodeDataList},					   {items, NodeTextList},					   {selection, MarkIndex}					  ])    end,    NewNode.create_window() ->    gs:window(win, gs:start(), [{width, ?WINDOW_WIDTH},				{height, ?WINDOW_HEIGHT},				{bg, ?DEFAULT_BG_COLOR},				{title, "[TV]   Connected nodes"},				{configure, true},				{destroy, true},				{cursor, arrow},				{keypress, true}			       ]),    gs:menubar(menubar, win, [{bg, ?DEFAULT_BG_COLOR}					]),    gs:menubutton(mbutt, menubar, [{bg, ?DEFAULT_BG_COLOR},				   {fg, {178, 34, 34}},  % firebrick				   {label, {text, " File "}},				   {underline, 1}				  ]),           % Create the actual menu!    gs:menu(menu, mbutt, [{bg, ?DEFAULT_BG_COLOR},			  {fg, {178, 34, 34}}]),     gs:menuitem(menu, [{bg, ?DEFAULT_BG_COLOR},		       {fg, {178, 34, 34}},		       {label, {text, " Close    Ctrl-C "}},		       {data, close_menu},		       {underline, 1}		      ]),    Xpos = 4,     Ypos = 40,    gs:listbox(node_listbox, win, [{x, Xpos},				   {y, Ypos},				   {width, ?WINDOW_WIDTH - 2 * Xpos},				   {height, ?WINDOW_HEIGHT - Ypos - Xpos},				   {bg, {255,255,255}},				   {vscroll, right},				   {hscroll, true},				   {click, true}			      ]).    

⌨️ 快捷键说明

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