4
%% Copyright Ericsson AB 2009. All Rights Reserved.
4
%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
6
6
%% The contents of this file are subject to the Erlang Public License,
7
7
%% Version 1.1, (the "License"); you may not use this file except in
8
8
%% compliance with the License. You should have received a copy of the
9
9
%% Erlang Public License along with this software. If not, it can be
10
10
%% retrieved online at http://www.erlang.org/.
12
12
%% Software distributed under the License is distributed on an "AS IS"
13
13
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
14
14
%% the License for the specific language governing rights and limitations
15
15
%% under the License.
19
19
-module(reltool_mod_win).
89
89
start_link(WxEnv, Xref, RelPid, Common, ModName) ->
90
proc_lib:start_link(?MODULE, init, [self(), WxEnv, Xref, RelPid, Common, ModName], infinity, []).
90
proc_lib:start_link(?MODULE,
92
[self(), WxEnv, Xref, RelPid, Common, ModName],
93
97
reltool_utils:cast(Pid, raise).
129
133
%% io:format("~s~p -> ~p\n", [S#state.name, self(), Msg]),
131
135
{system, From, SysMsg} ->
132
136
Dbg = C#common.sys_debug,
133
sys:handle_system_msg(SysMsg, From, S#state.parent_pid, ?MODULE, Dbg, S);
137
sys:handle_system_msg(SysMsg,
134
143
{cast, _From, raise} ->
135
144
wxFrame:raise(S#state.frame),
136
145
wxFrame:setFocus(S#state.frame),
204
213
Panel = wxPanel:new(S#state.book, []),
205
214
Main = wxBoxSizer:new(?wxHORIZONTAL),
207
UsedByCtrl = create_mods_list_ctrl(Panel, Main, "Modules used by others", " and their applications"),
216
UsedByCtrl = create_mods_list_ctrl(Panel,
218
"Modules used by others",
219
" and their applications"),
208
220
wxSizer:add(Main,
209
221
wxStaticLine:new(Panel, [{style, ?wxLI_VERTICAL}]),
210
222
[{border, 2}, {flag, ?wxALL bor ?wxEXPAND}]),
211
UsesCtrl = create_mods_list_ctrl(Panel, Main, "Used modules", " and their applications"),
223
UsesCtrl = create_mods_list_ctrl(Panel,
226
" and their applications"),
212
227
S2 = S#state{deps_used_by_ctrl = UsedByCtrl,
213
228
deps_uses_ctrl = UsesCtrl},
242
257
%% wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, ?MODS_APP_COL_WIDTH),
243
258
wxListItem:destroy(ListItem),
245
wxEvtHandler:connect(ListCtrl, size, [{skip, true}, {userData, mods_list_ctrl}]),
246
wxListCtrl:connect(ListCtrl, command_list_item_activated, [{userData, open_app}]),
260
wxEvtHandler:connect(ListCtrl, size,
261
[{skip, true}, {userData, mods_list_ctrl}]),
262
wxListCtrl:connect(ListCtrl, command_list_item_activated,
263
[{userData, open_app}]),
247
264
wxWindow:connect(ListCtrl, enter_window),
249
266
wxSizer:add(Sizer, ListCtrl,
288
306
do_create_code_page(#state{xref_pid = Xref, mod = M} = S, PageName) ->
289
307
Panel = wxPanel:new(S#state.book, []),
290
308
Editor = create_editor(Panel),
291
ToolTip = "Double click on a function call to search the function definition.",
309
ToolTip = "Double click on a function call to "
310
"search the function definition.",
292
311
wxBitmapButton:setToolTip(Editor, ToolTip),
293
312
{Objs, Data, SearchSz} = create_search_area(Panel),
295
314
{ok, App} = reltool_server:get_app(Xref, M#mod.app_name),
297
316
case App#app.is_escript of
298
317
true -> find_escript_bin(App, M);
299
318
false -> find_regular_bin(App, M)
302
321
load_code(Editor, ErlBin),
304
323
Sizer = wxBoxSizer:new(?wxVERTICAL),
305
324
wxSizer:add(Sizer, Editor, [{flag, ?wxEXPAND}, {proportion, 1}]),
306
325
wxSizer:add(Sizer, SearchSz, [{flag, ?wxEXPAND}]),
307
326
wxPanel:setSizer(Panel, Sizer),
308
327
wxNotebook:addPage(S#state.book, Panel, PageName, []),
309
#code_page{name = PageName, editor = Editor, find_objs = Objs, find_data = Data}.
328
#code_page{name = PageName,
311
333
find_regular_bin(App, Mod) ->
312
334
ActiveDir = App#app.active_dir,
313
335
SrcDir = filename:join([ActiveDir, "src"]),
314
336
ModStr = atom_to_list(Mod#mod.name),
315
Base = ModStr ++ ".erl",
316
Find = fun(F, _Acc) -> file:read_file(F) end,
317
case filelib:fold_files(SrcDir, Base, true, Find, {error, enoent}) of
337
Base = "^" ++ ModStr ++ "\\.erl$",
338
Find = fun(F, _Acc) -> throw(file:read_file(F)) end,
339
case catch filelib:fold_files(SrcDir, Base, true, Find, {error, enoent}) of
320
342
{error, enoent} ->
322
344
BeamFile = filename:join([ActiveDir, "ebin", ModStr ++ ".beam"]),
323
345
case beam_lib:chunks(BeamFile, [abstract_code]) of
324
346
{ok,{_,[{abstract_code,{_,AC}}]}} ->
325
list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)));
347
IoList = erl_prettypr:format(erl_syntax:form_list(AC)),
348
list_to_binary(IoList);
327
list_to_binary(["%% Bad luck, cannot find any debug info in the file \"", BeamFile])
350
list_to_binary(["%% Bad luck, cannot find any "
351
"debug info in the file \"", BeamFile])
342
366
case beam_lib:version(Bin) of
343
{ok,{M, _}} when M =:= ModName; FullName =:= "." ->
344
case beam_lib:chunks(Bin, [abstract_code]) of
367
{ok,{M, _}} when M =:= ModName;
369
case beam_lib:chunks(Bin,
345
371
{ok,{_,[{abstract_code,{_,AC}}]}} ->
346
{obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))};
373
erl_syntax:form_list(AC),
375
erl_prettypr:format(Form),
377
list_to_binary(IoList)};
363
394
{fun(FullName, _GetInfo, GetBin, Acc) ->
364
395
io:format("", []),
365
396
case filename:split(FullName) of
366
[_AppName, "ebin", F] when F =:= ObjFile, Acc =:= NotFound ->
367
case beam_lib:chunks(GetBin(), [abstract_code]) of
397
[_AppName, "ebin", F]
398
when F =:= ObjFile, Acc =:= NotFound ->
399
case beam_lib:chunks(GetBin(),
368
401
{ok,{_,[{abstract_code,{_,AC}}]}} ->
369
{obj, list_to_binary(erl_prettypr:format(erl_syntax:form_list(AC)))};
402
Form = erl_syntax:form_list(AC),
403
IoList = erl_prettypr:format(Form),
404
{obj, list_to_binary(IoList)};
379
414
filename:dirname(ActiveDir)}
382
case escript:foldl(Fun, NotFound, Escript) of
417
case reltool_utils:escript_foldl(Fun, NotFound, Escript) of
383
418
{ok, {text, Bin}} ->
385
420
{ok, {obj, Bin}} ->
388
list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, "."])
423
list_to_binary(["%% Bad luck, cannot find the "
424
"code in the escript ", Escript, "."])
391
427
throw:Reason when is_list(Reason) ->
392
list_to_binary(["%% Bad luck, cannot find the code in the escript ", Escript, ": ", Reason])
428
list_to_binary(["%% Bad luck, cannot find the code "
429
"in the escript ", Escript, ": ", Reason])
395
432
create_config_page(S) ->
400
437
handle_event(#state{xref_pid = Xref} = S, Wx) ->
401
438
%% io:format("wx: ~p\n", [Wx]),
403
#wx{obj= ListCtrl, userData = mods_list_ctrl, event = #wxSize{type = size, size = {W, _H}}} ->
441
userData = mods_list_ctrl,
442
event = #wxSize{type = size, size = {W, _H}}} ->
404
443
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_MOD_COL, (2 * W) div 3),
405
444
wxListCtrl:setColumnWidth(ListCtrl, ?MODS_APP_COL, W div 3),
407
446
#wx{userData = open_app,
409
event = #wxList{type = command_list_item_activated, itemIndex = Pos}} ->
448
event = #wxList{type = command_list_item_activated,
410
450
ModStr = wxListCtrl:getItemText(ListCtrl, Pos),
411
451
ModName = list_to_atom(ModStr),
412
452
{ok, Mod} = reltool_server:get_mod(Xref, ModName),
458
500
undefined -> "Source - "
460
502
Status = lists:concat([InclStatus,
461
" uses ", length(UsesModNames), " modules and ",
462
" is used by ", length(UsedByModNames), " modules."]),
503
" uses ", length(UsesModNames),
505
" is used by ", length(UsedByModNames),
463
507
wxStatusBar:setStatusText(Bar, Status),
464
508
UsesMods = [select_image(Xref, M) || M <- UsesModNames],
465
509
UsedByMods = [select_image(Xref, M) || M <- UsedByModNames],
535
581
wxTextCtrl:setValue(TextCtrl, Str),
538
find_string(#state{active_page = #code_page{editor = Editor,
539
find_objs = #find_objs{radio={NextO,_,CaseO}},
540
find_data = #find_data{found = Found} = Data} = P} = S,
584
find_string(#state{active_page =
585
#code_page{editor = Editor,
586
find_objs = #find_objs{radio={NextO,_,CaseO}},
587
find_data = #find_data{found = Found} = Data} = P} = S,
543
590
wxStyledTextCtrl:hideSelection(Editor, true),
544
591
Dir = wxRadioButton:getValue(NextO) xor wx_misc:getKeyState(?WXK_SHIFT),
545
592
Case = wxCheckBox:getValue(CaseO),
548
595
Found, Dir -> %% Forward Continuation
549
596
wxStyledTextCtrl:getAnchor(Editor);
550
Found -> %% Backward Continuation
597
Found -> %% Backward Continuation
551
598
wxStyledTextCtrl:getCurrentPos(Editor);
552
599
Dir -> %% Forward wrap
557
604
wxStyledTextCtrl:gotoPos(Editor,Pos),
558
605
wxStyledTextCtrl:searchAnchor(Editor),
560
607
if Case -> Flag bor ?wxSTC_FIND_MATCHCASE;
565
612
Dir -> wxStyledTextCtrl:searchNext(Editor, Flag2, Str);
566
613
true -> wxStyledTextCtrl:searchPrev(Editor, Flag2, Str)
571
618
wxStyledTextCtrl:hideSelection(Editor, false),
572
619
%% io:format("Found ~p ~n",[Res]),
573
620
LineNo = wxStyledTextCtrl:lineFromPosition(Editor,Res),
623
674
find_regexp_forward(S, "^" ++ FunName ++ "(");
624
675
do_goto_function(S, [ModStr, FunStr]) ->
625
676
case reltool_server:get_mod(S#state.xref_pid, list_to_atom(ModStr)) of
626
{ok, Mod} when Mod#mod.app_name =/= ?MISSING_APP ->
677
{ok, Mod} when Mod#mod.app_name =/= ?MISSING_APP_NAME ->
627
678
S2 = create_code_page(S#state{mod = Mod}, ModStr),
628
679
find_regexp_forward(S2, "^" ++ FunStr ++ "(");
630
wxStatusBar:setStatusText(S#state.status_bar, "No such module: " ++ ModStr),
681
wxStatusBar:setStatusText(S#state.status_bar,
682
"No such module: " ++ ModStr),
634
goto_back(#state{active_page = #code_page{editor = Editor, find_data = Data} = Page,
686
goto_back(#state{active_page =
687
#code_page{editor = Editor, find_data = Data} = Page,
635
688
code_pages = Pages} = S) ->
636
689
case Data#find_data.history of
637
690
[PrevPos | History] ->
638
691
LineNo = wxStyledTextCtrl:lineFromPosition(Editor, PrevPos),
639
692
Data2 = Data#find_data{history = History},
640
693
Page2 = Page#code_page{find_data = Data2},
641
Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
642
goto_line(S#state{active_page = Page2, code_pages = Pages2}, LineNo);
694
Pages2 = lists:keystore(Page2#code_page.name,
698
goto_line(S#state{active_page = Page2, code_pages = Pages2},
644
701
wxStatusBar:setStatusText(S#state.status_bar, "No history"),
648
add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S, CurrentPos) ->
705
add_pos_to_history(#state{active_page = Page, code_pages = Pages} = S,
649
707
Data = Page#code_page.find_data,
650
708
Data2 = Data#find_data{history = [CurrentPos | Data#find_data.history]},
651
709
Page2 = Page#code_page{find_data = Data2},
652
Pages2 = lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
711
lists:keystore(Page2#code_page.name, #code_page.name, Pages, Page2),
653
712
S#state{active_page = Page2, code_pages = Pages2}.
655
714
create_editor(Parent) ->
685
744
wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont),
686
745
wxStyledTextCtrl:styleSetForeground(Ed, Style, Color)
688
[SetStyle(Style) || Style <- Styles],
747
lists:foreach(fun (Style) -> SetStyle(Style) end, Styles),
689
748
wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()),
691
750
%% Margins Markers
692
751
%% Breakpoint Should be a pixmap?
693
wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{foreground, {170,20,20}}]),
694
wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE, [{background, {200,120,120}}]),
695
%% Disabled Breakpoint
696
wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{foreground, {20,20,170}}]),
697
wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE, [{background, {120,120,200}}]),
752
wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE,
753
[{foreground, {170,20,20}}]),
754
wxStyledTextCtrl:markerDefine(Ed, 0, ?wxSTC_MARK_CIRCLE,
755
[{background, {200,120,120}}]),
756
%% Disabled Breakpoint
757
wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE,
758
[{foreground, {20,20,170}}]),
759
wxStyledTextCtrl:markerDefine(Ed, 1, ?wxSTC_MARK_CIRCLE,
760
[{background, {120,120,200}}]),
700
wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{foreground, {20,170,20}}]),
701
wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW, [{background, {200,255,200}}]),
702
wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND, [{background, {200,255,200}}]),
763
wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW,
764
[{foreground, {20,170,20}}]),
765
wxStyledTextCtrl:markerDefine(Ed, 2, ?wxSTC_MARK_ARROW,
766
[{background, {200,255,200}}]),
767
wxStyledTextCtrl:markerDefine(Ed, 3, ?wxSTC_MARK_BACKGROUND,
768
[{background, {200,255,200}}]),
705
Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN,
771
Policy = ?wxSTC_CARET_SLOP bor ?wxSTC_CARET_JUMPS bor ?wxSTC_CARET_EVEN,
706
772
wxStyledTextCtrl:setYCaretPolicy(Ed, Policy, 3),
707
773
wxStyledTextCtrl:setVisiblePolicy(Ed, Policy, 3),
715
781
create_search_area(Parent) ->
716
782
Sizer = wxBoxSizer:new(?wxHORIZONTAL),
717
wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
783
wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
718
784
[{flag,?wxALIGN_CENTER_VERTICAL}]),
719
TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
785
TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
720
786
wxSizer:add(Sizer, TC1, [{proportion,3}, {flag, ?wxEXPAND}]),
721
787
Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"),
722
788
wxRadioButton:setValue(Nbtn, true),
726
792
Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"),
727
793
wxSizer:add(Sizer,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
728
794
wxSizer:add(Sizer, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]),
729
wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
795
wxSizer:add(Sizer, wxStaticText:new(Parent, ?wxID_ANY, "Goto Line:"),
730
796
[{flag,?wxALIGN_CENTER_VERTICAL}]),
731
TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
797
TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
732
798
wxSizer:add(Sizer, TC2, [{proportion,0}, {flag, ?wxEXPAND}]),
733
799
Button = wxButton:new(Parent, ?wxID_ANY, [{label, "Back"}]),
734
800
wxSizer:add(Sizer, Button, []),
736
wxEvtHandler:connect(Button, command_button_clicked, [{userData, history_back}]),
802
wxEvtHandler:connect(Button, command_button_clicked,
803
[{userData, history_back}]),
737
804
%% wxTextCtrl:connect(TC1, command_text_updated),
738
805
wxTextCtrl:connect(TC1, command_text_enter),
739
806
%% wxTextCtrl:connect(TC1, kill_focus),
748
815
wxStyledTextCtrl:setTextRaw(Ed, <<Code/binary, 0:8>>),
749
816
Lines = wxStyledTextCtrl:getLineCount(Ed),
750
817
Sz = trunc(math:log10(Lines))+1,
751
LW = wxStyledTextCtrl:textWidth(Ed, ?wxSTC_STYLE_LINENUMBER, lists:duplicate(Sz, $9)),
818
LW = wxStyledTextCtrl:textWidth(Ed,
819
?wxSTC_STYLE_LINENUMBER,
820
lists:duplicate(Sz, $9)),
752
821
%%io:format("~p ~p ~p~n", [Lines, Sz, LW]),
753
822
wxStyledTextCtrl:setMarginWidth(Ed, 0, LW+5),
754
823
wxStyledTextCtrl:setReadOnly(Ed, true),