diff options
Diffstat (limited to 'lib/tv/src/tv_db_search.erl')
-rw-r--r-- | lib/tv/src/tv_db_search.erl | 485 |
1 files changed, 485 insertions, 0 deletions
diff --git a/lib/tv/src/tv_db_search.erl b/lib/tv/src/tv_db_search.erl new file mode 100644 index 0000000000..edd3c188e2 --- /dev/null +++ b/lib/tv/src/tv_db_search.erl @@ -0,0 +1,485 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-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% +%%%********************************************************************* +%%% +%%% Description: Code for the search window. +%%% +%%%********************************************************************* +-module(tv_db_search). + + + +-export([create_window/1, + resize_window/1, + reset_window/1, + destroy_window/1, + mark_busy/1, + mark_nonbusy/1, + get_input_and_search/3, + update_search/4, + string_to_term/1 + ]). + + + + +-include("tv_int_def.hrl"). +-include("tv_int_msg.hrl"). +-include("tv_db_int_def.hrl"). + + + + +-define(WIN_WIDTH, 445). +-define(SMALL_WIN_HEIGHT, 117). +-define(BIG_WIN_HEIGHT, 335). +-define(FRAME_WIDTH, 429). % 334 +-define(OLD_FRAME_WIDTH, 334). +-define(FRAME_HEIGHT, 105). +-define(FRAME_XPOS, (10-2)). +-define(FRAME_YPOS, 10). +-define(ENTRY_XPOS, 9). +-define(ENTRY_YPOS, 31). +-define(ENTRY_WIDTH, (?OLD_FRAME_WIDTH-10-2*?ENTRY_XPOS-5)). +-define(LISTBOX_WIDTH, ?WIN_WIDTH-2*?FRAME_XPOS+1). +-define(LISTBOX_HEIGHT, 162). +-define(LISTBOX_XPOS, ?FRAME_XPOS-2). +-define(LISTBOX_YPOS, ?SMALL_WIN_HEIGHT+8). +-define(BTN_WIDTH, 80). +-define(BTN_HEIGHT, 30). +-define(BTN_XPOS, ?OLD_FRAME_WIDTH-6). +-define(BG_COLOUR, {217,217,217}). + + + + + + +create_window(true) -> + gs:config(win, [raise]); +create_window(false) -> + gs:window(win, gs:start(), [{width,?WIN_WIDTH}, + {height,?SMALL_WIN_HEIGHT}, + {data,small}, + {bg,?BG_COLOUR}, + {title,"[TV] Search Object"}, + {destroy,true}, + {configure,true}, + {cursor,arrow} + ]), + + F = gs:frame(win, [{width,?FRAME_WIDTH}, + {height,?FRAME_HEIGHT}, + {x,?FRAME_XPOS}, + {y,?FRAME_YPOS}, + {bw,2}, + {bg,?BG_COLOUR} + ]), + + gs:label(F, [{width,80}, + {height,25}, + {x,?ENTRY_XPOS+2}, + {y,8}, + {align,w}, + {bg,?BG_COLOUR}, + {fg, {0,0,0}}, + {label, {text,"Search for:"}} + ]), + + gs:entry(entry, F, [{width,?ENTRY_WIDTH}, + {height,30}, + {x,?ENTRY_XPOS}, + {y,?ENTRY_YPOS}, + {insert, {0,"<Search expression>"}}, + {bg, {255,255,255}}, + {fg, {0,0,0}}, + {cursor,text}, + {justify,left}, + {keypress,true}, + {setfocus,true} + ]), + + Group = list_to_atom("expr" ++ pid_to_list(self())), + RadioWidth = round(?ENTRY_WIDTH / 2), + gs:radiobutton(expr_term, F, [{width,RadioWidth - 45}, + {height,25}, + {x,?ENTRY_XPOS}, + {y,?ENTRY_YPOS+40}, + {group,Group}, + {align, c}, + {label,{text,"as term"}}, + {select,true} + ]), + gs:radiobutton(expr_regexp, F, [{width,RadioWidth + 45}, + {height,25}, + {x,?ENTRY_XPOS+RadioWidth-20-26}, + {y,?ENTRY_YPOS+40}, + {group,Group}, + {align,c}, + {label,{text,"as regular expression"}} + ]), + + gs:button(search, F, [{width,?BTN_WIDTH}, + {height,?BTN_HEIGHT}, + {x,?BTN_XPOS}, + {y,11}, + {label, {text,"Search"}}, + {bg,?BG_COLOUR}, + {fg, {0,0,0}} + ]), + gs:button(cancel, F, [{width,?BTN_WIDTH}, + {height,?BTN_HEIGHT}, + {x,?BTN_XPOS}, + {y,?BTN_HEIGHT+11+10}, + {label, {text,"Cancel"}}, + {data,cancel}, + {bg,?BG_COLOUR}, + {fg, {0,0,0}} + ]), + expand_window(), + gs:config(entry, [{select, {0,1000}}]), + gs:config(win, [{map,true}]). + + + + +resize_window(false) -> + done; +resize_window(true) -> + gs:config(win, [{width,?WIN_WIDTH}, + {height,?BIG_WIN_HEIGHT} + ]). + + + + +reset_window(false) -> + done; +reset_window(true) -> + gs:config(listbox, [clear]), + gs:config(objects_found, [{label, {text,""}}]). + + + + +destroy_window(false) -> + done; +destroy_window(true) -> + gs:destroy(win). + + + +mark_busy(false) -> + done; +mark_busy(true) -> + gs:config(win, [{cursor,busy}]), + gs:config(entry, [{cursor,busy}]). + + + + +mark_nonbusy(false) -> + done; +mark_nonbusy(true) -> + gs:config(win, [{cursor,arrow}]), + gs:config(entry, [{cursor,text}]). + + + + +get_input_and_search(DbList, IsRegExp, ListAsStr) -> + get_input_and_search(DbList, IsRegExp, true, ListAsStr). + + + + +get_input_and_search(DbList, IsRegExp, Notify, ListAsStr) -> + Str = get_entry_text(), + StrConvRes = case IsRegExp of + true -> + string_to_regexp(Str); + false -> + string_to_term(Str) + end, + + case StrConvRes of + {ok, TermOrRE} -> + search(IsRegExp, TermOrRE, DbList, ListAsStr); + {error, {_Reason, Msg}} when Notify -> + gs:config(win, [beep]), + tv_utils:notify(win, "TV Notification", Msg); + {error, {_Reason, _Msg}} -> + done + end. + + + +update_search(false, _DbList, _IsRegExp, _ListAsStr) -> + done; +update_search(true, DbList, true, ListAsStr) -> + get_input_and_search(DbList, false, false, ListAsStr); +update_search(true, DbList, false, ListAsStr) -> + get_input_and_search(DbList, true, false, ListAsStr). + + + +get_entry_text() -> + gs:read(entry,text). + + + +string_to_regexp(Str) -> + case regexp:parse(Str) of + {ok, RegExp} -> + {ok, RegExp}; + _Error -> + case get(error_msg_mode) of + normal -> + {error, {not_a_regexp, "Please enter a regular expression!"}}; + haiku -> + {error, {not_a_regexp, ["Being incorrect", + "The regular expression", + "Must now be retyped."]}} + end + end. + + + +string_to_term(Str) -> + case catch erl_scan:string(Str ++ ". ") of + {ok, ScannedStr, _No} -> + case erl_parse:parse_term(ScannedStr) of + {ok, Term} -> + {ok, Term}; + _Other -> + %% May be a PID, have to check this, since erl_scan + %% currently cannot handle this case... :-( + case catch list_to_pid(Str) of + Pid when is_pid(Pid) -> + {ok, Pid}; + _Error -> + case get(error_msg_mode) of + normal -> + {error, {not_a_term, "Please enter a valid term!"}}; + haiku -> + {error, {not_a_term, ["Aborted effort.", + "Reflect, repent and retype:", + "Enter valid term."]}} + end + end + end; + _Error -> + case get(error_msg_mode) of + normal -> + {error, {not_a_term, "Please enter a valid term!"}}; + haiku -> + {error, {not_a_term, ["Aborted effort.", + "Reflect, repent and retype:", + "Enter valid term."]}} + end + end. + + + +search(IsRegExp, SearchValue, DbList, ListAsStr) -> + gs:config(cancel, [{label, {text,"Stop"}}]), + mark_busy(true), + reset_window(true), + SearchRes = traverse(SearchValue, DbList, 1, length(DbList), [], IsRegExp, ListAsStr), + gs:config(cancel, [{label, {text,"Cancel"}}]), + mark_nonbusy(true), + SearchRes. + + + + + +expand_window() -> + gs:listbox(listbox, win, [{width,?LISTBOX_WIDTH}, + {height,?LISTBOX_HEIGHT}, + {x,?LISTBOX_XPOS}, + {y,?LISTBOX_YPOS}, + {bg, {255,255,255}}, + {fg, {0,0,0}}, + {scrollbg,?BG_COLOUR}, + {scrollfg,?BG_COLOUR}, + {hscroll,bottom}, + {vscroll,right}, + {click,true}, + {doubleclick,false}, + {selectmode,single} + ]), + gs:label(objects_found, win, [{width,?LISTBOX_WIDTH}, + {height,25}, + {x,?LISTBOX_XPOS}, + {y,?LISTBOX_YPOS+?LISTBOX_HEIGHT+13}, + {align,w}, + {bg,?BG_COLOUR}, + {fg, {0,0,0}} + ]), + gs:config(win, [{width,?WIN_WIDTH}, + {height,?BIG_WIN_HEIGHT} + ]). + + + + + + + +traverse(Pattern, [Object | T], Row, Length, Acc, IsRegExp, ListAsStr) -> + SearchRes = + case IsRegExp of + true -> + search_for_regexp(Pattern, Object, ListAsStr); + false -> + compare_terms(Pattern, Object) + end, + + NewAcc + = case SearchRes of + found -> + RowStr = integer_to_list(Row), + LengthStr = integer_to_list(Length), + ObjectStr = case ListAsStr of + true -> + lists:flatten(tv_io_lib:format("~p", [Object])); + false -> + lists:flatten(tv_io_lib:write(Object)) + end, + + gs:config(listbox, + [{add, + " Row " ++ RowStr ++ ":" ++ + lists:duplicate(length(LengthStr)-length(RowStr), " ") ++ + " " ++ ObjectStr} + ]), + gs:config(objects_found, + [{label, + {text,integer_to_list(length(Acc)+1) ++ + " object(s) found"}} + ]), + [{Row,Object} | Acc]; + not_found -> + Acc + end, + receive + {gs,cancel,click,_Data,_Args} -> + gs:config(objects_found, + [{label, + {text,integer_to_list(gs:read(listbox,size)) ++ + " object(s) found"}} + ]), + lists:reverse(NewAcc) + after + 0 -> + traverse(Pattern, T, Row+1, Length, NewAcc, IsRegExp, ListAsStr) + end; +traverse(_Pattern, [], _N, _Length, Acc, _IsRegExp, _ListAsStr) -> + gs:config(objects_found, + [{label, + {text,integer_to_list(gs:read(listbox,size)) ++ + " object(s) found"}} + ]), + lists:reverse(Acc). + + + + +search_for_regexp(Pattern, Elem, ListAsStr) -> + ListToSearch = + case ListAsStr of + true -> + lists:flatten(tv_io_lib:format("~p", [Elem])); + false -> + lists:flatten(tv_io_lib:write(Elem)) + end, + + case regexp:first_match(ListToSearch, Pattern) of + {match, _, _} -> + found; + _Other -> + not_found + %% The code below shall be used instead if it is desired to + %% compare each *element* in the tuples to the regular expression, + %% i.e., treat each element as a new line/string. + %% The difference is most easily explained through an example: + %% If we treat each tuple as a new line/string, the regular expression + %% "^{win" will match the string "{win, 1, 2, 3}", but not the string + %% "{1, {win,2}}". + %% If we treat each element as a new line/string, the RE "^{win" will match + %% both strings above. + + %% SearchList = tuple_to_list(Elem), + %% case lists:dropwhile( + %% fun(H) -> + %% nomatch == regexp:first_match(lists:flatten(io_lib:write(H)), + %% Pattern) + %% end, + %% SearchList) of + %% [] -> + %% not_found; + %% _AnyList -> + %% found + %% end + end. + + + + + +compare_terms(Term, Elem) when not is_tuple(Elem), not is_list(Elem), Term =/= Elem -> + not_found; +compare_terms(Term, Term) -> + %% Even the case Term = "{}" or "[]"!!! + found; +compare_terms(Term, Elem) when is_list(Elem) -> + traverse_list(Term, Elem); +compare_terms(Term, Elem) when is_tuple(Elem) -> + traverse_tuple(Term, Elem, 1, size(Elem)). + + + + + +traverse_tuple(Pattern, Tuple, N, Stop) when N =< Stop -> + Elem = element(N,Tuple), + case compare_terms(Pattern, Elem) of + found -> + found; + not_found -> + traverse_tuple(Pattern, Tuple, N+1, Stop) + end; +traverse_tuple(_Pattern, _Tuple, N, Stop) when N > Stop -> + not_found. + + + + + + +traverse_list(Pattern, [H | T]) -> + case compare_terms(Pattern, H) of + found -> + found; + not_found -> + traverse_list(Pattern, T) + end; +traverse_list(_Pattern, []) -> + not_found. + |