%% %% %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% %%------------------------------------------------------------ %% %% Simple text viewer %% %%------------------------------------------------------------ -module(appmon_txt). -compile([{nowarn_deprecated_function,{gs,config,2}}, {nowarn_deprecated_function,{gs,create,3}}, {nowarn_deprecated_function,{gs,destroy,1}}, {nowarn_deprecated_function,{gs,read,2}}, {nowarn_deprecated_function,{gs,start,1}}]). -export([start/0, start/1, print/1, fprint/1]). %% gen_server stuff -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]). -define(LOADTXT, "Load file"). -define(SAVETXT, "Save file"). -define(SAVEASTXT, "Save as"). -define(CLOSETXT, "Close"). -define(HELPTXT, "Help"). %%------------------------------------------------------------ %% %% start/0 starts an open text viewer that can be filled with %% whatever. %% %%------------------------------------------------------------ start() -> start([]). %%------------------------------------------------------------ %% %% start(ListOfOptions) starts an open text viewer with options %% %% Options can be %% {file, FileName} - insert contents of file %% locked - the text cannot be edited %% {text, Text} - insert text at startup %% %%------------------------------------------------------------ start(Opts) -> gen_server:start_link({local, ?MODULE}, ?MODULE, Opts, []). %% Start a text viewer if necessary print(Txt) -> catch start(), gen_server:call(?MODULE, {add_txt, Txt}), ok. fprint(File) -> catch start(), gen_server:call(?MODULE, {add_file, File}), ok. %%------------------------------------------------------------ %% gen server admin init(Opts) -> process_flag(trap_exit, true), setup_base_win(), default_status(), setup_opts(Opts), {ok, []}. terminate(_Reason, _State) -> ok. %%------------------------------------------------------------ %% gen server stuff handle_call({add_txt, Txt}, _From, State) -> do_insert_text(Txt), scroll_to_last_line(), {reply, ok, State}; handle_call({add_file, FileName}, _From, State) -> do_load_file(FileName), {reply, ok, State}; handle_call(_Request, _From, State) -> {reply, ok, State}. handle_cast(_Request, State) -> {noreply, State}. handle_info({gs, _, click, _, [?CLOSETXT|_]}, State) -> {stop, normal, State}; handle_info({gs, _, click, _, [?LOADTXT|_]}, State) -> ui_load(), {noreply, State}; handle_info({gs, _, configure, _, [W, H | _]}, State) -> resize(W, H), {noreply, State}; handle_info({gs, _, destroy, _, _}, State) -> {stop, normal, State}; handle_info(Request, State) -> io:format("~p got info: ~p~n", [self(), Request]), print_status("Not implemented"), {noreply, State}. %%------------------------------------------------------------ %% Handle options setup_opts([Opt|Opts]) -> setup_opt(Opt), setup_opts(Opts); setup_opts([]) -> ok. setup_opt(Opt) -> case Opt of {file, FileName} -> do_load_file(FileName); locked -> do_lock(); {text, Text} -> do_insert_text(Text); _Other -> ok end. do_load_file(FileName) -> case catch i_load_file(FileName) of ok -> default_status(); _Other -> print_status(lists:append(["File not found: ", FileName])) end. i_load_file(FileName) -> {ok, Bin} = file:read_file(FileName), L = binary_to_list(Bin), i_do_clear(), do_insert_text(L), ok. ui_load() -> Title = "Load file", Files = get_file_list(), case catch ui_list_dialog(Title, "File: ", Files) of {ok, FileName} -> do_load_file(FileName); _Other -> print_status("Load cancelled") end. get_file_list() -> case file:list_dir(".") of {ok, FileList} -> lists:sort(FileList); _Other -> [] end. do_insert_text(Text) -> gs:config(editor(), {insert, {'end', Text}}), ok. %% Scrolls editor to show the last rows scroll_to_last_line() -> H = gs:read(editor(), size), R = gs:read(editor(), height), TopRow = H-R/15, if TopRow > 0 -> gs:config(editor(), {vscrollpos, TopRow}); true -> gs:config(editor(), {vscrollpos, 0}) end, ok. do_lock() -> gs:config(editor(), {enable, false}). i_do_clear() -> gs:config(editor(), clear). %%------------------------------------------------------------ %% Graphical stuff label_h() -> 20. menu_h() -> 29. setup_base_win() -> H = 400, W=580, LabelHeight=label_h(), MenuHeight=menu_h(), F = gs:start([{kernel,true}]), set_winroot(F), Win = gs:create(window, F, [{width, W}, {height, H}, {title,"APPMON: Process Information"}]), E = gs:create(editor, Win, [{x, 0}, {y, MenuHeight}, {width, W}, {height, H-MenuHeight-LabelHeight-1}, {vscroll, right}]), set_editor(E), L = gs:create(label, Win, [{x, 0}, {y, H-LabelHeight}, {height,LabelHeight }, {width, W}, {align, w}]), set_status(L), print_status("Loading"), gs:config(Win, {map, true}), MB = gs:create(menubar, Win, []), FMB = gs:create(menubutton, MB, [{label, {text, "File"}}]), FM = gs:create(menu, FMB, []), gs:create(menuitem, FM, [{label, {text, ?CLOSETXT}}]), gs:config(Win, {configure, true}), ok. resize(W, H) -> gs:config(editor(), [{width, W}, {height, H-label_h()-menu_h()}]), gs:config(status(), [{y, H-label_h()}, {width, W}]), ok. %%------------------------------------------------------------ %% ui_list_dialog( %% %% Traditional dialog with a list box and a selection field that %% is updated from the list box. %% %% Returns {ok, String} if successful and something else if not %% %% Title - the name of the window %% LeadText - the lead text on the selection field %% List - a list of items that will be displayed in the list box %% %%------------------------------------------------------------ ui_list_dialog(Title, LeadText, TxtList) -> W = 200, H = 300, Win = gs:create(window, winroot(), [{title, Title}, {width, W},{height, H}]), Ok = gs:create(button, Win, [{x, 10}, {y,10}, {width, 50}, {height, 20}, {label, {text, "Ok"}}]), Cn = gs:create(button, Win, [{x, 70}, {y,10}, {width, 50}, {height, 20}, {label, {text, "Cancel"}}]), gs:create(label, Win, [{x, 10}, {y, 50}, {width, 60}, {height, 20}, {label, {text, LeadText}}]), Box = gs:create(entry, Win, [{x, 10}, {y, 70}, {width, 160}, {height, 20}, {keypress, true}]), List = gs:create(listbox, Win, [{x, 10}, {y, 100}, {width, 180}, {height, 190}, {items, TxtList}, {vscroll, right}, {hscroll, false}, {click, true}, {doubleclick, true}, {keypress, true}]), gs:config(Win, {map, true}), RetVal = ui_load_loop(Box, List, Ok, Cn), gs:destroy(Win), RetVal. ui_load_loop(Box, List, Ok, Cn) -> receive {gs, Box, keypress, _, ['Return'|_]} -> {ok, gs:read(Box, text)}; {gs, Box, keypress, _, _} -> ui_load_loop(Box, List, Ok, Cn); {gs, Ok, click, _, _} -> {ok, gs:read(Box, text)}; {gs, List, doubleclick, _, [_Idx, Txt|_]} -> {ok, Txt}; {gs, List, click, _, [_Idx, Txt|_]} -> gs:config(Box, {text, Txt}), ui_load_loop(Box, List, Ok, Cn); _Other -> something_else end. %% The status row at the bottom of the window set_status(Id) -> put(status_row, Id). status() -> get(status_row). print_status(Msg) -> gs:config(get(status_row), {label, {text, Msg}}). default_status() -> print_status("Done"). set_editor(X) -> put(editor, X). editor() -> get(editor). winroot() -> get(winroot). set_winroot(X) -> put(winroot, X).