def __filter_changed(self, bar, text, restore=False): self.__filter = None if not Query.match_all(text): self.__filter = Query(text, self.STAR) if not restore: self.activate()
def test_re(self): for s in ["album = /i hate/", "artist = /pi*/", "title = /x.y/"]: self.failUnless(Query(s).search(self.s1)) self.failIf(Query(s).search(self.s2)) f = Query("artist = /mu|piman/").search self.failUnless(f(self.s1)) self.failUnless(f(self.s2))
def GetSubsearchResultSet(self, previous_results, terms): query = Query("") for term in terms: query &= Query(term) songs = get_songs_for_ids(app.library, previous_results) ids = [get_song_id(s) for s in songs if query.search(s)] return ids
def __update_filter(self, entry, text): self.__filter = None if not Query.match_all(text): tags = self.__model.tags + ["album"] self.__filter = Query(text, star=tags).search self.__bg_filter = background_filter() self.view.get_model().refilter()
def GetInitialResultSet(self, terms): if terms: query = Query("") for term in terms: query &= Query(term) songs = filter(query.search, app.library) else: songs = app.library.values() ids = [get_song_id(s) for s in songs] return ids
def activate(self): text = self._get_text() if Query.is_parsable(text): star = dict.fromkeys(SongList.star) star.update(self.__star) self._filter = Query(text, star.keys()).search songs = filter(self._filter, self._library) bg = background_filter() if bg: songs = filter(bg, songs) self._panes[0].fill(songs)
def _get_songs(self): try: self._filter = Query(self._text, star=SongList.star).search except Query.error: pass else: if Query.match_all(self._text): songs = self._library.values() self._filter = None else: songs = filter(self._filter, self._library) return songs
def test_dumb_search_value_negate(self): self.failUnless(Query("!xyz").search(self.s1)) self.failUnless(Query("!!!xyz").search(self.s1)) self.failUnless(Query(" !!!&(xyz, zyx)").search(self.s1)) self.failIf(Query("!man").search(self.s1)) self.failUnless(Query("&(tests,piman)").search(self.s1)) self.failUnless(Query("&(tests,!nope)").search(self.s1)) self.failIf(Query("&(tests,!!nope)").search(self.s1)) self.failIf(Query("&(tests,!piman)").search(self.s1)) self.failUnless(Query("&(tests,|(foo,&(pi,!nope)))").search(self.s1))
def query(self, key): if key not in self.__CACHE: text, filter_ = self.GENRES[key] if filter_ is None: filter_ = key self.__CACHE[key] = Query(filter_, star=self.STAR) return self.__CACHE[key]
def search(self, text): try: filt = Query(text).search except Query.error: return [] else: return [Tag(self, track) for track in filter(filt, self._tracks)]
def restore(self): text = config.get("browsers", "query_text").decode("utf-8") entry = self.__search entry.set_text(text) # update_filter expects a parsable query if Query.is_parsable(text): self.__update_filter(entry, text, scroll_up=False, restore=True) keys = config.get("browsers", "albums").split("\n") # FIXME: If albums is "" then it could be either all albums or # no albums. If it's "" and some other stuff, assume no albums, # otherwise all albums. self.__inhibit() if keys == [""]: self.view.set_cursor((0,)) else: def select_fun(row): album = row[0] if not album: # all return False return album.str_key in keys self.view.select_by_func(select_fun) self.__uninhibit()
def __filter_changed(self, *args): self.__remove_timeout() text = self.__entry.get_text().decode('utf-8') if Query.is_parsable(text): self.__refill_id = gobject.idle_add( self.emit, 'query-changed', text)
def background_filter(): bg = config.get("browsers", "background").decode('utf-8') if not bg: return try: return Query(bg, SongList.star).search except Query.error: pass
def filter_text(self, text): self.__search.set_text(text) if Query.is_parsable(text): self.__update_filter(self.__search, text) self.__inhibit() self.view.set_cursor((0,)) self.__uninhibit() self.activate()
def test_numcmp(self): self.failUnless(Query.is_valid("#(t < 3)")) self.failUnless(Query.is_valid("#(t <= 3)")) self.failUnless(Query.is_valid("#(t > 3)")) self.failUnless(Query.is_valid("#(t >= 3)")) self.failUnless(Query.is_valid("#(t = 3)")) self.failUnless(Query.is_valid("#(t != 3)")) self.failIf(Query.is_valid("#(t !> 3)")) self.failIf(Query.is_valid("#(t >> 3)"))
def query(self, text, sort=None, star=Query.STAR): """Query the library and return matching songs.""" if isinstance(text, str): text = text.decode('utf-8') songs = self.values() if text != "": songs = filter(Query(text, star).search, songs) return songs
def test_not(self): self.failUnless(Query.is_valid('t = !/a/')) self.failUnless(Query.is_valid('t = !!/a/')) self.failUnless(Query.is_valid('!t = "a"')) self.failUnless(Query.is_valid('!!t = "a"')) self.failUnless(Query.is_valid('t = !|(/a/, !"b")')) self.failUnless(Query.is_valid('t = !!|(/a/, !"b")')) self.failUnless(Query.is_valid('!|(t = /a/)'))
def test_case(self): self.failUnless(Query("album = /i hate/").search(self.s1)) self.failUnless(Query("album = /I Hate/").search(self.s1)) self.failUnless(Query("album = /i Hate/").search(self.s1)) self.failUnless(Query("album = /i Hate/i").search(self.s1)) self.failUnless(Query(u"title = /ångström/").search(self.s4)) self.failIf(Query("album = /i hate/c").search(self.s1)) self.failIf(Query(u"title = /ångström/c").search(self.s4))
def activate(self): if self._text is not None and Query.is_parsable(self._text): star = dict.fromkeys(SongList.star) star.update(self.__star) self._filter = Query(self._text, star.keys()).search songs = filter(self._filter, self._library) bg = background_filter() if bg: songs = filter(bg, songs) self.__panes[0].fill(songs)
def test_and_or_operator(self): union = Query("|(foo=bar,bar=foo)") inter = Query("&(foo=bar,bar=foo)") neg = Query("foo=!bar") numcmp = Query("#(bar = 0)") tag = Query("foo=bar") tests = [ inter | tag, tag | tag, neg | neg, tag | inter, neg | union, union | union, inter | inter, numcmp | numcmp, numcmp | union ] self.failIf(filter(lambda x: not isinstance(x, type(union)), tests)) tests = [ inter & tag, tag & tag, neg & neg, tag & inter, neg & union, union & union, inter & inter, numcmp & numcmp, numcmp & inter ] self.failIf(filter(lambda x: not isinstance(x, type(inter)), tests))
def test_re(self): self.failUnless(Query.is_valid('t = /an re/')) self.failUnless(Query.is_valid('t = /an re/c')) self.failUnless(Query.is_valid('t = /an\\/re/')) self.failIf(Query.is_valid('t = /an/re/')) self.failUnless(Query.is_valid('t = /aaa/lsic')) self.failIf(Query.is_valid('t = /aaa/icslx'))
def test_trinary(self): self.failUnless(Query("#(11 < track < 13)").search(self.s2)) self.failUnless(Query("#(11 < track <= 12)").search(self.s2)) self.failUnless(Query("#(12 <= track <= 12)").search(self.s2)) self.failUnless(Query("#(12 <= track < 13)").search(self.s2)) self.failUnless(Query("#(13 > track > 11)").search(self.s2)) self.failUnless(Query("#(20 > track < 20)").search(self.s2))
def __save_search(self, entry, *args): # only save the query on focus-out if eager_search is turned on if args and not config.getboolean('settings', 'eager_search'): return text = entry.get_text().decode('utf-8').strip() if text and Query.is_parsable(text): # Adding the active text to the model triggers a changed signal # (get_active is no longer -1), so inhibit self.__inhibit() self.__combo.prepend_text(text) self.__combo.write() self.__uninhibit()
def __update_filter(self, entry, text, scroll_up=True, restore=False): model = self.view.get_model() self.__filter = None if not Query.match_all(text): self.__filter = Query(text, star=["~people", "album"]).search self.__bg_filter = background_filter() self.__inhibit() # We could be smart and try to scroll to a selected album # but that introduces lots of wild scrolling. Feel free to change it. # Without scrolling the TV trys to stay at the same position (40% down) # which makes no sence so always go to the top. if scroll_up: self.view.scroll_to_point(0, 0) # don't filter on restore if there is nothing to filter if not restore or self.__filter or self.__bg_filter: model.refilter() self.__uninhibit()
def test_andor(self): self.failUnless(Query.is_valid('a = |(/a/, /b/)')) self.failUnless(Query.is_valid('a = |(/b/)')) self.failUnless(Query.is_valid('|(a = /b/, c = /d/)')) self.failUnless(Query.is_valid('a = &(/a/, /b/)')) self.failUnless(Query.is_valid('a = &(/b/)')) self.failUnless(Query.is_valid('&(a = /b/, c = /d/)'))
def restore(self): text = config.get("browsers", "query_text").decode("utf-8") self.__searchbar.set_text(text) if Query.is_parsable(text): self.__filter_changed(self.__searchbar, text, restore=True) keys = config.get("browsers", "radio").splitlines() def select_func(row): return row[self.TYPE] != self.TYPE_SEP and row[self.KEY] in keys self.__inhibit() view = self.view if not view.select_by_func(select_func): for row in view.get_model(): if row[self.TYPE] == self.TYPE_FAV: view.set_cursor(row.path) break self.__uninhibit()
def __text_changed(self, *args): # the combobox has an active entry selected -> no timeout # todo: we need a timeout when the selection changed because # of keyboard input (up/down arrows) if self.__combo.get_active() != -1: self.__filter_changed() return if not config.getboolean('settings', 'eager_search'): return # remove the timeout self.__remove_timeout() # parse and new timeout text = self.__entry.get_text().decode('utf-8') if Query.is_parsable(text): self.__refill_id = GLib.timeout_add(self.timeout, self.__filter_changed)
def __text_changed(self, *args): # the combobox has an active entry selected -> no timeout # todo: we need a timeout when the selection changed because # of keyboard input (up/down arrows) if self.__combo.get_active() != -1: self.__filter_changed() return if not config.getboolean('settings', 'eager_search'): return # remove the timeout self.__remove_timeout() # parse and new timeout text = self.__entry.get_text().decode('utf-8') if Query.is_parsable(text): self.__refill_id = gobject.timeout_add( self.timeout, self.__filter_changed)
def restore(self): text = config.get("browsers", "query_text").decode("utf-8") entry = self.__search entry.set_text(text) # update_filter expects a parsable query if Query.is_parsable(text): self.__update_filter(entry, text, scroll_up=False, restore=True) albums = config.get("browsers", "albums").split("\n") # FIXME: If albums is "" then it could be either all albums or # no albums. If it's "" and some other stuff, assume no albums, # otherwise all albums. self.__inhibit() if albums == [""]: self.view.set_cursor((0,)) else: select = lambda r: r[0] and r[0].title in albums self.view.select_by_func(select) self.__uninhibit()
def test_black(self): for p in ["a test", "more test hooray"]: self.failUnlessEqual(None, Query.is_valid_color(p))
def test_trinary(self): self.failUnless(Query.is_valid("#(2 < t < 3)")) self.failUnless(Query.is_valid("#(2 >= t > 3)")) # useless, but valid self.failUnless(Query.is_valid("#(5 > t = 2)"))
def test_list(self): self.failUnless(Query.is_valid("#(t < 3, t > 9)")) self.failUnless(Query.is_valid("t = &(/a/, /b/)")) self.failUnless(Query.is_valid("s, t = |(/a/, /b/)")) self.failUnless(Query.is_valid("|(t = /a/, s = /b/)"))
def test_trailing(self): self.failIf(Query.is_valid('t = /an re/)')) self.failIf(Query.is_valid('|(a, b = /a/, c, d = /q/) woo'))
def test_emptylist(self): self.failIf(Query.is_valid("a = &()")) self.failIf(Query.is_valid("a = |()")) self.failIf(Query.is_valid("|()")) self.failIf(Query.is_valid("&()"))
def test_green(self): for p in ["a = /b/", "&(a = b, c = d)", "/abc/", "!x", "!&(abc, def)"]: self.failUnlessEqual(True, Query.is_valid_color(p))
def test_2007_07_27_synth_search(self): song = self.AF({"~filename": "foo/64K/bar.ogg"}) query = Query("~dirname = !64K") self.failIf(query.search(song), "%r, %r" % (query, song))
def test_taglist(self): self.failUnless(Query.is_valid('a, b = /a/')) self.failUnless(Query.is_valid('a, b, c = |(/a/)')) self.failUnless(Query.is_valid('|(a, b = /a/, c, d = /q/)')) self.failIf(Query.is_valid('a = /a/, b'))
def test_str(self): self.failUnless(Query.is_valid('t = "a str"')) self.failUnless(Query.is_valid('t = "a str"c')) self.failUnless(Query.is_valid('t = "a\\"str"'))
def test_red(self): for p in ["a = /w", "|(sa#"]: self.failUnlessEqual(False, Query.is_valid_color(p))
def test_match_all(self): self.failUnless(Query.match_all("")) self.failUnless(Query.match_all(" ")) self.failIf(Query.match_all("foo"))
def test_nesting(self): self.failUnless(Query.is_valid("|(s, t = &(/a/, /b/),!#(2 > q > 3))"))
def test_nonsense(self): self.failIf(Query.is_valid('a string')) self.failIf(Query.is_valid('t = #(a > b)')) self.failIf(Query.is_valid("=a= = /b/")) self.failIf(Query.is_valid("a = &(/b//")) self.failIf(Query.is_valid("(a = &(/b//)"))
def test_tag(self): self.failUnless(Query.is_valid('t = tag')) self.failUnless(Query.is_valid('t = !tag')) self.failUnless(Query.is_valid('t = |(tag, bar)')) self.failUnless(Query.is_valid('t = a"tag"')) self.failIf(Query.is_valid('t = a, tag'))
def test_empty(self): self.failUnless(Query.is_valid('')) self.failUnless(Query.is_parsable('')) self.failUnless(Query(''))