CoverArt Browser  v2.0
Browse your cover-art albums in Rhythmbox
/home/foss/Downloads/coverart-browser/coverart_controllers.py
00001 # -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
00002 #
00003 # Copyright (C) 2012 - fossfreedom
00004 # Copyright (C) 2012 - Agustin Carrasco
00005 #
00006 # This program is free software; you can redistribute it and/or modify
00007 # it under the terms of the GNU General Public License as published by
00008 # the Free Software Foundation; either version 2, or (at your option)
00009 # any later version.
00010 #
00011 # This program is distributed in the hope that it will be useful,
00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 # GNU General Public License for more details.
00015 #
00016 # You should have received a copy of the GNU General Public License
00017 # along with this program; if not, write to the Free Software
00018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
00019 
00020 from datetime import date
00021 from collections import OrderedDict
00022 from collections import namedtuple
00023 
00024 from gi.repository import GObject
00025 from gi.repository import Gdk
00026 from gi.repository import RB
00027 from gi.repository import Gio
00028 from gi.repository import GLib
00029 
00030 from coverart_browser_prefs import CoverLocale
00031 from coverart_browser_prefs import GSetting
00032 from coverart_utils import create_pixbuf_from_file_at_size
00033 from coverart_utils import GenreConfiguredSpriteSheet
00034 from coverart_utils import ConfiguredSpriteSheet
00035 from coverart_utils import get_stock_size
00036 from coverart_utils import CaseInsensitiveDict
00037 from coverart_utils import Theme
00038 import rb
00039 
00040 
00041 MenuNodeT = namedtuple('MenuNode', 'label menutype typevalue')
00042 
00043 
00044 def MenuNode(label, menutype=None, typevalue=None):
00045     return MenuNodeT(label, menutype, typevalue)
00046 
00047 
00048 class OptionsController(GObject.Object):
00049     # properties
00050     options = GObject.property(type=object, default=None)
00051     current_key = GObject.property(type=str, default=None)
00052     update_image = GObject.property(type=bool, default=False)
00053     enabled = GObject.property(type=bool, default=True)
00054 
00055     def __init__(self):
00056         super(OptionsController, self).__init__()
00057 
00058         # connect the variations on the current key to the controllers action
00059         self.connect('notify::current-key', self._do_action)
00060 
00061     def get_current_key_index(self):
00062         return self.options.index(self.current_key)
00063 
00064     def option_selected(self, key):
00065         if key != self.current_key:
00066             # update the current value
00067             self.current_key = key
00068 
00069     def _do_action(self, *args):
00070         self.do_action()
00071 
00072     def do_action(self):
00073         pass
00074 
00075     def get_current_image(self):
00076         return None
00077 
00078     def get_current_description(self):
00079         return self.current_key
00080 
00081     def update_images(self, *args):
00082         pass
00083 
00084     def create_spritesheet(self, plugin, sheet, typestr):
00085         '''
00086         helper function to create a specific spritesheet
00087         '''
00088         if sheet:
00089             del sheet
00090 
00091         return ConfiguredSpriteSheet(plugin, typestr, get_stock_size())
00092 
00093     def create_button_image(self, plugin, image, icon_name):
00094         '''
00095         helper function to create a button image
00096         '''
00097         if image:
00098             del image
00099 
00100         path = 'img/' + Theme(self.plugin).current + '/'
00101 
00102         return create_pixbuf_from_file_at_size(
00103             rb.find_plugin_file(self.plugin, path + icon_name),
00104             *get_stock_size())
00105 
00106 
00107 class PlaylistPopupController(OptionsController):
00108     def __init__(self, plugin, album_model):
00109         super(PlaylistPopupController, self).__init__()
00110 
00111         self._album_model = album_model
00112 
00113         shell = plugin.shell
00114         self.plugin = plugin
00115 
00116         # get the library name and initialize the superclass with it
00117         self._library_name = shell.props.library_source.props.name
00118 
00119         # get the queue name
00120         self._queue_name = shell.props.queue_source.props.name
00121 
00122         if " (" in self._queue_name:
00123             self._queue_name = self._queue_name[0:self._queue_name.find(" (")]
00124 
00125         self._spritesheet = None
00126         self._update_options(shell)
00127 
00128         # get the playlist model so we can monitor changes
00129         playlist_model = shell.props.display_page_model
00130 
00131         # connect signals to update playlists
00132         playlist_model.connect('row-inserted', self._update_options, shell)
00133         playlist_model.connect('row-deleted', self._update_options, shell)
00134         playlist_model.connect('row-changed', self._update_options, shell)
00135 
00136     def update_images(self, *args):
00137         self._spritesheet = self.create_spritesheet(self.plugin,
00138                                                     self._spritesheet, 'playlist')
00139 
00140         if args[-1]:
00141             self.update_image = True
00142 
00143     def _update_options(self, *args):
00144         shell = args[-1]
00145         self.update_images(False)
00146 
00147         playlist_manager = shell.props.playlist_manager
00148         still_exists = self.current_key == self._library_name or \
00149                        self.current_key == self._queue_name
00150 
00151         # retrieve the options
00152         values = OrderedDict()
00153 
00154         # library and play queue sources
00155         values[self._library_name] = None
00156         values[self._queue_name] = shell.props.queue_source
00157 
00158         # playlists
00159         playlists_entries = playlist_manager.get_playlists()
00160 
00161         for playlist in playlists_entries:
00162             if playlist.props.is_local:
00163                 name = playlist.props.name
00164                 values[name] = playlist
00165 
00166                 still_exists = still_exists or name == self.current_key
00167 
00168         self.values = values
00169         self.options = list(values.keys())
00170 
00171         self.current_key = self.current_key if still_exists else \
00172             self._library_name
00173 
00174     def do_action(self):
00175         playlist = self.values[self.current_key]
00176 
00177         if not playlist:
00178             self._album_model.remove_filter('model')
00179         else:
00180             self._album_model.replace_filter('model',
00181                                              playlist.get_query_model())
00182 
00183     def get_current_image(self):
00184         playlist = self.values[self.current_key]
00185 
00186         if self.current_key == self._library_name:
00187             image = self._spritesheet['music']
00188         elif self._queue_name in self.current_key:
00189             image = self._spritesheet['queue']
00190         elif isinstance(playlist, RB.StaticPlaylistSource):
00191             image = self._spritesheet['playlist']
00192         else:
00193             image = self._spritesheet['smart']
00194 
00195         return image
00196 
00197 
00198 class GenrePopupController(OptionsController):
00199     # properties
00200     new_genre_icon = GObject.property(type=bool, default=False)
00201 
00202     def __init__(self, plugin, album_model):
00203         super(GenrePopupController, self).__init__()
00204 
00205         cl = CoverLocale()
00206         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00207 
00208         self._album_model = album_model
00209 
00210         shell = plugin.shell
00211         self.plugin = plugin
00212 
00213         # create a new property model for the genres
00214         genres_model = RB.RhythmDBPropertyModel.new(shell.props.db,
00215                                                     RB.RhythmDBPropType.GENRE)
00216 
00217         query = shell.props.library_source.props.base_query_model
00218         genres_model.props.query_model = query
00219 
00220         # initial genre
00221         self._initial_genre = _('All Genres')
00222 
00223         self._spritesheet = None
00224         self._default_image = None
00225         self._unrecognised_image = None
00226 
00227         self._connect_properties()
00228         self._connect_signals(query, genres_model)
00229 
00230         # generate initial popup
00231         self._update_options(genres_model)
00232 
00233     def update_images(self, *args):
00234         if self._spritesheet:
00235             del self._spritesheet
00236 
00237         self._spritesheet = GenreConfiguredSpriteSheet(self.plugin,
00238                                                        'genre', get_stock_size())
00239         self._default_image = self.create_button_image(self.plugin,
00240                                                        self._default_image, 'default_genre.png')
00241         self._unrecognised_image = self.create_button_image(self.plugin,
00242                                                             self._unrecognised_image, 'unrecognised_genre.png')
00243 
00244         if args[-1]:
00245             self.update_image = True
00246 
00247     def _connect_signals(self, query, genres_model):
00248         # connect signals to update genres
00249         self.connect('notify::new-genre-icon', self._update_options, genres_model)
00250         query.connect('row-inserted', self._update_options, genres_model)
00251         query.connect('row-deleted', self._update_options, genres_model)
00252         query.connect('row-changed', self._update_options, genres_model)
00253 
00254     def _connect_properties(self):
00255         gs = GSetting()
00256         setting = gs.get_setting(gs.Path.PLUGIN)
00257 
00258         setting.bind(gs.PluginKey.NEW_GENRE_ICON, self, 'new_genre_icon',
00259                      Gio.SettingsBindFlags.GET)
00260 
00261     def _update_options(self, *args):
00262         genres_model = args[-1]
00263 
00264         self.update_images(False)
00265 
00266         still_exists = False
00267 
00268         # retrieve the options
00269         options = []
00270         row_num = 0
00271         for row in genres_model:
00272             if row_num == 0:
00273                 cl = CoverLocale()
00274                 cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00275                 genre = _('All Genres')
00276                 row_num = row_num + 1
00277             else:
00278                 genre = row[0]
00279 
00280             options.append(genre)
00281 
00282             still_exists = still_exists or genre == self.current_key
00283 
00284         self.options = options
00285 
00286         self.current_key = self.current_key if still_exists else \
00287             self._initial_genre
00288 
00289     def do_action(self):
00290         '''
00291         called when genre popup menu item chosen
00292         return None if the first entry in popup returned
00293         '''
00294         if self.current_key == self._initial_genre:
00295             self._album_model.remove_filter('genre')
00296         else:
00297             self._album_model.replace_filter('genre', self.current_key)
00298 
00299     def get_current_image(self):
00300         test_genre = self.current_key.lower()
00301 
00302         if test_genre == self._initial_genre.lower():
00303             image = self._default_image
00304         else:
00305             image = self._find_alternates(test_genre)
00306 
00307             if image == self._unrecognised_image and \
00308                             test_genre in self._spritesheet:
00309                 image = self._spritesheet[test_genre]
00310 
00311         return image
00312 
00313     def _find_alternates(self, test_genre):
00314         # the following genre checks are required
00315         # 1. if we have user defined genres
00316         # 2. then check locale specific system genres
00317         # 3. then check local specific alternates
00318         # 4. then check if we system genres
00319 
00320         # where necessary check if any of the genres are a substring
00321         # of test_genre - check in reverse order so that we
00322         # test largest strings first (prevents spurious matches with
00323         # short strings)
00324         # N.B. we use RB.search_fold since the strings can be
00325         # in a mixture of cases, both unicode (normalized or not) and str
00326         # and as usual python cannot mix and match these types.
00327 
00328 
00329         test_genre = RB.search_fold(test_genre)
00330 
00331         ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_USER)
00332         if ret:
00333             return sprite
00334 
00335         for genre in sorted(self._spritesheet.locale_names,
00336                             key=lambda b: (-len(b), b)):
00337             if RB.search_fold(genre) in test_genre:
00338                 return self._spritesheet[self._spritesheet.locale_names[genre]]
00339 
00340         # next check locale alternates
00341         ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_LOCALE)
00342         if ret:
00343             return sprite
00344 
00345         ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_SYSTEM)
00346         if ret:
00347             return sprite
00348 
00349         # check if any of the default genres are a substring
00350         # of test_genre - check in reverse order so that we
00351         # test largest strings first (prevents spurious matches with
00352         # short strings)
00353         for genre in sorted(self._spritesheet.names,
00354                             key=lambda b: (-len(b), b)):
00355             if RB.search_fold(genre) in test_genre:
00356                 return self._spritesheet[genre]
00357 
00358         # if no matches then default to unrecognised image
00359         return self._unrecognised_image
00360 
00361     def _match_genres(self, test_genre, genre_type):
00362         case_search = CaseInsensitiveDict(
00363             dict((k.name, v) for k, v in self._spritesheet.genre_alternate.items()
00364                  if k.genre_type == genre_type))
00365 
00366         if test_genre in case_search:
00367             return (True, self._spritesheet[case_search[test_genre]])
00368         else:
00369             return (False, None)
00370 
00371 
00372     def get_current_description(self):
00373         cl = CoverLocale()
00374         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00375         if self.current_key == self._initial_genre:
00376             return _('All Genres')
00377         else:
00378             return self.current_key
00379 
00380 
00381 class SortPopupController(OptionsController):
00382     def __init__(self, plugin, viewmgr):
00383         super(SortPopupController, self).__init__()
00384 
00385         self._viewmgr = viewmgr
00386         self.plugin = plugin
00387         # sorts dictionary
00388         cl = CoverLocale()
00389         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00390 
00391         self.values = OrderedDict([(_('Sort by album name'), 'name'),
00392                                    (_('Sort by album artist'), 'artist'),
00393                                    (_('Sort by year'), 'year'),
00394                                    (_('Sort by rating'), 'rating')])
00395 
00396         self.options = list(self.values.keys())
00397 
00398         # get the current sort key and initialise the superclass
00399         gs = GSetting()
00400         source_settings = gs.get_setting(gs.Path.PLUGIN)
00401         value = source_settings[gs.PluginKey.SORT_BY]
00402 
00403         self._spritesheet = None
00404         self.update_images(False)
00405 
00406         self.current_key = list(self.values.keys())[
00407             list(self.values.values()).index(value)]
00408 
00409     def update_images(self, *args):
00410         self._spritesheet = self.create_spritesheet(self.plugin,
00411                                                     self._spritesheet, 'sort')
00412 
00413         if args[-1]:
00414             self.update_image = True
00415 
00416     def do_action(self):
00417         sort = self.values[self.current_key]
00418 
00419         gs = GSetting()
00420         settings = gs.get_setting(gs.Path.PLUGIN)
00421         settings[gs.PluginKey.SORT_BY] = sort
00422 
00423         self._viewmgr.current_view.get_default_manager().emit('sort', "album")
00424 
00425     def get_current_image(self):
00426         sort = self.values[self.current_key]
00427         return self._spritesheet[sort]
00428 
00429 
00430 class ArtistSortPopupController(OptionsController):
00431     def __init__(self, plugin, viewmgr):
00432         super(ArtistSortPopupController, self).__init__()
00433 
00434         self._viewmgr = viewmgr
00435         self.plugin = plugin
00436         # sorts dictionary
00437         cl = CoverLocale()
00438         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00439 
00440         self.values = OrderedDict([(_('Sort by album name'), 'name_artist'),
00441                                    (_('Sort by year'), 'year_artist'),
00442                                    (_('Sort by rating'), 'rating_artist')])
00443 
00444         self.options = list(self.values.keys())
00445 
00446         # get the current sort key and initialise the superclass
00447         gs = GSetting()
00448         source_settings = gs.get_setting(gs.Path.PLUGIN)
00449         value = source_settings[gs.PluginKey.SORT_BY_ARTIST]
00450 
00451         if value not in list(self.values.values()):
00452             print("here")
00453             value = 'name_artist'
00454             source_settings[gs.PluginKey.SORT_BY_ARTIST] = value
00455 
00456         self._spritesheet = None
00457         self.update_images(False)
00458 
00459         self.current_key = list(self.values.keys())[
00460             list(self.values.values()).index(value)]
00461         print(self.current_key)
00462 
00463     def update_images(self, *args):
00464         self._spritesheet = self.create_spritesheet(self.plugin,
00465                                                     self._spritesheet, 'sort_artist')
00466 
00467         if args[-1]:
00468             self.update_image = True
00469 
00470     def do_action(self):
00471         sort = self.values[self.current_key]
00472 
00473         gs = GSetting()
00474         settings = gs.get_setting(gs.Path.PLUGIN)
00475         settings[gs.PluginKey.SORT_BY_ARTIST] = sort
00476 
00477         self._viewmgr.current_view.get_default_manager().emit('sort', "artist")
00478 
00479     def get_current_image(self):
00480         sort = self.values[self.current_key]
00481         return self._spritesheet[sort]
00482 
00483 
00484 class PropertiesMenuController(OptionsController):
00485     favourites = GObject.property(type=bool, default=False)
00486     follow = GObject.property(type=bool, default=False)
00487 
00488     def __init__(self, plugin, source):
00489         super(PropertiesMenuController, self).__init__()
00490 
00491         self._source = source
00492         self.plugin = plugin
00493         self._connect_properties()
00494         # sorts dictionary
00495         cl = CoverLocale()
00496         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00497         # options
00498         self.values = OrderedDict()
00499         self.values[MenuNode(_('Download all covers'))] = 'download'
00500         self.values[MenuNode(_('Play random album'))] = 'random'
00501         self.values[MenuNode(_('Follow playing song'), 'check',
00502                              (True if self.follow else False))] = 'follow'
00503         self.values[MenuNode('separator1', 'separator')] = ''
00504         self.values[MenuNode(_('Use favourites only'), 'check',
00505                              (True if self.favourites else False))] = 'favourite'
00506         self.values[MenuNode('separator2', 'separator')] = ''
00507         self.values[MenuNode(_('Browser Preferences'))] = 'browser prefs'
00508         self.values[MenuNode(_('Search Preferences'))] = 'search prefs'
00509 
00510         self.options = list(self.values.keys())
00511 
00512         self.update_images(False)
00513 
00514         if self.favourites:
00515             self._source.propertiesbutton_callback('favourite')
00516 
00517         if self.follow:
00518             self._source.propertiesbutton_callback('follow')
00519 
00520         self.current_key = None
00521 
00522     def _connect_properties(self):
00523         gs = GSetting()
00524         setting = gs.get_setting(gs.Path.PLUGIN)
00525         setting.bind(
00526             gs.PluginKey.USE_FAVOURITES,
00527             self,
00528             'favourites',
00529             Gio.SettingsBindFlags.DEFAULT)
00530         setting.bind(
00531             gs.PluginKey.FOLLOWING,
00532             self,
00533             'follow',
00534             Gio.SettingsBindFlags.DEFAULT)
00535 
00536     def _change_key(self, dict, old, new):
00537         for i in range(len(dict)):
00538             k, v = dict.popitem(False)
00539             dict[new if old == k else k] = v
00540 
00541     def update_images(self, *args):
00542         self._image = self.create_button_image(self.plugin,
00543                                                None, 'properties.png')
00544 
00545         if args[-1]:
00546             self.update_image = True
00547 
00548     def do_action(self):
00549         if self.current_key:
00550             key = [node for node in self.values if node.label == self.current_key]
00551 
00552             if self.current_key == _('Use favourites only'):
00553                 self.favourites = not self.favourites
00554 
00555             if self.current_key == _('Follow playing song'):
00556                 self.follow = not self.follow
00557 
00558             self._source.propertiesbutton_callback(self.values[key[0]])
00559             self.current_key = None
00560 
00561     def get_current_image(self):
00562         return self._image
00563 
00564     def get_current_description(self):
00565         return _('Properties')
00566 
00567 
00568 class DecadePopupController(OptionsController):
00569     def __init__(self, plugin, album_model):
00570         super(DecadePopupController, self).__init__()
00571 
00572         self._album_model = album_model
00573         self.plugin = plugin
00574 
00575         self._spritesheet = None
00576 
00577         # decade options
00578         cl = CoverLocale()
00579         cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00580 
00581         self.values = OrderedDict()
00582 
00583         self.values[_('All Decades')] = [-1, 'All Decades']
00584         #'20s' as in the decade 2010
00585         self.values[_('20s')] = [2020, '20s']
00586         #'10s' as in the decade 2010
00587         self.values[_('10s')] = [2010, '10s']
00588         #'00s' as in the decade 2000
00589         self.values[_('00s')] = [2000, '00s']
00590         #'90s' as in the decade 1990
00591         self.values[_('90s')] = [1990, '90s']
00592         #'80s' as in the decade 1980
00593         self.values[_('80s')] = [1980, '80s']
00594         #'70s' as in the decade 1970
00595         self.values[_('70s')] = [1970, '70s']
00596         #'60s' as in the decade 1960
00597         self.values[_('60s')] = [1960, '60s']
00598         #'50s' as in the decade 1950
00599         self.values[_('50s')] = [1950, '50s']
00600         #'40s' as in the decade 1940
00601         self.values[_('40s')] = [1940, '40s']
00602         #'30s' as in the decade 1930
00603         self.values[_('30s')] = [1930, '30s']
00604         #'Older' as in 'older than the year 1930'
00605         self.values[_('Older')] = [-1, 'Older']
00606 
00607         self.options = list(self.values.keys())
00608 
00609         # if we aren't on the 20s yet, remove it
00610         if date.today().year < 2020:
00611             self.options.remove(_('20s'))
00612 
00613         # define a initial decade an set the initial key
00614         self._initial_decade = self.options[0]
00615         self.update_images(False)
00616 
00617         self.current_key = self._initial_decade
00618 
00619     def update_images(self, *args):
00620         self._spritesheet = self.create_spritesheet(self.plugin,
00621                                                     self._spritesheet, 'decade')
00622 
00623         if args[-1]:
00624             self.update_image = True
00625 
00626     def do_action(self):
00627         if self.current_key == self._initial_decade:
00628             self._album_model.remove_filter('decade')
00629         else:
00630             self._album_model.replace_filter('decade',
00631                                              self.values[self.current_key][0])
00632 
00633     def get_current_image(self):
00634         decade = self.values[self.current_key][1]
00635         return self._spritesheet[decade]
00636 
00637     def get_current_description(self):
00638         return self.current_key
00639 
00640 
00641 class SortOrderToggleController(OptionsController):
00642     toolbar_type = "album"
00643 
00644     def __init__(self, plugin, viewmgr):
00645         super(SortOrderToggleController, self).__init__()
00646 
00647         self._viewmgr = viewmgr
00648         self.plugin = plugin
00649 
00650         # options
00651         self.values = OrderedDict([(_('Sort in descending order'), False),
00652                                    (_('Sort in ascending order'), True)])
00653         self.options = list(self.values.keys())
00654 
00655         self._images = []
00656 
00657         # set the current key
00658         self.gs = GSetting()
00659         self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
00660         self.key = self.get_key()
00661         sort_order = self.settings[self.key]
00662         self.current_key = list(self.values.keys())[
00663             list(self.values.values()).index(sort_order)]
00664         self.update_images(False)
00665 
00666     def get_key(self):
00667         return self.gs.PluginKey.SORT_ORDER
00668 
00669     def update_images(self, *args):
00670         # initialize images
00671         if len(self._images) > 0:
00672             del self._images[:]
00673 
00674         self._images.append(self.create_button_image(self.plugin,
00675                                                      None, 'arrow_down.png'))
00676         self._images.append(self.create_button_image(self.plugin,
00677                                                      None, 'arrow_up.png'))
00678 
00679         if args[-1]:
00680             self.update_image = True
00681 
00682     def do_action(self):
00683         sort_order = self.values[self.current_key]
00684         self.settings[self.key] = sort_order
00685         self._viewmgr.current_view.get_default_manager().emit('sort', self.toolbar_type)
00686 
00687     def get_current_image(self):
00688         return self._images[self.get_current_key_index()]
00689 
00690 
00691 class ArtistSortOrderToggleController(SortOrderToggleController):
00692     toolbar_type = "artist"
00693 
00694     def __init__(self, plugin, model):
00695         super(ArtistSortOrderToggleController, self).__init__(plugin, model)
00696 
00697     def get_key(self):
00698         return self.gs.PluginKey.SORT_ORDER_ARTIST
00699 
00700 
00701 class AlbumSearchEntryController(OptionsController):
00702     # properties
00703     search_text = GObject.property(type=str, default='')
00704 
00705     def __init__(self, album_model):
00706         super(AlbumSearchEntryController, self).__init__()
00707 
00708         self._album_model = album_model
00709         self._filter_type = 'all'
00710 
00711         # options
00712         self.values = OrderedDict()
00713         self.values[_('Search all fields')] = 'all'
00714         self.values[_('Search album artists')] = 'album_artist'
00715         self.values[_('Search track artists')] = 'artist'
00716         self.values[_('Search composers')] = 'composers'
00717         self.values[_('Search albums')] = 'album_name'
00718         self.values[_('Search titles')] = 'track'
00719 
00720         self.options = list(self.values.keys())
00721         self.current_key = list(self.values.keys())[0]
00722 
00723         self._typing = False
00724         self._typing_counter = 0
00725         self._current_search_text = ""
00726 
00727     def do_action(self):
00728         # remove old filter
00729         self._album_model.remove_filter(self._filter_type, False)
00730 
00731         # assign the new filter
00732         self._filter_type = self.values[self.current_key]
00733 
00734         self.do_search(self.search_text, True)
00735 
00736     def _search_typing(self, *args):
00737         self._typing_counter = self._typing_counter + 1
00738 
00739         if self._typing_counter >= 4 and self._typing:
00740             self._typing = False
00741             self._change_filter(self._current_search_text, False)
00742 
00743         return self._typing
00744 
00745     def _change_filter(self, search_text, force):
00746         #self.search_text = search_text
00747         self._current_search_text = search_text
00748 
00749         if search_text:
00750             self._album_model.replace_filter(self._filter_type,
00751                                              search_text)
00752         elif not force:
00753             self._album_model.remove_filter(self._filter_type)
00754 
00755     def do_search(self, search_text, force=False):
00756         '''
00757         if self.search_text != search_text or force:
00758             self.search_text = search_text
00759 
00760             if search_text:
00761                 self._album_model.replace_filter(self._filter_type,
00762                     search_text)
00763             elif not force:
00764                 self._album_model.remove_filter(self._filter_type)
00765 
00766         '''
00767         #self.search_text = search_text
00768         if force:
00769             self._typing_counter = 99
00770             self._typing = False
00771             self._change_filter(search_text, force)
00772             return
00773 
00774         if self._current_search_text != search_text:
00775 
00776             #self.search_text = search_text
00777             self._current_search_text = search_text
00778             self._typing_counter = 0
00779 
00780             if not self._typing:
00781                 self._typing = True
00782 
00783                 Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
00784                                         self._search_typing)
00785 
00786 
00787 class AlbumQuickSearchController(object):
00788     def __init__(self, album_manager):
00789         self._album_manager = album_manager
00790 
00791     def connect_quick_search(self, quick_search):
00792         quick_search.connect('quick-search', self._on_quick_search)
00793         quick_search.connect('arrow-pressed', self._on_arrow_pressed)
00794         quick_search.connect('hide', self._on_hide)
00795 
00796     def _on_quick_search(self, quick_search, search_text, *args):
00797         album = self._album_manager.model.find_first_visible('album_name',
00798                                                              search_text)
00799 
00800         if album:
00801             path = self._album_manager.model.get_path(album)
00802             self._album_manager.current_view.select_and_scroll_to_path(path)
00803 
00804     def _on_arrow_pressed(self, quick_search, key, *args):
00805         current = self._album_manager.current_view.get_selected_objects()[0]
00806         search_text = quick_search.get_text()
00807         album = None
00808 
00809         if key == Gdk.KEY_Up:
00810             album = self._album_manager.model.find_first_visible(
00811                 'album_name', search_text, current, True)
00812         elif key == Gdk.KEY_Down:
00813             album = self._album_manager.model.find_first_visible(
00814                 'album_name', search_text, current)
00815 
00816         if album:
00817             path = self._album_manager.model.get_path(album)
00818             self._album_manager.current_view.select_and_scroll_to_path(path)
00819 
00820     def _on_hide(self, quick_search, *args):
00821         self._album_manager.current_view.grab_focus()
00822 
00823 
00824 class ViewController(OptionsController):
00825     def __init__(self, shell, viewmgr):
00826         super(ViewController, self).__init__()
00827 
00828         self._viewmgr = viewmgr
00829 
00830         from coverart_browser_source import Views
00831 
00832         views = Views(shell)
00833 
00834         self.values = OrderedDict()
00835         for view_name in views.get_view_names():
00836             self.values[views.get_menu_name(view_name)] = view_name
00837             print(view_name)
00838 
00839         self.options = list(self.values.keys())
00840         viewmgr.connect('new-view', self.on_notify_view_name)
00841 
00842     def on_notify_view_name(self, *args):
00843         for key in self.options:
00844             if self.values[key] == self._viewmgr.view_name:
00845                 self.current_key = key
00846 
00847     def do_action(self):
00848         if self._viewmgr.view_name != self.values[self.current_key]:
00849             self._viewmgr.view_name = self.values[self.current_key]
 All Classes Functions