%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% %CopyrightEnd%
%%
%%
%% ------------------------------------------------------------
%% File Selection Dialog
%% ------------------------------------------------------------
-module(file_dialog).
-compile([{nowarn_deprecated_function,{gs,config,2}},
{nowarn_deprecated_function,{gs,create,4}},
{nowarn_deprecated_function,{gs,label,2}},
{nowarn_deprecated_function,{gs,read,2}},
{nowarn_deprecated_function,{gs,start,0}}]).
-export([start/0,start/1,start/2,fs_init/3]).
-include_lib("kernel/include/file.hrl").
%% ----- File Selection ----
start() ->
{ok,Dir}=file:get_cwd(),
start(Dir,[]).
start(Dir) ->
start(Dir,[]).
start(Dir,File) ->
Dir0 = case lists:last(Dir) of
$/ -> Dir;
_ -> lists:append(Dir,"/")
end,
Pid=spawn(file_dialog,fs_init,[Dir0,File,self()]),
receive
{file_dialog,Pid,Result} -> Result
end.
%% ------------------------------------------------------------
fs_init(Dir,File,Owner) ->
S=gs:start(),
gs:create(window,win,S,[{width,250},{height,265},{title,"File Dialog"},
{configure,true}]),
gs:create(label,label,win,[{y,0},{width,250},{label, {text,Dir}}]),
gs:label(win,[{width,50},{y,30},{x,5},{label, {text,"File:"}}]),
gs:create(entry,entry,win,[{y,30},{width,190},{x,55},
{keypress,true},{focus,true}]),
gs:create(listbox,lb,win,[{x,5},{y,60},{width,160},{height,199},
{vscroll,right},{click,true},{doubleclick,true}]),
gs:create(button,ok,win,[{label, {text,"OK"}},{width,40},{x,185},{y,170}]),
gs:create(button,cancel,win,[{label, {text,"Cancel"}},{x,175},{y,220},{width,65}]),
Items=refresh(Dir),
%% --- select File if it's given ---
case index_member(File,Items) of
{ok,Index} ->
gs:config(lb,{selection,clear}),
gs:config(lb,{selection,Index});
_ -> true
end,
gs:config(win,{map,true}),
fs_loop(Dir,Owner).
fs_loop(Dir,Owner) ->
receive
{gs,ok,click,_,_} ->
entered_name(Dir,Owner);
{gs,cancel,click,_,_} ->
Owner ! {file_dialog,self(),cancel};
{gs,entry,keypress,_,['Return'|_]} ->
entered_name(Dir,Owner);
{gs,entry,keypress,_,[_Keysym|_]} ->
fs_loop(Dir,Owner);
{gs,lb,click,_,_} ->
clicked(Dir,Owner);
{gs,lb,doubleclick,_,_} ->
double_clicked(Dir,Owner);
{gs,win,configure,_,[250,265|_]} -> % already got that size
fs_loop(Dir,Owner);
{gs,win,configure,_,_} ->
gs:config(win,[{geometry,{250,265}}]),
fs_loop(Dir,Owner);
stop ->
exit(normal);
{gs,_,destroy,_,_} ->
Owner ! {file_dialog,self(),cancel};
X ->
io:format("file_dialog: got other: ~w.~n",[X]),
fs_loop(Dir,Owner)
end.
refresh(Dir) ->
gs:config(lb,clear),
gs:config(label,{label, {text,Dir}}),
gs:config(entry,{text,""}),
Items=["../"|get_files(Dir)],
gs:config(lb,[{items,Items}]),
Items.
entered_name(Dir,Owner) ->
File=gs:read(entry,text),
case check_file(Dir,File) of
{file,Dir2,File2} ->
Owner ! {file_dialog,self(),{ok,Dir2,File2}};
{dir,Dir2} ->
refresh(Dir2),
fs_loop(Dir2,Owner);
{error,no_file} ->
double_clicked(Dir,Owner);
_ ->
fs_loop(Dir,Owner)
end.
clicked(Dir,Owner) ->
[Idx|_]=gs:read(lb,selection),
File=gs:read(lb,{get,Idx}),
case lists:last(File) of
$/ -> %it's a dir
true;
_ -> % it's a file
gs:config(entry,{text,File})
end,
fs_loop(Dir,Owner).
double_clicked(Dir,Owner) ->
case gs:read(lb,selection) of
[0] -> % up one dir
NewDir=up_one_dir(Dir),
refresh(NewDir),
fs_loop(NewDir,Owner);
[] ->
fs_loop(Dir,Owner);
[Idx] ->
File=gs:read(lb,{get,Idx}),
case lists:last(File) of
$/ -> % down a dir
NewDir=lists:append(Dir,File),
refresh(NewDir),
fs_loop(NewDir,Owner);
_ -> % done
Owner!{file_dialog,self(),{ok,Dir,File}}
end
end.
%% checks if a file exists
%% returns {file,Dir,File}
%% {dir,Dir}
%% or {error,What}
check_file(Dir,File) ->
case catch lists:last(File) of
$/ -> % File is a Dir
NewDir = case File of
[$/|_] -> %absolute path
File;
_ -> %relative path
lists:append(Dir,File)
end,
case file:list_dir(NewDir) of
{ok,_} -> {dir,NewDir};
_ -> {error,bad_dir}
end;
{'EXIT',_Why} -> {error,no_file};
_ ->
Words=string:tokens(File,[$/,$\\]),
NewFile=lists:last(Words),
NewDir = case File of
[$/|_] -> %absolute path
up_one_dir(File);
_ -> %relative path
case up_one_dir(File) of
[$/] -> Dir;
[$/|SubDir] -> lists:flatten([Dir,SubDir,$/])
end
end,
case file:read_file_info(lists:append(NewDir,NewFile)) of
{ok,_} ->
{file,NewDir,NewFile};
_ ->
{error,bad_file}
end
end.
get_files(Dir) ->
{ok,Files} = file:list_dir(Dir),
add_slash(Dir,lists:sort(Files)).
add_slash(_,[]) -> [];
add_slash(Dir,[H|T]) ->
case file:read_file_info(lists:append(Dir,[$/|H])) of
{ok,FI} when FI#file_info.type==directory ->
[lists:append(H,"/")|add_slash(Dir,T)];
_ ->
[H|add_slash(Dir,T)]
end.
%filter([H|T]) ->
% case lists:last(H) of
% $/ -> [H|filter(T)];
% _ ->
% Len =length(H),
% if Len>4 ->
% case lists:nthtail(Len-4,H) of
% ".erl" -> [H|filter(T)];
% _ -> filter(T)
% end;
% true -> filter(T)
% end
% end;
%filter([]) ->
% [].
%% like member but also returns index
index_member(Item,List) ->
i_m(0,Item,List).
i_m(N,Item,[Item|_List]) ->
{ok,N};
i_m(N,Item,[_|List]) ->
i_m(N+1,Item,List);
i_m(_N,_Item,[]) ->
false.
up_one_dir(Dir) ->
L =string:tokens(Dir,[$/,$\\]),
lists:flatten(rem_last(L)).
rem_last([_Last]) ->
[$/];
rem_last([Head|Tail]) ->
[$/,Head|rem_last(Tail)];
rem_last([]) ->
[$/].
%% ----------------------------------------
%% done