aboutsummaryrefslogtreecommitdiffstats
path: root/lib/debugger/src/dbg_wx_filedialog_win.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/debugger/src/dbg_wx_filedialog_win.erl')
-rw-r--r--lib/debugger/src/dbg_wx_filedialog_win.erl572
1 files changed, 572 insertions, 0 deletions
diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl
new file mode 100644
index 0000000000..d883438639
--- /dev/null
+++ b/lib/debugger/src/dbg_wx_filedialog_win.erl
@@ -0,0 +1,572 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(dbg_wx_filedialog_win).
+
+-behaviour(wx_object).
+
+%% API
+-export([new/3, getFilename/1, getFilenames/1, getDirectory/1, destroy/1]).
+
+%% Internal
+-export([init/1, handle_call/3, handle_event/2,
+ handle_info/2, code_change/3, terminate/2]).
+
+-include_lib("wx/include/wx.hrl").
+-include("dbg_wx_filedialog_win.hrl").
+
+-define(ID_PATH, 200).
+-define(COMPLETION_WIN, 201).
+-record(state, {win,
+ back, forward, up, %% Buttons
+ text, %% Text (Path)
+ ptext,
+ icons=[],
+ completion,
+ list,
+ path,
+ files,
+ rstack = [],
+ fstack = [],
+ filter,
+ sort,
+ cancel,
+ ok}).
+
+-record(file,
+ {name = "", %% File or dir name
+ type = "file", %% Type descr
+ date = "", %% Modification date
+ icon = 0, %% Icon
+ color = {0,0,0}
+ }).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Client API
+
+
+%% Options are:
+%% {message, Title}
+%% {defaultDir, Path}
+%% {filter, fun(Dir,File) -> skip | {DescriptionStr, icon_type}}
+%% {icons, [{icon_type,wxBitmap}]}
+
+new(Parent, Id, Options0) ->
+ wx_object:start_link(?MODULE, [Parent, Id, Options0], []).
+
+getFilename(FD) ->
+ wx_object:call(FD, getFilename).
+getFilenames(FD) ->
+ wx_object:call(FD, getFilenames).
+getDirectory(FD) ->
+ wx_object:call(FD, getDirectory).
+destroy(FD) ->
+ wx_object:call(FD, destroy).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Object Callbacks
+init([Parent, Id, Options0]) ->
+ Name = proplists:get_value(message, Options0, "Open"),
+ Size = proplists:get_value(size, Options0, ?wxDefaultSize),
+ Pos = proplists:get_value(pos, Options0, ?wxDefaultPosition),
+ {ok, DefPath} = file:get_cwd(),
+ Path = proplists:get_value(defaultDir, Options0, DefPath),
+ ExtraIcons = proplists:get_value(icons, Options0, []),
+ Filter = proplists:get_value(filter, Options0, fun file_type_and_icon/2),
+ SortCol = sort_col(proplists:get_value(sort, Options0, name)),
+ Dlg = wxDialog:new(Parent, Id, Name, [{size,Size}, {pos,Pos},
+ {style, ?wxDEFAULT_DIALOG_STYLE
+ bor ?wxRESIZE_BORDER}]),
+
+ %% Top
+ Back = wxButton:new(Dlg, ?wxID_BACKWARD),
+ wxButton:disable(Back),
+ Forw = wxButton:new(Dlg, ?wxID_FORWARD),
+ wxButton:disable(Forw),
+ Up = wxButton:new(Dlg, ?wxID_UP),
+ Dir = wxTextCtrl:new(Dlg, ?ID_PATH, [{style, ?wxTE_PROCESS_ENTER}]),
+ update_dir(Path, Dir),
+ wxTextCtrl:connect(Dir, command_text_updated),
+ wxTextCtrl:connect(Dir, command_text_enter),
+ Self = self(),
+ IsTab = fun(Ev = #wx{event=#wxKey{keyCode=KC,
+ controlDown=false,shiftDown=false, altDown=false}},
+ _Object) when KC =:= ?WXK_TAB ; KC =:= ?WXK_ESCAPE ->
+ Self ! Ev;
+ (_Ev, Object) ->
+ %% Let the default handler handle anything else
+ wxEvent:skip(Object)
+ end,
+
+ wxTextCtrl:connect(Dir, char, [{callback, IsTab}]),
+
+ Top = wxBoxSizer:new(?wxHORIZONTAL),
+ wxSizer:add(Top, Back, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Top, Forw, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Top, Up, [{border, 2},{flag,?wxALL bor ?wxEXPAND}]),
+
+ %% List Ctrl
+ {Art, IconMap} = create_icons(ExtraIcons),
+
+ LC = wxListCtrl:new(Dlg, [{style, ?wxLC_REPORT bor ?wxVSCROLL}, {size, {400,200}}]),
+ wxListCtrl:assignImageList(LC, Art, ?wxIMAGE_LIST_SMALL),
+
+ LI = wxListItem:new(),
+ Add = fun(MenuName, Row) ->
+ wxListItem:setText(LI, MenuName),
+ wxListItem:setAlign(LI, ?wxLIST_FORMAT_LEFT),
+ wxListCtrl:insertColumn(LC, Row, LI),
+ Row + 1
+ end,
+ lists:foldl(Add, 0, ["Name", "Type", "Modified"]),
+ wxListItem:destroy(LI),
+
+ Files = list_files(Path, {SortCol,false}, Filter),
+ update_files(Files,LC,IconMap),
+
+ wxListCtrl:setColumnWidth(LC, 0, ?wxLIST_AUTOSIZE),
+ wxListCtrl:setColumnWidth(LC, 1, ?wxLIST_AUTOSIZE),
+ wxListCtrl:setColumnWidth(LC, 2, ?wxLIST_AUTOSIZE),
+ wxListCtrl:connect(LC, command_list_item_activated),
+ wxListCtrl:connect(LC, command_list_col_click),
+ wxListCtrl:connect(LC, size, [{skip, true}]),
+
+ %% Bottom buttons
+ Bott = wxDialog:createButtonSizer(Dlg, ?wxCANCEL bor ?wxOK),
+ wxDialog:connect(Dlg, command_button_clicked),
+
+ %% Ok done
+ Box = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+ wxSizer:add(Box, LC, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(Box, Bott, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
+
+ wxWindow:setSizer(Dlg, Box),
+ wxSizer:fit(Box, Dlg),
+ wxSizer:setSizeHints(Box,Dlg),
+ State = #state{win=Dlg,
+ back=Back, forward=Forw, up=Up,
+ text=Dir,
+ list=LC,
+ icons=IconMap,
+ sort ={SortCol,false},
+ filter = Filter,
+ path=Path,
+ files=Files
+ },
+ {Dlg, State}.
+
+%% calls
+handle_call(getFilename, _From, State = #state{list=LC, files=Fs}) ->
+ case wxListCtrl:getNextItem(LC, -1, [{state,?wxLIST_STATE_SELECTED}]) of
+ -1 ->
+ {reply, "", State};
+ Item ->
+ {reply, (lists:nth(Item+1,Fs))#file.name, State}
+ end;
+
+handle_call(getFilenames, _From, State = #state{list=LC, files=Fs}) ->
+ Items = get_selection(LC,-1, []),
+ Files = [(lists:nth(Item+1,Fs))#file.name || Item <- Items],
+ {reply, Files, State};
+
+handle_call(getDirectory, _From, State = #state{path=Dir}) ->
+ {reply, Dir, State};
+
+handle_call(destroy, _From, State) ->
+ {stop, normal, ok, State}.
+
+%% events
+handle_event(#wx{id=?wxID_UP}, State0) ->
+ State = update_window(change_dir(0, State0)),
+ {noreply, State};
+
+handle_event(#wx{id=?wxID_BACKWARD}, State0 = #state{rstack=[Prev|Stack]}) ->
+ State = update_window(change_dir(Prev, State0#state{rstack=Stack}, forward)),
+ {noreply, State};
+
+handle_event(#wx{id=?wxID_FORWARD}, State0 = #state{fstack=[Prev|Stack]}) ->
+ State = update_window(change_dir(Prev, State0#state{fstack=Stack}, reverse)),
+ {noreply, State};
+
+handle_event(#wx{id=Id=?wxID_CANCEL}, State = #state{win=Win}) ->
+ wxDialog:endModal(Win,Id),
+ {noreply, State};
+
+handle_event(#wx{id=Id=?wxID_OK}, State = #state{win=Win}) ->
+ wxDialog:endModal(Win,Id),
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_col_click, col=Column0}},
+ State0 = #state{files=Fs, sort=Sort0}) ->
+ case Column0 >= 0 of
+ true ->
+ Column = sort_col(Column0+1),
+ Sort = case Sort0 of
+ {Column,Bool} -> {Column, not Bool};
+ {_,_} -> {Column, false}
+ end,
+ {noreply, update_window(State0#state{files=sort_files(Fs,Sort),sort=Sort})};
+ false ->
+ {noreply, State0}
+ end;
+
+handle_event(#wx{event=#wxList{itemIndex=Index}},
+ State0 = #state{files=Fs,win=Win}) ->
+ case lists:nth(Index+1, Fs) of
+ #file{type="directory"} ->
+ State = update_window(change_dir(Index, State0)),
+ {noreply, State};
+ _Dbg = #file{} ->
+ wxDialog:endModal(Win,?wxID_OK),
+ {noreply, State0}
+ end;
+
+handle_event(#wx{event=#wxCommand{type=command_text_updated, cmdString=Wanted}},
+ State = #state{ptext=Previous, completion=Comp}) ->
+ case Previous =:= undefined orelse lists:prefix(Wanted, Previous) of
+ true ->
+ case Comp of
+ {Temp,_} -> wxWindow:destroy(Temp);
+ undefined -> ok
+ end,
+ {noreply, State#state{ptext=Wanted,completion=undefined}};
+ false ->
+ {noreply, show_completion(Wanted, State)}
+ end;
+
+handle_event(#wx{event=#wxCommand{type=command_text_enter, cmdString=Wanted}},
+ State) ->
+ case filelib:is_dir(Wanted, erl_prim_loader) of
+ true ->
+ {Path0, Dir} = split_dir(Wanted),
+ Path = filename:join(Path0,Dir),
+ {noreply, update_window(change_dir(Path, State))};
+ false ->
+ {Path, _} = split_dir(Wanted),
+ {noreply, update_window(change_dir(Path, State))}
+ end;
+
+handle_event(#wx{event=#wxKey{keyCode=?WXK_TAB}},
+ State = #state{text=TC, ptext=Wanted, completion=Comp}) ->
+ case wxTextCtrl:getSelection(TC) of
+ {Pos,Pos} ->
+ {noreply, show_completion(Wanted, State)};
+ _ ->
+ wxTextCtrl:setInsertionPointEnd(TC),
+ destroy_completion(Comp),
+ {noreply, State#state{completion=undefined}}
+ end;
+
+handle_event(#wx{id=?COMPLETION_WIN, event=#wxCommand{cmdString=[]}}, State) ->
+ {noreply, State};
+handle_event(#wx{id=?COMPLETION_WIN, obj=LB,
+ event=_Ev=#wxCommand{cmdString=Dir,commandInt=N}},
+ State = #state{ptext=Wanted0, text=TC}) ->
+ case wxListBox:isSelected(LB, N) of
+ true ->
+ Wanted = case Wanted0 of
+ undefined -> wxTextCtrl:getValue(TC);
+ _ -> Wanted0
+ end,
+ Path1 = case filelib:is_dir(Wanted, erl_prim_loader) of
+ true -> Wanted;
+ false ->
+ {ThePath, _} = split_dir(Wanted),
+ ThePath
+ end,
+ Path = filename:join(Path1, Dir),
+ {noreply, update_window(change_dir(Path, State))};
+ false ->
+ {noreply, State}
+ end;
+
+handle_event(#wx{event=#wxSize{size={Width,_}}}, State = #state{list=LC}) ->
+ wx:batch(fun() ->
+ Tot = wx:foldl(fun(C,Sum) ->
+ Sum + wxListCtrl:getColumnWidth(LC, C)
+ end, 0, [1,2]),
+ wxListCtrl:setColumnWidth(LC, 0, Width-Tot-30)
+ end),
+ {noreply, State};
+
+handle_event(Event,State) ->
+ io:format("~p Got ~p ~n",[self(), Event]),
+ {noreply, State}.
+
+handle_info(_Msg, State) ->
+ {noreply,State}.
+
+terminate(_Reason,State) ->
+ wxDialog:destroy(State#state.win),
+ ok.
+
+code_change(_,_,State) ->
+ State.
+
+%%%%%%%%%%%%%%%%%%%%%%% Internal %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+update_window(State = #state{files=Fs, list=LC,
+ path=Path, text=TC,
+ icons=Icons,
+ completion = Comp}) ->
+ update_files(Fs, LC, Icons),
+ update_dir(Path, TC),
+ if State#state.rstack == [] -> wxButton:disable(State#state.back);
+ true -> wxButton:enable(State#state.back)
+ end,
+ if State#state.fstack == [] -> wxButton:disable(State#state.forward);
+ true -> wxButton:enable(State#state.forward)
+ end,
+ if Path == "/" -> wxButton:disable(State#state.up);
+ true -> wxButton:enable(State#state.up)
+ end,
+ destroy_completion(Comp),
+ State#state{completion=undefined, ptext=undefined}.
+
+update_dir(Path, TC) ->
+ case Path of
+ "/" ->
+ wxTextCtrl:setValue(TC, Path);
+ _ ->
+ wxTextCtrl:setValue(TC, Path ++ "/")
+ end,
+ wxTextCtrl:setInsertionPointEnd(TC).
+
+update_files(Files,LC, Icons) ->
+ wxListCtrl:deleteAllItems(LC),
+ wx:foldl(fun(F=#file{name=Name,type=TypeStr,date=Date, color=Color},Row) ->
+ wxListCtrl:insertItem(LC, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(LC, Row, {240,240,255});
+ true -> ignore
+ end,
+ wxListCtrl:setItemTextColour(LC, Row, Color),
+ wxListCtrl:setItem(LC, Row, 0, Name, [{imageId,get_icon(F,Icons)}]),
+ wxListCtrl:setItem(LC, Row, 2, format_date(Date)),
+ wxListCtrl:setItem(LC, Row, 1, TypeStr),
+ Row+1
+ end, 0, Files).
+
+show_completion(undefined, State = #state{text=TC}) ->
+ show_completion(wxTextCtrl:getValue(TC), State);
+show_completion(Wanted, State = #state{text=TC, win=Win, list=LC, completion=Comp}) ->
+ Paths0 = filelib:wildcard(Wanted ++ "*", erl_prim_loader),
+ Paths = [File || File <- Paths0, filelib:is_dir(File, erl_prim_loader)],
+ case Paths of
+ [Path] ->
+ Start = length(Wanted),
+ wxTextCtrl:setValue(TC, Path++"/"),
+ wxTextCtrl:setInsertionPoint(TC, Start),
+ wxTextCtrl:setSelection(TC, Start, -1),
+ destroy_completion(Comp),
+ wxWindow:setFocus(TC),
+ State#state{ptext=Path, completion=undefined};
+ Paths when Comp =:= undefined ->
+ {PosX,PosY} = wxListCtrl:getPosition(LC),
+ {SzX, SzY} = wxListCtrl:getSize(LC),
+ Pos0 = {PosX+5,PosY},
+ Size = {SzX-50,SzY-50},
+ Files = [filename:basename(File) || File <- Paths],
+ Temp = case os:type() of
+ {win32,nt} ->
+ Pos = wxWindow:clientToScreen(Win,Pos0),
+ wxFrame:new(Win, -1, "",
+ [{pos, Pos}, {size, Size},
+ {style, ?wxFRAME_FLOAT_ON_PARENT}]);
+ _ ->
+ wxWindow:new(Win, -1,
+ [{pos, Pos0}, {size, Size},
+ {style, ?wxFRAME_FLOAT_ON_PARENT}])
+ end,
+ LB = wxListBox:new(Temp, ?COMPLETION_WIN,
+ [{style, ?wxLB_SINGLE}, {choices, Files}, {size, Size}]),
+
+ wxListBox:connect(LB, command_listbox_doubleclicked),
+ wxListBox:connect(LB, command_listbox_selected),
+ wxWindow:show(Temp),
+ wxWindow:setFocus(TC),
+ State#state{completion = {Temp, LB}, ptext=Wanted};
+ Paths ->
+ {_Temp, LB} = Comp,
+ wxListBox:clear(LB),
+ Files = [filename:basename(File) || File <- Paths],
+ wxListBox:insertItems(LB,Files,0),
+ wxWindow:setFocus(TC),
+ State#state{ptext=Wanted}
+ end.
+
+destroy_completion(undefined) -> ok;
+destroy_completion({Window, _}) ->
+ Parent = wxWindow:getParent(Window),
+ wxWindow:destroy(Window),
+ wxWindow:refresh(Parent).
+
+split_dir(Path0) ->
+ Split1 = filename:split(Path0),
+ case lists:reverse(Split1) of
+ [File| Split2] when Split2 =/= [] ->
+ Split3 = lists:reverse(Split2),
+ Path = filename:join(Split3),
+ {Path, File};
+ _ ->
+ {"/", ""}
+ end.
+
+change_dir(What,State) ->
+ change_dir(What,State,new).
+
+change_dir(Num, State = #state{files=Fs0, path=Path0},Stack)
+ when is_integer(Num) ->
+ case lists:nth(Num+1, Fs0) of
+ #file{name=".."} ->
+ {Path,_} = split_dir(Path0);
+ #file{name=Dir} ->
+ Path = filename:join(Path0, Dir)
+ end,
+ change_dir(Path, State, Stack);
+change_dir(Path, State0 = #state{path=Path0, sort=Sort, filter=Filter},StackDir) ->
+ Files = list_files(Path, Sort, Filter),
+ add_to_stack(StackDir, Path0, State0#state{files=Files, path=Path}).
+
+add_to_stack(new, Path, State = #state{rstack=Stack0}) ->
+ Stack = [Path|Stack0],
+ State#state{rstack=Stack, fstack=[]};
+add_to_stack(reverse, Path, State = #state{rstack=Stack0}) ->
+ Stack = [Path|Stack0],
+ State#state{rstack=Stack};
+add_to_stack(forward, Path, State = #state{fstack=Stack0}) ->
+ Stack = [Path|Stack0],
+ State#state{fstack=Stack}.
+
+list_files(Dir, Sort, Filter) ->
+ Contents0 = filelib:wildcard(Dir ++ "/*", erl_prim_loader),
+ Contents = case Dir of
+ "/" -> Contents0;
+ _ -> [".."|Contents0]
+ end,
+ {Ds0,Fs0} = get_file_info(Contents, Dir, Filter, [], []),
+ sort_files(lists:reverse(Ds0), Fs0, Sort).
+
+sort_files(Mixed, Sort) ->
+ {Ds,Fs} =
+ lists:foldr(fun(Dir = #file{type="directory"}, {Ds,Fs}) ->
+ {[Dir|Ds],Fs};
+ (File, {Ds,Fs}) ->
+ {Ds,[File|Fs]}
+ end, {[],[]}, Mixed),
+ sort_files(Ds,Fs,Sort).
+
+sort_files(Ds0, Fs0, {SortElement, Rev}) ->
+ {Top,Ds1} = case Ds0 of
+ [Up=#file{name=".."}|Rest] -> {Up,Rest};
+ _ -> {undefined, Ds0}
+ end,
+ Ds = lists:keysort(SortElement, Ds1),
+ Fs = case Rev of
+ true -> lists:reverse(lists:keysort(SortElement,Fs0));
+ false -> lists:keysort(SortElement,Fs0)
+ end,
+ case Top of
+ undefined -> Ds ++ Fs;
+ _ -> [Top|Ds++Fs]
+ end.
+
+get_file_info([AbsName|Rest],Dir,Filter, Files,Dirs) ->
+ Name = filename:basename(AbsName),
+ Mod = filelib:last_modified(AbsName, erl_prim_loader),
+ IsDir = filelib:is_dir(AbsName, erl_prim_loader),
+ Entry0 = #file{name=Name, date=Mod},
+ case IsDir of
+ true when Name =:= ".." ->
+ Entry = Entry0#file{type="directory",icon=prev_dir},
+ get_file_info(Rest, Dir, Filter, Files, [Entry|Dirs]);
+ true ->
+ Entry = Entry0#file{type="directory",icon=dir},
+ get_file_info(Rest, Dir, Filter, Files, [Entry|Dirs]);
+ false ->
+ case Filter(Dir,Name) of
+ {Type,Icon,Color} ->
+ Entry = Entry0#file{type=Type,icon=Icon,color=Color},
+ get_file_info(Rest, Dir, Filter, [Entry|Files], Dirs);
+ skip ->
+ get_file_info(Rest, Dir, Filter, Files, Dir)
+ end
+ end;
+get_file_info([], _, _, Fs,Ds) ->
+ {Ds,Fs}.
+
+format_date({{Y,M,D},{H,Mi,S}}) ->
+ lists:flatten(io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",[Y,M,D,H,Mi,S]));
+format_date(_) ->
+ "unknown".
+
+get_selection(LC, Prev, Acc) ->
+ case wxListCtrl:getNextItem(LC, Prev, [{state,?wxLIST_STATE_SELECTED}]) of
+ -1 ->
+ lists:reverse(Acc);
+ Item ->
+ get_selection(LC, Item, [Item|Acc])
+ end.
+
+file_type_and_icon(_Dir, Name) ->
+ case filename:extension(Name) of
+ ".erl" ->
+ {"erl src", erl_src, {0,90,0}};
+ ".hrl" ->
+ {"erl hrl", erl_hrl, {0,90,0}};
+ ".beam" ->
+ {"erl bin", erl_bin, {0,0,0}};
+ _ ->
+ {"file", file, {0,0,0}}
+ end.
+
+create_icons(Extra) ->
+ Art = wxImageList:new(16,16),
+ BuiltIn0 = [{file, "wxART_NORMAL_FILE"},
+ {dir, "wxART_FOLDER"},
+ {prev_dir, "wxART_GO_DIR_UP"}],
+ BuiltIn = [{Type, wxArtProvider:getBitmap(ArtID, [{size, {16,16}}])} ||
+ {Type,ArtID} <- BuiltIn0],
+
+ Test = [{Type, wxBitmap:new(wxImage:new(16,16,Bin))}
+ || {Type,Bin} <-
+ [{erl_src, ?ERL_SRC},
+ {erl_hrl, ?ERL_HRL},
+ {erl_bin, ?ERL_BIN}]],
+
+ Icons = BuiltIn ++ Test ++ Extra,
+ [wxImageList:add(Art, Image) || {_, Image} <- Icons],
+ {Art, ids(Icons, 0)}.
+
+get_icon(#file{icon=Icon}, Icons) ->
+ proplists:get_value(Icon,Icons, 0).
+
+ids([{Type,_}|Rest], Id) ->
+ [{Type,Id}|ids(Rest,Id+1)];
+ids([],_) -> [].
+
+sort_col(1) -> #file.name;
+sort_col(2) -> #file.type;
+sort_col(3) -> #file.date;
+sort_col(name) -> #file.name;
+sort_col(type) -> #file.type;
+sort_col(date) -> #file.date.
+