%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 1996-2009. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. %% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. %% %% %CopyrightEnd% %%------------------------------------------------------------ %% %% Digraph handling for process view GUI. Feeble attempt at data %% separation. Provides functional interface to the data structures %% vdata and edata, v for vertex and e for edge. %% %%------------------------------------------------------------ -module(appmon_dg). -include("appmon_dg.hrl"). %% Exports for vertices -export([get/3, get/2, set/4, av/3, add/4, del/2, visited/3]). %% Exports for edges -export([eget/2, eget/3, eset/4, eadd/4, edel/2, ae/3]). %% Exports for convenience -export([print_dg/1]). %%------------------------------------------------------------ eget(all, DG) -> digraph:edges(DG). eget(data, DG, E) -> case digraph:edge(DG, E) of {_, _V1, _V2, Data} -> Data; _Other -> false end; eget(edge, DG, {V1, V2}) -> case digraph:edge(DG, {V1, V2}) of {E, W1, W2, ED} -> {E, W1, W2, ED}; Other -> case digraph:edge(DG, {V2, V1}) of {E, W1, W2, ED} -> {E, W1, W2, ED}; Other -> false end end; %% Weight in edge name eget(edge, DG, {V1, V2, Weight}) -> case digraph:edge(DG, {V1, V2, Weight}) of {E, W1, W2, ED} -> {E, W1, W2, ED}; _Other -> false end; eget(in, DG, V) -> efilter(digraph:in_edges(DG, V)). efilter(Es) -> lists:filter(fun({_V1, _V2, primary}) -> true; (_E) -> false end, Es). eset(ref, DG, E, Ref) -> {E2, _V1, _V2, D} = eget(edge, DG, E), update_e(DG, E2, D#edata{ref=Ref}); eset(line, DG, E, Line) -> {E2, _V1, _V2, D} = eget(edge, DG, E), update_e(DG, E2, D#edata{line=Line}). edel(DG, E) -> digraph:del_edge(DG, E). eadd(DG, E, D, Ref) -> case eget(edge, DG, E) of {_, _, _, ED} when is_record(ED, edata), ED#edata.ref == Ref -> known; {_, _, _, ED} when is_record(ED, edata), ED#edata.ref /= Ref -> update_e(DG, E, ED#edata{ref=Ref}), updated; _Other -> ae(DG, E, D) end. ae(DG, {V1, V2, Weight}, D) -> digraph:add_edge(DG, {V1, V2, Weight}, V1, V2, D). update_e(DG, {V1, V2, Weight}, D) -> digraph:del_edge(DG, {V1, V2, Weight}), digraph:add_edge(DG, {V1, V2, Weight}, V1, V2, D). %% Filter destination vertex from a list of edges vfilter(Vs) -> lists:map(fun({_V1, V2, _Weight}) -> V2; ({_V1, V2}) -> V2 end, Vs). get(all, DG) -> digraph:vertices(DG). get(data, DG, {V1, V2}) -> case digraph:edge(DG, {V1, V2}) of {_,_,_,Data} -> Data; _Other -> false end; get(data, DG, V) -> case digraph:vertex(DG, V) of {_,Data} -> Data; _Other -> false end; %% Return all children of vertex V (those which V has edges to) get(out, DG, V) -> vfilter(efilter(digraph:out_edges(DG, V))); get(in, DG, V) -> digraph:in_neighbours(DG, V); get(edges, DG, V) -> digraph:edges(DG, V); get(w, DG, V) -> Data = get(data, DG, V), Data#vdata.width; get(x, DG, V) -> Data = get(data, DG, V), Data#vdata.x. set(type, DG, V, Type) -> D = get(data, DG, V), av(DG, V, D#vdata{type=Type}); set(ref, DG, V, Ref) -> D = get(data, DG, V), av(DG, V, D#vdata{ref=Ref}); set(y, DG, V, Y) -> D = get(data, DG, V), av(DG, V, D#vdata{y=Y}); set(data, DG, V, D) when is_record(D, vdata)-> av(DG, V, D); set(x, DG, V, X) -> D = get(data, DG, V), if D#vdata.x /= X -> av(DG, V, D#vdata{x=X}); true -> true end. visited(DG, {V1, V2}, Ref) -> % for edge D = eget(data, DG, {V1, V2}), if is_record(D, edata), D#edata.ref == Ref -> true; true -> false end; visited(DG, V, Ref) -> D = get(data, DG, V), if is_record(D, vdata), D#vdata.ref == Ref -> true; true -> false end. add(DG, V, D, Ref) -> case get(data, DG, V) of D2 when is_record(D2, vdata), D2#vdata.ref==Ref -> io:format("Ooops in ~p:add vertex~n", [?MODULE]), known; D2 when is_record(D2, vdata) -> %%io:format("~p touch vertex ~p~n", [self(), V]), set(ref, DG, V, Ref), set(type, DG, V, D#vdata.type), save_coords(DG, V), updated; _Other -> av(DG, V, D), added end. save_coords(DG, V) -> D = get(data, DG, V), D2 = D#vdata{origx=D#vdata.x, origy=D#vdata.y}, av(DG, V, D2). del(DG, V) -> digraph:del_vertex(DG, V). av(DG, V, D) -> digraph:add_vertex(DG, V, D). print_dg(DG) -> io:format("Vertices:~n", []), lists:foreach(fun(V) -> io:format(" ~p ~p~n", [V, get(data, DG, V)]) end, get(all, DG)), io:format("Edges:~n", []), lists:foreach(fun(V) -> io:format(" ~p ~p~n", [V, eget(edge, DG, V)]) end, eget(all, DG)), true.