diff options
Diffstat (limited to 'lib/observer/src/observer_lib.erl')
-rw-r--r-- | lib/observer/src/observer_lib.erl | 225 |
1 files changed, 202 insertions, 23 deletions
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index f7712cf3da..ce85fb4af6 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -19,17 +19,24 @@ -module(observer_lib). -export([get_wx_parent/1, - display_info_dialog/1, user_term/3, user_term_multiline/3, + display_info_dialog/1, display_yes_no_dialog/1, + user_term/3, user_term_multiline/3, interval_dialog/4, start_timer/1, stop_timer/1, display_info/2, fill_info/2, update_info/2, to_str/1, create_menus/3, create_menu_item/3, create_attrs/0, - set_listctrl_col_size/2 + set_listctrl_col_size/2, + create_status_bar/1, + html_window/2 ]). -include_lib("wx/include/wx.hrl"). -include("observer_defs.hrl"). +-define(SINGLE_LINE_STYLE, ?wxBORDER_NONE bor ?wxTE_READONLY bor ?wxTE_RICH2). +-define(MULTI_LINE_STYLE, ?SINGLE_LINE_STYLE bor ?wxTE_MULTILINE). + + get_wx_parent(Window) -> Parent = wxWindow:getParent(Window), case wx:is_null(Parent) of @@ -101,6 +108,12 @@ display_info_dialog(Str) -> wxMessageDialog:destroy(Dlg), ok. +display_yes_no_dialog(Str) -> + Dlg = wxMessageDialog:new(wx:null(), Str, [{style,?wxYES_NO}]), + R = wxMessageDialog:showModal(Dlg), + wxMessageDialog:destroy(Dlg), + R. + %% display_info(Parent, [{Title, [{Label, Info}]}]) -> {Panel, Sizer, InfoFieldsToUpdate} display_info(Frame, Info) -> Panel = wxPanel:new(Frame), @@ -108,24 +121,50 @@ display_info(Frame, Info) -> Sizer = wxBoxSizer:new(?wxVERTICAL), wxSizer:addSpacer(Sizer, 5), Add = fun(BoxInfo) -> - {Box, InfoFs} = create_box(Panel, BoxInfo), - wxSizer:add(Sizer, Box, [{flag, ?wxEXPAND bor ?wxALL}, - {border, 5}]), - wxSizer:addSpacer(Sizer, 5), - InfoFs + case create_box(Panel, BoxInfo) of + {Box, InfoFs} -> + wxSizer:add(Sizer, Box, [{flag, ?wxEXPAND bor ?wxALL}, + {border, 5}]), + wxSizer:addSpacer(Sizer, 5), + InfoFs; + undefined -> + [] + end end, InfoFs = [Add(I) || I <- Info], wxWindow:setSizerAndFit(Panel, Sizer), {Panel, Sizer, InfoFs}. +fill_info([{dynamic, Key}|Rest], Data) + when is_atom(Key); is_function(Key) -> + %% Special case used by crashdump_viewer when the value decides + %% which header to use + case get_value(Key, Data) of + undefined -> fill_info(Rest, Data); + {Str,Value} -> [{Str, Value} | fill_info(Rest, Data)] + end; fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) -> - [{Str, get_value(Key, Data)} | fill_info(Rest, Data)]; + case get_value(Key, Data) of + undefined -> fill_info(Rest, Data); + Value -> [{Str, Value} | fill_info(Rest, Data)] + end; +fill_info([{Str,Attrib,Key}|Rest], Data) when is_atom(Key); is_function(Key) -> + case get_value(Key, Data) of + undefined -> fill_info(Rest, Data); + Value -> [{Str,Attrib,Value} | fill_info(Rest, Data)] + end; fill_info([{Str, {Format, Key}}|Rest], Data) when is_atom(Key); is_function(Key), is_atom(Format) -> case get_value(Key, Data) of - undefined -> [{Str, undefined} | fill_info(Rest, Data)]; + undefined -> fill_info(Rest, Data); Value -> [{Str, {Format, Value}} | fill_info(Rest, Data)] end; +fill_info([{Str, Attrib, {Format, Key}}|Rest], Data) + when is_atom(Key); is_function(Key), is_atom(Format) -> + case get_value(Key, Data) of + undefined -> fill_info(Rest, Data); + Value -> [{Str, Attrib, {Format, Value}} | fill_info(Rest, Data)] + end; fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) -> [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)]; fill_info([{Str,Attrib,SubStructure}|Rest], Data) -> @@ -147,13 +186,18 @@ update_info([], []) -> ok. update_info2([Field|Fs], [{_Str, Value}|Rest]) -> - wxStaticText:setLabel(Field, to_str(Value)), + wxTextCtrl:setValue(Field, to_str(Value)), update_info2(Fs, Rest); update_info2([], []) -> ok. to_str(Value) when is_atom(Value) -> atom_to_list(Value); +to_str({Unit, X}) when (Unit==bytes orelse Unit==time_ms) andalso is_list(X) -> + try list_to_integer(X) of + B -> to_str({Unit,B}) + catch error:badarg -> X + end; to_str({bytes, B}) -> KB = B div 1024, MB = KB div 1024, @@ -289,26 +333,142 @@ get_box_info({Title, List}) when is_list(List) -> {Title, ?wxALIGN_LEFT, List}; get_box_info({Title, left, List}) -> {Title, ?wxALIGN_LEFT, List}; get_box_info({Title, right, List}) -> {Title, ?wxALIGN_RIGHT, List}. +create_box(_Panel, {scroll_boxes,[]}) -> + undefined; +create_box(Panel, {scroll_boxes,Data}) -> + OuterBox = wxBoxSizer:new(?wxHORIZONTAL), + Cursor = wxCursor:new(?wxCURSOR_HAND), + AddBox = fun({Title,Proportion,{Format,List}}) -> + Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, + [{label, Title}]), + Scroll = wxScrolledWindow:new(Panel), + wxScrolledWindow:enableScrolling(Scroll,true,true), + wxScrolledWindow:setScrollbars(Scroll,1,1,0,0), + ScrollSizer = wxBoxSizer:new(?wxVERTICAL), + wxScrolledWindow:setSizer(Scroll, ScrollSizer), + BC = wxWindow:getBackgroundColour(Panel), + wxWindow:setBackgroundColour(Scroll,BC), + case Format of + click -> + [begin + TC = link_entry(Scroll, Link, Cursor), + wxWindow:setBackgroundColour(TC,BC), + wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}]) + end || Link <- List]; + plain -> + [begin + TC = wxTextCtrl:new(Scroll, ?wxID_ANY, + [{style,?SINGLE_LINE_STYLE}, + {value,String}]), + wxSizer:add(ScrollSizer,TC,[{flag,?wxEXPAND}]) + end || String <- List] + end, + wxSizer:add(Box,Scroll,[{flag,?wxEXPAND}]), + wxSizer:add(OuterBox,Box, + [{proportion,Proportion},{flag,?wxEXPAND}]), + {Scroll,length(List)} + end, + Boxes = [AddBox(Entry) || Entry <- Data], + wxCursor:destroy(Cursor), + + MaxL = lists:foldl(fun({_,L},Max) when L>Max -> L; + (_,Max) -> Max + end, + 0, + Boxes), + + Dummy = wxTextCtrl:new(Panel, ?wxID_ANY, [{style, ?SINGLE_LINE_STYLE}]), + {_,H} = wxWindow:getSize(Dummy), + wxTextCtrl:destroy(Dummy), + + MaxH = if MaxL > 8 -> 8*H; + true -> MaxL*H + end, + [wxWindow:setMinSize(B,{0,MaxH}) || {B,_} <- Boxes], + wxSizer:layout(OuterBox), + {OuterBox, []}; + create_box(Panel, Data) -> {Title, Align, Info} = get_box_info(Data), - Box = wxStaticBoxSizer:new(?wxHORIZONTAL, Panel, [{label, Title}]), - Left = wxBoxSizer:new(?wxVERTICAL), - Right = wxBoxSizer:new(?wxVERTICAL), - Expand = [{flag, ?wxEXPAND}], - ExpAlign = [{flag, Align}], - AddRow = fun({Desc, Value}) -> - wxSizer:add(Left, wxStaticText:new(Panel, ?wxID_ANY, Desc ++ ":"), Expand), - Field = wxStaticText:new(Panel, ?wxID_ANY, to_str(Value)), - wxSizer:add(Right, Field, ExpAlign), + Box = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, Title}]), + LeftSize = get_max_size(Panel,Info), + LeftProportion = [{proportion,0}], + RightProportion = [{proportion,1}, {flag, Align bor ?wxEXPAND}], + AddRow = fun({Desc0, Value0}) -> + Desc = Desc0++":", + Line = wxBoxSizer:new(?wxHORIZONTAL), + wxSizer:add(Line, + wxTextCtrl:new(Panel, ?wxID_ANY, + [{style,?SINGLE_LINE_STYLE}, + {size,LeftSize}, + {value,Desc}]), + LeftProportion), + Field = + case Value0 of + {click,"unknown"} -> + wxTextCtrl:new(Panel, ?wxID_ANY, + [{style,?MULTI_LINE_STYLE}, + {value,"unknown"}]); + {click,Value} -> + link_entry(Panel,{Value,Value}); + _ -> + Value = to_str(Value0), + wxTextCtrl:new(Panel, ?wxID_ANY, + [{style,?MULTI_LINE_STYLE}, + {value,Value}]) + end, + wxSizer:add(Line, 10, 0), % space of size 10 horisontally + wxSizer:add(Line, Field, RightProportion), + + {_,H,_,_} = wxTextCtrl:getTextExtent(Field,"W"), + wxTextCtrl:setMinSize(Field,{0,H}), + + wxSizer:add(Box, Line, [{proportion,0},{flag,?wxEXPAND}]), Field end, InfoFields = [AddRow(Entry) || Entry <- Info], - wxSizer:add(Box, Left), - wxSizer:addSpacer(Box, 10), - wxSizer:add(Box, Right), - wxSizer:addSpacer(Box, 30), {Box, InfoFields}. +link_entry(Panel, Link) -> + Cursor = wxCursor:new(?wxCURSOR_HAND), + TC = link_entry(Panel, Link, Cursor), + wxCursor:destroy(Cursor), + TC. +link_entry(Panel,{Target,Str},Cursor) -> + TC = wxTextCtrl:new(Panel, ?wxID_ANY, + [{style, ?SINGLE_LINE_STYLE}]), + wxTextCtrl:setForegroundColour(TC,?wxBLUE), + wxTextCtrl:appendText(TC, Str), + wxWindow:setCursor(TC, Cursor), + wxTextCtrl:connect(TC, left_down, [{userData,Target}]), + wxTextCtrl:connect(TC, enter_window), + wxTextCtrl:connect(TC, leave_window), + ToolTip = wxToolTip:new("Click to see properties for " ++ Target), + wxWindow:setToolTip(TC, ToolTip), + TC. + +html_window(Panel,Html) -> + Win = wxHtmlWindow:new(Panel, [{style, ?wxHW_SCROLLBAR_AUTO}]), + wxHtmlWindow:setPage(Win,Html), + wxHtmlWindow:connect(Win,command_html_link_clicked), + Win. + +get_max_size(Panel,Info) -> + Txt = wxTextCtrl:new(Panel, ?wxID_ANY, []), + Size = get_max_size(Txt,Info,0,0), + wxTextCtrl:destroy(Txt), + Size. + +get_max_size(Txt,[{Desc,_}|Info],MaxX,MaxY) -> + {X,Y,_,_} = wxTextCtrl:getTextExtent(Txt,Desc++":"), + if X>MaxX -> + get_max_size(Txt,Info,X,Y); + true -> + get_max_size(Txt,Info,MaxX,MaxY) + end; +get_max_size(_,[],X,Y) -> + {X+2,Y}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set_listctrl_col_size(LCtrl, Total) -> wx:batch(fun() -> calc_last(LCtrl, Total) end). @@ -430,3 +590,22 @@ ensure_last_is_dot(String) -> false -> String ++ "." end. + +%%%----------------------------------------------------------------- +%%% Status bar for warnings +create_status_bar(Panel) -> + StatusStyle = ?wxTE_MULTILINE bor ?wxTE_READONLY bor ?wxTE_RICH2, + Red = wxTextAttr:new(?wxRED), + + %% wxTextCtrl:setSize/3 does not work, so we must create a dummy + %% text ctrl first to get the size of the text, then set it when + %% creating the real text ctrl. + Dummy = wxTextCtrl:new(Panel, ?wxID_ANY,[{style,StatusStyle}]), + {X,Y,_,_} = wxTextCtrl:getTextExtent(Dummy,"WARNING"), + wxTextCtrl:destroy(Dummy), + StatusBar = wxTextCtrl:new(Panel, ?wxID_ANY, + [{style,StatusStyle}, + {size,{X,Y+2}}]), % Y+2 to avoid scrollbar + wxTextCtrl:setDefaultStyle(StatusBar,Red), + wxTextAttr:destroy(Red), + StatusBar. |