reformat code according to pycharm

Esse commit está contido em:
fossfreedom
2014-05-24 14:52:09 +01:00
commit a5a3d6b85c
22 arquivos alterados com 2184 adições e 2096 exclusões
+176 -176
Ver Arquivo
@@ -55,6 +55,7 @@ ALBUM_LOAD_CHUNK = 50
# default chunk of albums to process when loading covers # default chunk of albums to process when loading covers
COVER_LOAD_CHUNK = 5 COVER_LOAD_CHUNK = 5
class Cover(GObject.Object): class Cover(GObject.Object):
''' '''
Cover of an Album. It may be initialized either by a file path to the image Cover of an Album. It may be initialized either by a file path to the image
@@ -73,8 +74,8 @@ class Cover(GObject.Object):
def __init__(self, size, image): def __init__(self, size, image):
super(Cover, self).__init__() super(Cover, self).__init__()
assert isinstance( image, str ), "image should be a string" assert isinstance(image, str), "image should be a string"
self.original = image self.original = image
self._create_pixbuf(size) self._create_pixbuf(size)
@@ -90,7 +91,7 @@ class Cover(GObject.Object):
def _create_pixbuf(self, size): def _create_pixbuf(self, size):
self.pixbuf = create_pixbuf_from_file_at_size( self.pixbuf = create_pixbuf_from_file_at_size(
self.original, size, size) self.original, size, size)
self.size = size self.size = size
@@ -114,7 +115,6 @@ class Shadow(Cover):
class ShadowedCover(Cover): class ShadowedCover(Cover):
def __init__(self, shadow, image): def __init__(self, shadow, image):
super(ShadowedCover, self).__init__(shadow.cover_size, image) super(ShadowedCover, self).__init__(shadow.cover_size, image)
@@ -142,11 +142,11 @@ class ShadowedCover(Cover):
# draw cover # draw cover
Gdk.cairo_set_source_pixbuf(context, self.pixbuf, self._shadow.width, Gdk.cairo_set_source_pixbuf(context, self.pixbuf, self._shadow.width,
self._shadow.width) self._shadow.width)
context.paint() context.paint()
self.pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, self.pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
self._shadow.size, self._shadow.size) self._shadow.size, self._shadow.size)
class Track(GObject.Object): class Track(GObject.Object):
@@ -162,10 +162,10 @@ class Track(GObject.Object):
__gsignals__ = { __gsignals__ = {
'modified': (GObject.SIGNAL_RUN_LAST, None, ()), 'modified': (GObject.SIGNAL_RUN_LAST, None, ()),
'deleted': (GObject.SIGNAL_RUN_LAST, None, ()) 'deleted': (GObject.SIGNAL_RUN_LAST, None, ())
} }
__hash__ = GObject.__hash__ __hash__ = GObject.__hash__
def __init__(self, entry, db=None): def __init__(self, entry, db=None):
super(Track, self).__init__() super(Track, self).__init__()
@@ -174,7 +174,7 @@ class Track(GObject.Object):
def __eq__(self, other): def __eq__(self, other):
return rb.entry_equal(self.entry, other.entry) return rb.entry_equal(self.entry, other.entry)
@property @property
def title(self): def title(self):
return self.entry.get_string(RB.RhythmDBPropType.TITLE) return self.entry.get_string(RB.RhythmDBPropType.TITLE)
@@ -214,7 +214,7 @@ class Track(GObject.Object):
@property @property
def location(self): def location(self):
return self.entry.get_string(RB.RhythmDBPropType.LOCATION) return self.entry.get_string(RB.RhythmDBPropType.LOCATION)
@property @property
def composer(self): def composer(self):
return self.entry.get_string(RB.RhythmDBPropType.COMPOSER) return self.entry.get_string(RB.RhythmDBPropType.COMPOSER)
@@ -231,8 +231,8 @@ class Track(GObject.Object):
def album_artist_sort(self): def album_artist_sort(self):
sort = self.entry.get_string( sort = self.entry.get_string(
RB.RhythmDBPropType.ALBUM_ARTIST_SORTNAME_FOLDED) or \ RB.RhythmDBPropType.ALBUM_ARTIST_SORTNAME_FOLDED) or \
self.entry.get_string(RB.RhythmDBPropType.ALBUM_ARTIST_FOLDED) or \ self.entry.get_string(RB.RhythmDBPropType.ALBUM_ARTIST_FOLDED) or \
self.entry.get_string(RB.RhythmDBPropType.ARTIST_FOLDED) self.entry.get_string(RB.RhythmDBPropType.ARTIST_FOLDED)
return NaturalString(sort) return NaturalString(sort)
@@ -240,7 +240,7 @@ class Track(GObject.Object):
def album_sort(self): def album_sort(self):
sort = self.entry.get_string( sort = self.entry.get_string(
RB.RhythmDBPropType.ALBUM_SORTNAME_FOLDED) or \ RB.RhythmDBPropType.ALBUM_SORTNAME_FOLDED) or \
self.entry.get_string(RB.RhythmDBPropType.ALBUM_FOLDED) self.entry.get_string(RB.RhythmDBPropType.ALBUM_FOLDED)
return NaturalString(sort) return NaturalString(sort)
@@ -269,10 +269,10 @@ class Album(GObject.Object):
'modified': (GObject.SIGNAL_RUN_FIRST, None, ()), 'modified': (GObject.SIGNAL_RUN_FIRST, None, ()),
'emptied': (GObject.SIGNAL_RUN_LAST, None, ()), 'emptied': (GObject.SIGNAL_RUN_LAST, None, ()),
'cover-updated': (GObject.SIGNAL_RUN_LAST, None, ()) 'cover-updated': (GObject.SIGNAL_RUN_LAST, None, ())
} }
__hash__ = GObject.__hash__ __hash__ = GObject.__hash__
def __init__(self, name, artist, cover): def __init__(self, name, artist, cover):
super(Album, self).__init__() super(Album, self).__init__()
@@ -324,12 +324,12 @@ class Album(GObject.Object):
[track.title for track in self._tracks])) [track.title for track in self._tracks]))
return self._titles return self._titles
@property @property
def composers(self): def composers(self):
if not self._composers: if not self._composers:
composers = [track.composer for track in self._tracks if track.composer] composers = [track.composer for track in self._tracks if track.composer]
if composers: if composers:
self._composers = ' '.join(set(composers)) self._composers = ' '.join(set(composers))
return self._composers return self._composers
@@ -345,7 +345,7 @@ class Album(GObject.Object):
self._year = 0 self._year = 0
return self._year return self._year
@property @property
def real_year(self): def real_year(self):
''' '''
@@ -356,16 +356,16 @@ class Album(GObject.Object):
if calc_year == 0: if calc_year == 0:
calc_year = date.today().year calc_year = date.today().year
else: else:
calc_year = datetime.fromordinal(calc_year).year calc_year = datetime.fromordinal(calc_year).year
return calc_year return calc_year
@property @property
def calc_year_sort(self): def calc_year_sort(self):
''' '''
returns a str combinationi of real_year + album name returns a str combinationi of real_year + album name
''' '''
return str(self.real_year) + self.name return str(self.real_year) + self.name
@property @property
@@ -374,12 +374,12 @@ class Album(GObject.Object):
self._genres = set([track.genre for track in self._tracks]) self._genres = set([track.genre for track in self._tracks])
return self._genres return self._genres
@property @property
def rating(self): def rating(self):
if not self._rating: if not self._rating:
ratings = [track.rating for track in self._tracks ratings = [track.rating for track in self._tracks
if track.rating and track.rating != 0] if track.rating and track.rating != 0]
if len(ratings) > 0: if len(ratings) > 0:
self._rating = sum(ratings) / len(self._tracks) self._rating = sum(ratings) / len(self._tracks)
@@ -393,7 +393,7 @@ class Album(GObject.Object):
track.rating = new_rating track.rating = new_rating
self._rating = None self._rating = None
self.emit('modified') self.emit('modified')
@property @property
def track_count(self): def track_count(self):
return len(self._tracks) return len(self._tracks)
@@ -416,7 +416,7 @@ class Album(GObject.Object):
self._cover = new_cover self._cover = new_cover
self._cover_resized_id = self._cover.connect('resized', self._cover_resized_id = self._cover.connect('resized',
lambda *args: self.emit('cover-updated')) lambda *args: self.emit('cover-updated'))
self.emit('cover-updated') self.emit('cover-updated')
@@ -435,7 +435,7 @@ class Album(GObject.Object):
else: else:
# otherwise, only return the entries over the threshold # otherwise, only return the entries over the threshold
tracks = [track for track in self._tracks tracks = [track for track in self._tracks
if track.rating >= rating_threshold] if track.rating >= rating_threshold]
return sorted(tracks, key=lambda track: (track.disc_number, track.track_number)) return sorted(tracks, key=lambda track: (track.disc_number, track.track_number))
@@ -447,26 +447,26 @@ class Album(GObject.Object):
''' '''
self._tracks.append(track) self._tracks.append(track)
ids = (track.connect('modified', self._track_modified), ids = (track.connect('modified', self._track_modified),
track.connect('deleted', self._track_deleted)) track.connect('deleted', self._track_deleted))
self._signals_id[track] = ids self._signals_id[track] = ids
self.emit('modified') self.emit('modified')
def _track_modified(self, track): def _track_modified(self, track):
print ("_track_modified") print("_track_modified")
if track.album != self.name: if track.album != self.name:
self._track_deleted(track) self._track_deleted(track)
else: else:
self.emit('modified') self.emit('modified')
def _track_deleted(self, track): def _track_deleted(self, track):
print ("_track_deleted") print("_track_deleted")
self._tracks.remove(track) self._tracks.remove(track)
#list(map(track.disconnect, self._signals_id[track])) #list(map(track.disconnect, self._signals_id[track]))
for signal_id in self._signals_id[track]: for signal_id in self._signals_id[track]:
track.disconnect(signal_id) track.disconnect(signal_id)
del self._signals_id[track] del self._signals_id[track]
if len(self._tracks) == 0: if len(self._tracks) == 0:
@@ -497,15 +497,14 @@ class Album(GObject.Object):
def __eq__(self, other): def __eq__(self, other):
return other and self.name == other.name and \ return other and self.name == other.name and \
self.artist == other.artist self.artist == other.artist
def __ne__(self, other): def __ne__(self, other):
return not other or\ return not other or \
self.name + self.artist != other.name + other.artist self.name + self.artist != other.name + other.artist
class AlbumFilters(object): class AlbumFilters(object):
@classmethod @classmethod
def nay_filter(cls, *args): def nay_filter(cls, *args):
def filt(*args): def filt(*args):
@@ -524,7 +523,7 @@ class AlbumFilters(object):
words = RB.search_fold(searchtext).split() words = RB.search_fold(searchtext).split()
params = list(map(RB.search_fold, [album.name, album.artist, params = list(map(RB.search_fold, [album.name, album.artist,
album.artists, album.track_titles, album.composers])) album.artists, album.track_titles, album.composers]))
matches = [] matches = []
for word in words: for word in words:
@@ -560,7 +559,7 @@ class AlbumFilters(object):
return RB.search_fold(searchtext) in RB.search_fold(album.artists) return RB.search_fold(searchtext) in RB.search_fold(album.artists)
return filt return filt
@classmethod @classmethod
def similar_artist_filter(cls, searchtext=None): def similar_artist_filter(cls, searchtext=None):
def filt(album): def filt(album):
@@ -572,7 +571,7 @@ class AlbumFilters(object):
words = RB.search_fold(searchtext).split() words = RB.search_fold(searchtext).split()
params = list(map(RB.search_fold, [album.artist, params = list(map(RB.search_fold, [album.artist,
album.artists])) album.artists]))
matches = [] matches = []
for word in words: for word in words:
@@ -588,7 +587,7 @@ class AlbumFilters(object):
return False not in matches return False not in matches
return filt return filt
@classmethod @classmethod
def album_name_filter(cls, searchtext=None): def album_name_filter(cls, searchtext=None):
def filt(album): def filt(album):
@@ -605,18 +604,18 @@ class AlbumFilters(object):
if not searchtext: if not searchtext:
return True return True
return RB.search_fold(searchtext) in RB.search_fold( return RB.search_fold(searchtext) in RB.search_fold(
album.track_titles) album.track_titles)
return filt return filt
@classmethod @classmethod
def composer_filter(cls, searchtext=None): def composer_filter(cls, searchtext=None):
def filt(album): def filt(album):
if not searchtext: if not searchtext:
return True return True
return RB.search_fold(searchtext) in RB.search_fold( return RB.search_fold(searchtext) in RB.search_fold(
album.composers) album.composers)
return filt return filt
@@ -628,7 +627,7 @@ class AlbumFilters(object):
return True return True
genres = RB.search_fold(' '.join(album.genres)) genres = RB.search_fold(' '.join(album.genres))
return RB.search_fold(searchtext) in genres return RB.search_fold(searchtext) in genres
return filt return filt
@@ -657,6 +656,7 @@ class AlbumFilters(object):
or -1 for all albums older than our standard range which is 1930 or -1 for all albums older than our standard range which is 1930
or an actual decade for 1930 to 2020 or an actual decade for 1930 to 2020
''' '''
def filt(album): def filt(album):
if not searchdecade: if not searchdecade:
return True return True
@@ -691,7 +691,6 @@ AlbumFilters.keys = {
'decade': AlbumFilters.decade_filter 'decade': AlbumFilters.decade_filter
} }
sort_keys = { sort_keys = {
'name': ('album_sort', 'album_sort'), 'name': ('album_sort', 'album_sort'),
'artist': ('album_artist_sort', 'album_artist_sort'), 'artist': ('album_artist_sort', 'album_artist_sort'),
@@ -720,7 +719,7 @@ class AlbumsModel(GObject.Object):
'visual-updated': ((GObject.SIGNAL_RUN_LAST, None, (object, object))), 'visual-updated': ((GObject.SIGNAL_RUN_LAST, None, (object, object))),
'filter-changed': ((GObject.SIGNAL_RUN_FIRST, None, ())), 'filter-changed': ((GObject.SIGNAL_RUN_FIRST, None, ())),
'album-added': ((GObject.SIGNAL_RUN_LAST, None, (object,))) 'album-added': ((GObject.SIGNAL_RUN_LAST, None, (object,)))
} }
# list of columns names and positions on the TreeModel # list of columns names and positions on the TreeModel
columns = {'tooltip': 0, 'pixbuf': 1, 'album': 2, 'markup': 3, 'show': 4} columns = {'tooltip': 0, 'pixbuf': 1, 'album': 2, 'markup': 3, 'show': 4}
@@ -731,10 +730,10 @@ class AlbumsModel(GObject.Object):
self._iters = {} self._iters = {}
self._albums = SortedCollection( self._albums = SortedCollection(
key=lambda album: getattr(album, 'name')) key=lambda album: getattr(album, 'name'))
self._sortkey = {'type':'name', 'order':True} self._sortkey = {'type': 'name', 'order': True}
self._tree_store = Gtk.ListStore(str, GdkPixbuf.Pixbuf, object, str, self._tree_store = Gtk.ListStore(str, GdkPixbuf.Pixbuf, object, str,
bool) bool)
# filters # filters
self._filters = {} self._filters = {}
@@ -757,7 +756,7 @@ class AlbumsModel(GObject.Object):
markup = self.emit('generate-markup', album) markup = self.emit('generate-markup', album)
self._tree_store.set(tree_iter, self.columns['markup'], self._tree_store.set(tree_iter, self.columns['markup'],
markup) markup)
self._emit_signal(tree_iter, 'visual-updated') self._emit_signal(tree_iter, 'visual-updated')
def error(exception): def error(exception):
@@ -766,7 +765,7 @@ class AlbumsModel(GObject.Object):
return ALBUM_LOAD_CHUNK, process, None, error, None return ALBUM_LOAD_CHUNK, process, None, error, None
def _album_modified(self, album): def _album_modified(self, album):
print ("_album_modified") print("_album_modified")
tree_iter = self._iters[album.name][album.artist]['iter'] tree_iter = self._iters[album.name][album.artist]['iter']
if self._tree_store.iter_is_valid(tree_iter): if self._tree_store.iter_is_valid(tree_iter):
@@ -776,7 +775,7 @@ class AlbumsModel(GObject.Object):
self._generate_values(album) self._generate_values(album)
self._tree_store.set(tree_iter, self.columns['tooltip'], tooltip, self._tree_store.set(tree_iter, self.columns['tooltip'], tooltip,
self.columns['markup'], markup, self.columns['show'], hidden) self.columns['markup'], markup, self.columns['show'], hidden)
# reorder the album # reorder the album
new_pos = self._albums.reorder(album) new_pos = self._albums.reorder(album)
@@ -794,8 +793,8 @@ class AlbumsModel(GObject.Object):
self._tree_store.move_before(tree_iter, old_iter) self._tree_store.move_before(tree_iter, old_iter)
# inform that the album is updated # inform that the album is updated
print ("album modified") print("album modified")
print (album) print(album)
self._emit_signal(tree_iter, 'album-updated') self._emit_signal(tree_iter, 'album-updated')
def _cover_updated(self, album): def _cover_updated(self, album):
@@ -806,7 +805,7 @@ class AlbumsModel(GObject.Object):
pixbuf = album.cover.pixbuf pixbuf = album.cover.pixbuf
self._tree_store.set_value(tree_iter, self.columns['pixbuf'], self._tree_store.set_value(tree_iter, self.columns['pixbuf'],
pixbuf) pixbuf)
self._emit_signal(tree_iter, 'visual-updated') self._emit_signal(tree_iter, 'visual-updated')
@@ -836,12 +835,12 @@ class AlbumsModel(GObject.Object):
tree_iter = self._tree_store.insert(self._albums.insert(album), values) tree_iter = self._tree_store.insert(self._albums.insert(album), values)
# connect signals # connect signals
ids = (album.connect('modified', self._album_modified), ids = (album.connect('modified', self._album_modified),
album.connect('cover-updated', self._cover_updated), album.connect('cover-updated', self._cover_updated),
album.connect('emptied', self.remove)) album.connect('emptied', self.remove))
if not album.name in self._iters: if not album.name in self._iters:
self._iters[album.name] = {} self._iters[album.name] = {}
self._iters[album.name][album.artist] = {'album': album, self._iters[album.name][album.artist] = {'album': album,
'iter': tree_iter, 'ids': ids} 'iter': tree_iter, 'ids': ids}
self.emit('album-added', album) self.emit('album-added', album)
return tree_iter return tree_iter
@@ -859,8 +858,8 @@ class AlbumsModel(GObject.Object):
:param album: `Album` to be removed from the model. :param album: `Album` to be removed from the model.
''' '''
print ("album model remove") print("album model remove")
print (album) print(album)
self._albums.remove(album) self._albums.remove(album)
self._tree_store.remove(self._iters[album.name][album.artist]['iter']) self._tree_store.remove(self._iters[album.name][album.artist]['iter'])
@@ -886,18 +885,18 @@ class AlbumsModel(GObject.Object):
:param album_name: `str` name of the album. :param album_name: `str` name of the album.
''' '''
return self._iters[album_name][album_artist]['album'] return self._iters[album_name][album_artist]['album']
def get_from_dbentry(self, entry): def get_from_dbentry(self, entry):
''' '''
Returns the album containing the track corresponding to rhythmdbentry Returns the album containing the track corresponding to rhythmdbentry
:param entry: `RhythmDBEntry` :param entry: `RhythmDBEntry`
''' '''
album_artist = entry.get_string(RB.RhythmDBPropType.ALBUM_ARTIST) album_artist = entry.get_string(RB.RhythmDBPropType.ALBUM_ARTIST)
album_artist = album_artist if album_artist else entry.get_string(RB.RhythmDBPropType.ARTIST) album_artist = album_artist if album_artist else entry.get_string(RB.RhythmDBPropType.ARTIST)
album_name = entry.get_string(RB.RhythmDBPropType.ALBUM) album_name = entry.get_string(RB.RhythmDBPropType.ALBUM)
return self._iters[album_name][album_artist]['album'] return self._iters[album_name][album_artist]['album']
def get_all(self): def get_all(self):
@@ -942,9 +941,9 @@ class AlbumsModel(GObject.Object):
return self._filtered_store.convert_child_path_to_path( return self._filtered_store.convert_child_path_to_path(
self._tree_store.get_path( self._tree_store.get_path(
self._iters[album.name][album.artist]['iter'])) self._iters[album.name][album.artist]['iter']))
def find_first_visible(self, filter_key, filter_arg, start=None, def find_first_visible(self, filter_key, filter_arg, start=None,
backwards=False): backwards=False):
album_filter = AlbumFilters.keys[filter_key](filter_arg) album_filter = AlbumFilters.keys[filter_key](filter_arg)
albums = reversed(self._albums) if backwards else self._albums albums = reversed(self._albums) if backwards else self._albums
@@ -993,24 +992,24 @@ class AlbumsModel(GObject.Object):
''' '''
Changes the sorting strategy for the model. Changes the sorting strategy for the model.
''' '''
gs = GSetting() gs = GSetting()
source_settings = gs.get_setting(gs.Path.PLUGIN) source_settings = gs.get_setting(gs.Path.PLUGIN)
key = source_settings[gs.PluginKey.SORT_BY] key = source_settings[gs.PluginKey.SORT_BY]
order = source_settings[gs.PluginKey.SORT_ORDER] order = source_settings[gs.PluginKey.SORT_ORDER]
print ("current") print("current")
print (self._sortkey) print(self._sortkey)
print ("registry") print("registry")
print (key) print(key)
print (order) print(order)
if key == self._sortkey['type']: if key == self._sortkey['type']:
key = None key = None
else: else:
self._sortkey['type'] = key self._sortkey['type'] = key
if order != self._sortkey['order']: if order != self._sortkey['order']:
reverse = True reverse = True
self._sortkey['order'] = order self._sortkey['order'] = order
@@ -1020,17 +1019,17 @@ class AlbumsModel(GObject.Object):
def key_function(album): def key_function(album):
keys = [getattr(album, prop) for prop in props] keys = [getattr(album, prop) for prop in props]
return keys return keys
if not key and not reverse: if not key and not reverse:
print ("nothing to sort") print("nothing to sort")
return return
print (key) print(key)
print (reverse) print(reverse)
if key: if key:
props = sort_keys[key] props = sort_keys[key]
self._albums.key = key_function self._albums.key = key_function
if reverse: if reverse:
self._albums = reversed(self._albums) self._albums = reversed(self._albums)
@@ -1089,15 +1088,15 @@ class AlbumsModel(GObject.Object):
def do_filter_changed(self): def do_filter_changed(self):
pos = 0 pos = 0
for show_result in list(map(self._album_filter, self._albums)): for show_result in list(map(self._album_filter, self._albums)):
self.show( self._albums[pos], show_result ) self.show(self._albums[pos], show_result)
pos = pos + 1 pos = pos + 1
def _album_filter(self, album): def _album_filter(self, album):
for f in list(self._filters.values()): for f in list(self._filters.values()):
if not f(album): if not f(album):
return False return False
return True return True
def recreate_text(self): def recreate_text(self):
''' '''
@@ -1105,6 +1104,7 @@ class AlbumsModel(GObject.Object):
''' '''
self._recreate_text(iter(self._albums)) self._recreate_text(iter(self._albums))
class AlbumLoader(GObject.Object): class AlbumLoader(GObject.Object):
''' '''
Loads and updates Rhythmbox's tracks and albums, updating the model Loads and updates Rhythmbox's tracks and albums, updating the model
@@ -1116,7 +1116,7 @@ class AlbumLoader(GObject.Object):
__gsignals__ = { __gsignals__ = {
'albums-load-finished': (GObject.SIGNAL_RUN_LAST, None, (object,)), 'albums-load-finished': (GObject.SIGNAL_RUN_LAST, None, (object,)),
'model-load-finished': (GObject.SIGNAL_RUN_LAST, None, ()) 'model-load-finished': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self, album_manager): def __init__(self, album_manager):
super(AlbumLoader, self).__init__() super(AlbumLoader, self).__init__()
@@ -1129,11 +1129,11 @@ class AlbumLoader(GObject.Object):
def _connect_signals(self): def _connect_signals(self):
# connect signals for updating the albums # connect signals for updating the albums
self.entry_changed_id = self._album_manager.db.connect('entry-changed', self.entry_changed_id = self._album_manager.db.connect('entry-changed',
self._entry_changed_callback) self._entry_changed_callback)
self.entry_added_id = self._album_manager.db.connect('entry-added', self.entry_added_id = self._album_manager.db.connect('entry-added',
self._entry_added_callback) self._entry_added_callback)
self.entry_deleted_id = self._album_manager.db.connect('entry-deleted', self.entry_deleted_id = self._album_manager.db.connect('entry-deleted',
self._entry_deleted_callback) self._entry_deleted_callback)
@idle_iterator @idle_iterator
def _load_albums(self): def _load_albums(self):
@@ -1143,7 +1143,7 @@ class AlbumLoader(GObject.Object):
# allocate the track # allocate the track
track = Track(entry, self._album_manager.db) track = Track(entry, self._album_manager.db)
self._tracks[track.location] = track self._tracks[track.location] = track
album_name = track.album album_name = track.album
album_artist = track.album_artist album_artist = track.album_artist
album_artist = album_artist if album_artist else track.artist album_artist = album_artist if album_artist else track.artist
@@ -1155,11 +1155,11 @@ class AlbumLoader(GObject.Object):
album = data['albums'][album_name][album_artist] album = data['albums'][album_name][album_artist]
else: else:
album = Album(album_name, album_artist, album = Album(album_name, album_artist,
self._album_manager.cover_man.unknown_cover) self._album_manager.cover_man.unknown_cover)
data['albums'][album_name][album_artist] = album data['albums'][album_name][album_artist] = album
album.add_track(track) album.add_track(track)
def after(data): def after(data):
# update the progress # update the progress
data['progress'] += ALBUM_LOAD_CHUNK data['progress'] += ALBUM_LOAD_CHUNK
@@ -1209,36 +1209,36 @@ class AlbumLoader(GObject.Object):
# this now works correctly # this now works correctly
def analyse_change(change): def analyse_change(change):
print (change.prop) print(change.prop)
if change.prop is RB.RhythmDBPropType.ALBUM \ if change.prop is RB.RhythmDBPropType.ALBUM \
or change.prop is RB.RhythmDBPropType.ALBUM_ARTIST \ or change.prop is RB.RhythmDBPropType.ALBUM_ARTIST \
or change.prop is RB.RhythmDBPropType.ARTIST \ or change.prop is RB.RhythmDBPropType.ARTIST \
or change.prop is RhythmDBPropType.ALBUM_SORTNAME \ or change.prop is RhythmDBPropType.ALBUM_SORTNAME \
or change.prop is RhythmDBPropType.ALBUM_ARTIST_SORTNAME: or change.prop is RhythmDBPropType.ALBUM_ARTIST_SORTNAME:
# called when the album of a entry is modified # called when the album of a entry is modified
track.emit('deleted') track.emit('deleted')
track.emit('modified') track.emit('modified')
print ("change prop album or artist") print("change prop album or artist")
self._allocate_track(track) self._allocate_track(track)
elif change.prop is RB.RhythmDBPropType.HIDDEN: elif change.prop is RB.RhythmDBPropType.HIDDEN:
# called when an entry gets hidden (e.g.:the sound file is # called when an entry gets hidden (e.g.:the sound file is
# removed. # removed.
if changes.new: if changes.new:
print ("change prop new") print("change prop new")
track.emit('deleted') track.emit('deleted')
else: else:
print ("change prop dunno") print("change prop dunno")
self._allocate_track(track) self._allocate_track(track)
# look at all the changes and update the albums accordingly # look at all the changes and update the albums accordingly
try: try:
track = self._tracks[Track(entry).location] track = self._tracks[Track(entry).location]
if rb3compat.is_rb3(): if rb3compat.is_rb3():
#RB3 has a simple rhythmdbentrychange array to deal with so we #RB3 has a simple rhythmdbentrychange array to deal with so we
#just need to loop each element of the array #just need to loop each element of the array
for change in changes: for change in changes:
analyse_change(change) analyse_change(change)
else: else:
@@ -1247,15 +1247,15 @@ class AlbumLoader(GObject.Object):
while changes.n_values != 0: while changes.n_values != 0:
change = changes.values change = changes.values
analyse_change(change) analyse_change(change)
# removes the last change from the GValueArray # removes the last change from the GValueArray
changes.remove(0) changes.remove(0)
except: except:
# we have a problem houston ... RB2.98 and 2.99 cant cope # we have a problem houston ... RB2.98 and 2.99 cant cope
# lets just assume something has just changed # lets just assume something has just changed
track = self._tracks[Track(entry).location] track = self._tracks[Track(entry).location]
print ("except") print("except")
track.emit('modified') track.emit('modified')
print("CoverArtBrowser DEBUG - end entry_changed_callback") print("CoverArtBrowser DEBUG - end entry_changed_callback")
@@ -1289,15 +1289,15 @@ class AlbumLoader(GObject.Object):
album_artist = album_artist if album_artist else track.artist album_artist = album_artist if album_artist else track.artist
if self._album_manager.model.contains(album_name, album_artist): if self._album_manager.model.contains(album_name, album_artist):
print ("allocate track - contains") print("allocate track - contains")
album = self._album_manager.model.get(album_name, album_artist) album = self._album_manager.model.get(album_name, album_artist)
print (album) print(album)
album.add_track(track) album.add_track(track)
else: else:
print ("allocate track - does not contain") print("allocate track - does not contain")
album = Album(album_name, album_artist, album = Album(album_name, album_artist,
self._album_manager.cover_man.unknown_cover) self._album_manager.cover_man.unknown_cover)
print (album) print(album)
album.add_track(track) album.add_track(track)
self._album_manager.cover_man.load_cover(album) self._album_manager.cover_man.load_cover(album)
self._album_manager.model.add(album) self._album_manager.model.add(album)
@@ -1310,7 +1310,7 @@ class AlbumLoader(GObject.Object):
print("CoverArtBrowser DEBUG - load_albums") print("CoverArtBrowser DEBUG - load_albums")
self._load_albums(iter(query_model), albums={}, model=query_model, self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.) total=len(query_model), progress=0.)
print("CoverArtBrowser DEBUG - load_albums finished") print("CoverArtBrowser DEBUG - load_albums finished")
@@ -1324,7 +1324,6 @@ class AlbumLoader(GObject.Object):
class CoverRequester(GObject.Object): class CoverRequester(GObject.Object):
def __init__(self, cover_db): def __init__(self, cover_db):
super(CoverRequester, self).__init__() super(CoverRequester, self).__init__()
@@ -1383,7 +1382,7 @@ class CoverRequester(GObject.Object):
# add a timeout to the request # add a timeout to the request
Gdk.threads_add_timeout_seconds(GLib.PRIORITY_DEFAULT_IDLE, 40, Gdk.threads_add_timeout_seconds(GLib.PRIORITY_DEFAULT_IDLE, 40,
self._next, self._queue_id) self._next, self._queue_id)
else: else:
# if there're no more elements, clean the state of the requester # if there're no more elements, clean the state of the requester
self._running = False self._running = False
@@ -1419,8 +1418,8 @@ class CoverRequester(GObject.Object):
def stop(self): def stop(self):
''' Clears the queue, forcing the requester to stop. ''' ''' Clears the queue, forcing the requester to stop. '''
del self._queue[:] del self._queue[:]
class CoverManager(GObject.Object): class CoverManager(GObject.Object):
''' '''
Manager that takes care of cover loading and updating. Manager that takes care of cover loading and updating.
@@ -1433,7 +1432,7 @@ class CoverManager(GObject.Object):
# signals # signals
__gsignals__ = { __gsignals__ = {
'load-finished': (GObject.SIGNAL_RUN_LAST, None, ()) 'load-finished': (GObject.SIGNAL_RUN_LAST, None, ())
} }
# properties # properties
has_finished_loading = False has_finished_loading = False
@@ -1446,12 +1445,12 @@ class CoverManager(GObject.Object):
self._manager = manager self._manager = manager
self._requester = CoverRequester(self.cover_db) self._requester = CoverRequester(self.cover_db)
self.unknown_cover = None #to be defined by inherited class self.unknown_cover = None #to be defined by inherited class
self.album_manager = None #to be defined by inherited class self.album_manager = None #to be defined by inherited class
# connect the signal to update cover arts when added # connect the signal to update cover arts when added
self.req_id = self.cover_db.connect('added', self.req_id = self.cover_db.connect('added',
self.coverart_added_callback) self.coverart_added_callback)
self.connect('load-finished', self._on_load_finished) self.connect('load-finished', self._on_load_finished)
def _on_load_finished(self, *args): def _on_load_finished(self, *args):
@@ -1505,7 +1504,7 @@ class CoverManager(GObject.Object):
# create a key and look for the art location # create a key and look for the art location
key = coverobject.create_ext_db_key() key = coverobject.create_ext_db_key()
art_location = self.cover_db.lookup(key) art_location = self.cover_db.lookup(key)
# try to create a cover # try to create a cover
if art_location: if art_location:
coverobject.cover = self.create_cover(art_location) coverobject.cover = self.create_cover(art_location)
@@ -1536,16 +1535,16 @@ class CoverManager(GObject.Object):
if not check_lastfm(self.force_lastfm_check): if not check_lastfm(self.force_lastfm_check):
# display error message and quit # display error message and quit
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("Enable LastFM plugin and log in first")) _("Enable LastFM plugin and log in first"))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
return return
if coverobjects is None: if coverobjects is None:
self._requester.replace_queue( self._requester.replace_queue(
list(self._manager.model.get_all()), callback) list(self._manager.model.get_all()), callback)
@@ -1557,10 +1556,10 @@ class CoverManager(GObject.Object):
Cancel the current cover request, if there is one running. Cancel the current cover request, if there is one running.
''' '''
self._requester.stop() self._requester.stop()
def update_pixbuf_cover(self, coverobject, pixbuf): def update_pixbuf_cover(self, coverobject, pixbuf):
pass pass
def update_cover(self, coverobject, pixbuf=None, uri=None): def update_cover(self, coverobject, pixbuf=None, uri=None):
''' '''
Updates the cover database, inserting the pixbuf as the cover art for Updates the cover database, inserting the pixbuf as the cover art for
@@ -1599,7 +1598,7 @@ class CoverManager(GObject.Object):
self.update_cover(coverobject, cover) self.update_cover(coverobject, cover)
except: except:
print("The URI doesn't point to an image or " + \ print("The URI doesn't point to an image or " + \
"the image couldn't be opened.") "the image couldn't be opened.")
async = rb.Loader() async = rb.Loader()
async.get_url(uri, cover_update, coverobject) async.get_url(uri, cover_update, coverobject)
@@ -1609,11 +1608,11 @@ class AlbumCoverManager(CoverManager):
# properties # properties
add_shadow = GObject.property(type=bool, default=False) add_shadow = GObject.property(type=bool, default=False)
shadow_image = GObject.property(type=str, default="above") shadow_image = GObject.property(type=str, default="above")
def __init__(self, plugin, album_manager): def __init__(self, plugin, album_manager):
self.cover_db = RB.ExtDB(name='album-art') self.cover_db = RB.ExtDB(name='album-art')
super(AlbumCoverManager, self).__init__(plugin, album_manager) super(AlbumCoverManager, self).__init__(plugin, album_manager)
self.album_manager = album_manager self.album_manager = album_manager
self._connect_properties() self._connect_properties()
self._connect_signals(plugin) self._connect_signals(plugin)
@@ -1625,29 +1624,29 @@ class AlbumCoverManager(CoverManager):
self.connect('notify::cover-size', self._on_cover_size_changed) self.connect('notify::cover-size', self._on_cover_size_changed)
self.connect('notify::add-shadow', self._on_add_shadow_changed, plugin) self.connect('notify::add-shadow', self._on_add_shadow_changed, plugin)
self.connect('notify::shadow-image', self._on_add_shadow_changed, self.connect('notify::shadow-image', self._on_add_shadow_changed,
plugin) plugin)
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover_size', setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover_size',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.ADD_SHADOW, self, 'add_shadow', setting.bind(gs.PluginKey.ADD_SHADOW, self, 'add_shadow',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.SHADOW_IMAGE, self, 'shadow_image', setting.bind(gs.PluginKey.SHADOW_IMAGE, self, 'shadow_image',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
def create_unknown_cover(self, plugin): def create_unknown_cover(self, plugin):
# create the unknown cover # create the unknown cover
self._shadow = Shadow(self.cover_size, self._shadow = Shadow(self.cover_size,
rb.find_plugin_file(plugin, 'img/album-shadow-%s.png' % rb.find_plugin_file(plugin, 'img/album-shadow-%s.png' %
self.shadow_image)) self.shadow_image))
self.unknown_cover = self.create_cover( self.unknown_cover = self.create_cover(
rb.find_plugin_file(plugin, 'img/rhythmbox-missing-artwork.svg')) rb.find_plugin_file(plugin, 'img/rhythmbox-missing-artwork.svg'))
super(AlbumCoverManager,self).create_unknown_cover(plugin) super(AlbumCoverManager, self).create_unknown_cover(plugin)
def create_cover(self, image): def create_cover(self, image):
if self.add_shadow: if self.add_shadow:
cover = ShadowedCover(self._shadow, image) cover = ShadowedCover(self._shadow, image)
@@ -1655,14 +1654,14 @@ class AlbumCoverManager(CoverManager):
cover = Cover(self.cover_size, image) cover = Cover(self.cover_size, image)
return cover return cover
def _on_add_shadow_changed(self, obj, prop, plugin): def _on_add_shadow_changed(self, obj, prop, plugin):
# update the unknown_cover # update the unknown_cover
self.create_unknown_cover(plugin) self.create_unknown_cover(plugin)
# recreate all the covers # recreate all the covers
self.load_covers() self.load_covers()
def _on_cover_size_changed(self, *args): def _on_cover_size_changed(self, *args):
''' '''
Updates the showing albums cover size. Updates the showing albums cover size.
@@ -1680,22 +1679,22 @@ class AlbumCoverManager(CoverManager):
def update_item_width(self): def update_item_width(self):
self.album_manager.current_view.resize_icon(self.cover_size) self.album_manager.current_view.resize_icon(self.cover_size)
def update_pixbuf_cover(self, coverobject, pixbuf): def update_pixbuf_cover(self, coverobject, pixbuf):
# if it's a pixbuf, assign it to all the artist for the album # if it's a pixbuf, assign it to all the artist for the album
key = RB.ExtDBKey.create_storage('album', coverobject.name)
key.add_field('artist', coverobject.artist)
self.cover_db.store(key, RB.ExtDBSourceType.USER_EXPLICIT,
pixbuf)
for artist in coverobject.artists.split(', '):
key = RB.ExtDBKey.create_storage('album', coverobject.name) key = RB.ExtDBKey.create_storage('album', coverobject.name)
key.add_field('artist', coverobject.artist) key.add_field('artist', artist)
self.cover_db.store(key, RB.ExtDBSourceType.USER_EXPLICIT, self.cover_db.store(key, RB.ExtDBSourceType.USER_EXPLICIT,
pixbuf) pixbuf)
for artist in coverobject.artists.split(', '):
key = RB.ExtDBKey.create_storage('album', coverobject.name)
key.add_field('artist', artist)
self.cover_db.store(key, RB.ExtDBSourceType.USER_EXPLICIT,
pixbuf)
@idle_iterator @idle_iterator
def _resize_covers(self): def _resize_covers(self):
def process(coverobject, data): def process(coverobject, data):
@@ -1728,7 +1727,7 @@ class TextManager(GObject.Object):
display_text_ellipsize_enabled = GObject.property(type=bool, default=False) display_text_ellipsize_enabled = GObject.property(type=bool, default=False)
display_text_ellipsize_length = GObject.property(type=int, default=0) display_text_ellipsize_length = GObject.property(type=int, default=0)
display_font_size = GObject.property(type=int, default=0) display_font_size = GObject.property(type=int, default=0)
def __init__(self, album_manager): def __init__(self, album_manager):
super(TextManager, self).__init__() super(TextManager, self).__init__()
@@ -1745,16 +1744,16 @@ class TextManager(GObject.Object):
''' '''
# connect signals for the loader properties # connect signals for the loader properties
self.connect('notify::display-text-ellipsize-enabled', self.connect('notify::display-text-ellipsize-enabled',
self._on_notify_display_text_ellipsize) self._on_notify_display_text_ellipsize)
self.connect('notify::display-text-ellipsize-length', self.connect('notify::display-text-ellipsize-length',
self._on_notify_display_text_ellipsize) self._on_notify_display_text_ellipsize)
self.connect('notify::display-font-size', self.connect('notify::display-font-size',
self._on_notify_display_text_ellipsize) self._on_notify_display_text_ellipsize)
self._album_manager.model.connect('generate-tooltip', self._album_manager.model.connect('generate-tooltip',
self._generate_tooltip) self._generate_tooltip)
self._album_manager.model.connect('generate-markup', self._album_manager.model.connect('generate-markup',
self._generate_markup_text) self._generate_markup_text)
def _connect_properties(self): def _connect_properties(self):
''' '''
@@ -1764,27 +1763,27 @@ class TextManager(GObject.Object):
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, self, setting.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, self,
'display_text_ellipsize_enabled', Gio.SettingsBindFlags.GET) 'display_text_ellipsize_enabled', Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH, self, setting.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH, self,
'display_text_ellipsize_length', 'display_text_ellipsize_length',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_FONT_SIZE, self, 'display_font_size', setting.bind(gs.PluginKey.DISPLAY_FONT_SIZE, self, 'display_font_size',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
def _on_notify_display_text_ellipsize(self, *args): def _on_notify_display_text_ellipsize(self, *args):
''' '''
Callback called when one of the properties related with the ellipsize Callback called when one of the properties related with the ellipsize
option is changed. option is changed.
''' '''
self._album_manager.model.recreate_text() self._album_manager.model.recreate_text()
def _generate_tooltip(self, model, album): def _generate_tooltip(self, model, album):
''' '''
Utility function that creates the tooltip for this album to set into Utility function that creates the tooltip for this album to set into
the model. the model.
''' '''
return cgi.escape(rb3compat.unicodeencode(_('%s by %s'), 'utf-8') % (album.name, return cgi.escape(rb3compat.unicodeencode(_('%s by %s'), 'utf-8') % (album.name,
album.artists)) album.artists))
def _generate_markup_text(self, model, album): def _generate_markup_text(self, model, album):
''' '''
@@ -1815,6 +1814,7 @@ class TextManager(GObject.Object):
markup = "<span font='%d'><b>%s</b>\n<i>%s</i></span>" markup = "<span font='%d'><b>%s</b>\n<i>%s</i></span>"
return markup % (self.display_font_size, name, artist) return markup % (self.display_font_size, name, artist)
class AlbumManager(GObject.Object): class AlbumManager(GObject.Object):
''' '''
Main construction that glues together the different managers, the loader Main construction that glues together the different managers, the loader
@@ -1828,12 +1828,12 @@ class AlbumManager(GObject.Object):
# properties # properties
progress = GObject.property(type=float, default=0) progress = GObject.property(type=float, default=0)
# signals # signals
__gsignals__ = { __gsignals__ = {
'sort': (GObject.SIGNAL_RUN_LAST, None, (object,)) 'sort': (GObject.SIGNAL_RUN_LAST, None, (object,))
} }
def __init__(self, plugin, current_view): def __init__(self, plugin, current_view):
super(AlbumManager, self).__init__() super(AlbumManager, self).__init__()
@@ -1847,6 +1847,7 @@ class AlbumManager(GObject.Object):
self.loader = AlbumLoader(self) self.loader = AlbumLoader(self)
self.cover_man = AlbumCoverManager(plugin, self) self.cover_man = AlbumCoverManager(plugin, self)
from coverart_artistview import ArtistManager from coverart_artistview import ArtistManager
self.artist_man = ArtistManager(plugin, self, plugin.shell) self.artist_man = ArtistManager(plugin, self, plugin.shell)
self.text_man = TextManager(self) self.text_man = TextManager(self)
self._show_policy = current_view.show_policy.initialise(self) self._show_policy = current_view.show_policy.initialise(self)
@@ -1860,11 +1861,10 @@ class AlbumManager(GObject.Object):
''' '''
# connect signal to the loader so it shows the albums when it finishes # connect signal to the loader so it shows the albums when it finishes
self._load_finished_id = self.loader.connect('model-load-finished', self._load_finished_id = self.loader.connect('model-load-finished',
self._load_finished_callback) self._load_finished_callback)
self.connect('sort', self._sort_album) self.connect('sort', self._sort_album)
def _sort_album(self, widget, param): def _sort_album(self, widget, param):
toolbar_type = param toolbar_type = param
if not toolbar_type or toolbar_type == "album": if not toolbar_type or toolbar_type == "album":
+339 -335
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+262 -255
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+57 -54
Ver Arquivo
@@ -41,10 +41,12 @@ from coverart_toolbar import TopToolbar
import coverart_rb3compat as rb3compat import coverart_rb3compat as rb3compat
class CoverArtBrowserEntryType(RB.RhythmDBEntryType): class CoverArtBrowserEntryType(RB.RhythmDBEntryType):
''' '''
Entry type for our source. Entry type for our source.
''' '''
def __init__(self): def __init__(self):
''' '''
Initializes the entry type. Initializes the entry type.
@@ -90,44 +92,44 @@ class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable):
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
entry_type.category = RB.RhythmDBEntryCategory.NORMAL entry_type.category = RB.RhythmDBEntryCategory.NORMAL
group = RB.DisplayPageGroup.get_by_id('library') group = RB.DisplayPageGroup.get_by_id('library')
# load plugin icon # load plugin icon
theme = Gtk.IconTheme.get_default() theme = Gtk.IconTheme.get_default()
rb.append_plugin_source_path(theme, '/icons') rb.append_plugin_source_path(theme, '/icons')
# lets assume that python3 versions of RB only has the new icon attribute in the source # lets assume that python3 versions of RB only has the new icon attribute in the source
if rb3compat.PYVER >=3: if rb3compat.PYVER >= 3:
iconfile = Gio.File.new_for_path( iconfile = Gio.File.new_for_path(
rb.find_plugin_file(self, 'img/covermgr_rb3.png')) rb.find_plugin_file(self, 'img/covermgr_rb3.png'))
self.source = CoverArtBrowserSource( self.source = CoverArtBrowserSource(
shell=self.shell, shell=self.shell,
name=_("CoverArt"), name=_("CoverArt"),
entry_type=entry_type, entry_type=entry_type,
plugin=self, plugin=self,
icon=Gio.FileIcon.new(iconfile), icon=Gio.FileIcon.new(iconfile),
query_model=self.shell.props.library_source.props.base_query_model) query_model=self.shell.props.library_source.props.base_query_model)
else: else:
what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.LARGE_TOOLBAR) what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.LARGE_TOOLBAR)
pxbf = GdkPixbuf.Pixbuf.new_from_file_at_size( pxbf = GdkPixbuf.Pixbuf.new_from_file_at_size(
rb.find_plugin_file(self, 'img/covermgr.png'), width, height) rb.find_plugin_file(self, 'img/covermgr.png'), width, height)
self.source = CoverArtBrowserSource(
shell=self.shell,
name=_("CoverArt"), entry_type=entry_type,
plugin=self, pixbuf=pxbf,
query_model=self.shell.props.library_source.props.base_query_model)
self.source = CoverArtBrowserSource(
shell=self.shell,
name=_("CoverArt"), entry_type=entry_type,
plugin=self, pixbuf=pxbf,
query_model=self.shell.props.library_source.props.base_query_model)
self.shell.register_entry_type_for_source(self.source, entry_type) self.shell.register_entry_type_for_source(self.source, entry_type)
self.shell.append_display_page(self.source, group) self.shell.append_display_page(self.source, group)
self.source.props.query_model.connect('complete', self.load_complete) self.source.props.query_model.connect('complete', self.load_complete)
if rb3compat.PYVER >=3: if rb3compat.PYVER >= 3:
self._externalmenu = ExternalPluginMenu(self) self._externalmenu = ExternalPluginMenu(self)
else: else:
self._externalmenu = None self._externalmenu = None
cl.switch_locale(cl.Locale.RB) cl.switch_locale(cl.Locale.RB)
print("CoverArtBrowser DEBUG - end do_activate") print("CoverArtBrowser DEBUG - end do_activate")
@@ -145,7 +147,7 @@ class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable):
del self.source del self.source
print("CoverArtBrowser DEBUG - end do_deactivate") print("CoverArtBrowser DEBUG - end do_deactivate")
def load_complete(self, *args, **kwargs): def load_complete(self, *args, **kwargs):
''' '''
Called by Rhythmbox when it has completed loading all data Called by Rhythmbox when it has completed loading all data
@@ -157,64 +159,65 @@ class CoverArtBrowserPlugin(GObject.Object, Peas.Activatable):
if setting[gs.PluginKey.AUTOSTART]: if setting[gs.PluginKey.AUTOSTART]:
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.source) self.source)
def _translation_helper(self): def _translation_helper(self):
''' '''
a method just to help out with translation strings a method just to help out with translation strings
it is not meant to be called by itself it is not meant to be called by itself
''' '''
# define .plugin text strings used for translation # define .plugin text strings used for translation
plugin = _('CoverArt Browser') plugin = _('CoverArt Browser')
desc = _('Browse and play your albums through their covers') desc = _('Browse and play your albums through their covers')
#. TRANSLATORS: This is the icon-grid view that the user sees #. TRANSLATORS: This is the icon-grid view that the user sees
tile = _('Tiles') tile = _('Tiles')
#. TRANSLATORS: This is the cover-flow view the user sees - they can swipe album covers from side-to-side #. TRANSLATORS: This is the cover-flow view the user sees - they can swipe album covers from side-to-side
artist = _('Flow') artist = _('Flow')
#. TRANSLATORS: percentage size that the image will be expanded #. TRANSLATORS: percentage size that the image will be expanded
scale = _('Scale by %:') scale = _('Scale by %:')
class ExternalPluginMenu(GObject.Object):
class ExternalPluginMenu(GObject.Object):
toolbar_pos = GObject.property(type=str, default=TopToolbar.name) toolbar_pos = GObject.property(type=str, default=TopToolbar.name)
def __init__(self, plugin): def __init__(self, plugin):
super(ExternalPluginMenu, self).__init__() super(ExternalPluginMenu, self).__init__()
self.plugin = plugin self.plugin = plugin
self.shell = plugin.shell self.shell = plugin.shell
self.source = plugin.source self.source = plugin.source
self.app_id = None self.app_id = None
from coverart_browser_source import Views from coverart_browser_source import Views
self._views = Views(self.shell) self._views = Views(self.shell)
self._connect_properties() self._connect_properties()
self._connect_signals() self._connect_signals()
self._create_menu() self._create_menu()
def _connect_signals(self): def _connect_signals(self):
self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos) self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
self.shell.props.display_page_tree.connect( self.shell.props.display_page_tree.connect(
"selected", self.on_page_change "selected", self.on_page_change
) )
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos', setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
def _on_notify_toolbar_pos(self, *args): def _on_notify_toolbar_pos(self, *args):
if self.toolbar_pos == TopToolbar.name: if self.toolbar_pos == TopToolbar.name:
self._create_menu() self._create_menu()
else: else:
self.cleanup() self.cleanup()
def cleanup(self): def cleanup(self):
if self.app_id: if self.app_id:
app = Gio.Application.get_default() app = Gio.Application.get_default()
@@ -225,46 +228,46 @@ class ExternalPluginMenu(GObject.Object):
def _create_menu(self): def _create_menu(self):
app = Gio.Application.get_default() app = Gio.Application.get_default()
self.app_id = 'coverart-browser' self.app_id = 'coverart-browser'
self.locations = ['library-toolbar', 'queue-toolbar'] self.locations = ['library-toolbar', 'queue-toolbar']
action_name = 'coverart-browser-views' action_name = 'coverart-browser-views'
self.action = Gio.SimpleAction.new_stateful( self.action = Gio.SimpleAction.new_stateful(
action_name, GLib.VariantType.new('s'), action_name, GLib.VariantType.new('s'),
self._views.get_action_name(ListView.name) self._views.get_action_name(ListView.name)
) )
self.action.connect("activate", self.view_change_cb) self.action.connect("activate", self.view_change_cb)
app.add_action(self.action) app.add_action(self.action)
menu_item = Gio.MenuItem() menu_item = Gio.MenuItem()
section = Gio.Menu() section = Gio.Menu()
menu = Gio.Menu() menu = Gio.Menu()
toolbar_item = Gio.MenuItem() toolbar_item = Gio.MenuItem()
for view_name in self._views.get_view_names(): for view_name in self._views.get_view_names():
menu_item.set_label(self._views.get_menu_name(view_name)) menu_item.set_label(self._views.get_menu_name(view_name))
menu_item.set_action_and_target_value( menu_item.set_action_and_target_value(
'app.' + action_name, self._views.get_action_name(view_name) 'app.' + action_name, self._views.get_action_name(view_name)
) )
section.append_item(menu_item) section.append_item(menu_item)
menu.append_section(None, section) menu.append_section(None, section)
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
toolbar_item.set_label(_('Views')) toolbar_item.set_label(_('Views'))
cl.switch_locale(cl.Locale.RB) cl.switch_locale(cl.Locale.RB)
toolbar_item.set_submenu(menu) toolbar_item.set_submenu(menu)
for location in self.locations: for location in self.locations:
app.add_plugin_menu_item(location, self.app_id, toolbar_item) app.add_plugin_menu_item(location, self.app_id, toolbar_item)
def on_page_change(self, display_page_tree, page): def on_page_change(self, display_page_tree, page):
''' '''
Called when the display page changes. Grabs query models and sets the Called when the display page changes. Grabs query models and sets the
active view. active view.
''' '''
if page == self.shell.props.library_source: if page == self.shell.props.library_source:
self.action.set_state(self._views.get_action_name(ListView.name)) self.action.set_state(self._views.get_action_name(ListView.name))
elif page == self.shell.props.queue_source: elif page == self.shell.props.queue_source:
@@ -282,11 +285,11 @@ class ExternalPluginMenu(GObject.Object):
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting[gs.PluginKey.VIEW_NAME] = view_name setting[gs.PluginKey.VIEW_NAME] = view_name
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.source) self.source)
elif view_name == ListView.name: elif view_name == ListView.name:
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.library_source) self.shell.props.library_source)
elif view_name == QueueView.name: elif view_name == QueueView.name:
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.queue_source) self.shell.props.queue_source)
+85 -84
Ver Arquivo
@@ -33,6 +33,7 @@ from stars import ReactiveStar
from stars import StarSize from stars import StarSize
import coverart_rb3compat as rb3compat import coverart_rb3compat as rb3compat
def webkit_support(): def webkit_support():
''' '''
function that returns True/False if webkit technology is supported function that returns True/False if webkit technology is supported
@@ -41,6 +42,7 @@ def webkit_support():
settings = gs.get_setting(gs.Path.PLUGIN) settings = gs.get_setting(gs.Path.PLUGIN)
return settings[gs.PluginKey.WEBKIT] return settings[gs.PluginKey.WEBKIT]
class CoverLocale: class CoverLocale:
''' '''
This class manages the locale This class manages the locale
@@ -238,7 +240,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
GObject.Object.__init__(self) GObject.Object.__init__(self)
gs = GSetting() gs = GSetting()
self.settings = gs.get_setting(gs.Path.PLUGIN) self.settings = gs.get_setting(gs.Path.PLUGIN)
self._first_run = True self._first_run = True
def do_create_configure_widget(self): def do_create_configure_widget(self):
@@ -246,39 +248,39 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
Creates the plugin's preferences dialog Creates the plugin's preferences dialog
''' '''
return self._create_display_contents(self) return self._create_display_contents(self)
def display_preferences_dialog(self, plugin): def display_preferences_dialog(self, plugin):
if self._first_run: if self._first_run:
self._first_run = False self._first_run = False
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self._dialog = Gtk.Dialog(modal=True, destroy_with_parent=True) self._dialog = Gtk.Dialog(modal=True, destroy_with_parent=True)
self._dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK) self._dialog.add_button(Gtk.STOCK_OK, Gtk.ResponseType.OK)
self._dialog.set_title(_('Browser Preferences')) self._dialog.set_title(_('Browser Preferences'))
content_area = self._dialog.get_content_area() content_area = self._dialog.get_content_area()
content_area.pack_start(self._create_display_contents(plugin), True, True, 0) content_area.pack_start(self._create_display_contents(plugin), True, True, 0)
helpbutton = self._dialog.add_button(Gtk.STOCK_HELP, Gtk.ResponseType.HELP) helpbutton = self._dialog.add_button(Gtk.STOCK_HELP, Gtk.ResponseType.HELP)
helpbutton.connect('clicked', self._display_help) helpbutton.connect('clicked', self._display_help)
self._dialog.show_all() self._dialog.show_all()
while True: while True:
response = self._dialog.run() response = self._dialog.run()
if response != Gtk.ResponseType.HELP: if response != Gtk.ResponseType.HELP:
break break
self._dialog.hide() self._dialog.hide()
def _display_help(self, *args): def _display_help(self, *args):
peas = Peas.Engine.get_default() peas = Peas.Engine.get_default()
uri = peas.get_plugin_info('coverart_browser').get_help_uri() uri = peas.get_plugin_info('coverart_browser').get_help_uri()
webbrowser.open(uri) webbrowser.open(uri)
def _create_display_contents(self, plugin): def _create_display_contents(self, plugin):
# create the ui # create the ui
cl = CoverLocale() cl = CoverLocale()
@@ -286,10 +288,10 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
builder = Gtk.Builder() builder = Gtk.Builder()
builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN) builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
builder.add_from_file(rb.find_plugin_file(plugin, builder.add_from_file(rb.find_plugin_file(plugin,
'ui/coverart_browser_prefs.ui')) 'ui/coverart_browser_prefs.ui'))
self.launchpad_button = builder.get_object('show_launchpad') self.launchpad_button = builder.get_object('show_launchpad')
self.launchpad_label = builder.get_object('launchpad_label') self.launchpad_label = builder.get_object('launchpad_label')
builder.connect_signals(self) builder.connect_signals(self)
#. TRANSLATORS: Do not translate this string. #. TRANSLATORS: Do not translate this string.
@@ -299,25 +301,25 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.launchpad_label.set_text(translators) self.launchpad_label.set_text(translators)
else: else:
self.launchpad_button.set_visible(False) self.launchpad_button.set_visible(False)
gs = GSetting() gs = GSetting()
# bind the toggles to the settings # bind the toggles to the settings
toggle_statusbar = builder.get_object('custom_statusbar_checkbox') toggle_statusbar = builder.get_object('custom_statusbar_checkbox')
self.settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, self.settings.bind(gs.PluginKey.CUSTOM_STATUSBAR,
toggle_statusbar, 'active', Gio.SettingsBindFlags.DEFAULT) toggle_statusbar, 'active', Gio.SettingsBindFlags.DEFAULT)
toggle_bottom = builder.get_object('display_bottom_checkbox') toggle_bottom = builder.get_object('display_bottom_checkbox')
self.settings.bind(gs.PluginKey.DISPLAY_BOTTOM, toggle_bottom, self.settings.bind(gs.PluginKey.DISPLAY_BOTTOM, toggle_bottom,
'active', Gio.SettingsBindFlags.DEFAULT) 'active', Gio.SettingsBindFlags.DEFAULT)
toggle_text = builder.get_object('display_text_checkbox') toggle_text = builder.get_object('display_text_checkbox')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT, toggle_text, 'active', self.settings.bind(gs.PluginKey.DISPLAY_TEXT, toggle_text, 'active',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
box_text = builder.get_object('display_text_box') box_text = builder.get_object('display_text_box')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT, box_text, 'sensitive', self.settings.bind(gs.PluginKey.DISPLAY_TEXT, box_text, 'sensitive',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
self.display_text_pos = self.settings[gs.PluginKey.DISPLAY_TEXT_POS] self.display_text_pos = self.settings[gs.PluginKey.DISPLAY_TEXT_POS]
self.display_text_under_radiobutton = builder.get_object('display_text_under_radiobutton') self.display_text_under_radiobutton = builder.get_object('display_text_under_radiobutton')
self.display_text_within_radiobutton = builder.get_object('display_text_within_radiobutton') self.display_text_within_radiobutton = builder.get_object('display_text_within_radiobutton')
@@ -327,40 +329,39 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
else: else:
self.display_text_within_radiobutton.set_active(True) self.display_text_within_radiobutton.set_active(True)
random_scale = builder.get_object('random_adjustment') random_scale = builder.get_object('random_adjustment')
self.settings.bind(gs.PluginKey.RANDOM, random_scale, 'value', self.settings.bind(gs.PluginKey.RANDOM, random_scale, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
toggle_text_ellipsize = builder.get_object( toggle_text_ellipsize = builder.get_object(
'display_text_ellipsize_checkbox') 'display_text_ellipsize_checkbox')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE,
toggle_text_ellipsize, 'active', Gio.SettingsBindFlags.DEFAULT) toggle_text_ellipsize, 'active', Gio.SettingsBindFlags.DEFAULT)
box_text_ellipsize_length = builder.get_object( box_text_ellipsize_length = builder.get_object(
'display_text_ellipsize_length_box') 'display_text_ellipsize_length_box')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE, self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE,
box_text_ellipsize_length, 'sensitive', Gio.SettingsBindFlags.GET) box_text_ellipsize_length, 'sensitive', Gio.SettingsBindFlags.GET)
spinner_text_ellipsize_length = builder.get_object( spinner_text_ellipsize_length = builder.get_object(
'display_text_ellipsize_length_spin') 'display_text_ellipsize_length_spin')
self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH, self.settings.bind(gs.PluginKey.DISPLAY_TEXT_ELLIPSIZE_LENGTH,
spinner_text_ellipsize_length, 'value', spinner_text_ellipsize_length, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
spinner_font_size = builder.get_object( spinner_font_size = builder.get_object(
'display_font_spin') 'display_font_spin')
self.settings.bind(gs.PluginKey.DISPLAY_FONT_SIZE, self.settings.bind(gs.PluginKey.DISPLAY_FONT_SIZE,
spinner_font_size, 'value', spinner_font_size, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
cover_size_scale = builder.get_object('cover_size_adjustment') cover_size_scale = builder.get_object('cover_size_adjustment')
self.settings.bind(gs.PluginKey.COVER_SIZE, cover_size_scale, 'value', self.settings.bind(gs.PluginKey.COVER_SIZE, cover_size_scale, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
add_shadow = builder.get_object('add_shadow_checkbox') add_shadow = builder.get_object('add_shadow_checkbox')
self.settings.bind(gs.PluginKey.ADD_SHADOW, add_shadow, 'active', self.settings.bind(gs.PluginKey.ADD_SHADOW, add_shadow, 'active',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
rated_box = builder.get_object('rated_box') rated_box = builder.get_object('rated_box')
self.stars = ReactiveStar(size=StarSize.BIG) self.stars = ReactiveStar(size=StarSize.BIG)
@@ -375,53 +376,53 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
autostart = builder.get_object('autostart_checkbox') autostart = builder.get_object('autostart_checkbox')
self.settings.bind(gs.PluginKey.AUTOSTART, self.settings.bind(gs.PluginKey.AUTOSTART,
autostart, 'active', Gio.SettingsBindFlags.DEFAULT) autostart, 'active', Gio.SettingsBindFlags.DEFAULT)
toolbar_pos_combo = builder.get_object('show_in_combobox') toolbar_pos_combo = builder.get_object('show_in_combobox')
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
toolbar_pos_combo.pack_start(renderer, True) toolbar_pos_combo.pack_start(renderer, True)
toolbar_pos_combo.add_attribute(renderer, 'text', 1) toolbar_pos_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.TOOLBAR_POS, toolbar_pos_combo, self.settings.bind(gs.PluginKey.TOOLBAR_POS, toolbar_pos_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT) 'active-id', Gio.SettingsBindFlags.DEFAULT)
light_source_combo = builder.get_object('light_source_combobox') light_source_combo = builder.get_object('light_source_combobox')
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
light_source_combo.pack_start(renderer, True) light_source_combo.pack_start(renderer, True)
light_source_combo.add_attribute(renderer, 'text', 1) light_source_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.SHADOW_IMAGE, light_source_combo, self.settings.bind(gs.PluginKey.SHADOW_IMAGE, light_source_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT) 'active-id', Gio.SettingsBindFlags.DEFAULT)
combo_liststore = builder.get_object('combo_liststore') combo_liststore = builder.get_object('combo_liststore')
from coverart_utils import Theme from coverart_utils import Theme
for theme in Theme(self).themes: for theme in Theme(self).themes:
combo_liststore.append([theme, theme]) combo_liststore.append([theme, theme])
theme_combo = builder.get_object('theme_combobox') theme_combo = builder.get_object('theme_combobox')
renderer = Gtk.CellRendererText() renderer = Gtk.CellRendererText()
theme_combo.pack_start(renderer, True) theme_combo.pack_start(renderer, True)
theme_combo.add_attribute(renderer, 'text', 1) theme_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.THEME, theme_combo, self.settings.bind(gs.PluginKey.THEME, theme_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT) 'active-id', Gio.SettingsBindFlags.DEFAULT)
button_relief = builder.get_object('button_relief_checkbox') button_relief = builder.get_object('button_relief_checkbox')
self.settings.bind(gs.PluginKey.BUTTON_RELIEF, button_relief, 'active', self.settings.bind(gs.PluginKey.BUTTON_RELIEF, button_relief, 'active',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
# create user data files # create user data files
cachedir = RB.user_cache_dir() + "/coverart_browser/usericons" cachedir = RB.user_cache_dir() + "/coverart_browser/usericons"
if not os.path.exists(cachedir): if not os.path.exists(cachedir):
os.makedirs(cachedir) os.makedirs(cachedir)
popup = cachedir + "/popups.xml" popup = cachedir + "/popups.xml"
temp = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml') temp = RB.find_user_data_file('plugins/coverart_browser/img/usericons/popups.xml')
# lets see if there is a legacy file - if necessary copy it to the cache dir # lets see if there is a legacy file - if necessary copy it to the cache dir
if os.path.isfile(temp) and not os.path.isfile(popup): if os.path.isfile(temp) and not os.path.isfile(popup):
shutil.copyfile(temp, popup) shutil.copyfile(temp, popup)
if not os.path.isfile(popup): if not os.path.isfile(popup):
template = rb.find_plugin_file(plugin, 'template/popups.xml') template = rb.find_plugin_file(plugin, 'template/popups.xml')
folder = os.path.split(popup)[0] folder = os.path.split(popup)[0]
@@ -441,13 +442,13 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self._iters = {} self._iters = {}
for key in list(self._sheet.keys()): for key in list(self._sheet.keys()):
store_iter = self.alt_liststore.append([key, self._sheet[key]]) store_iter = self.alt_liststore.append([key, self._sheet[key]])
self._iters[(key,self.GENRE_POPUP)] = store_iter self._iters[(key, self.GENRE_POPUP)] = store_iter
for key, value in self._sheet.genre_alternate.items(): for key, value in self._sheet.genre_alternate.items():
if key.genre_type == GenreConfiguredSpriteSheet.GENRE_USER: if key.genre_type == GenreConfiguredSpriteSheet.GENRE_USER:
store_iter = self.alt_user_liststore.append([key.name, store_iter = self.alt_user_liststore.append([key.name,
self._sheet[self._sheet.genre_alternate[key]], self._sheet[self._sheet.genre_alternate[key]],
self._sheet.genre_alternate[key]]) self._sheet.genre_alternate[key]])
self._iters[(key.name, self.GENRE_LIST)] = store_iter self._iters[(key.name, self.GENRE_LIST)] = store_iter
self.amend_mode = False self.amend_mode = False
@@ -463,15 +464,15 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
padding_scale = builder.get_object('padding_adjustment') padding_scale = builder.get_object('padding_adjustment')
self.settings.bind(gs.PluginKey.ICON_PADDING, padding_scale, 'value', self.settings.bind(gs.PluginKey.ICON_PADDING, padding_scale, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
spacing_scale = builder.get_object('spacing_adjustment') spacing_scale = builder.get_object('spacing_adjustment')
self.settings.bind(gs.PluginKey.ICON_SPACING, spacing_scale, 'value', self.settings.bind(gs.PluginKey.ICON_SPACING, spacing_scale, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
icon_automatic = builder.get_object('icon_automatic_checkbox') icon_automatic = builder.get_object('icon_automatic_checkbox')
self.settings.bind(gs.PluginKey.ICON_AUTOMATIC, self.settings.bind(gs.PluginKey.ICON_AUTOMATIC,
icon_automatic, 'active', Gio.SettingsBindFlags.DEFAULT) icon_automatic, 'active', Gio.SettingsBindFlags.DEFAULT)
#flow tab #flow tab
flow_combo = builder.get_object('flow_combobox') flow_combo = builder.get_object('flow_combobox')
@@ -479,27 +480,27 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
flow_combo.pack_start(renderer, True) flow_combo.pack_start(renderer, True)
flow_combo.add_attribute(renderer, 'text', 1) flow_combo.add_attribute(renderer, 'text', 1)
self.settings.bind(gs.PluginKey.FLOW_APPEARANCE, flow_combo, self.settings.bind(gs.PluginKey.FLOW_APPEARANCE, flow_combo,
'active-id', Gio.SettingsBindFlags.DEFAULT) 'active-id', Gio.SettingsBindFlags.DEFAULT)
flow_hide = builder.get_object('hide_caption_checkbox') flow_hide = builder.get_object('hide_caption_checkbox')
self.settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self.settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION,
flow_hide, 'active', Gio.SettingsBindFlags.DEFAULT) flow_hide, 'active', Gio.SettingsBindFlags.DEFAULT)
flow_scale = builder.get_object('cover_scale_adjustment') flow_scale = builder.get_object('cover_scale_adjustment')
self.settings.bind(gs.PluginKey.FLOW_SCALE, flow_scale, 'value', self.settings.bind(gs.PluginKey.FLOW_SCALE, flow_scale, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
flow_width = builder.get_object('cover_width_adjustment') flow_width = builder.get_object('cover_width_adjustment')
self.settings.bind(gs.PluginKey.FLOW_WIDTH, flow_width, 'value', self.settings.bind(gs.PluginKey.FLOW_WIDTH, flow_width, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
flow_max = builder.get_object('flow_max_adjustment') flow_max = builder.get_object('flow_max_adjustment')
self.settings.bind(gs.PluginKey.FLOW_MAX, flow_max, 'value', self.settings.bind(gs.PluginKey.FLOW_MAX, flow_max, 'value',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
flow_automatic = builder.get_object('automatic_checkbox') flow_automatic = builder.get_object('automatic_checkbox')
self.settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self.settings.bind(gs.PluginKey.FLOW_AUTOMATIC,
flow_automatic, 'active', Gio.SettingsBindFlags.DEFAULT) flow_automatic, 'active', Gio.SettingsBindFlags.DEFAULT)
self.background_colour = self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] self.background_colour = self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR]
self.white_radiobutton = builder.get_object('white_radiobutton') self.white_radiobutton = builder.get_object('white_radiobutton')
@@ -509,13 +510,13 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.white_radiobutton.set_active(True) self.white_radiobutton.set_active(True)
else: else:
self.black_radiobutton.set_active(True) self.black_radiobutton.set_active(True)
# return the dialog # return the dialog
return builder.get_object('main_notebook') return builder.get_object('main_notebook')
def on_flow_combobox_changed(self, combobox): def on_flow_combobox_changed(self, combobox):
current_val = combobox.get_model()[combobox.get_active()][0] current_val = combobox.get_model()[combobox.get_active()][0]
gs=GSetting() gs = GSetting()
if self.settings[gs.PluginKey.FLOW_APPEARANCE] != current_val: if self.settings[gs.PluginKey.FLOW_APPEARANCE] != current_val:
if current_val == 'flow-vert': if current_val == 'flow-vert':
default_size = 150 default_size = 150
@@ -523,10 +524,10 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
default_size = 600 default_size = 600
self.settings[gs.PluginKey.FLOW_WIDTH] = default_size self.settings[gs.PluginKey.FLOW_WIDTH] = default_size
if current_val == 'carousel': if current_val == 'carousel':
self.settings[gs.PluginKey.FLOW_HIDE_CAPTION] = True self.settings[gs.PluginKey.FLOW_HIDE_CAPTION] = True
def on_background_radio_toggled(self, button): def on_background_radio_toggled(self, button):
if button.get_active(): if button.get_active():
gs = GSetting() gs = GSetting()
@@ -534,7 +535,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'W' self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'W'
else: else:
self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'B' self.settings[gs.PluginKey.FLOW_BACKGROUND_COLOUR] = 'B'
def on_display_text_pos_radio_toggled(self, button): def on_display_text_pos_radio_toggled(self, button):
if button.get_active(): if button.get_active():
gs = GSetting() gs = GSetting()
@@ -543,7 +544,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
else: else:
self.settings[gs.PluginKey.DISPLAY_TEXT_POS] = False self.settings[gs.PluginKey.DISPLAY_TEXT_POS] = False
self.settings[gs.PluginKey.ADD_SHADOW] = False self.settings[gs.PluginKey.ADD_SHADOW] = False
def on_add_shadow_checkbox_toggled(self, button): def on_add_shadow_checkbox_toggled(self, button):
if button.get_active(): if button.get_active():
#gs = GSetting() #gs = GSetting()
@@ -559,32 +560,32 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
''' '''
action when genre edit area is saved action when genre edit area is saved
''' '''
entry_value = self.genre_entry.get_text() entry_value = self.genre_entry.get_text()
treeiter = self.genre_combobox.get_active_iter() treeiter = self.genre_combobox.get_active_iter()
icon_value = self.alt_liststore[treeiter][0] icon_value = self.alt_liststore[treeiter][0]
# model 0 is the icon name, model 1 is the pixbuf # model 0 is the icon name, model 1 is the pixbuf
if self.amend_mode: if self.amend_mode:
key = self._sheet.amend_genre_info(self.current_genre, key = self._sheet.amend_genre_info(self.current_genre,
entry_value, icon_value) entry_value, icon_value)
self.alt_user_liststore[self._iters[(self.current_genre, self.alt_user_liststore[self._iters[(self.current_genre,
self.GENRE_LIST)]][1]=self._sheet[self._sheet.genre_alternate[key]] self.GENRE_LIST)]][1] = self._sheet[self._sheet.genre_alternate[key]]
self.alt_user_liststore[self._iters[(self.current_genre, self.alt_user_liststore[self._iters[(self.current_genre,
self.GENRE_LIST)]][0]=key.name self.GENRE_LIST)]][0] = key.name
store_iter = self._iters[(self.current_genre, self.GENRE_LIST)] store_iter = self._iters[(self.current_genre, self.GENRE_LIST)]
del self._iters[(self.current_genre, self.GENRE_LIST)] del self._iters[(self.current_genre, self.GENRE_LIST)]
self._iters[(key.name, self.GENRE_LIST)] = store_iter self._iters[(key.name, self.GENRE_LIST)] = store_iter
else: else:
self.amend_mode = True self.amend_mode = True
key = self._sheet.amend_genre_info('', key = self._sheet.amend_genre_info('',
entry_value, icon_value) entry_value, icon_value)
self.current_genre = key.name self.current_genre = key.name
store_iter = self.alt_user_liststore.append([key.name, store_iter = self.alt_user_liststore.append([key.name,
self._sheet[self._sheet.genre_alternate[key]], self._sheet[self._sheet.genre_alternate[key]],
self._sheet.genre_alternate[key]]) self._sheet.genre_alternate[key]])
self._iters[(key.name, self.GENRE_LIST)] = store_iter self._iters[(key.name, self.GENRE_LIST)] = store_iter
selection = self.genre_view.get_selection() selection = self.genre_view.get_selection()
selection.select_iter(store_iter) selection.select_iter(store_iter)
@@ -592,23 +593,23 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.save_button.set_sensitive(False) self.save_button.set_sensitive(False)
self._toggle_new_genre_state() self._toggle_new_genre_state()
def on_genre_filechooserbutton_file_set(self, filechooser): def on_genre_filechooserbutton_file_set(self, filechooser):
''' '''
action when genre new icon button is pressed action when genre new icon button is pressed
''' '''
key = self._sheet.add_genre_icon( self.filechooserdialog.get_filename() ) key = self._sheet.add_genre_icon(self.filechooserdialog.get_filename())
store_iter = self.alt_liststore.append([key.name, self._sheet[key.name]]) store_iter = self.alt_liststore.append([key.name, self._sheet[key.name]])
self._iters[(key.name,self.GENRE_POPUP)] = store_iter self._iters[(key.name, self.GENRE_POPUP)] = store_iter
gs = GSetting() gs = GSetting()
last_genre_folder = self.filechooserdialog.get_current_folder() last_genre_folder = self.filechooserdialog.get_current_folder()
print (last_genre_folder) print(last_genre_folder)
print (self.filechooserdialog.get_filename()) print(self.filechooserdialog.get_filename())
if last_genre_folder: if last_genre_folder:
self.settings[gs.PluginKey.LAST_GENRE_FOLDER] = last_genre_folder self.settings[gs.PluginKey.LAST_GENRE_FOLDER] = last_genre_folder
def on_genre_view_selection_changed(self, view): def on_genre_view_selection_changed(self, view):
''' '''
action when user selects a row in the list of genres action when user selects a row in the list of genres
@@ -620,7 +621,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
if index != '': if index != '':
self.genre_combobox.set_active_iter(self._iters[(index, self.GENRE_POPUP)]) self.genre_combobox.set_active_iter(self._iters[(index, self.GENRE_POPUP)])
self.amend_mode = True self.amend_mode = True
self.current_genre=rb3compat.unicodestr(model[genre_iter][0], 'utf-8') self.current_genre = rb3compat.unicodestr(model[genre_iter][0], 'utf-8')
else: else:
self.genre_entry.set_text('') self.genre_entry.set_text('')
self.genre_combobox.set_active_iter(None) self.genre_combobox.set_active_iter(None)
@@ -634,7 +635,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.blank_iter = None self.blank_iter = None
except: except:
self.blank_iter = None self.blank_iter = None
def on_add_button_clicked(self, button): def on_add_button_clicked(self, button):
''' '''
action when a new genre is added to the table action when a new genre is added to the table
@@ -645,8 +646,8 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self.blank_iter = self.alt_user_liststore.append(['', None, '']) self.blank_iter = self.alt_user_liststore.append(['', None, ''])
selection = self.genre_view.get_selection() selection = self.genre_view.get_selection()
selection.select_iter(self.blank_iter) selection.select_iter(self.blank_iter)
def on_delete_button_clicked(self, button): def on_delete_button_clicked(self, button):
''' '''
action when a genre is to be deleted action when a genre is to be deleted
@@ -655,7 +656,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
model, genre_iter = selection.get_selected() model, genre_iter = selection.get_selected()
if genre_iter: if genre_iter:
index = rb3compat.unicodestr(model[genre_iter][0],'utf-8') index = rb3compat.unicodestr(model[genre_iter][0], 'utf-8')
model.remove(genre_iter) model.remove(genre_iter)
if index: if index:
@@ -663,7 +664,7 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
self._sheet.delete_genre(index) self._sheet.delete_genre(index)
self._toggle_new_genre_state() self._toggle_new_genre_state()
def set_save_sensitivity(self, _): def set_save_sensitivity(self, _):
''' '''
action to toggle the state of the save button depending action to toggle the state of the save button depending
@@ -703,8 +704,8 @@ class Preferences(GObject.Object, PeasGtk.Configurable):
else: else:
test = True test = True
self.settings[gs.PluginKey.NEW_GENRE_ICON]=test self.settings[gs.PluginKey.NEW_GENRE_ICON] = test
def on_show_launchpad_toggled(self, button): def on_show_launchpad_toggled(self, button):
self.launchpad_label.set_visible(button.get_active()) self.launchpad_label.set_visible(button.get_active())
+187 -178
Ver Arquivo
@@ -61,7 +61,7 @@ class CoverArtBrowserSource(RB.Source):
rating_threshold = GObject.property(type=float, default=0) rating_threshold = GObject.property(type=float, default=0)
artist_paned_pos = GObject.property(type=str) artist_paned_pos = GObject.property(type=str)
min_paned_pos = 40 min_paned_pos = 40
# unique instance of the source # unique instance of the source
instance = None instance = None
@@ -83,7 +83,7 @@ class CoverArtBrowserSource(RB.Source):
self.favourites = False self.favourites = False
self.follow_song = False self.follow_song = False
self.task_progress = None self.task_progress = None
def _connect_properties(self): def _connect_properties(self):
''' '''
Connects the source properties to the saved preferences. Connects the source properties to the saved preferences.
@@ -107,14 +107,14 @@ class CoverArtBrowserSource(RB.Source):
show the selected album info. show the selected album info.
Also, it makes sure to show the progress on the album loading Also, it makes sure to show the progress on the album loading
''' '''
try: try:
# this will only work for RB3.0 and later # this will only work for RB3.0 and later
if not self.task_progress: if not self.task_progress:
self.task_progress = RB.TaskProgressSimple.new() self.task_progress = RB.TaskProgressSimple.new()
except: except:
pass pass
try: try:
progress = self.album_manager.progress progress = self.album_manager.progress
progress_text = _('Loading...') if progress < 1 else '' progress_text = _('Loading...') if progress < 1 else ''
@@ -123,9 +123,9 @@ class CoverArtBrowserSource(RB.Source):
if progress < 1: if progress < 1:
if self.props.shell.props.task_list.get_model().n_items() == 0: if self.props.shell.props.task_list.get_model().n_items() == 0:
self.props.shell.props.task_list.add_task(self.task_progress) self.props.shell.props.task_list.add_task(self.task_progress)
self.task_progress.props.task_progress = progress self.task_progress.props.task_progress = progress
self.task_progress.props.task_label=progress_text self.task_progress.props.task_label = progress_text
else: else:
self.task_progress.props.task_outcome = RB.TaskOutcome.COMPLETE self.task_progress.props.task_outcome = RB.TaskOutcome.COMPLETE
except: except:
@@ -173,7 +173,7 @@ class CoverArtBrowserSource(RB.Source):
self.actiongroup = ActionGroup(self.shell, 'coverplaylist_submenu') self.actiongroup = ActionGroup(self.shell, 'coverplaylist_submenu')
self._browser_preferences = None self._browser_preferences = None
self._search_preferences = None self._search_preferences = None
# indicate that the source was activated before # indicate that the source was activated before
self.hasActivated = True self.hasActivated = True
@@ -198,7 +198,7 @@ class CoverArtBrowserSource(RB.Source):
ui = Gtk.Builder() ui = Gtk.Builder()
ui.set_translation_domain(cl.Locale.LOCALE_DOMAIN) ui.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
ui.add_from_file(rb.find_plugin_file(self.plugin, ui.add_from_file(rb.find_plugin_file(self.plugin,
'ui/coverart_browser.ui')) 'ui/coverart_browser.ui'))
ui.connect_signals(self) ui.connect_signals(self)
# load the page and put it in the source # load the page and put it in the source
@@ -208,9 +208,9 @@ class CoverArtBrowserSource(RB.Source):
# get widgets for main icon-view # get widgets for main icon-view
self.status_label = ui.get_object('status_label') self.status_label = ui.get_object('status_label')
window = ui.get_object('scrolled_window') window = ui.get_object('scrolled_window')
self.viewmgr = ViewManager(self, window) self.viewmgr = ViewManager(self, window)
# get widgets for the artist paned # get widgets for the artist paned
self.artist_paned = ui.get_object('vertical_paned') self.artist_paned = ui.get_object('vertical_paned')
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50, self._change_artist_paned_pos, self.viewmgr.view_name) Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50, self._change_artist_paned_pos, self.viewmgr.view_name)
@@ -221,22 +221,22 @@ class CoverArtBrowserSource(RB.Source):
# define menu's # define menu's
self.popup_menu = Menu(self.plugin, self.shell) self.popup_menu = Menu(self.plugin, self.shell)
self.popup_menu.load_from_file('ui/coverart_browser_pop_rb2.ui', self.popup_menu.load_from_file('ui/coverart_browser_pop_rb2.ui',
'ui/coverart_browser_pop_rb3.ui') 'ui/coverart_browser_pop_rb3.ui')
self._external_plugins = None self._external_plugins = None
signals = \ signals = \
{ 'play_album_menu_item' : self.play_album_menu_item_callback, {'play_album_menu_item': self.play_album_menu_item_callback,
'queue_album_menu_item' : self.queue_album_menu_item_callback, 'queue_album_menu_item': self.queue_album_menu_item_callback,
'add_to_playing_menu_item' : self.add_to_playing_menu_item_callback, 'add_to_playing_menu_item': self.add_to_playing_menu_item_callback,
'new_playlist' : self.add_playlist_menu_item_callback, 'new_playlist': self.add_playlist_menu_item_callback,
'cover_search_menu_item' : self.cover_search_menu_item_callback, 'cover_search_menu_item': self.cover_search_menu_item_callback,
'export_embed_menu_item' : self.export_embed_menu_item_callback, 'export_embed_menu_item': self.export_embed_menu_item_callback,
'show_properties_menu_item' : self.show_properties_menu_item_callback, 'show_properties_menu_item': self.show_properties_menu_item_callback,
'play_similar_artist_menu_item' : self.play_similar_artist_menu_item_callback} 'play_similar_artist_menu_item': self.play_similar_artist_menu_item_callback}
self.popup_menu.connect_signals(signals) self.popup_menu.connect_signals(signals)
self.popup_menu.connect('pre-popup', self.pre_popup_menu_callback) self.popup_menu.connect('pre-popup', self.pre_popup_menu_callback)
self.status_label = ui.get_object('status_label') self.status_label = ui.get_object('status_label')
self.request_status_box = ui.get_object('request_status_box') self.request_status_box = ui.get_object('request_status_box')
self.request_spinner = ui.get_object('request_spinner') self.request_spinner = ui.get_object('request_spinner')
@@ -248,24 +248,24 @@ class CoverArtBrowserSource(RB.Source):
#setup Track Pane #setup Track Pane
setting = self.gs.get_setting(self.gs.Path.PLUGIN) setting = self.gs.get_setting(self.gs.Path.PLUGIN)
setting.bind(self.gs.PluginKey.PANED_POSITION, setting.bind(self.gs.PluginKey.PANED_POSITION,
self.paned, 'collapsible-y', Gio.SettingsBindFlags.DEFAULT) self.paned, 'collapsible-y', Gio.SettingsBindFlags.DEFAULT)
setting.bind(self.gs.PluginKey.DISPLAY_BOTTOM, setting.bind(self.gs.PluginKey.DISPLAY_BOTTOM,
self.paned.get_child2(), 'visible', Gio.SettingsBindFlags.DEFAULT) self.paned.get_child2(), 'visible', Gio.SettingsBindFlags.DEFAULT)
self.entryviewpane = EntryViewPane(self.shell, self.entryviewpane = EntryViewPane(self.shell,
self.plugin, self.plugin,
self, self,
self.entry_view_grid, self.entry_view_grid,
self.viewmgr) self.viewmgr)
#---- set up info pane -----# #---- set up info pane -----#
info_stack = ui.get_object('info_stack') info_stack = ui.get_object('info_stack')
info_button_box = ui.get_object('info_button_box') info_button_box = ui.get_object('info_button_box')
artist_info_paned = ui.get_object('vertical_info_paned') artist_info_paned = ui.get_object('vertical_info_paned')
self.artist_info = ArtistInfoPane(info_button_box, self.artist_info = ArtistInfoPane(info_button_box,
info_stack, info_stack,
artist_info_paned, artist_info_paned,
self) self)
# quick search # quick search
self.quick_search = ui.get_object('quick_search_entry') self.quick_search = ui.get_object('quick_search_entry')
@@ -278,7 +278,7 @@ class CoverArtBrowserSource(RB.Source):
by the user. It also creates and configure some custom widgets. by the user. It also creates and configure some custom widgets.
''' '''
print("CoverArtBrowser DEBUG - _setup_source") print("CoverArtBrowser DEBUG - _setup_source")
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
@@ -287,7 +287,7 @@ class CoverArtBrowserSource(RB.Source):
# create an album manager # create an album manager
self.album_manager = AlbumManager(self.plugin, self.viewmgr.current_view) self.album_manager = AlbumManager(self.plugin, self.viewmgr.current_view)
self.viewmgr.current_view.initialise(self) self.viewmgr.current_view.initialise(self)
# setup cover search pane # setup cover search pane
self.entryviewpane.setup_source() self.entryviewpane.setup_source()
@@ -306,24 +306,24 @@ class CoverArtBrowserSource(RB.Source):
self.quick_search_controller.connect_quick_search(self.quick_search) self.quick_search_controller.connect_quick_search(self.quick_search)
# set sensitivity of export menu item for iconview # set sensitivity of export menu item for iconview
self.popup_menu.set_sensitive('export_embed_menu_item', self.popup_menu.set_sensitive('export_embed_menu_item',
CoverArtExport(self.plugin, CoverArtExport(self.plugin,
self.shell, self.album_manager).is_search_plugin_enabled()) self.shell, self.album_manager).is_search_plugin_enabled())
# setup the statusbar component # setup the statusbar component
self.statusbar = Statusbar(self) self.statusbar = Statusbar(self)
# initialise the toolbar manager # initialise the toolbar manager
self.toolbar_manager = ToolbarManager(self.plugin, self.page, self.toolbar_manager = ToolbarManager(self.plugin, self.page,
self.viewmgr) self.viewmgr)
self.viewmgr.current_view.emit('update-toolbar') self.viewmgr.current_view.emit('update-toolbar')
cl.switch_locale(cl.Locale.RB) cl.switch_locale(cl.Locale.RB)
# setup the artist paned # setup the artist paned
artist_pview = None artist_pview = None
for view in self.shell.props.library_source.get_property_views(): for view in self.shell.props.library_source.get_property_views():
print (view.props.title) print(view.props.title)
print (_("Artist")) print(_("Artist"))
if view.props.title == _("Artist"): if view.props.title == _("Artist"):
artist_pview = view artist_pview = view
break break
@@ -333,11 +333,11 @@ class CoverArtBrowserSource(RB.Source):
self.artist_treeview.set_model(artist_pview.get_model()) self.artist_treeview.set_model(artist_pview.get_model())
setting = self.gs.get_setting(self.gs.Path.PLUGIN) setting = self.gs.get_setting(self.gs.Path.PLUGIN)
setting.bind(self.gs.PluginKey.ARTIST_PANED_POSITION, setting.bind(self.gs.PluginKey.ARTIST_PANED_POSITION,
self, 'artist-paned-pos', Gio.SettingsBindFlags.DEFAULT) self, 'artist-paned-pos', Gio.SettingsBindFlags.DEFAULT)
self.artist_paned.connect('button-release-event',
self.artist_paned_button_release_callback)
self.artist_paned.connect('button-release-event',
self.artist_paned_button_release_callback)
# intercept JumpToPlaying Song action so that we can scroll to the playing album # intercept JumpToPlaying Song action so that we can scroll to the playing album
appshell = rb3compat.ApplicationShell(self.shell) appshell = rb3compat.ApplicationShell(self.shell)
action = appshell.lookup_action("", "jump-to-playing", "win") action = appshell.lookup_action("", "jump-to-playing", "win")
@@ -347,9 +347,9 @@ class CoverArtBrowserSource(RB.Source):
# should be automatically selected # should be automatically selected
self.shell.props.shell_player.connect('playing-song-changed', self.playing_song_callback) self.shell.props.shell_player.connect('playing-song-changed', self.playing_song_callback)
self.echonest_similar_playlist = None self.echonest_similar_playlist = None
print("CoverArtBrowser DEBUG - end _setup_source") print("CoverArtBrowser DEBUG - end _setup_source")
def playing_song_callback(self, *args): def playing_song_callback(self, *args):
@@ -363,7 +363,7 @@ class CoverArtBrowserSource(RB.Source):
Callback when the popup menu is about to be displayed Callback when the popup menu is about to be displayed
''' '''
state,sensitive = self.shell.props.shell_player.get_playing() state, sensitive = self.shell.props.shell_player.get_playing()
if not state: if not state:
sensitive = False sensitive = False
@@ -373,12 +373,12 @@ class CoverArtBrowserSource(RB.Source):
if not self._external_plugins: if not self._external_plugins:
# initialise external plugin menu support # initialise external plugin menu support
self._external_plugins = \ self._external_plugins = \
CreateExternalPluginMenu("ca_covers_view", CreateExternalPluginMenu("ca_covers_view",
8, self.popup_menu) 8, self.popup_menu)
self._external_plugins.create_menu('popup_menu', True) self._external_plugins.create_menu('popup_menu', True)
self.playlist_menu_item_callback() self.playlist_menu_item_callback()
def jump_to_playing(self, *args): def jump_to_playing(self, *args):
''' '''
Callback when the JumpToPlaying action is invoked Callback when the JumpToPlaying action is invoked
@@ -389,14 +389,14 @@ class CoverArtBrowserSource(RB.Source):
# if the source page that was played from is not the plugin then # if the source page that was played from is not the plugin then
# nothing to do # nothing to do
return return
album = None album = None
entry = self.shell.props.shell_player.get_playing_entry() entry = self.shell.props.shell_player.get_playing_entry()
if entry: if entry:
album = self.album_manager.model.get_from_dbentry(entry) album = self.album_manager.model.get_from_dbentry(entry)
self.viewmgr.current_view.scroll_to_album(album) self.viewmgr.current_view.scroll_to_album(album)
def artist_paned_button_release_callback(self, *args): def artist_paned_button_release_callback(self, *args):
@@ -404,45 +404,45 @@ class CoverArtBrowserSource(RB.Source):
Callback when the artist paned handle is released from its mouse click. Callback when the artist paned handle is released from its mouse click.
''' '''
child_width = self._get_child_width() child_width = self._get_child_width()
paned_positions = eval(self.artist_paned_pos) paned_positions = eval(self.artist_paned_pos)
found = None found = None
for viewpos in paned_positions: for viewpos in paned_positions:
if self.viewmgr.view_name in viewpos: if self.viewmgr.view_name in viewpos:
found = viewpos found = viewpos
break break
if not found: if not found:
return return
paned_positions.remove(found) paned_positions.remove(found)
if child_width <= self.min_paned_pos: if child_width <= self.min_paned_pos:
child_width = 0 child_width = 0
self.artist_paned.set_position(child_width) self.artist_paned.set_position(child_width)
paned_positions.append(self.viewmgr.view_name + ":" + str(child_width)) paned_positions.append(self.viewmgr.view_name + ":" + str(child_width))
self.artist_paned_pos = repr(paned_positions) self.artist_paned_pos = repr(paned_positions)
def on_view_changed(self, widget, view_name): def on_view_changed(self, widget, view_name):
self._change_artist_paned_pos(view_name) self._change_artist_paned_pos(view_name)
def _change_artist_paned_pos(self, view_name): def _change_artist_paned_pos(self, view_name):
paned_positions = eval(self.artist_paned_pos) paned_positions = eval(self.artist_paned_pos)
print (paned_positions) print(paned_positions)
found = None found = None
for viewpos in paned_positions: for viewpos in paned_positions:
if view_name in viewpos: if view_name in viewpos:
found = viewpos found = viewpos
break break
print (found) print(found)
if not found: if not found:
return return
child_width = int(found.split(":")[1]) child_width = int(found.split(":")[1])
print (child_width) print(child_width)
# odd case - if the pane is not visible but the position is zero # odd case - if the pane is not visible but the position is zero
# then the paned position on visible=true is some large arbitary value # then the paned position on visible=true is some large arbitary value
# hence - set it to be 1 px larger than the real value, then set it back # hence - set it to be 1 px larger than the real value, then set it back
@@ -450,11 +450,11 @@ class CoverArtBrowserSource(RB.Source):
self.artist_paned.set_position(child_width + 1) self.artist_paned.set_position(child_width + 1)
self.artist_paned.set_visible(True) self.artist_paned.set_visible(True)
self.artist_paned.set_position(child_width) self.artist_paned.set_position(child_width)
def _get_child_width(self): def _get_child_width(self):
child = self.artist_paned.get_child1() child = self.artist_paned.get_child1()
return child.get_allocated_width() return child.get_allocated_width()
def on_artist_treeview_selection_changed(self, view): def on_artist_treeview_selection_changed(self, view):
model, artist_iter = view.get_selected() model, artist_iter = view.get_selected()
if artist_iter: if artist_iter:
@@ -469,7 +469,7 @@ class CoverArtBrowserSource(RB.Source):
self.album_manager.model.replace_filter('quick_artist', artist) self.album_manager.model.replace_filter('quick_artist', artist)
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
def _apply_settings(self): def _apply_settings(self):
''' '''
Applies all the settings related to the source and connects those that Applies all the settings related to the source and connects those that
@@ -480,8 +480,8 @@ class CoverArtBrowserSource(RB.Source):
# connect some signals to the loader to keep the source informed # connect some signals to the loader to keep the source informed
self.album_mod_id = self.album_manager.model.connect('album-updated', self.album_mod_id = self.album_manager.model.connect('album-updated',
self.on_album_updated) self.on_album_updated)
self.notify_prog_id = self.album_manager.connect( self.notify_prog_id = self.album_manager.connect(
'notify::progress', lambda *args: self.notify_status_changed()) 'notify::progress', lambda *args: self.notify_status_changed())
@@ -495,8 +495,8 @@ class CoverArtBrowserSource(RB.Source):
print("CoverArtBrowser DEBUG - load_finished_callback") print("CoverArtBrowser DEBUG - load_finished_callback")
#if not self.request_status_box.get_visible(): #if not self.request_status_box.get_visible():
# it should only be enabled if no cover request is going on # it should only be enabled if no cover request is going on
#self.source_menu_search_all_item.set_sensitive(True) #self.source_menu_search_all_item.set_sensitive(True)
# enable sorting on the entryview # enable sorting on the entryview
self.entry_view.set_columns_clickable(True) self.entry_view.set_columns_clickable(True)
@@ -529,19 +529,20 @@ class CoverArtBrowserSource(RB.Source):
Callback called when the play similar artist option is selected from Callback called when the play similar artist option is selected from
the cover view popup. It plays similar artists music. the cover view popup. It plays similar artists music.
''' '''
def play_similar_artist_menu_item_callback(self, *args): def play_similar_artist_menu_item_callback(self, *args):
if not self.echonest_similar_playlist: if not self.echonest_similar_playlist:
self.echonest_similar_playlist = \ self.echonest_similar_playlist = \
EchoNestPlaylist( self.shell, EchoNestPlaylist(self.shell,
self.shell.props.queue_source) self.shell.props.queue_source)
selected_albums = self.viewmgr.current_view.get_selected_objects() selected_albums = self.viewmgr.current_view.get_selected_objects()
album = selected_albums[0] album = selected_albums[0]
tracks = album.get_tracks() tracks = album.get_tracks()
entry = tracks[0].entry entry = tracks[0].entry
self.echonest_similar_playlist.start(entry, reinitialise=True) self.echonest_similar_playlist.start(entry, reinitialise=True)
def show_properties_menu_item_callback(self, *args): def show_properties_menu_item_callback(self, *args):
''' '''
Callback called when the show album properties option is selected from Callback called when the show album properties option is selected from
@@ -594,7 +595,7 @@ class CoverArtBrowserSource(RB.Source):
selected_albums = self.viewmgr.current_view.get_selected_objects() selected_albums = self.viewmgr.current_view.get_selected_objects()
threshold = self.rating_threshold if favourites else 0 threshold = self.rating_threshold if favourites else 0
total = 0 total = 0
for album in selected_albums: for album in selected_albums:
# Retrieve and sort the entries of the album # Retrieve and sort the entries of the album
tracks = album.get_tracks(threshold) tracks = album.get_tracks(threshold)
@@ -605,10 +606,11 @@ class CoverArtBrowserSource(RB.Source):
if total == 0 and threshold: if total == 0 and threshold:
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("No tracks have been added because no tracks meet the favourite rating threshold")) _(
"No tracks have been added because no tracks meet the favourite rating threshold"))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
@@ -652,7 +654,7 @@ class CoverArtBrowserSource(RB.Source):
self.favourites) self.favourites)
def playlist_fillmenu(self, popup_menu, menubar, section_name, def playlist_fillmenu(self, popup_menu, menubar, section_name,
actiongroup, func, favourite=False): actiongroup, func, favourite=False):
print("CoverArtBrowser DEBUG - playlist_fillmenu") print("CoverArtBrowser DEBUG - playlist_fillmenu")
playlist_manager = self.shell.props.playlist_manager playlist_manager = self.shell.props.playlist_manager
@@ -665,32 +667,32 @@ class CoverArtBrowserSource(RB.Source):
if playlists_entries: if playlists_entries:
for playlist in playlists_entries: for playlist in playlists_entries:
if playlist.props.is_local and \ if playlist.props.is_local and \
isinstance(playlist, RB.StaticPlaylistSource): isinstance(playlist, RB.StaticPlaylistSource):
args = (playlist, favourite)
args=(playlist, favourite)
# take the name of the playlist, strip out non-english characters and reduce the string # take the name of the playlist, strip out non-english characters and reduce the string
# to just a-to-z characters i.e. this will make the action_name valid in RB3 # to just a-to-z characters i.e. this will make the action_name valid in RB3
ascii_name = unicodedata.normalize('NFKD', \ ascii_name = unicodedata.normalize('NFKD', \
rb3compat.unicodestr(playlist.props.name, 'utf-8')).encode('ascii','ignore') rb3compat.unicodestr(playlist.props.name, 'utf-8')).encode(
'ascii', 'ignore')
ascii_name = ascii_name.decode(encoding='UTF-8') ascii_name = ascii_name.decode(encoding='UTF-8')
ascii_name = re.sub(r'[^a-zA-Z]', '', ascii_name) ascii_name = re.sub(r'[^a-zA-Z]', '', ascii_name)
action = actiongroup.add_action(func=func, action = actiongroup.add_action(func=func,
action_name=ascii_name, action_name=ascii_name,
playlist=playlist,favourite=favourite, playlist=playlist, favourite=favourite,
label=playlist.props.name) label=playlist.props.name)
popup_menu.add_menu_item( menubar, section_name, popup_menu.add_menu_item(menubar, section_name,
action ) action)
def add_to_static_playlist_menu_item_callback(self, action, param, args): def add_to_static_playlist_menu_item_callback(self, action, param, args):
print('''CoverArtBrowser DEBUG - print('''CoverArtBrowser DEBUG -
add_to_static_playlist_menu_item_callback''') add_to_static_playlist_menu_item_callback''')
playlist=args['playlist'] playlist = args['playlist']
favourite = args['favourite'] favourite = args['favourite']
self.queue_selected_album(playlist, favourite) self.queue_selected_album(playlist, favourite)
def add_playlist_menu_item_callback(self, *args): def add_playlist_menu_item_callback(self, *args):
@@ -710,27 +712,27 @@ class CoverArtBrowserSource(RB.Source):
selected_albums = [] selected_albums = []
gs = GSetting() gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN) settings = gs.get_setting(gs.Path.PLUGIN)
to_queue = settings[gs.PluginKey.RANDOM] to_queue = settings[gs.PluginKey.RANDOM]
if num_albums <= to_queue: if num_albums <= to_queue:
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("The number of albums to randomly play is less than that displayed.")) _("The number of albums to randomly play is less than that displayed."))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
return return
album_col = self.album_manager.model.columns['album'] album_col = self.album_manager.model.columns['album']
chosen = {} chosen = {}
# now loop through finding unique random albums # now loop through finding unique random albums
# i.e. ensure we dont queue the same album twice # i.e. ensure we dont queue the same album twice
for loop in range(0, to_queue): for loop in range(0, to_queue):
while True: while True:
pos = random.randint(0, num_albums - 1) pos = random.randint(0, num_albums - 1)
@@ -752,14 +754,15 @@ class CoverArtBrowserSource(RB.Source):
if total == 0 and threshold: if total == 0 and threshold:
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("No tracks have been added because no tracks meet the favourite rating threshold")) _(
"No tracks have been added because no tracks meet the favourite rating threshold"))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
self.props.query_model = query_model self.props.query_model = query_model
# Start the music # Start the music
@@ -781,7 +784,7 @@ class CoverArtBrowserSource(RB.Source):
self.request_status_box.show_all() self.request_status_box.show_all()
self.album_manager.cover_man.search_covers(selected_albums, self.album_manager.cover_man.search_covers(selected_albums,
self.update_request_status_bar) self.update_request_status_bar)
print("CoverArtBrowser DEBUG - end cover_search_menu_item_callback()") print("CoverArtBrowser DEBUG - end cover_search_menu_item_callback()")
@@ -795,7 +798,7 @@ class CoverArtBrowserSource(RB.Source):
selected_albums = self.viewmgr.current_view.get_selected_objects() selected_albums = self.viewmgr.current_view.get_selected_objects()
CoverArtExport(self.plugin, CoverArtExport(self.plugin,
self.shell, self.album_manager).embed_albums(selected_albums) self.shell, self.album_manager).embed_albums(selected_albums)
print("CoverArtBrowser DEBUG - export_embed_menu_item_callback()") print("CoverArtBrowser DEBUG - export_embed_menu_item_callback()")
@@ -837,15 +840,15 @@ class CoverArtBrowserSource(RB.Source):
then if necessary scroll the view to the last selected album then if necessary scroll the view to the last selected album
params is "album" or a tuple of "album" and "force_expand" boolean params is "album" or a tuple of "album" and "force_expand" boolean
''' '''
if isinstance(params, tuple): if isinstance(params, tuple):
album, force = params album, force = params
else: else:
album = params album = params
force = PanedCollapsible.Paned.DEFAULT force = PanedCollapsible.Paned.DEFAULT
if (album and self.click_count == 1 \ if (album and self.click_count == 1 \
and self.last_selected_album is album) or force != PanedCollapsible.Paned.DEFAULT: and self.last_selected_album is album) or force != PanedCollapsible.Paned.DEFAULT:
# check if it's a second or third click on the album and expand # check if it's a second or third click on the album and expand
# or collapse the entry view accordingly # or collapse the entry view accordingly
self.paned.expand(force) self.paned.expand(force)
@@ -866,7 +869,7 @@ class CoverArtBrowserSource(RB.Source):
self.statusbar.emit('display-status', self.viewmgr.current_view) self.statusbar.emit('display-status', self.viewmgr.current_view)
def propertiesbutton_callback(self, choice): def propertiesbutton_callback(self, choice):
if choice == 'download': if choice == 'download':
self.request_status_box.show_all() self.request_status_box.show_all()
self._cover_search_manager = self.viewmgr.current_view.get_default_manager() self._cover_search_manager = self.viewmgr.current_view.get_default_manager()
@@ -884,12 +887,13 @@ class CoverArtBrowserSource(RB.Source):
elif choice == 'browser prefs': elif choice == 'browser prefs':
if not self._browser_preferences: if not self._browser_preferences:
self._browser_preferences = Preferences() self._browser_preferences = Preferences()
self._browser_preferences.display_preferences_dialog(self.plugin) self._browser_preferences.display_preferences_dialog(self.plugin)
elif choice == 'search prefs': elif choice == 'search prefs':
try: try:
if not self._search_preferences: if not self._search_preferences:
from gi.repository import Peas from gi.repository import Peas
peas = Peas.Engine.get_default() peas = Peas.Engine.get_default()
plugin_info = peas.get_plugin_info('coverart_search_providers') plugin_info = peas.get_plugin_info('coverart_search_providers')
module_name = plugin_info.get_module_name() module_name = plugin_info.get_module_name()
@@ -901,15 +905,16 @@ class CoverArtBrowserSource(RB.Source):
self._search_preferences.display_preferences_dialog(self._search_preferences) self._search_preferences.display_preferences_dialog(self._search_preferences)
except: except:
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("Please install and activate the latest version of the Coverart Search Providers plugin")) _(
"Please install and activate the latest version of the Coverart Search Providers plugin"))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
else: else:
assert 1==2, ("unknown choice %s", choice) assert 1 == 2, ("unknown choice %s", choice)
@classmethod @classmethod
def get_instance(cls, **kwargs): def get_instance(cls, **kwargs):
@@ -921,12 +926,13 @@ class CoverArtBrowserSource(RB.Source):
return cls.instance return cls.instance
class Statusbar(GObject.Object): class Statusbar(GObject.Object):
# signals # signals
__gsignals__ = { __gsignals__ = {
'display-status': (GObject.SIGNAL_RUN_LAST, None, (object,)) 'display-status': (GObject.SIGNAL_RUN_LAST, None, (object,))
} }
custom_statusbar_enabled = GObject.property(type=bool, default=False) custom_statusbar_enabled = GObject.property(type=bool, default=False)
def __init__(self, source): def __init__(self, source):
@@ -946,11 +952,11 @@ class Statusbar(GObject.Object):
settings = gs.get_setting(gs.Path.PLUGIN) settings = gs.get_setting(gs.Path.PLUGIN)
settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, self, settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, self,
'custom_statusbar_enabled', Gio.SettingsBindFlags.GET) 'custom_statusbar_enabled', Gio.SettingsBindFlags.GET)
def _connect_signals(self, source): def _connect_signals(self, source):
self.connect('notify::custom-statusbar-enabled', self.connect('notify::custom-statusbar-enabled',
self._custom_statusbar_enabled_changed) self._custom_statusbar_enabled_changed)
self.connect('display-status', self._update) self.connect('display-status', self._update)
def _custom_statusbar_enabled_changed(self, *args): def _custom_statusbar_enabled_changed(self, *args):
@@ -980,30 +986,31 @@ class Statusbar(GObject.Object):
# 'interesting stuff' about the album # 'interesting stuff' about the album
if len(albums) == 1: if len(albums) == 1:
#. TRANSLATORS - for example "abba's greatest hits by ABBA" #. TRANSLATORS - for example "abba's greatest hits by ABBA"
self.status = rb3compat.unicodedecode(_('%s by %s') % self.status = rb3compat.unicodedecode(_('%s by %s') %
(album.name, album.artist), 'UTF-8') (album.name, album.artist), 'UTF-8')
else: else:
#. TRANSLATORS - the number of albums that have been selected/highlighted #. TRANSLATORS - the number of albums that have been selected/highlighted
self.status = rb3compat.unicodedecode(_('%d selected albums') % self.status = rb3compat.unicodedecode(_('%d selected albums') %
(len(albums)), 'UTF-8') (len(albums)), 'UTF-8')
if track_count == 1: if track_count == 1:
self.status += rb3compat.unicodedecode(_(' with 1 track'), 'UTF-8') self.status += rb3compat.unicodedecode(_(' with 1 track'), 'UTF-8')
else: else:
self.status += rb3compat.unicodedecode(_(' with %d tracks') % self.status += rb3compat.unicodedecode(_(' with %d tracks') %
track_count, 'UTF-8') track_count, 'UTF-8')
if duration == 1: if duration == 1:
self.status += rb3compat.unicodedecode(_(' and a duration of 1 minute'), 'UTF-8') self.status += rb3compat.unicodedecode(_(' and a duration of 1 minute'), 'UTF-8')
else: else:
self.status += rb3compat.unicodedecode(_(' and a duration of %d minutes') % self.status += rb3compat.unicodedecode(_(' and a duration of %d minutes') %
duration, 'UTF-8') duration, 'UTF-8')
def _update(self, widget, current_view): def _update(self, widget, current_view):
albums = current_view.get_selected_objects() albums = current_view.get_selected_objects()
self._generate_status(albums) self._generate_status(albums)
self.current_statusbar.update(self.status) self.current_statusbar.update(self.status)
class SourceStatusBar(object): class SourceStatusBar(object):
def __init__(self, source): def __init__(self, source):
self._source = source self._source = source
@@ -1031,7 +1038,8 @@ class CustomStatusBar(object):
def update(self, status): def update(self, status):
self._label.set_text(status) self._label.set_text(status)
class Views: class Views:
''' '''
This class describes the different views available This class describes the different views available
@@ -1061,40 +1069,40 @@ class Views:
queue_name = shell.props.queue_source.props.name queue_name = shell.props.queue_source.props.name
self._values = OrderedDict() self._values = OrderedDict()
cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self._values[CoverIconView.name] = [_('Tiles'), cl = CoverLocale()
GLib.Variant.new_string('coverart-browser-tile')] cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self._values[CoverIconView.name] = [_('Tiles'),
GLib.Variant.new_string('coverart-browser-tile')]
if webkit_support(): if webkit_support():
self._values[CoverFlowView.name] = [_('Flow'), self._values[CoverFlowView.name] = [_('Flow'),
GLib.Variant.new_string('coverart-browser-coverflow')] GLib.Variant.new_string('coverart-browser-coverflow')]
self._values[ArtistView.name] = [_('Artist'), self._values[ArtistView.name] = [_('Artist'),
GLib.Variant.new_string('coverart-browser-artist')] GLib.Variant.new_string('coverart-browser-artist')]
self._values[ListView.name] = [library_name, self._values[ListView.name] = [library_name,
GLib.Variant.new_string('coverart-browser-list')] GLib.Variant.new_string('coverart-browser-list')]
self._values[QueueView.name] = [queue_name, self._values[QueueView.name] = [queue_name,
GLib.Variant.new_string('coverart-browser-queue')] GLib.Variant.new_string('coverart-browser-queue')]
cl.switch_locale(cl.Locale.RB) cl.switch_locale(cl.Locale.RB)
print (self._values) print(self._values)
def get_view_names(self): def get_view_names(self):
return list(self._values.keys()) return list(self._values.keys())
def get_view_name_for_action(self, action_name): def get_view_name_for_action(self, action_name):
for view_name in self.get_view_names(): for view_name in self.get_view_names():
if self.get_action_name(view_name) == action_name: if self.get_action_name(view_name) == action_name:
return view_name return view_name
return None return None
def get_menu_name(self, view_name): def get_menu_name(self, view_name):
return self._values[view_name][0] return self._values[view_name][0]
def get_action_name(self, view_name): def get_action_name(self, view_name):
return self._values[view_name][1] return self._values[view_name][1]
def __init__(self, plugin): def __init__(self, plugin):
""" Create singleton instance """ """ Create singleton instance """
# Check whether we already have an instance # Check whether we already have an instance
@@ -1118,33 +1126,33 @@ class ViewManager(GObject.Object):
# signals # signals
__gsignals__ = { __gsignals__ = {
'new-view': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'new-view': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
# properties # properties
view_name = GObject.property(type=str, default=CoverIconView.name) view_name = GObject.property(type=str, default=CoverIconView.name)
def __init__(self, source, window): def __init__(self, source, window):
super(ViewManager, self).__init__() super(ViewManager, self).__init__()
self.source = source self.source = source
self.window = window self.window = window
# initialize views # initialize views
self._views = {} self._views = {}
ui = Gtk.Builder() ui = Gtk.Builder()
ui.add_from_file(rb.find_plugin_file(source.plugin, ui.add_from_file(rb.find_plugin_file(source.plugin,
'ui/coverart_iconview.ui')) 'ui/coverart_iconview.ui'))
self._views[CoverIconView.name] = ui.get_object('covers_view') self._views[CoverIconView.name] = ui.get_object('covers_view')
self._views[CoverFlowView.name] = CoverFlowView() self._views[CoverFlowView.name] = CoverFlowView()
self._views[ListView.name] = ListView() self._views[ListView.name] = ListView()
self._views[QueueView.name] = QueueView() self._views[QueueView.name] = QueueView()
ui.add_from_file(rb.find_plugin_file(source.plugin, ui.add_from_file(rb.find_plugin_file(source.plugin,
'ui/coverart_artistview.ui')) 'ui/coverart_artistview.ui'))
self._views[ArtistView.name] = ui.get_object('artist_view') self._views[ArtistView.name] = ui.get_object('artist_view')
self._lastview = None self._lastview = None
self.controller = ViewController(source.shell, self) self.controller = ViewController(source.shell, self)
# connect signal and properties # connect signal and properties
self._connect_signals() self._connect_signals()
self._connect_properties() self._connect_properties()
@@ -1152,22 +1160,22 @@ class ViewManager(GObject.Object):
if self.current_view.use_plugin_window: if self.current_view.use_plugin_window:
window.add(self.current_view.view) window.add(self.current_view.view)
window.show_all() window.show_all()
@property @property
def current_view(self): def current_view(self):
return self._views[self.view_name] return self._views[self.view_name]
def get_view(self, view_name): def get_view(self, view_name):
return self._views[view_name] return self._views[view_name]
def _connect_signals(self): def _connect_signals(self):
self.connect('notify::view-name', self.on_notify_view_name) self.connect('notify::view-name', self.on_notify_view_name)
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.VIEW_NAME, self, 'view_name', setting.bind(gs.PluginKey.VIEW_NAME, self, 'view_name',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
def on_notify_view_name(self, *args): def on_notify_view_name(self, *args):
if self._lastview and self.view_name != self._lastview: if self._lastview and self.view_name != self._lastview:
@@ -1175,42 +1183,42 @@ class ViewManager(GObject.Object):
current_album = None current_album = None
if len(selected) > 0: if len(selected) > 0:
current_album = self._views[self._lastview].get_selected_objects()[0] current_album = self._views[self._lastview].get_selected_objects()[0]
if self._views[self.view_name].use_plugin_window: if self._views[self.view_name].use_plugin_window:
child = self.window.get_child() child = self.window.get_child()
if child: if child:
self.window.remove(child) self.window.remove(child)
self.window.add(self._views[self.view_name].view) self.window.add(self._views[self.view_name].view)
self.window.show_all() self.window.show_all()
self.click_count = 0 self.click_count = 0
self._views[self._lastview].panedposition = self.source.paned.get_expansion_status() self._views[self._lastview].panedposition = self.source.paned.get_expansion_status()
self._views[self.view_name].switch_to_view(self.source, current_album) self._views[self.view_name].switch_to_view(self.source, current_album)
self._views[self.view_name].emit('update-toolbar') self._views[self.view_name].emit('update-toolbar')
self._views[self.view_name].get_default_manager().emit('sort', None) self._views[self.view_name].get_default_manager().emit('sort', None)
if self._views[self.view_name].use_plugin_window: if self._views[self.view_name].use_plugin_window:
self.source.paned.expand(self._views[self.view_name].panedposition) self.source.paned.expand(self._views[self.view_name].panedposition)
self.current_view.set_popup_menu(self.source.popup_menu) self.current_view.set_popup_menu(self.source.popup_menu)
self.source.album_manager.current_view = self.current_view self.source.album_manager.current_view = self.current_view
if self._views[self.view_name].use_plugin_window: if self._views[self.view_name].use_plugin_window:
# we only ever save plugin views not external views # we only ever save plugin views not external views
saved_view = self.view_name saved_view = self.view_name
else: else:
saved_view = self._lastview saved_view = self._lastview
self._lastview = self.view_name self._lastview = self.view_name
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting[gs.PluginKey.VIEW_NAME] = saved_view setting[gs.PluginKey.VIEW_NAME] = saved_view
self.emit('new-view', self.view_name) self.emit('new-view', self.view_name)
def get_view_icon_name(self, view_name): def get_view_icon_name(self, view_name):
return self._views[view_name].get_view_icon_name() return self._views[view_name].get_view_icon_name()
@@ -1226,5 +1234,6 @@ class ViewManager(GObject.Object):
colour = '#0000FF' colour = '#0000FF'
return colour return colour
GObject.type_register(CoverArtBrowserSource) GObject.type_register(CoverArtBrowserSource)
+106 -109
Ver Arquivo
@@ -37,14 +37,15 @@ import rb
import coverart_rb3compat as rb3compat import coverart_rb3compat as rb3compat
from collections import namedtuple from collections import namedtuple
MenuNodeT = namedtuple('MenuNode', 'label menutype typevalue') MenuNodeT = namedtuple('MenuNode', 'label menutype typevalue')
def MenuNode(label, menutype=None, typevalue=None): def MenuNode(label, menutype=None, typevalue=None):
return MenuNodeT(label, menutype, typevalue) return MenuNodeT(label, menutype, typevalue)
class OptionsController(GObject.Object):
class OptionsController(GObject.Object):
# properties # properties
options = GObject.property(type=object, default=None) options = GObject.property(type=object, default=None)
current_key = GObject.property(type=str, default=None) current_key = GObject.property(type=str, default=None)
@@ -86,10 +87,10 @@ class OptionsController(GObject.Object):
''' '''
if sheet: if sheet:
del sheet del sheet
return ConfiguredSpriteSheet(plugin, typestr, get_stock_size()) return ConfiguredSpriteSheet(plugin, typestr, get_stock_size())
def create_button_image( self, plugin, image, icon_name): def create_button_image(self, plugin, image, icon_name):
''' '''
helper function to create a button image helper function to create a button image
''' '''
@@ -97,13 +98,13 @@ class OptionsController(GObject.Object):
del image del image
path = 'img/' + Theme(self.plugin).current + '/' path = 'img/' + Theme(self.plugin).current + '/'
return create_pixbuf_from_file_at_size( return create_pixbuf_from_file_at_size(
rb.find_plugin_file(self.plugin, path + icon_name), rb.find_plugin_file(self.plugin, path + icon_name),
*get_stock_size()) *get_stock_size())
class PlaylistPopupController(OptionsController):
class PlaylistPopupController(OptionsController):
def __init__(self, plugin, album_model): def __init__(self, plugin, album_model):
super(PlaylistPopupController, self).__init__() super(PlaylistPopupController, self).__init__()
@@ -123,7 +124,7 @@ class PlaylistPopupController(OptionsController):
self._spritesheet = None self._spritesheet = None
self._update_options(shell) self._update_options(shell)
# get the playlist model so we can monitor changes # get the playlist model so we can monitor changes
if rb3compat.is_rb3(shell): if rb3compat.is_rb3(shell):
playlist_model = shell.props.display_page_model playlist_model = shell.props.display_page_model
@@ -137,8 +138,8 @@ class PlaylistPopupController(OptionsController):
playlist_model.connect('row-changed', self._update_options, shell) playlist_model.connect('row-changed', self._update_options, shell)
def update_images(self, *args): def update_images(self, *args):
self._spritesheet = self.create_spritesheet( self.plugin, self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'playlist') self._spritesheet, 'playlist')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
@@ -146,10 +147,10 @@ class PlaylistPopupController(OptionsController):
def _update_options(self, *args): def _update_options(self, *args):
shell = args[-1] shell = args[-1]
self.update_images(False) self.update_images(False)
playlist_manager = shell.props.playlist_manager playlist_manager = shell.props.playlist_manager
still_exists = self.current_key == self._library_name or\ still_exists = self.current_key == self._library_name or \
self.current_key == self._queue_name self.current_key == self._queue_name
# retrieve the options # retrieve the options
values = OrderedDict() values = OrderedDict()
@@ -171,7 +172,7 @@ class PlaylistPopupController(OptionsController):
self.values = values self.values = values
self.options = list(values.keys()) self.options = list(values.keys())
self.current_key = self.current_key if still_exists else\ self.current_key = self.current_key if still_exists else \
self._library_name self._library_name
def do_action(self): def do_action(self):
@@ -181,7 +182,7 @@ class PlaylistPopupController(OptionsController):
self._album_model.remove_filter('model') self._album_model.remove_filter('model')
else: else:
self._album_model.replace_filter('model', self._album_model.replace_filter('model',
playlist.get_query_model()) playlist.get_query_model())
def get_current_image(self): def get_current_image(self):
playlist = self.values[self.current_key] playlist = self.values[self.current_key]
@@ -215,7 +216,7 @@ class GenrePopupController(OptionsController):
# create a new property model for the genres # create a new property model for the genres
genres_model = RB.RhythmDBPropertyModel.new(shell.props.db, genres_model = RB.RhythmDBPropertyModel.new(shell.props.db,
RB.RhythmDBPropType.GENRE) RB.RhythmDBPropType.GENRE)
query = shell.props.library_source.props.base_query_model query = shell.props.library_source.props.base_query_model
genres_model.props.query_model = query genres_model.props.query_model = query
@@ -229,21 +230,21 @@ class GenrePopupController(OptionsController):
self._connect_properties() self._connect_properties()
self._connect_signals(query, genres_model) self._connect_signals(query, genres_model)
# generate initial popup # generate initial popup
self._update_options(genres_model) self._update_options(genres_model)
def update_images(self, *args): def update_images(self, *args):
if self._spritesheet: if self._spritesheet:
del self._spritesheet del self._spritesheet
self._spritesheet = GenreConfiguredSpriteSheet(self.plugin, self._spritesheet = GenreConfiguredSpriteSheet(self.plugin,
'genre', get_stock_size()) 'genre', get_stock_size())
self._default_image = self.create_button_image( self.plugin, self._default_image = self.create_button_image(self.plugin,
self._default_image, 'default_genre.png') self._default_image, 'default_genre.png')
self._unrecognised_image = self.create_button_image( self.plugin, self._unrecognised_image = self.create_button_image(self.plugin,
self._unrecognised_image, 'unrecognised_genre.png') self._unrecognised_image, 'unrecognised_genre.png')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
@@ -259,13 +260,13 @@ class GenrePopupController(OptionsController):
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.NEW_GENRE_ICON, self, 'new_genre_icon', setting.bind(gs.PluginKey.NEW_GENRE_ICON, self, 'new_genre_icon',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
def _update_options(self, *args): def _update_options(self, *args):
genres_model = args[-1] genres_model = args[-1]
self.update_images(False) self.update_images(False)
still_exists = False still_exists = False
# retrieve the options # retrieve the options
@@ -284,7 +285,7 @@ class GenrePopupController(OptionsController):
self.options = options self.options = options
self.current_key = self.current_key if still_exists else\ self.current_key = self.current_key if still_exists else \
self._initial_genre self._initial_genre
def do_action(self): def do_action(self):
@@ -306,7 +307,7 @@ class GenrePopupController(OptionsController):
image = self._find_alternates(test_genre) image = self._find_alternates(test_genre)
if image == self._unrecognised_image and \ if image == self._unrecognised_image and \
test_genre in self._spritesheet: test_genre in self._spritesheet:
image = self._spritesheet[test_genre] image = self._spritesheet[test_genre]
return image return image
@@ -326,15 +327,15 @@ class GenrePopupController(OptionsController):
# in a mixture of cases, both unicode (normalized or not) and str # in a mixture of cases, both unicode (normalized or not) and str
# and as usual python cannot mix and match these types. # and as usual python cannot mix and match these types.
test_genre = RB.search_fold(test_genre) test_genre = RB.search_fold(test_genre)
ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_USER) ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_USER)
if ret: if ret:
return sprite return sprite
for genre in sorted(self._spritesheet.locale_names, for genre in sorted(self._spritesheet.locale_names,
key=lambda b: (-len(b), b)): key=lambda b: (-len(b), b)):
if RB.search_fold(genre) in test_genre: if RB.search_fold(genre) in test_genre:
return self._spritesheet[self._spritesheet.locale_names[genre]] return self._spritesheet[self._spritesheet.locale_names[genre]]
@@ -346,23 +347,23 @@ class GenrePopupController(OptionsController):
ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_SYSTEM) ret, sprite = self._match_genres(test_genre, self._spritesheet.GENRE_SYSTEM)
if ret: if ret:
return sprite return sprite
# check if any of the default genres are a substring # check if any of the default genres are a substring
# of test_genre - check in reverse order so that we # of test_genre - check in reverse order so that we
# test largest strings first (prevents spurious matches with # test largest strings first (prevents spurious matches with
# short strings) # short strings)
for genre in sorted(self._spritesheet.names, for genre in sorted(self._spritesheet.names,
key=lambda b: (-len(b), b)): key=lambda b: (-len(b), b)):
if RB.search_fold(genre) in test_genre: if RB.search_fold(genre) in test_genre:
return self._spritesheet[genre] return self._spritesheet[genre]
# if no matches then default to unrecognised image # if no matches then default to unrecognised image
return self._unrecognised_image return self._unrecognised_image
def _match_genres(self, test_genre, genre_type): def _match_genres(self, test_genre, genre_type):
case_search = CaseInsensitiveDict( case_search = CaseInsensitiveDict(
dict((k.name, v) for k, v in self._spritesheet.genre_alternate.items() dict((k.name, v) for k, v in self._spritesheet.genre_alternate.items()
if k.genre_type==genre_type)) if k.genre_type == genre_type))
if test_genre in case_search: if test_genre in case_search:
return (True, self._spritesheet[case_search[test_genre]]) return (True, self._spritesheet[case_search[test_genre]])
@@ -378,23 +379,22 @@ class GenrePopupController(OptionsController):
class SortPopupController(OptionsController): class SortPopupController(OptionsController):
def __init__(self, plugin, viewmgr): def __init__(self, plugin, viewmgr):
super(SortPopupController, self).__init__() super(SortPopupController, self).__init__()
self._viewmgr=viewmgr self._viewmgr = viewmgr
self.plugin = plugin self.plugin = plugin
# sorts dictionary # sorts dictionary
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.values = OrderedDict([(_('Sort by album name'), 'name'), self.values = OrderedDict([(_('Sort by album name'), 'name'),
(_('Sort by album artist'), 'artist'), (_('Sort by album artist'), 'artist'),
(_('Sort by year'), 'year'), (_('Sort by year'), 'year'),
(_('Sort by rating'), 'rating')]) (_('Sort by rating'), 'rating')])
self.options = list(self.values.keys()) self.options = list(self.values.keys())
# get the current sort key and initialise the superclass # get the current sort key and initialise the superclass
gs = GSetting() gs = GSetting()
source_settings = gs.get_setting(gs.Path.PLUGIN) source_settings = gs.get_setting(gs.Path.PLUGIN)
@@ -402,17 +402,17 @@ class SortPopupController(OptionsController):
self._spritesheet = None self._spritesheet = None
self.update_images(False) self.update_images(False)
self.current_key = list(self.values.keys())[ self.current_key = list(self.values.keys())[
list(self.values.values()).index(value)] list(self.values.values()).index(value)]
def update_images(self, *args): def update_images(self, *args):
self._spritesheet = self.create_spritesheet( self.plugin, self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'sort') self._spritesheet, 'sort')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
def do_action(self): def do_action(self):
sort = self.values[self.current_key] sort = self.values[self.current_key]
@@ -425,9 +425,9 @@ class SortPopupController(OptionsController):
def get_current_image(self): def get_current_image(self):
sort = self.values[self.current_key] sort = self.values[self.current_key]
return self._spritesheet[sort] return self._spritesheet[sort]
class ArtistSortPopupController(OptionsController):
class ArtistSortPopupController(OptionsController):
def __init__(self, plugin, viewmgr): def __init__(self, plugin, viewmgr):
super(ArtistSortPopupController, self).__init__() super(ArtistSortPopupController, self).__init__()
@@ -438,35 +438,35 @@ class ArtistSortPopupController(OptionsController):
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.values = OrderedDict([(_('Sort by album name'), 'name_artist'), self.values = OrderedDict([(_('Sort by album name'), 'name_artist'),
(_('Sort by year'), 'year_artist'), (_('Sort by year'), 'year_artist'),
(_('Sort by rating'), 'rating_artist')]) (_('Sort by rating'), 'rating_artist')])
self.options = list(self.values.keys()) self.options = list(self.values.keys())
# get the current sort key and initialise the superclass # get the current sort key and initialise the superclass
gs = GSetting() gs = GSetting()
source_settings = gs.get_setting(gs.Path.PLUGIN) source_settings = gs.get_setting(gs.Path.PLUGIN)
value = source_settings[gs.PluginKey.SORT_BY_ARTIST] value = source_settings[gs.PluginKey.SORT_BY_ARTIST]
if value not in list(self.values.values()): if value not in list(self.values.values()):
print ("here") print("here")
value = 'name_artist' value = 'name_artist'
source_settings[gs.PluginKey.SORT_BY_ARTIST]=value source_settings[gs.PluginKey.SORT_BY_ARTIST] = value
self._spritesheet = None self._spritesheet = None
self.update_images(False) self.update_images(False)
self.current_key = list(self.values.keys())[ self.current_key = list(self.values.keys())[
list(self.values.values()).index(value)] list(self.values.values()).index(value)]
print (self.current_key) print(self.current_key)
def update_images(self, *args): def update_images(self, *args):
self._spritesheet = self.create_spritesheet( self.plugin, self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'sort_artist') self._spritesheet, 'sort_artist')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
def do_action(self): def do_action(self):
sort = self.values[self.current_key] sort = self.values[self.current_key]
@@ -499,18 +499,18 @@ class PropertiesMenuController(OptionsController):
self.values[MenuNode(_('Download all covers'))] = 'download' self.values[MenuNode(_('Download all covers'))] = 'download'
self.values[MenuNode(_('Play random album'))] = 'random' self.values[MenuNode(_('Play random album'))] = 'random'
self.values[MenuNode(_('Follow playing song'), 'check', self.values[MenuNode(_('Follow playing song'), 'check',
(True if self.follow else False))] = 'follow' (True if self.follow else False))] = 'follow'
self.values[MenuNode('separator1', 'separator')] = '' self.values[MenuNode('separator1', 'separator')] = ''
self.values[MenuNode(_('Use favourites only'), 'check', self.values[MenuNode(_('Use favourites only'), 'check',
(True if self.favourites else False))] = 'favourite' (True if self.favourites else False))] = 'favourite'
self.values[MenuNode('separator2', 'separator')] = '' self.values[MenuNode('separator2', 'separator')] = ''
self.values[MenuNode(_('Browser Preferences'))] = 'browser prefs' self.values[MenuNode(_('Browser Preferences'))] = 'browser prefs'
self.values[MenuNode(_('Search Preferences'))] = 'search prefs' self.values[MenuNode(_('Search Preferences'))] = 'search prefs'
self.options = list(self.values.keys()) self.options = list(self.values.keys())
self.update_images(False) self.update_images(False)
if self.favourites: if self.favourites:
self._source.propertiesbutton_callback('favourite') self._source.propertiesbutton_callback('favourite')
@@ -518,7 +518,7 @@ class PropertiesMenuController(OptionsController):
self._source.propertiesbutton_callback('follow') self._source.propertiesbutton_callback('follow')
self.current_key = None self.current_key = None
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
@@ -532,23 +532,23 @@ class PropertiesMenuController(OptionsController):
self, self,
'follow', 'follow',
Gio.SettingsBindFlags.DEFAULT) Gio.SettingsBindFlags.DEFAULT)
def _change_key(self, dict, old, new): def _change_key(self, dict, old, new):
for i in range(len(dict)): for i in range(len(dict)):
k,v = dict.popitem(False) k, v = dict.popitem(False)
dict[new if old == k else k] = v dict[new if old == k else k] = v
def update_images(self, *args): def update_images(self, *args):
self._image = self.create_button_image( self.plugin, self._image = self.create_button_image(self.plugin,
None, 'properties.png') None, 'properties.png')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
def do_action(self): def do_action(self):
if self.current_key: if self.current_key:
key = [node for node in self.values if node.label == self.current_key] key = [node for node in self.values if node.label == self.current_key]
if self.current_key == _('Use favourites only'): if self.current_key == _('Use favourites only'):
self.favourites = not self.favourites self.favourites = not self.favourites
@@ -564,8 +564,8 @@ class PropertiesMenuController(OptionsController):
def get_current_description(self): def get_current_description(self):
return _('Properties') return _('Properties')
class DecadePopupController(OptionsController):
class DecadePopupController(OptionsController):
def __init__(self, plugin, album_model): def __init__(self, plugin, album_model):
super(DecadePopupController, self).__init__() super(DecadePopupController, self).__init__()
@@ -573,7 +573,7 @@ class DecadePopupController(OptionsController):
self.plugin = plugin self.plugin = plugin
self._spritesheet = None self._spritesheet = None
# decade options # decade options
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
@@ -613,13 +613,13 @@ class DecadePopupController(OptionsController):
# define a initial decade an set the initial key # define a initial decade an set the initial key
self._initial_decade = self.options[0] self._initial_decade = self.options[0]
self.update_images(False) self.update_images(False)
self.current_key = self._initial_decade self.current_key = self._initial_decade
def update_images(self, *args): def update_images(self, *args):
self._spritesheet = self.create_spritesheet( self.plugin, self._spritesheet = self.create_spritesheet(self.plugin,
self._spritesheet, 'decade') self._spritesheet, 'decade')
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
@@ -628,7 +628,7 @@ class DecadePopupController(OptionsController):
self._album_model.remove_filter('decade') self._album_model.remove_filter('decade')
else: else:
self._album_model.replace_filter('decade', self._album_model.replace_filter('decade',
self.values[self.current_key][0]) self.values[self.current_key][0])
def get_current_image(self): def get_current_image(self):
decade = self.values[self.current_key][1] decade = self.values[self.current_key][1]
@@ -639,22 +639,21 @@ class DecadePopupController(OptionsController):
class SortOrderToggleController(OptionsController): class SortOrderToggleController(OptionsController):
toolbar_type = "album" toolbar_type = "album"
def __init__(self, plugin, viewmgr): def __init__(self, plugin, viewmgr):
super(SortOrderToggleController, self).__init__() super(SortOrderToggleController, self).__init__()
self._viewmgr = viewmgr self._viewmgr = viewmgr
self.plugin = plugin self.plugin = plugin
# options # options
self.values = OrderedDict([(_('Sort in descending order'), False), self.values = OrderedDict([(_('Sort in descending order'), False),
(_('Sort in ascending order'), True)]) (_('Sort in ascending order'), True)])
self.options = list(self.values.keys()) self.options = list(self.values.keys())
self._images = [] self._images = []
# set the current key # set the current key
self.gs = GSetting() self.gs = GSetting()
self.settings = self.gs.get_setting(self.gs.Path.PLUGIN) self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
@@ -663,44 +662,43 @@ class SortOrderToggleController(OptionsController):
self.current_key = list(self.values.keys())[ self.current_key = list(self.values.keys())[
list(self.values.values()).index(sort_order)] list(self.values.values()).index(sort_order)]
self.update_images(False) self.update_images(False)
def get_key(self): def get_key(self):
return self.gs.PluginKey.SORT_ORDER return self.gs.PluginKey.SORT_ORDER
def update_images(self, *args): def update_images(self, *args):
# initialize images # initialize images
if len(self._images) > 0: if len(self._images) > 0:
del self._images[:] del self._images[:]
self._images.append(self.create_button_image( self.plugin, self._images.append(self.create_button_image(self.plugin,
None, 'arrow_down.png')) None, 'arrow_down.png'))
self._images.append(self.create_button_image( self.plugin, self._images.append(self.create_button_image(self.plugin,
None, 'arrow_up.png')) None, 'arrow_up.png'))
if args[-1]: if args[-1]:
self.update_image = True self.update_image = True
def do_action(self): def do_action(self):
sort_order = self.values[self.current_key] sort_order = self.values[self.current_key]
self.settings[self.key] = sort_order self.settings[self.key] = sort_order
self._viewmgr.current_view.get_default_manager().emit('sort', self.toolbar_type) self._viewmgr.current_view.get_default_manager().emit('sort', self.toolbar_type)
def get_current_image(self): def get_current_image(self):
return self._images[self.get_current_key_index()] return self._images[self.get_current_key_index()]
class ArtistSortOrderToggleController(SortOrderToggleController): class ArtistSortOrderToggleController(SortOrderToggleController):
toolbar_type = "artist" toolbar_type = "artist"
def __init__(self, plugin, model): def __init__(self, plugin, model):
super(ArtistSortOrderToggleController, self).__init__(plugin, model) super(ArtistSortOrderToggleController, self).__init__(plugin, model)
def get_key(self): def get_key(self):
return self.gs.PluginKey.SORT_ORDER_ARTIST return self.gs.PluginKey.SORT_ORDER_ARTIST
class AlbumSearchEntryController(OptionsController): class AlbumSearchEntryController(OptionsController):
# properties # properties
search_text = GObject.property(type=str, default='') search_text = GObject.property(type=str, default='')
@@ -750,7 +748,7 @@ class AlbumSearchEntryController(OptionsController):
if search_text: if search_text:
self._album_model.replace_filter(self._filter_type, self._album_model.replace_filter(self._filter_type,
search_text) search_text)
elif not force: elif not force:
self._album_model.remove_filter(self._filter_type) self._album_model.remove_filter(self._filter_type)
@@ -783,12 +781,10 @@ class AlbumSearchEntryController(OptionsController):
self._typing = True self._typing = True
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
self._search_typing) self._search_typing)
class AlbumQuickSearchController(object): class AlbumQuickSearchController(object):
def __init__(self, album_manager): def __init__(self, album_manager):
self._album_manager = album_manager self._album_manager = album_manager
@@ -799,7 +795,7 @@ class AlbumQuickSearchController(object):
def _on_quick_search(self, quick_search, search_text, *args): def _on_quick_search(self, quick_search, search_text, *args):
album = self._album_manager.model.find_first_visible('album_name', album = self._album_manager.model.find_first_visible('album_name',
search_text) search_text)
if album: if album:
path = self._album_manager.model.get_path(album) path = self._album_manager.model.get_path(album)
@@ -824,24 +820,25 @@ class AlbumQuickSearchController(object):
def _on_hide(self, quick_search, *args): def _on_hide(self, quick_search, *args):
self._album_manager.current_view.grab_focus() self._album_manager.current_view.grab_focus()
class ViewController(OptionsController):
class ViewController(OptionsController):
def __init__(self, shell, viewmgr): def __init__(self, shell, viewmgr):
super(ViewController, self).__init__() super(ViewController, self).__init__()
self._viewmgr = viewmgr self._viewmgr = viewmgr
from coverart_browser_source import Views from coverart_browser_source import Views
views = Views(shell) views = Views(shell)
self.values = OrderedDict() self.values = OrderedDict()
for view_name in views.get_view_names(): for view_name in views.get_view_names():
self.values[views.get_menu_name(view_name)] = view_name self.values[views.get_menu_name(view_name)] = view_name
print (view_name) print(view_name)
self.options = list(self.values.keys()) self.options = list(self.values.keys())
viewmgr.connect('new-view', self.on_notify_view_name) viewmgr.connect('new-view', self.on_notify_view_name)
def on_notify_view_name(self, *args): def on_notify_view_name(self, *args):
for key in self.options: for key in self.options:
if self.values[key] == self._viewmgr.view_name: if self.values[key] == self._viewmgr.view_name:
+64 -61
Ver Arquivo
@@ -34,6 +34,7 @@ from os.path import expanduser
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
from collections import namedtuple from collections import namedtuple
class FlowShowingPolicy(GObject.Object): class FlowShowingPolicy(GObject.Object):
''' '''
Policy that mostly takes care of how and when things should be showed on Policy that mostly takes care of how and when things should be showed on
@@ -55,6 +56,7 @@ class FlowShowingPolicy(GObject.Object):
self._album_manager = album_manager self._album_manager = album_manager
self._model = album_manager.model self._model = album_manager.model
class CoverFlowView(AbstractView): class CoverFlowView(AbstractView):
__gtype_name__ = "CoverFlowView" __gtype_name__ = "CoverFlowView"
@@ -69,59 +71,60 @@ class CoverFlowView(AbstractView):
flow_appearance = GObject.property(type=str, default='coverflow') flow_appearance = GObject.property(type=str, default='coverflow')
flow_max = GObject.property(type=int, default=100) flow_max = GObject.property(type=int, default=100)
panedposition = PanedCollapsible.Paned.EXPAND panedposition = PanedCollapsible.Paned.EXPAND
def __init__(self): def __init__(self):
super(CoverFlowView, self).__init__() super(CoverFlowView, self).__init__()
self.show_policy = FlowShowingPolicy(self) self.show_policy = FlowShowingPolicy(self)
if webkit_support(): if webkit_support():
from gi.repository import WebKit from gi.repository import WebKit
self.view = WebKit.WebView() self.view = WebKit.WebView()
else: else:
self.view = None self.view = None
self._last_album = None self._last_album = None
self._has_initialised = False self._has_initialised = False
self._filter_changed_inprogress = False self._filter_changed_inprogress = False
self._on_first_use = True self._on_first_use = True
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
settings = gs.get_setting(gs.Path.PLUGIN) settings = gs.get_setting(gs.Path.PLUGIN)
settings.bind(gs.PluginKey.FLOW_APPEARANCE, self, settings.bind(gs.PluginKey.FLOW_APPEARANCE, self,
'flow_appearance', Gio.SettingsBindFlags.GET) 'flow_appearance', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self, settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self,
'flow_hide', Gio.SettingsBindFlags.GET) 'flow_hide', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_SCALE, self, settings.bind(gs.PluginKey.FLOW_SCALE, self,
'flow_scale', Gio.SettingsBindFlags.GET) 'flow_scale', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self, settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self,
'flow_automatic', Gio.SettingsBindFlags.GET) 'flow_automatic', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_BACKGROUND_COLOUR, self, settings.bind(gs.PluginKey.FLOW_BACKGROUND_COLOUR, self,
'flow_background', Gio.SettingsBindFlags.GET) 'flow_background', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_WIDTH, self, settings.bind(gs.PluginKey.FLOW_WIDTH, self,
'flow_width', Gio.SettingsBindFlags.GET) 'flow_width', Gio.SettingsBindFlags.GET)
settings.bind(gs.PluginKey.FLOW_MAX, self, settings.bind(gs.PluginKey.FLOW_MAX, self,
'flow_max', Gio.SettingsBindFlags.GET) 'flow_max', Gio.SettingsBindFlags.GET)
def _connect_signals(self, source): def _connect_signals(self, source):
self.connect('notify::flow-background', self.connect('notify::flow-background',
self.filter_changed) self.filter_changed)
self.connect('notify::flow-scale', self.connect('notify::flow-scale',
self.filter_changed) self.filter_changed)
self.connect('notify::flow-hide', self.connect('notify::flow-hide',
self.filter_changed) self.filter_changed)
self.connect('notify::flow-width', self.connect('notify::flow-width',
self.filter_changed) self.filter_changed)
self.connect('notify::flow-appearance', self.connect('notify::flow-appearance',
self.filter_changed) self.filter_changed)
self.connect('notify::flow-max', self.connect('notify::flow-max',
self.filter_changed) self.filter_changed)
def filter_changed(self, *args): def filter_changed(self, *args):
# we can get several filter_changed calls per second # we can get several filter_changed calls per second
# lets simplify the processing & potential flickering when the # lets simplify the processing & potential flickering when the
# call to this method has slowed stopped # call to this method has slowed stopped
self._filter_changed_event = True self._filter_changed_event = True
if self._filter_changed_inprogress: if self._filter_changed_inprogress:
@@ -136,16 +139,16 @@ class CoverFlowView(AbstractView):
else: else:
self._filter_changed_event = False self._filter_changed_event = False
return True return True
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, filter_events, None) Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, filter_events, None)
def _filter_changed(self, *args): def _filter_changed(self, *args):
path = rb.find_plugin_file(self.plugin, 'coverflow/index.html') path = rb.find_plugin_file(self.plugin, 'coverflow/index.html')
f = open(path) f = open(path)
string = f.read() string = f.read()
f.close() f.close()
if self.flow_background == 'W': if self.flow_background == 'W':
background_colour = 'white' background_colour = 'white'
if len(self.album_manager.model.store) <= self.flow_max: if len(self.album_manager.model.store) <= self.flow_max:
@@ -161,13 +164,13 @@ class CoverFlowView(AbstractView):
string = string.replace('#BACKGROUND_COLOUR', background_colour) string = string.replace('#BACKGROUND_COLOUR', background_colour)
string = string.replace('#FOREGROUND_COLOUR', foreground_colour) string = string.replace('#FOREGROUND_COLOUR', foreground_colour)
string = string.replace('#FACTOR', str(float(self.flow_scale)/100)) string = string.replace('#FACTOR', str(float(self.flow_scale) / 100))
if self.flow_hide: if self.flow_hide:
caption = "" caption = ""
else: else:
caption = '<div class="globalCaption"></div>' caption = '<div class="globalCaption"></div>'
string = string.replace('#GLOBAL_CAPTION', caption) string = string.replace('#GLOBAL_CAPTION', caption)
addon = background_colour addon = background_colour
@@ -187,46 +190,46 @@ class CoverFlowView(AbstractView):
identifier = "'start'" identifier = "'start'"
else: else:
identifier = str(identifier) identifier = str(identifier)
string = string.replace('#START', identifier) string = string.replace('#START', identifier)
#TRANSLATORS: for example 'Number of covers limited to 150' #TRANSLATORS: for example 'Number of covers limited to 150'
display_message = _("Number of covers limited to %d") % self.flow_max display_message = _("Number of covers limited to %d") % self.flow_max
string = string.replace('#MAXCOVERS', string = string.replace('#MAXCOVERS',
'<p>' + display_message + '</p>') '<p>' + display_message + '</p>')
items = self.flow.initialise(self.album_manager.model, self.flow_max) items = self.flow.initialise(self.album_manager.model, self.flow_max)
string = string.replace('#ITEMS', items) string = string.replace('#ITEMS', items)
base = os.path.dirname(path) + "/" base = os.path.dirname(path) + "/"
Gdk.threads_enter() Gdk.threads_enter()
print (string) print(string)
self.view.load_string(string, "text/html", "UTF-8", "file://" + base) self.view.load_string(string, "text/html", "UTF-8", "file://" + base)
Gdk.threads_leave() Gdk.threads_leave()
if self._on_first_use: if self._on_first_use:
self._on_first_use = False self._on_first_use = False
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
self.source.show_hide_pane, (self.last_album, PanedCollapsible.Paned.EXPAND)) self.source.show_hide_pane, (self.last_album, PanedCollapsible.Paned.EXPAND))
def get_view_icon_name(self): def get_view_icon_name(self):
return "flowview.png" return "flowview.png"
def initialise(self, source): def initialise(self, source):
if self._has_initialised: if self._has_initialised:
return return
self._has_initialised = True self._has_initialised = True
super(CoverFlowView,self).initialise(source) super(CoverFlowView, self).initialise(source)
self.album_manager = source.album_manager self.album_manager = source.album_manager
self.ext_menu_pos = 6 self.ext_menu_pos = 6
self._connect_properties() self._connect_properties()
self._connect_signals(source) self._connect_signals(source)
# lets check that all covers have finished loading before # lets check that all covers have finished loading before
# initialising the flowcontrol and other signals # initialising the flowcontrol and other signals
if not self.album_manager.cover_man.has_finished_loading: if not self.album_manager.cover_man.has_finished_loading:
@@ -243,7 +246,7 @@ class CoverFlowView(AbstractView):
self.album_manager.model.connect('album-updated', self.filter_changed) self.album_manager.model.connect('album-updated', self.filter_changed)
self.album_manager.model.connect('visual-updated', self.filter_changed) self.album_manager.model.connect('visual-updated', self.filter_changed)
self.album_manager.model.connect('filter-changed', self.filter_changed) self.album_manager.model.connect('filter-changed', self.filter_changed)
self.filter_changed() self.filter_changed()
@property @property
@@ -270,12 +273,12 @@ class CoverFlowView(AbstractView):
# to expand the entry view # to expand the entry view
if self.flow_automatic: if self.flow_automatic:
self.source.click_count += 1 self.source.click_count += 1
self.last_album = album self.last_album = album
if self.source.click_count == 1: if self.source.click_count == 1:
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
self.source.show_hide_pane, album) self.source.show_hide_pane, album)
def item_activated_callback(self, album): def item_activated_callback(self, album):
''' '''
@@ -291,8 +294,8 @@ class CoverFlowView(AbstractView):
Callback called when something is dropped onto the flow view - hopefully a webpath Callback called when something is dropped onto the flow view - hopefully a webpath
to a picture to a picture
''' '''
print ("item_drop_callback %s" % webpath) print("item_drop_callback %s" % webpath)
print ("dropped on album %s" % album) print("dropped on album %s" % album)
self.album_manager.cover_man.update_cover(album, uri=webpath) self.album_manager.cover_man.update_cover(album, uri=webpath)
def get_selected_objects(self): def get_selected_objects(self):
@@ -309,22 +312,22 @@ class CoverFlowView(AbstractView):
def switch_to_view(self, source, album): def switch_to_view(self, source, album):
self.initialise(source) self.initialise(source)
self.show_policy.initialise(source.album_manager) self.show_policy.initialise(source.album_manager)
self.last_album = album self.last_album = album
self.scroll_to_album(self.last_album) self.scroll_to_album(self.last_album)
def grab_focus(self): def grab_focus(self):
self.view.grab_focus() self.view.grab_focus()
def scroll_to_album(self, album): def scroll_to_album(self, album):
self.flow.scroll_to_album(album, self.view) self.flow.scroll_to_album(album, self.view)
class FlowControl(object): class FlowControl(object):
def __init__(self, callback_view): def __init__(self, callback_view):
self.callback_view = callback_view self.callback_view = callback_view
self.album_identifier = {} self.album_identifier = {}
def get_identifier(self, album): def get_identifier(self, album):
index = -1 index = -1
for row in self.album_identifier: for row in self.album_identifier:
@@ -355,11 +358,11 @@ class FlowControl(object):
obj['identifier'] = str(index) obj['identifier'] = str(index)
webview.execute_script("update_album('%s')" % json.dumps(obj)) webview.execute_script("update_album('%s')" % json.dumps(obj))
def receive_message_signal(self, webview, param): def receive_message_signal(self, webview, param):
# this will be key to passing stuff back and forth - need # this will be key to passing stuff back and forth - need
# to develop some-sort of message protocol to distinguish "events" # to develop some-sort of message protocol to distinguish "events"
title = webview.get_title() title = webview.get_title()
if (not title) or (title == '"clear"'): if (not title) or (title == '"clear"'):
return return
@@ -368,7 +371,7 @@ class FlowControl(object):
try: try:
signal = args["signal"] signal = args["signal"]
except: except:
print ("unhandled: %s " % title) print("unhandled: %s " % title)
return return
if signal == 'clickactive': if signal == 'clickactive':
@@ -380,9 +383,9 @@ class FlowControl(object):
self.callback_view.item_activated_callback(self.album_identifier[int(args['param'][0])]) self.callback_view.item_activated_callback(self.album_identifier[int(args['param'][0])])
elif signal == 'dropactive': elif signal == 'dropactive':
self.callback_view.item_drop_callback(self.album_identifier[int(args['param'][0])], self.callback_view.item_drop_callback(self.album_identifier[int(args['param'][0])],
args['param'][1]) args['param'][1])
else: else:
print ("unhandled signal: %s" % signal) print("unhandled signal: %s" % signal)
def scroll_to_album(self, album, webview): def scroll_to_album(self, album, webview):
for row in self.album_identifier: for row in self.album_identifier:
@@ -396,14 +399,14 @@ class FlowControl(object):
index = 0 index = 0
items = "" items = ""
self.album_identifier = {} self.album_identifier = {}
def html_elements(fullfilename, title, caption, identifier): def html_elements(fullfilename, title, caption, identifier):
return '<div class="item"><img class="content" src="' +\ return '<div class="item"><img class="content" src="' + \
escape(fullfilename) + '" title="' +\ escape(fullfilename) + '" title="' + \
escape(title) + '" identifier="' +\ escape(title) + '" identifier="' + \
identifier + '"/> <div class="caption">' +\ identifier + '"/> <div class="caption">' + \
escape(caption) + '</div> </div>' escape(caption) + '</div> </div>'
for row in model.store: for row in model.store:
@@ -415,7 +418,7 @@ class FlowControl(object):
self.album_identifier[index] = row[album_col] self.album_identifier[index] = row[album_col]
items += html_elements( items += html_elements(
fullfilename = cover, fullfilename=cover,
caption=row[album_col].name, caption=row[album_col].name,
title=row[album_col].artist, title=row[album_col].artist,
identifier=str(index)) identifier=str(index))
+142 -140
Ver Arquivo
@@ -32,132 +32,134 @@ from coverart_browser_prefs import GSetting
from coverart_album import AlbumsModel from coverart_album import AlbumsModel
from coverart_widgets import AbstractView from coverart_widgets import AbstractView
from coverart_widgets import PanedCollapsible from coverart_widgets import PanedCollapsible
import coverart_rb3compat as rb3compat import coverart_rb3compat as rb3compat
import rb import rb
PLAY_SIZE_X = 30 PLAY_SIZE_X = 30
PLAY_SIZE_Y = 30 PLAY_SIZE_Y = 30
class CellRendererThumb(Gtk.CellRendererPixbuf): class CellRendererThumb(Gtk.CellRendererPixbuf):
markup=GObject.property(type=str, default="") markup = GObject.property(type=str, default="")
def __init__(self, font_description, cell_area_source): def __init__(self, font_description, cell_area_source):
super(CellRendererThumb, self).__init__() super(CellRendererThumb, self).__init__()
self.font_description = font_description self.font_description = font_description
self.cell_area_source = cell_area_source self.cell_area_source = cell_area_source
ypad = 0 ypad = 0
def do_render(self, cr, widget, def do_render(self, cr, widget,
background_area, background_area,
cell_area, cell_area,
flags): flags):
x_offset = cell_area.x + 1 x_offset = cell_area.x + 1
y_offset = cell_area.y + 1 y_offset = cell_area.y + 1
wi = 0 wi = 0
he = 0 he = 0
#IMAGE #IMAGE
pixbuf = self.props.pixbuf.scale_simple(cell_area.width-2, cell_area.height-2, pixbuf = self.props.pixbuf.scale_simple(cell_area.width - 2, cell_area.height - 2,
GdkPixbuf.InterpType.NEAREST) GdkPixbuf.InterpType.NEAREST)
Gdk.cairo_set_source_pixbuf(cr, pixbuf, x_offset, y_offset) Gdk.cairo_set_source_pixbuf(cr, pixbuf, x_offset, y_offset)
cr.paint() cr.paint()
alpha = 0.40 alpha = 0.40
if((flags & Gtk.CellRendererState.PRELIT) == Gtk.CellRendererState.PRELIT): if ((flags & Gtk.CellRendererState.PRELIT) == Gtk.CellRendererState.PRELIT):
alpha -= 0.15 alpha -= 0.15
if hasattr(Gtk.IconView, "get_cell_rect") and self.cell_area_source.hover_pixbuf: if hasattr(Gtk.IconView, "get_cell_rect") and self.cell_area_source.hover_pixbuf:
# this only works on Gtk+3.6 and later # this only works on Gtk+3.6 and later
Gdk.cairo_set_source_pixbuf(cr, Gdk.cairo_set_source_pixbuf(cr,
self.cell_area_source.hover_pixbuf, x_offset, y_offset) self.cell_area_source.hover_pixbuf, x_offset, y_offset)
cr.paint() cr.paint()
#if((flags & Gtk.CellRendererState.SELECTED) == Gtk.CellRendererState.SELECTED or \ #if((flags & Gtk.CellRendererState.SELECTED) == Gtk.CellRendererState.SELECTED or \
# (flags & Gtk.CellRendererState.FOCUSED) == Gtk.CellRendererState.FOCUSED): # (flags & Gtk.CellRendererState.FOCUSED) == Gtk.CellRendererState.FOCUSED):
# alpha -= 0.15 # alpha -= 0.15
if not(self.cell_area_source.display_text and self.cell_area_source.display_text_pos==False): if not (self.cell_area_source.display_text and self.cell_area_source.display_text_pos == False):
return return
#PANGO LAYOUT #PANGO LAYOUT
layout_width = cell_area.width - 2 layout_width = cell_area.width - 2
pango_layout = PangoCairo.create_layout(cr) pango_layout = PangoCairo.create_layout(cr)
pango_layout.set_markup(self.markup , -1) pango_layout.set_markup(self.markup, -1)
pango_layout.set_alignment(Pango.Alignment.CENTER) pango_layout.set_alignment(Pango.Alignment.CENTER)
pango_layout.set_font_description(self.font_description) pango_layout.set_font_description(self.font_description)
pango_layout.set_width( int(layout_width * Pango.SCALE)) pango_layout.set_width(int(layout_width * Pango.SCALE))
pango_layout.set_wrap(Pango.WrapMode.WORD_CHAR) pango_layout.set_wrap(Pango.WrapMode.WORD_CHAR)
wi,he = pango_layout.get_pixel_size() wi, he = pango_layout.get_pixel_size()
rect_offset = y_offset + (int((2.0 * self.cell_area_source.cover_size) / 3.0)) rect_offset = y_offset + (int((2.0 * self.cell_area_source.cover_size) / 3.0))
rect_height = int(self.cell_area_source.cover_size / 3.0) rect_height = int(self.cell_area_source.cover_size / 3.0)
was_to_large = False; was_to_large = False;
if(he > rect_height): if (he > rect_height):
was_to_large = True was_to_large = True
pango_layout.set_ellipsize(Pango.EllipsizeMode.END) pango_layout.set_ellipsize(Pango.EllipsizeMode.END)
pango_layout.set_height( int((self.cell_area_source.cover_size / 3.0) * Pango.SCALE)) pango_layout.set_height(int((self.cell_area_source.cover_size / 3.0) * Pango.SCALE))
wi, he = pango_layout.get_pixel_size() wi, he = pango_layout.get_pixel_size()
#RECTANGLE #RECTANGLE
cr.set_source_rgba(0.0, 0.0, 0.0, alpha) cr.set_source_rgba(0.0, 0.0, 0.0, alpha)
cr.set_line_width(0) cr.set_line_width(0)
cr.rectangle(x_offset, cr.rectangle(x_offset,
rect_offset, rect_offset,
cell_area.width - 1, cell_area.width - 1,
rect_height - 1) rect_height - 1)
cr.fill() cr.fill()
#DRAW FONT #DRAW FONT
cr.set_source_rgba(1.0, 1.0, 1.0, 1.0) cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
cr.move_to(x_offset, cr.move_to(x_offset,
y_offset y_offset
+ 2.0 * self.cell_area_source.cover_size / 3.0 + 2.0 * self.cell_area_source.cover_size / 3.0
+ (((self.cell_area_source.cover_size/3.0) - he) / 2.0) + (((self.cell_area_source.cover_size / 3.0) - he) / 2.0)
) )
PangoCairo.show_layout(cr, pango_layout) PangoCairo.show_layout(cr, pango_layout)
class AlbumArtCellArea(Gtk.CellAreaBox): class AlbumArtCellArea(Gtk.CellAreaBox):
font_family = GObject.property(type=str, default="Sans") font_family = GObject.property(type=str, default="Sans")
font_size = GObject.property(type=int, default=10) font_size = GObject.property(type=int, default=10)
cover_size = GObject.property(type=int, default=0) cover_size = GObject.property(type=int, default=0)
display_text_pos = GObject.property(type=bool, default=False) display_text_pos = GObject.property(type=bool, default=False)
display_text = GObject.property(type=bool, default=False) display_text = GObject.property(type=bool, default=False)
hover_pixbuf = GObject.property(type=object, default=None) hover_pixbuf = GObject.property(type=object, default=None)
def __init__(self, ): def __init__(self, ):
super(AlbumArtCellArea, self).__init__() super(AlbumArtCellArea, self).__init__()
self.font_description = Pango.FontDescription.new() self.font_description = Pango.FontDescription.new()
self.font_description.set_family(self.font_family) self.font_description.set_family(self.font_family)
self.font_description.set_size(int(self.font_size * Pango.SCALE)) self.font_description.set_size(int(self.font_size * Pango.SCALE))
self._connect_properties() self._connect_properties()
#Add own cellrenderer #Add own cellrenderer
renderer_thumb = CellRendererThumb(self.font_description, self) renderer_thumb = CellRendererThumb(self.font_description, self)
self.pack_start(renderer_thumb, False, False, False) self.pack_start(renderer_thumb, False, False, False)
self.attribute_connect(renderer_thumb, "pixbuf", AlbumsModel.columns['pixbuf']) self.attribute_connect(renderer_thumb, "pixbuf", AlbumsModel.columns['pixbuf'])
self.attribute_connect(renderer_thumb, "markup", AlbumsModel.columns['markup']) self.attribute_connect(renderer_thumb, "markup", AlbumsModel.columns['markup'])
self.props.spacing = 2 self.props.spacing = 2
def _connect_properties(self): def _connect_properties(self):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size', setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos', setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text', setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
class AlbumShowingPolicy(GObject.Object): class AlbumShowingPolicy(GObject.Object):
''' '''
Policy that mostly takes care of how and when things should be showed on Policy that mostly takes care of how and when things should be showed on
@@ -182,7 +184,7 @@ class AlbumShowingPolicy(GObject.Object):
def _connect_signals(self): def _connect_signals(self):
self._cover_view.props.vadjustment.connect('value-changed', self._cover_view.props.vadjustment.connect('value-changed',
self._viewport_changed) self._viewport_changed)
self._model.connect('album-updated', self._album_updated) self._model.connect('album-updated', self._album_updated)
self._model.connect('visual-updated', self._album_updated) self._model.connect('visual-updated', self._album_updated)
@@ -215,6 +217,7 @@ class AlbumShowingPolicy(GObject.Object):
# if our path is on the viewport, emit the signal to update it # if our path is on the viewport, emit the signal to update it
self._cover_view.queue_draw() self._cover_view.queue_draw()
class CoverIconView(EnhancedIconView, AbstractView): class CoverIconView(EnhancedIconView, AbstractView):
__gtype_name__ = "CoverIconView" __gtype_name__ = "CoverIconView"
@@ -226,11 +229,11 @@ class CoverIconView(EnhancedIconView, AbstractView):
display_text_pos = GObject.property(type=bool, default=False) display_text_pos = GObject.property(type=bool, default=False)
name = 'coverview' name = 'coverview'
panedposition = PanedCollapsible.Paned.COLLAPSE panedposition = PanedCollapsible.Paned.COLLAPSE
__gsignals__ = { __gsignals__ = {
'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ()) 'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
if not rb3compat.compare_pygobject_version("3.9"): if not rb3compat.compare_pygobject_version("3.9"):
@@ -238,8 +241,8 @@ class CoverIconView(EnhancedIconView, AbstractView):
else: else:
# this works in trusty but not in earlier versions - define in the super above # this works in trusty but not in earlier versions - define in the super above
super(CoverIconView, self).__init__(*args, **kwargs) super(CoverIconView, self).__init__(*args, **kwargs)
self.props.cell_area = AlbumArtCellArea() self.props.cell_area = AlbumArtCellArea()
self.gs = GSetting() self.gs = GSetting()
# custom text renderer # custom text renderer
self._text_renderer = None self._text_renderer = None
@@ -249,19 +252,19 @@ class CoverIconView(EnhancedIconView, AbstractView):
self._last_play_path = None self._last_play_path = None
self._recheck_in_progress = False self._recheck_in_progress = False
self._current_hover_path = None self._current_hover_path = None
def initialise(self, source): def initialise(self, source):
if self._has_initialised: if self._has_initialised:
return return
self._has_initialised = True self._has_initialised = True
self.view_name = "covers_view" self.view_name = "covers_view"
super(CoverIconView,self).initialise(source) super(CoverIconView, self).initialise(source)
self.shell = source.shell self.shell = source.shell
self.album_manager = source.album_manager self.album_manager = source.album_manager
# setup iconview drag&drop support # setup iconview drag&drop support
# first drag and drop on the coverart view to receive coverart # first drag and drop on the coverart view to receive coverart
self.enable_model_drag_dest([], Gdk.DragAction.COPY) self.enable_model_drag_dest([], Gdk.DragAction.COPY)
@@ -269,7 +272,7 @@ class CoverIconView(EnhancedIconView, AbstractView):
self.drag_dest_add_text_targets() self.drag_dest_add_text_targets()
self.connect('drag-drop', self.on_drag_drop) self.connect('drag-drop', self.on_drag_drop)
self.connect('drag-data-received', self.connect('drag-data-received',
self.on_drag_data_received) self.on_drag_data_received)
self.source.paned.connect("expanded", self.bottom_expander_expanded_callback) self.source.paned.connect("expanded", self.bottom_expander_expanded_callback)
# lastly support drag-drop from coverart to devices/nautilus etc # lastly support drag-drop from coverart to devices/nautilus etc
@@ -278,34 +281,34 @@ class CoverIconView(EnhancedIconView, AbstractView):
[], Gdk.DragAction.COPY) [], Gdk.DragAction.COPY)
#targets = Gtk.TargetList.new([Gtk.TargetEntry.new("application/x-rhythmbox-entry", 0, 0), #targets = Gtk.TargetList.new([Gtk.TargetEntry.new("application/x-rhythmbox-entry", 0, 0),
# Gtk.TargetEntry.new("text/uri-list", 0, 1) ]) # Gtk.TargetEntry.new("text/uri-list", 0, 1) ])
targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0) ]) targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0)])
# N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c # N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c
targets.add_uri_targets(1) targets.add_uri_targets(1)
self.drag_source_set_target_list(targets) self.drag_source_set_target_list(targets)
self.connect("drag-data-get", self.on_drag_data_get) self.connect("drag-data-get", self.on_drag_data_get)
# set the model to the view # set the model to the view
#self.set_pixbuf_column(AlbumsModel.columns['pixbuf']) #self.set_pixbuf_column(AlbumsModel.columns['pixbuf'])
self.set_model(self.album_manager.model.store) self.set_model(self.album_manager.model.store)
# setup view to monitor mouse movements # setup view to monitor mouse movements
self.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
self.hover_pixbufs = { self.hover_pixbufs = {
'button_play':None, 'button_play': None,
'button_play_hover':None, 'button_play_hover': None,
'button_playpause':None, 'button_playpause': None,
'button_playpause_hover':None, 'button_playpause_hover': None,
'button_queue':None, 'button_queue': None,
'button_queue_hover':None } 'button_queue_hover': None}
for pixbuf_type in self.hover_pixbufs: for pixbuf_type in self.hover_pixbufs:
filename = 'img/' + pixbuf_type + '.png' filename = 'img/' + pixbuf_type + '.png'
filename = rb.find_plugin_file(self.plugin, filename) filename = rb.find_plugin_file(self.plugin, filename)
self.hover_pixbufs[pixbuf_type] = GdkPixbuf.Pixbuf.new_from_file_at_size(filename, self.hover_pixbufs[pixbuf_type] = GdkPixbuf.Pixbuf.new_from_file_at_size(filename,
PLAY_SIZE_X, PLAY_SIZE_Y) PLAY_SIZE_X, PLAY_SIZE_Y)
self._connect_properties() self._connect_properties()
self._connect_signals() self._connect_signals()
@@ -327,32 +330,32 @@ class CoverIconView(EnhancedIconView, AbstractView):
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.DISPLAY_TEXT, self, setting.bind(self.gs.PluginKey.DISPLAY_TEXT, self,
'display_text_enabled', Gio.SettingsBindFlags.GET) 'display_text_enabled', Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self, setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self,
'icon_automatic', Gio.SettingsBindFlags.GET) 'icon_automatic', Gio.SettingsBindFlags.GET)
setting.bind(self.gs.PluginKey.DISPLAY_TEXT_POS, self, setting.bind(self.gs.PluginKey.DISPLAY_TEXT_POS, self,
'display-text-pos', Gio.SettingsBindFlags.GET) 'display-text-pos', Gio.SettingsBindFlags.GET)
def _connect_signals(self): def _connect_signals(self):
self.connect("item-clicked", self.item_clicked_callback) self.connect("item-clicked", self.item_clicked_callback)
self.connect("selection-changed", self.selectionchanged_callback) self.connect("selection-changed", self.selectionchanged_callback)
self.connect("item-activated", self.item_activated_callback) self.connect("item-activated", self.item_activated_callback)
self.connect('notify::icon-spacing', self.connect('notify::icon-spacing',
self.on_notify_icon_spacing) self.on_notify_icon_spacing)
self.connect('notify::icon-padding', self.connect('notify::icon-padding',
self.on_notify_icon_padding) self.on_notify_icon_padding)
self.connect('notify::display-text-enabled', self.connect('notify::display-text-enabled',
self._activate_markup) self._activate_markup)
self.connect('notify::display-text-pos', self.connect('notify::display-text-pos',
self._activate_markup) self._activate_markup)
self.connect("motion-notify-event", self.on_pointer_motion) self.connect("motion-notify-event", self.on_pointer_motion)
def get_view_icon_name(self): def get_view_icon_name(self):
return "iconview.png" return "iconview.png"
def resize_icon(self, cover_size): def resize_icon(self, cover_size):
''' '''
Callback called when to resize the icon Callback called when to resize the icon
[common to all views] [common to all views]
@@ -383,7 +386,7 @@ class CoverIconView(EnhancedIconView, AbstractView):
return result return result
def on_drag_data_received(self, widget, drag_context, x, y, data, info, def on_drag_data_received(self, widget, drag_context, x, y, data, info,
time): time):
''' '''
Callback called when the drag source has prepared the data (pixbuf) Callback called when the drag source has prepared the data (pixbuf)
for us to use. for us to use.
@@ -446,62 +449,61 @@ class CoverIconView(EnhancedIconView, AbstractView):
widget.stop_emission_by_name('drag-begin') widget.stop_emission_by_name('drag-begin')
else: else:
widget.stop_emission('drag-begin') widget.stop_emission('drag-begin')
def _cover_play_hotspot(self, path, in_vacinity=False): def _cover_play_hotspot(self, path, in_vacinity=False):
if path and hasattr(self, "get_cell_rect"): if path and hasattr(self, "get_cell_rect"):
# get_cell_rect only exists in Gtk+3.6 and later # get_cell_rect only exists in Gtk+3.6 and later
valid, rect = self.get_cell_rect(path, None) # rect of widget coords valid, rect = self.get_cell_rect(path, None) # rect of widget coords
cursor_x, cursor_y = self.get_pointer() # returns widget coords cursor_x, cursor_y = self.get_pointer() # returns widget coords
c_x = cursor_x - rect.x c_x = cursor_x - rect.x
c_y = cursor_y - rect.y c_y = cursor_y - rect.y
sizing = (rect.width / 2) if in_vacinity else 0
if c_x < (PLAY_SIZE_X + sizing) and \
c_y < (PLAY_SIZE_Y + sizing) and \
c_x > (self.icon_padding + self.icon_spacing) and \
c_y > (self.icon_padding + self.icon_spacing):
sizing = (rect.width / 2) if in_vacinity else 0
if c_x < (PLAY_SIZE_X + sizing) and \
c_y < (PLAY_SIZE_Y + sizing) and \
c_x > (self.icon_padding + self.icon_spacing) and \
c_y > (self.icon_padding + self.icon_spacing):
return True return True
return False return False
def on_pointer_motion(self, widget, event): def on_pointer_motion(self, widget, event):
self._calculate_hotspot(event) self._calculate_hotspot(event)
def _calculate_hotspot(self, event): def _calculate_hotspot(self, event):
path = self.get_path_at_pos(event.x, event.y) path = self.get_path_at_pos(event.x, event.y)
(_, playing) = self.shell.props.shell_player.get_playing() (_, playing) = self.shell.props.shell_player.get_playing()
if playing and not self._last_play_path: if playing and not self._last_play_path:
entry = self.shell.props.shell_player.get_playing_entry() entry = self.shell.props.shell_player.get_playing_entry()
album = self.album_manager.model.get_from_dbentry(entry) album = self.album_manager.model.get_from_dbentry(entry)
self._last_play_path = self.album_manager.model.get_path(album) self._last_play_path = self.album_manager.model.get_path(album)
if playing and self._last_play_path == path: if playing and self._last_play_path == path:
icon = 'button_playpause' icon = 'button_playpause'
elif playing: elif playing:
icon = 'button_queue' icon = 'button_queue'
else: else:
icon = 'button_play' icon = 'button_play'
def recheck_hotspot(args): def recheck_hotspot(args):
path = args[0] path = args[0]
in_vacinity = args[1] in_vacinity = args[1]
if self._cover_play_hotspot(path, in_vacinity): if self._cover_play_hotspot(path, in_vacinity):
current_path = self.get_path_at_pos(event.x, event.y) current_path = self.get_path_at_pos(event.x, event.y)
if current_path == path: if current_path == path:
self._current_hover_path = path self._current_hover_path = path
else: else:
self._current_hover_path = None self._current_hover_path = None
self._recheck_in_progress = False self._recheck_in_progress = False
self._calculate_hotspot(event) self._calculate_hotspot(event)
self.queue_draw() self.queue_draw()
if self._cover_play_hotspot(path, in_vacinity=True): if self._cover_play_hotspot(path, in_vacinity=True):
exact_hotspot = self._cover_play_hotspot(path) exact_hotspot = self._cover_play_hotspot(path)
if path == self._current_hover_path: if path == self._current_hover_path:
@@ -512,39 +514,39 @@ class CoverIconView(EnhancedIconView, AbstractView):
if not self._recheck_in_progress: if not self._recheck_in_progress:
self._recheck_in_progress = True self._recheck_in_progress = True
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 150, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 150,
recheck_hotspot, (path, False)) recheck_hotspot, (path, False))
hover = None hover = None
else: else:
hover = None hover = None
if not self._recheck_in_progress: if not self._recheck_in_progress:
self._recheck_in_progress = True self._recheck_in_progress = True
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 450, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 450,
recheck_hotspot, (path, True)) recheck_hotspot, (path, True))
else: else:
hover = None hover = None
self.props.cell_area.hover_pixbuf = hover self.props.cell_area.hover_pixbuf = hover
if hover and path: if hover and path:
valid, rect = self.get_cell_rect(path, None) valid, rect = self.get_cell_rect(path, None)
self.props.window.invalidate_rect(rect, True) self.props.window.invalidate_rect(rect, True)
self.queue_draw() self.queue_draw()
def item_clicked_callback(self, iconview, event, path): def item_clicked_callback(self, iconview, event, path):
''' '''
Callback called when the user clicks somewhere on the cover_view. Callback called when the user clicks somewhere on the cover_view.
Along with source "show_hide_pane", takes care of showing/hiding the bottom Along with source "show_hide_pane", takes care of showing/hiding the bottom
pane after a second click on a selected album. pane after a second click on a selected album.
''' '''
# first test if we've clicked on the cover-play icon # first test if we've clicked on the cover-play icon
if self._cover_play_hotspot(path): if self._cover_play_hotspot(path):
(_, playing) = self.shell.props.shell_player.get_playing() (_, playing) = self.shell.props.shell_player.get_playing()
# first see if anything is playing... # first see if anything is playing...
if playing: if playing:
entry = self.shell.props.shell_player.get_playing_entry() entry = self.shell.props.shell_player.get_playing_entry()
album = self.album_manager.model.get_from_dbentry(entry) album = self.album_manager.model.get_from_dbentry(entry)
# if the current playing entry corresponds to the album # if the current playing entry corresponds to the album
# we are hovering over then we are requesting to pause # we are hovering over then we are requesting to pause
if self.album_manager.model.get_from_path(path) == album: if self.album_manager.model.get_from_path(path) == album:
@@ -552,33 +554,33 @@ class CoverIconView(EnhancedIconView, AbstractView):
self.shell.props.shell_player.pause() self.shell.props.shell_player.pause()
self.on_pointer_motion(self, event) self.on_pointer_motion(self, event)
return return
# if we are not playing and the last thing played is what # if we are not playing and the last thing played is what
# we are still hovering over then we must be requesting to play # we are still hovering over then we must be requesting to play
if self._last_play_path and self._last_play_path == path: if self._last_play_path and self._last_play_path == path:
self.shell.props.shell_player.play() self.shell.props.shell_player.play()
self.on_pointer_motion(self, event) self.on_pointer_motion(self, event)
return return
# otherwise, this must be a new album so we are asking just # otherwise, this must be a new album so we are asking just
# to play this new album ... just need a short interval # to play this new album ... just need a short interval
# for the selection event to kick in first # for the selection event to kick in first
def delay(*args): def delay(*args):
if playing: # if we are playing then queue up the next album if playing: # if we are playing then queue up the next album
self.source.queue_selected_album(None, self.source.favourites) self.source.queue_selected_album(None, self.source.favourites)
else: # otherwise just play it else: # otherwise just play it
self._last_play_path = path self._last_play_path = path
self.source.play_selected_album(self.source.favourites) self.source.play_selected_album(self.source.favourites)
self.props.cell_area.hover_pixbuf= \ self.props.cell_area.hover_pixbuf = \
self.hover_pixbufs['button_play_hover'] self.hover_pixbufs['button_play_hover']
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
delay, None) delay, None)
return return
# to expand the entry view # to expand the entry view
ctrl = event.state & Gdk.ModifierType.CONTROL_MASK ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
shift = event.state & Gdk.ModifierType.SHIFT_MASK shift = event.state & Gdk.ModifierType.SHIFT_MASK
@@ -587,10 +589,10 @@ class CoverIconView(EnhancedIconView, AbstractView):
self.source.click_count += 1 if not ctrl and not shift else 0 self.source.click_count += 1 if not ctrl and not shift else 0
if self.source.click_count == 1: if self.source.click_count == 1:
album = self.album_manager.model.get_from_path(path)\ album = self.album_manager.model.get_from_path(path) \
if path else None if path else None
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
self.source.show_hide_pane, album) self.source.show_hide_pane, album)
def item_activated_callback(self, iconview, path): def item_activated_callback(self, iconview, path):
''' '''
@@ -640,16 +642,16 @@ class CoverIconView(EnhancedIconView, AbstractView):
# set the renderer # set the renderer
self.pack_end(self._text_renderer, False) self.pack_end(self._text_renderer, False)
self.add_attribute(self._text_renderer, self.add_attribute(self._text_renderer,
'markup', AlbumsModel.columns['markup']) 'markup', AlbumsModel.columns['markup'])
elif self._text_renderer: elif self._text_renderer:
# remove the cell renderer # remove the cell renderer
self.props.cell_area.remove(self._text_renderer) self.props.cell_area.remove(self._text_renderer)
if self.display_text_enabled: if self.display_text_enabled:
self.set_tooltip_column(-1) # turnoff tooltips self.set_tooltip_column(-1) # turnoff tooltips
else: else:
self.set_tooltip_column(AlbumsModel.columns['tooltip']) self.set_tooltip_column(AlbumsModel.columns['tooltip'])
def bottom_expander_expanded_callback(self, paned, expand): def bottom_expander_expanded_callback(self, paned, expand):
''' '''
Callback connected to expanded signal of the paned GtkExpander Callback connected to expanded signal of the paned GtkExpander
@@ -663,17 +665,17 @@ class CoverIconView(EnhancedIconView, AbstractView):
self.source.last_selected_album) self.source.last_selected_album)
self.scroll_to_path(path, False, 0, 0) self.scroll_to_path(path, False, 0, 0)
return False return False
Gdk.threads_add_idle(GObject.PRIORITY_DEFAULT_IDLE, Gdk.threads_add_idle(GObject.PRIORITY_DEFAULT_IDLE,
scroll_to_album, None) scroll_to_album, None)
def switch_to_view(self, source, album): def switch_to_view(self, source, album):
self.initialise(source) self.initialise(source)
self.show_policy.initialise(source.album_manager) self.show_policy.initialise(source.album_manager)
self.scroll_to_album(album) self.scroll_to_album(album)
def grab_focus(self): def grab_focus(self):
+139 -135
Ver Arquivo
@@ -39,10 +39,12 @@ from coverart_widgets import PixbufButton
MIN_IMAGE_SIZE = 100 MIN_IMAGE_SIZE = 100
class EntryViewPane(object): class EntryViewPane(object):
''' '''
encapulates all of the Track Pane objects encapulates all of the Track Pane objects
''' '''
def __init__(self, shell, plugin, source, entry_view_grid, viewmgr): def __init__(self, shell, plugin, source, entry_view_grid, viewmgr):
self.gs = GSetting() self.gs = GSetting()
@@ -84,7 +86,7 @@ class EntryViewPane(object):
self.entry_view_grid.attach(self.stars, 1, 1, 1, 1) self.entry_view_grid.attach(self.stars, 1, 1, 1, 1)
stack_switcher = Gtk.StackSwitcher() stack_switcher = Gtk.StackSwitcher()
stack_switcher.set_stack(self.stack) stack_switcher.set_stack(self.stack)
self.entry_view_grid.attach( stack_switcher, 0, 1, 1, 1) self.entry_view_grid.attach(stack_switcher, 0, 1, 1, 1)
viewtoggle = PixbufButton() viewtoggle = PixbufButton()
viewtoggle.set_image(create_button_image(self.plugin, "entryview.png")) viewtoggle.set_image(create_button_image(self.plugin, "entryview.png"))
viewtoggle.props.halign = Gtk.Align.END viewtoggle.props.halign = Gtk.Align.END
@@ -101,8 +103,8 @@ class EntryViewPane(object):
self.entry_view_grid.show_all() self.entry_view_grid.show_all()
def entry_view_toggled(self, widget, initialised = False): def entry_view_toggled(self, widget, initialised=False):
print ("DEBUG - entry_view_toggled") print("DEBUG - entry_view_toggled")
if widget.get_active(): if widget.get_active():
next_view = self.entry_view_full next_view = self.entry_view_full
show_coverart = False show_coverart = False
@@ -167,13 +169,13 @@ class EntryViewPane(object):
def cover_search(self, album_artist, manager): def cover_search(self, album_artist, manager):
self.cover_search_pane.do_search(album_artist, self.cover_search_pane.do_search(album_artist,
manager.cover_man.update_cover) manager.cover_man.update_cover)
def update_selection(self, last_selected_album, click_count): def update_selection(self, last_selected_album, click_count):
''' '''
Update the source view when an item gets selected. Update the source view when an item gets selected.
''' '''
print ("DEBUG - update_with_selection") print("DEBUG - update_with_selection")
selected = self.viewmgr.current_view.get_selected_objects() selected = self.viewmgr.current_view.get_selected_objects()
# clear the entry view # clear the entry view
@@ -223,18 +225,18 @@ class EntryViewPane(object):
# update the cover search pane with the first selected album # update the cover search pane with the first selected album
if cover_search_pane_visible: if cover_search_pane_visible:
self.cover_search_pane.do_search(selected[0], self.cover_search_pane.do_search(selected[0],
self.source.album_manager.cover_man.update_cover) self.source.album_manager.cover_man.update_cover)
return last_selected_album, click_count return last_selected_album, click_count
class ResultsGrid(Gtk.Grid): class ResultsGrid(Gtk.Grid):
# signals # signals
__gsignals__ = { __gsignals__ = {
'update-cover': (GObject.SIGNAL_RUN_LAST, None, (GObject.Object,RB.RhythmDBEntry)) 'update-cover': (GObject.SIGNAL_RUN_LAST, None, (GObject.Object, RB.RhythmDBEntry))
} }
image_width = 0 image_width = 0
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ResultsGrid, self).__init__(*args, **kwargs) super(ResultsGrid, self).__init__(*args, **kwargs)
@@ -279,7 +281,7 @@ class ResultsGrid(Gtk.Grid):
def update_cover(self, widget, source, entry): def update_cover(self, widget, source, entry):
self.oldval = 0 # force a redraw self.oldval = 0 # force a redraw
if entry: if entry:
album = source.album_manager.model.get_from_dbentry(entry) album = source.album_manager.model.get_from_dbentry(entry)
self.pixbuf = GdkPixbuf.Pixbuf().new_from_file(album.cover.original) self.pixbuf = GdkPixbuf.Pixbuf().new_from_file(album.cover.original)
@@ -293,23 +295,23 @@ class ResultsGrid(Gtk.Grid):
self.image1.queue_draw() self.image1.queue_draw()
else: else:
self.image2.queue_draw() self.image2.queue_draw()
def window_resize(self, widget): def window_resize(self, widget):
alloc = self.get_allocation() alloc = self.get_allocation()
if alloc.height < 10: if alloc.height < 10:
return return
if (alloc.width / 3) <= (MIN_IMAGE_SIZE+30) or \ if (alloc.width / 3) <= (MIN_IMAGE_SIZE + 30) or \
(alloc.height) <= (MIN_IMAGE_SIZE+30): (alloc.height) <= (MIN_IMAGE_SIZE + 30):
self.frame.props.visible = False self.frame.props.visible = False
else: else:
self.frame.props.visible = True self.frame.props.visible = True
framealloc = self.frame.get_allocation() framealloc = self.frame.get_allocation()
minval = min(framealloc.width-30, framealloc.height-30) minval = min(framealloc.width - 30, framealloc.height - 30)
if self.oldval == minval: if self.oldval == minval:
return return
print ("resizing") print("resizing")
self.oldval = minval self.oldval = minval
if self.pixbuf: if self.pixbuf:
p = self.pixbuf.scale_simple(minval, minval, GdkPixbuf.InterpType.BILINEAR) p = self.pixbuf.scale_simple(minval, minval, GdkPixbuf.InterpType.BILINEAR)
@@ -322,30 +324,29 @@ class ResultsGrid(Gtk.Grid):
else: else:
self.image1.set_from_pixbuf(p) self.image1.set_from_pixbuf(p)
self.stack.set_visible_child_name("image1") self.stack.set_visible_child_name("image1")
def change_view(self, entry_view, show_coverart): def change_view(self, entry_view, show_coverart):
print ("debug - change_view") print("debug - change_view")
widget = self.get_child_at(0, 0) widget = self.get_child_at(0, 0)
if widget: if widget:
self.remove(widget) self.remove(widget)
if not show_coverart: if not show_coverart:
widget = self.get_child_at(6, 0) widget = self.get_child_at(6, 0)
if widget: if widget:
self.remove(widget) self.remove(widget)
entry_view.props.hexpand = True entry_view.props.hexpand = True
entry_view.props.vexpand = True entry_view.props.vexpand = True
self.attach(entry_view, 0, 0, 3, 1) self.attach(entry_view, 0, 0, 3, 1)
if show_coverart: if show_coverart:
self.attach(self.frame, 6, 0, 1, 1) self.attach(self.frame, 6, 0, 1, 1)
self.show_all() self.show_all()
class BaseView(RB.EntryView):
class BaseView(RB.EntryView):
def __init__(self, shell, source): def __init__(self, shell, source):
''' '''
Initializes the entryview. Initializes the entryview.
@@ -355,64 +356,64 @@ class BaseView(RB.EntryView):
self.plugin = self.source.props.plugin self.plugin = self.source.props.plugin
super(RB.EntryView, self).__init__(db=shell.props.db, super(RB.EntryView, self).__init__(db=shell.props.db,
shell_player=shell.props.shell_player, is_drag_source=True, shell_player=shell.props.shell_player, is_drag_source=True,
visible_columns=[]) visible_columns=[])
cl = CoverLocale() cl = CoverLocale()
cl.switch_locale(cl.Locale.RB) cl.switch_locale(cl.Locale.RB)
self.display_columns() self.display_columns()
cl.switch_locale(cl.Locale.LOCALE_DOMAIN) cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
self.define_menu() self.define_menu()
# connect signals to the shell to know when the playing state changes # connect signals to the shell to know when the playing state changes
self.shell.props.shell_player.connect('playing-song-changed', self.shell.props.shell_player.connect('playing-song-changed',
self.playing_song_changed) self.playing_song_changed)
self.shell.props.shell_player.connect('playing-changed', self.shell.props.shell_player.connect('playing-changed',
self.playing_changed) self.playing_changed)
self.actiongroup = ActionGroup(self.shell, 'coverentryplaylist_submenu') self.actiongroup = ActionGroup(self.shell, 'coverentryplaylist_submenu')
self.external_plugins = None self.external_plugins = None
self.source_query_model = self.source.source_query_model # RB.RhythmDBQueryModel.new_empty(self.shell.props.db) self.source_query_model = self.source.source_query_model # RB.RhythmDBQueryModel.new_empty(self.shell.props.db)
self.qm = RB.RhythmDBQueryModel.new_empty(self.shell.props.db) self.qm = RB.RhythmDBQueryModel.new_empty(self.shell.props.db)
self.set_model(self.qm) self.set_model(self.qm)
# connect the sort-order to the library source sort # connect the sort-order to the library source sort
library_view = self.shell.props.library_source.get_entry_view() library_view = self.shell.props.library_source.get_entry_view()
library_view.connect('notify::sort-order', library_view.connect('notify::sort-order',
self._on_library_sorting_changed) self._on_library_sorting_changed)
self._on_library_sorting_changed(library_view, self._on_library_sorting_changed(library_view,
library_view.props.sort_order) library_view.props.sort_order)
# connect to the sort-order property # connect to the sort-order property
self.connect('notify::sort-order', self._notify_sort_order, self.connect('notify::sort-order', self._notify_sort_order,
library_view) library_view)
self.echonest_similar_playlist = None self.echonest_similar_playlist = None
self.echonest_similar_genre_playlist = None self.echonest_similar_genre_playlist = None
self.lastfm_similar_playlist = None self.lastfm_similar_playlist = None
self.set_columns_clickable(False) self.set_columns_clickable(False)
self.connect('selection-changed', self.selection_changed) self.connect('selection-changed', self.selection_changed)
self.artists = "" self.artists = ""
def __del__(self): def __del__(self):
del self.action_group del self.action_group
del self.play_action del self.play_action
del self.queue_action del self.queue_action
def define_menu(self): def define_menu(self):
pass pass
def display_columns(self): def display_columns(self):
pass pass
def selection_changed(self, entry_view): def selection_changed(self, entry_view):
entries = entry_view.get_selected_entries() entries = entry_view.get_selected_entries()
if entries and len(entries) > 0: if entries and len(entries) > 0:
@@ -427,13 +428,13 @@ class BaseView(RB.EntryView):
(_, playing) = self.shell.props.shell_player.get_playing() (_, playing) = self.shell.props.shell_player.get_playing()
self.playing_changed(self.shell.props.shell_player, playing) self.playing_changed(self.shell.props.shell_player, playing)
artists = album.artists.split(', ') artists = album.artists.split(', ')
if self.artists == "": if self.artists == "":
self.artists = artists self.artists = artists
else: else:
self.artists = list(set(self.artists + artists)) self.artists = list(set(self.artists + artists))
print("CoverArtBrowser DEBUG - add_album()") print("CoverArtBrowser DEBUG - add_album()")
def clear(self): def clear(self):
@@ -443,7 +444,7 @@ class BaseView(RB.EntryView):
self.qm.remove_entry(row[0]) self.qm.remove_entry(row[0])
self.artists = "" self.artists = ""
print("CoverArtBrowser DEBUG - clear()") print("CoverArtBrowser DEBUG - clear()")
def do_entry_activated(self, entry): def do_entry_activated(self, entry):
@@ -452,49 +453,49 @@ class BaseView(RB.EntryView):
self.play_track_menu_item_callback(entry) self.play_track_menu_item_callback(entry)
print("CoverArtBrowser DEBUG - do_entry_activated()") print("CoverArtBrowser DEBUG - do_entry_activated()")
return True return True
def pre_popup_menu_callback(self, *args): def pre_popup_menu_callback(self, *args):
pass pass
def do_show_popup(self, over_entry): def do_show_popup(self, over_entry):
if over_entry: if over_entry:
print("CoverArtBrowser DEBUG - do_show_popup()") print("CoverArtBrowser DEBUG - do_show_popup()")
self.popup.popup(self.source, self.popup.popup(self.source,
'entryview_popup_menu', 0, Gtk.get_current_event_time()) 'entryview_popup_menu', 0, Gtk.get_current_event_time())
return over_entry return over_entry
def play_similar_artist_menu_item_callback(self, *args): def play_similar_artist_menu_item_callback(self, *args):
if not self.echonest_similar_playlist: if not self.echonest_similar_playlist:
self.echonest_similar_playlist = \ self.echonest_similar_playlist = \
EchoNestPlaylist( self.shell, EchoNestPlaylist(self.shell,
self.shell.props.queue_source) self.shell.props.queue_source)
selected = self.get_selected_entries() selected = self.get_selected_entries()
entry = selected[0] entry = selected[0]
self.echonest_similar_playlist.start(entry, reinitialise=True) self.echonest_similar_playlist.start(entry, reinitialise=True)
def play_similar_genre_menu_item_callback(self, *args): def play_similar_genre_menu_item_callback(self, *args):
if not self.echonest_similar_genre_playlist: if not self.echonest_similar_genre_playlist:
self.echonest_similar_genre_playlist = \ self.echonest_similar_genre_playlist = \
EchoNestGenrePlaylist( self.shell, EchoNestGenrePlaylist(self.shell,
self.shell.props.queue_source) self.shell.props.queue_source)
selected = self.get_selected_entries() selected = self.get_selected_entries()
entry = selected[0] entry = selected[0]
self.echonest_similar_genre_playlist.start(entry, reinitialise=True) self.echonest_similar_genre_playlist.start(entry, reinitialise=True)
def play_similar_track_menu_item_callback(self, *args): def play_similar_track_menu_item_callback(self, *args):
if not self.lastfm_similar_playlist: if not self.lastfm_similar_playlist:
self.lastfm_similar_playlist = \ self.lastfm_similar_playlist = \
LastFMTrackPlaylist( self.shell, LastFMTrackPlaylist(self.shell,
self.shell.props.queue_source) self.shell.props.queue_source)
selected = self.get_selected_entries() selected = self.get_selected_entries()
entry = selected[0] entry = selected[0]
self.lastfm_similar_playlist.start(entry, reinitialise=True) self.lastfm_similar_playlist.start(entry, reinitialise=True)
def play_track_menu_item_callback(self, *args): def play_track_menu_item_callback(self, *args):
print("CoverArtBrowser DEBUG - play_track_menu_item_callback()") print("CoverArtBrowser DEBUG - play_track_menu_item_callback()")
@@ -504,12 +505,12 @@ class BaseView(RB.EntryView):
selected = self.get_selected_entries() selected = self.get_selected_entries()
entry = selected[0] entry = selected[0]
if len(selected) == 1: if len(selected) == 1:
self.source_query_model.copy_contents(self.qm) self.source_query_model.copy_contents(self.qm)
else: else:
self.add_tracks_to_source(self.source_query_model) self.add_tracks_to_source(self.source_query_model)
self.source.props.query_model = self.source_query_model self.source.props.query_model = self.source_query_model
# Start the music # Start the music
@@ -536,7 +537,7 @@ class BaseView(RB.EntryView):
selected.reverse() selected.reverse()
selected = sorted(selected, selected = sorted(selected,
key=lambda song: song.get_ulong(RB.RhythmDBPropType.TRACK_NUMBER)) key=lambda song: song.get_ulong(RB.RhythmDBPropType.TRACK_NUMBER))
for entry in selected: for entry in selected:
source.add_entry(entry, -1) source.add_entry(entry, -1)
@@ -551,7 +552,7 @@ class BaseView(RB.EntryView):
for entry in selected: for entry in selected:
self.shell.props.db.entry_set(entry, RB.RhythmDBPropType.RATING, self.shell.props.db.entry_set(entry, RB.RhythmDBPropType.RATING,
rating) rating)
self.shell.props.db.commit() self.shell.props.db.commit()
@@ -560,7 +561,7 @@ class BaseView(RB.EntryView):
info_dialog = RB.SongInfo(source=self.source, entry_view=self) info_dialog = RB.SongInfo(source=self.source, entry_view=self)
info_dialog.show_all() info_dialog.show_all()
print("CoverArtBrowser DEBUG - show_properties_menu_item_callback()") print("CoverArtBrowser DEBUG - show_properties_menu_item_callback()")
def playing_song_changed(self, shell_player, entry): def playing_song_changed(self, shell_player, entry):
@@ -599,8 +600,8 @@ class BaseView(RB.EntryView):
def add_to_static_playlist_menu_item_callback(self, action, param, args): def add_to_static_playlist_menu_item_callback(self, action, param, args):
print("CoverArtBrowser DEBUG - " + \ print("CoverArtBrowser DEBUG - " + \
"add_to_static_playlist_menu_item_callback") "add_to_static_playlist_menu_item_callback")
playlist = args['playlist'] playlist = args['playlist']
self.add_tracks_to_source(playlist) self.add_tracks_to_source(playlist)
@@ -615,68 +616,69 @@ class BaseView(RB.EntryView):
# update library source's view direction # update library source's view direction
library_view.set_sorting_type(self.props.sort_order) library_view.set_sorting_type(self.props.sort_order)
class CoverArtCompactEntryView(BaseView): class CoverArtCompactEntryView(BaseView):
__hash__ = GObject.__hash__ __hash__ = GObject.__hash__
def __init__(self, shell, source): def __init__(self, shell, source):
''' '''
Initializes the entryview. Initializes the entryview.
''' '''
super(CoverArtCompactEntryView, self).__init__(shell, source) super(CoverArtCompactEntryView, self).__init__(shell, source)
def display_columns(self): def display_columns(self):
self.col_map = OrderedDict([ self.col_map = OrderedDict([
('track-number', RB.EntryViewColumn.TRACK_NUMBER), ('track-number', RB.EntryViewColumn.TRACK_NUMBER),
('title', RB.EntryViewColumn.TITLE), ('title', RB.EntryViewColumn.TITLE),
('artist', RB.EntryViewColumn.ARTIST), ('artist', RB.EntryViewColumn.ARTIST),
('rating', RB.EntryViewColumn.RATING), ('rating', RB.EntryViewColumn.RATING),
('duration', RB.EntryViewColumn.DURATION) ('duration', RB.EntryViewColumn.DURATION)
]) ])
for entry in self.col_map: for entry in self.col_map:
visible = False if entry == 'artist' else True visible = False if entry == 'artist' else True
self.append_column(self.col_map[entry], visible) self.append_column(self.col_map[entry], visible)
def add_album(self, album): def add_album(self, album):
super(CoverArtCompactEntryView, self).add_album(album) super(CoverArtCompactEntryView, self).add_album(album)
if len(self.artists) > 1: if len(self.artists) > 1:
self.get_column(RB.EntryViewColumn.ARTIST).set_visible(True) self.get_column(RB.EntryViewColumn.ARTIST).set_visible(True)
else: else:
self.get_column(RB.EntryViewColumn.ARTIST).set_visible(False) self.get_column(RB.EntryViewColumn.ARTIST).set_visible(False)
def define_menu(self): def define_menu(self):
popup = Menu(self.plugin, self.shell) popup = Menu(self.plugin, self.shell)
popup.load_from_file('N/A', popup.load_from_file('N/A',
'ui/coverart_entryview_compact_pop_rb3.ui') 'ui/coverart_entryview_compact_pop_rb3.ui')
signals = { signals = {
'ev_compact_play_track_menu_item' : self.play_track_menu_item_callback, 'ev_compact_play_track_menu_item': self.play_track_menu_item_callback,
'ev_compact_queue_track_menu_item' : self.queue_track_menu_item_callback, 'ev_compact_queue_track_menu_item': self.queue_track_menu_item_callback,
'ev_compact_add_to_playing_menu_item' : self.add_to_playing_menu_item_callback, 'ev_compact_add_to_playing_menu_item': self.add_to_playing_menu_item_callback,
'ev_compact_new_playlist' : self.add_playlist_menu_item_callback, 'ev_compact_new_playlist': self.add_playlist_menu_item_callback,
'ev_compact_show_properties_menu_item' : self.show_properties_menu_item_callback, 'ev_compact_show_properties_menu_item': self.show_properties_menu_item_callback,
'ev_compact_similar_track_menu_item' : self.play_similar_track_menu_item_callback, 'ev_compact_similar_track_menu_item': self.play_similar_track_menu_item_callback,
'ev_compact_similar_artist_menu_item' : self.play_similar_artist_menu_item_callback, 'ev_compact_similar_artist_menu_item': self.play_similar_artist_menu_item_callback,
'ev_compact_similar_genre_menu_item' : self.play_similar_genre_menu_item_callback } 'ev_compact_similar_genre_menu_item': self.play_similar_genre_menu_item_callback}
popup.connect_signals(signals) popup.connect_signals(signals)
popup.connect('pre-popup', self.pre_popup_menu_callback) popup.connect('pre-popup', self.pre_popup_menu_callback)
self.popup = popup self.popup = popup
def playlist_menu_item_callback(self, *args): def playlist_menu_item_callback(self, *args):
print("CoverArtBrowser DEBUG - playlist_menu_item_callback") print("CoverArtBrowser DEBUG - playlist_menu_item_callback")
self.source.playlist_fillmenu(self.popup, 'ev_compact_playlist_sub_menu_item', 'ev_compact_playlist_section', self.source.playlist_fillmenu(self.popup, 'ev_compact_playlist_sub_menu_item', 'ev_compact_playlist_section',
self.actiongroup, self.add_to_static_playlist_menu_item_callback) self.actiongroup, self.add_to_static_playlist_menu_item_callback)
def pre_popup_menu_callback(self, *args): def pre_popup_menu_callback(self, *args):
''' '''
Callback when the popup menu is about to be displayed Callback when the popup menu is about to be displayed
''' '''
state,sensitive = self.shell.props.shell_player.get_playing() state, sensitive = self.shell.props.shell_player.get_playing()
if not state: if not state:
sensitive = False sensitive = False
@@ -684,52 +686,53 @@ class CoverArtCompactEntryView(BaseView):
if not self.external_plugins: if not self.external_plugins:
self.external_plugins = \ self.external_plugins = \
CreateExternalPluginMenu("ev_compact_entryview", 5, self.popup) CreateExternalPluginMenu("ev_compact_entryview", 5, self.popup)
self.external_plugins.create_menu('entryview_compact_popup_menu') self.external_plugins.create_menu('entryview_compact_popup_menu')
self.playlist_menu_item_callback() self.playlist_menu_item_callback()
class CoverArtEntryView(BaseView): class CoverArtEntryView(BaseView):
__hash__ = GObject.__hash__ __hash__ = GObject.__hash__
def __init__(self, shell, source): def __init__(self, shell, source):
''' '''
Initializes the entryview. Initializes the entryview.
''' '''
super(CoverArtEntryView, self).__init__(shell, source) super(CoverArtEntryView, self).__init__(shell, source)
def display_columns(self): def display_columns(self):
self.col_map = OrderedDict([ self.col_map = OrderedDict([
('track-number', RB.EntryViewColumn.TRACK_NUMBER), ('track-number', RB.EntryViewColumn.TRACK_NUMBER),
('title', RB.EntryViewColumn.TITLE), ('title', RB.EntryViewColumn.TITLE),
('genre', RB.EntryViewColumn.GENRE), ('genre', RB.EntryViewColumn.GENRE),
('artist', RB.EntryViewColumn.ARTIST), ('artist', RB.EntryViewColumn.ARTIST),
('album', RB.EntryViewColumn.ALBUM), ('album', RB.EntryViewColumn.ALBUM),
('composer', RB.EntryViewColumn.COMPOSER), ('composer', RB.EntryViewColumn.COMPOSER),
('date', RB.EntryViewColumn.YEAR), ('date', RB.EntryViewColumn.YEAR),
('duration', RB.EntryViewColumn.DURATION), ('duration', RB.EntryViewColumn.DURATION),
('bitrate', RB.EntryViewColumn.QUALITY), ('bitrate', RB.EntryViewColumn.QUALITY),
('play-count', RB.EntryViewColumn.PLAY_COUNT), ('play-count', RB.EntryViewColumn.PLAY_COUNT),
('beats-per-minute', RB.EntryViewColumn.BPM), ('beats-per-minute', RB.EntryViewColumn.BPM),
('comment', RB.EntryViewColumn.COMMENT), ('comment', RB.EntryViewColumn.COMMENT),
('location', RB.EntryViewColumn.LOCATION), ('location', RB.EntryViewColumn.LOCATION),
('rating', RB.EntryViewColumn.RATING), ('rating', RB.EntryViewColumn.RATING),
('last-played', RB.EntryViewColumn.LAST_PLAYED), ('last-played', RB.EntryViewColumn.LAST_PLAYED),
('first-seen', RB.EntryViewColumn.FIRST_SEEN) ('first-seen', RB.EntryViewColumn.FIRST_SEEN)
]) ])
for entry in self.col_map: for entry in self.col_map:
visible = True if entry == 'title' else False visible = True if entry == 'title' else False
self.append_column(self.col_map[entry], visible) self.append_column(self.col_map[entry], visible)
# connect the visible-columns global setting to update our entryview # connect the visible-columns global setting to update our entryview
gs = GSetting() gs = GSetting()
rhythm_settings = gs.get_setting(gs.Path.RBSOURCE) rhythm_settings = gs.get_setting(gs.Path.RBSOURCE)
rhythm_settings.connect('changed::visible-columns', rhythm_settings.connect('changed::visible-columns',
self.on_visible_columns_changed) self.on_visible_columns_changed)
self.on_visible_columns_changed(rhythm_settings, 'visible-columns') self.on_visible_columns_changed(rhythm_settings, 'visible-columns')
def on_visible_columns_changed(self, settings, key): def on_visible_columns_changed(self, settings, key):
print("CoverArtBrowser DEBUG - on_visible_columns_changed()") print("CoverArtBrowser DEBUG - on_visible_columns_changed()")
# reset current columns # reset current columns
@@ -739,11 +742,11 @@ class CoverArtEntryView(BaseView):
if entry in settings[key]: if entry in settings[key]:
col.set_visible(True) col.set_visible(True)
else: else:
if entry != 'title': if entry != 'title':
col.set_visible(False) col.set_visible(False)
print ("CoverArtBrowser DEBUG - end on_visible_columns_changed()") print("CoverArtBrowser DEBUG - end on_visible_columns_changed()")
def define_menu(self): def define_menu(self):
popup = Menu(self.plugin, self.shell) popup = Menu(self.plugin, self.shell)
popup.load_from_file('N/A', popup.load_from_file('N/A',
@@ -751,29 +754,29 @@ class CoverArtEntryView(BaseView):
signals = { signals = {
'ev_full_play_track_menu_item': self.play_track_menu_item_callback, 'ev_full_play_track_menu_item': self.play_track_menu_item_callback,
'ev_full_queue_track_menu_item': self.queue_track_menu_item_callback, 'ev_full_queue_track_menu_item': self.queue_track_menu_item_callback,
'ev_full_add_to_playing_menu_item' : self.add_to_playing_menu_item_callback, 'ev_full_add_to_playing_menu_item': self.add_to_playing_menu_item_callback,
'ev_full_new_playlist': self.add_playlist_menu_item_callback, 'ev_full_new_playlist': self.add_playlist_menu_item_callback,
'ev_full_show_properties_menu_item': self.show_properties_menu_item_callback, 'ev_full_show_properties_menu_item': self.show_properties_menu_item_callback,
'ev_full_similar_track_menu_item': self.play_similar_track_menu_item_callback, 'ev_full_similar_track_menu_item': self.play_similar_track_menu_item_callback,
'ev_full_similar_artist_menu_item': self.play_similar_artist_menu_item_callback, 'ev_full_similar_artist_menu_item': self.play_similar_artist_menu_item_callback,
'ev_full_similar_genre_menu_item': self.play_similar_genre_menu_item_callback } 'ev_full_similar_genre_menu_item': self.play_similar_genre_menu_item_callback}
popup.connect_signals(signals) popup.connect_signals(signals)
popup.connect('pre-popup', self.pre_popup_menu_callback) popup.connect('pre-popup', self.pre_popup_menu_callback)
self.popup = popup self.popup = popup
def playlist_menu_item_callback(self, *args): def playlist_menu_item_callback(self, *args):
print("CoverArtBrowser DEBUG - playlist_menu_item_callback") print("CoverArtBrowser DEBUG - playlist_menu_item_callback")
self.source.playlist_fillmenu(self.popup, 'ev_full_playlist_sub_menu_item', 'ev_full_playlist_section', self.source.playlist_fillmenu(self.popup, 'ev_full_playlist_sub_menu_item', 'ev_full_playlist_section',
self.actiongroup, self.add_to_static_playlist_menu_item_callback) self.actiongroup, self.add_to_static_playlist_menu_item_callback)
def pre_popup_menu_callback(self, *args): def pre_popup_menu_callback(self, *args):
''' '''
Callback when the popup menu is about to be displayed Callback when the popup menu is about to be displayed
''' '''
state,sensitive = self.shell.props.shell_player.get_playing() state, sensitive = self.shell.props.shell_player.get_playing()
if not state: if not state:
sensitive = False sensitive = False
@@ -781,11 +784,12 @@ class CoverArtEntryView(BaseView):
if not self.external_plugins: if not self.external_plugins:
self.external_plugins = \ self.external_plugins = \
CreateExternalPluginMenu("ev_full_entryview", 5, self.popup) CreateExternalPluginMenu("ev_full_entryview", 5, self.popup)
self.external_plugins.create_menu('entryview_full_popup_menu') self.external_plugins.create_menu('entryview_full_popup_menu')
self.playlist_menu_item_callback() self.playlist_menu_item_callback()
GObject.type_register(CoverArtEntryView) GObject.type_register(CoverArtEntryView)
GObject.type_register(CoverArtCompactEntryView) GObject.type_register(CoverArtCompactEntryView)
+54 -52
Ver Arquivo
@@ -35,55 +35,56 @@ import os
import sys import sys
import subprocess import subprocess
class CoverArtExport(GObject.Object): class CoverArtExport(GObject.Object):
''' '''
This class provides for various export routines This class provides for various export routines
''' '''
TARGET_BITRATE = 128 TARGET_BITRATE = 128
def __init__(self, plugin, shell, album_manager): def __init__(self, plugin, shell, album_manager):
self.plugin = plugin self.plugin = plugin
self.shell = shell self.shell = shell
self.album_manager = album_manager self.album_manager = album_manager
self._gstreamer_has_initialised = False self._gstreamer_has_initialised = False
def is_search_plugin_enabled(self): def is_search_plugin_enabled(self):
peas = Peas.Engine.get_default() peas = Peas.Engine.get_default()
loaded_plugins = peas.get_loaded_plugins() loaded_plugins = peas.get_loaded_plugins()
result = False result = False
if 'coverart_search_providers' in loaded_plugins: if 'coverart_search_providers' in loaded_plugins:
info = peas.get_plugin_info('coverart_search_providers') info = peas.get_plugin_info('coverart_search_providers')
version = info.get_version() version = info.get_version()
if NaturalString(version) >= "0.9": if NaturalString(version) >= "0.9":
result = True result = True
return result return result
def embed_albums(self, selected_albums): def embed_albums(self, selected_albums):
''' '''
method to create the menu items for all supported plugins method to create the menu items for all supported plugins
:selected_albums: `Album` - array of albums :selected_albums: `Album` - array of albums
''' '''
self._initialise_gstreamer() self._initialise_gstreamer()
from coverart_search_tracks import CoverArtTracks from coverart_search_tracks import CoverArtTracks
search_tracks = CoverArtTracks() search_tracks = CoverArtTracks()
playlist_manager = self.shell.props.playlist_manager playlist_manager = self.shell.props.playlist_manager
playlists_entries = playlist_manager.get_playlists() playlists_entries = playlist_manager.get_playlists()
ui = Gtk.Builder() ui = Gtk.Builder()
ui.add_from_file(rb.find_plugin_file(self.plugin, ui.add_from_file(rb.find_plugin_file(self.plugin,
'ui/coverart_exportembed.ui')) 'ui/coverart_exportembed.ui'))
ui.connect_signals(self) ui.connect_signals(self)
embeddialog = ui.get_object('exportembeddialog') embeddialog = ui.get_object('exportembeddialog')
folderchooserbutton = ui.get_object('folderchooserbutton') folderchooserbutton = ui.get_object('folderchooserbutton')
use_album_name_checkbutton = ui.get_object('use_album_name_checkbutton') use_album_name_checkbutton = ui.get_object('use_album_name_checkbutton')
open_filemanager_checkbutton = ui.get_object('open_filemanager_checkbutton') open_filemanager_checkbutton = ui.get_object('open_filemanager_checkbutton')
convert_checkbutton = ui.get_object('convert_checkbutton') convert_checkbutton = ui.get_object('convert_checkbutton')
@@ -92,12 +93,12 @@ class CoverArtExport(GObject.Object):
resize_spinbutton = ui.get_object('resize_spinbutton') resize_spinbutton = ui.get_object('resize_spinbutton')
bitrate_spinbutton.set_value(self.TARGET_BITRATE) bitrate_spinbutton.set_value(self.TARGET_BITRATE)
resize_spinbutton.set_value(128) resize_spinbutton.set_value(128)
downloads_dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD) downloads_dir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DOWNLOAD)
folderchooserbutton.set_current_folder(downloads_dir) folderchooserbutton.set_current_folder(downloads_dir)
response = embeddialog.run() response = embeddialog.run()
if response != Gtk.ResponseType.OK: if response != Gtk.ResponseType.OK:
embeddialog.destroy() embeddialog.destroy()
return return
@@ -113,7 +114,7 @@ class CoverArtExport(GObject.Object):
resize = int(resize_spinbutton.get_value()) resize = int(resize_spinbutton.get_value())
else: else:
resize = -1 resize = -1
embeddialog.destroy() embeddialog.destroy()
albums = {} albums = {}
@@ -127,27 +128,28 @@ class CoverArtExport(GObject.Object):
def complete(): def complete():
self.album_manager.progress = 1 self.album_manager.progress = 1
if open_filemanager: if open_filemanager:
#code taken from http://stackoverflow.com/questions/1795111/is-there-a-cross-platform-way-to-open-a-file-browser-in-python #code taken from http://stackoverflow.com/questions/1795111/is-there-a-cross-platform-way-to-open-a-file-browser-in-python
if sys.platform=='win32': if sys.platform == 'win32':
import winreg import winreg
path= r('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon')
path = r('SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon')
for root in (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE): for root in (winreg.HKEY_CURRENT_USER, winreg.HKEY_LOCAL_MACHINE):
try: try:
with winreg.OpenKey(root, path) as k: with winreg.OpenKey(root, path) as k:
value, regtype= winreg.QueryValueEx(k, 'Shell') value, regtype = winreg.QueryValueEx(k, 'Shell')
except WindowsError: except WindowsError:
pass pass
else: else:
if regtype in (winreg.REG_SZ, winreg.REG_EXPAND_SZ): if regtype in (winreg.REG_SZ, winreg.REG_EXPAND_SZ):
shell= value shell = value
break break
else: else:
shell= 'Explorer.exe' shell = 'Explorer.exe'
subprocess.Popen([shell, final_folder_store]) subprocess.Popen([shell, final_folder_store])
elif sys.platform=='darwin': elif sys.platform == 'darwin':
subprocess.Popen(['open', final_folder_store]) subprocess.Popen(['open', final_folder_store])
else: else:
@@ -156,29 +158,29 @@ class CoverArtExport(GObject.Object):
self._albumiter = iter(albums) self._albumiter = iter(albums)
self._tracknumber = 0 self._tracknumber = 0
self._album = next(self._albumiter) self._album = next(self._albumiter)
def idle_call(data): def idle_call(data):
exit_idle = True exit_idle = True
track = albums[self._album][self._tracknumber] track = albums[self._album][self._tracknumber]
if not process_track(self._album, track): if not process_track(self._album, track):
exit_idle = False exit_idle = False
self._tracknumber = self._tracknumber + 1 self._tracknumber = self._tracknumber + 1
if self._tracknumber >= len(albums[self._album]): if self._tracknumber >= len(albums[self._album]):
try: try:
self._tracknumber = 0 self._tracknumber = 0
self._album = next(self._albumiter) self._album = next(self._albumiter)
except StopIteration: except StopIteration:
exit_idle = False exit_idle = False
if not exit_idle: if not exit_idle:
complete() complete()
return exit_idle return exit_idle
def process_track(album, track): def process_track(album, track):
self.album_manager.progress = self._track_count / total self.album_manager.progress = self._track_count / total
self._track_count = self._track_count + 1 self._track_count = self._track_count + 1
@@ -186,16 +188,16 @@ class CoverArtExport(GObject.Object):
key = album.create_ext_db_key() key = album.create_ext_db_key()
finalPath = rb3compat.unquote(track.location)[7:] finalPath = rb3compat.unquote(track.location)[7:]
album_name = RB.search_fold(album.name) album_name = RB.search_fold(album.name)
if use_album_name: if use_album_name:
folder_store = final_folder_store + '/' + album_name folder_store = final_folder_store + '/' + album_name
else: else:
folder_store = final_folder_store folder_store = final_folder_store
try: try:
if not os.path.exists(folder_store): if not os.path.exists(folder_store):
os.makedirs(folder_store) os.makedirs(folder_store)
if convert: if convert:
self.convert_to_mp3(finalPath, folder_store, bitrate) self.convert_to_mp3(finalPath, folder_store, bitrate)
finalPath = self._calc_mp3_filename(finalPath, folder_store) finalPath = self._calc_mp3_filename(finalPath, folder_store)
@@ -208,27 +210,27 @@ class CoverArtExport(GObject.Object):
dest = os.path.join(folder_store, os.path.basename(finalPath)) dest = os.path.join(folder_store, os.path.basename(finalPath))
desturi = 'file://' + rb3compat.pathname2url(dest) desturi = 'file://' + rb3compat.pathname2url(dest)
return search_tracks.embed(desturi, key, resize) return search_tracks.embed(desturi, key, resize)
data = None data = None
Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, idle_call, data) Gdk.threads_add_idle(GLib.PRIORITY_DEFAULT_IDLE, idle_call, data)
def _initialise_gstreamer(self): def _initialise_gstreamer(self):
if self._gstreamer_has_initialised: if self._gstreamer_has_initialised:
return return
self._gstreamer_has_initialised = True self._gstreamer_has_initialised = True
Gst.init(None) Gst.init(None)
def on_new_decoded_pad(dbin, pad): def on_new_decoded_pad(dbin, pad):
decode = pad.get_parent() decode = pad.get_parent()
pipeline = decode.get_parent() pipeline = decode.get_parent()
convert = pipeline.get_by_name('convert') convert = pipeline.get_by_name('convert')
decode.link(convert) decode.link(convert)
#we are going to mimic the following #we are going to mimic the following
# gst-launch-1.0 filesrc location="02 - ABBA - Knowing Me, Knowing You.ogg" ! # gst-launch-1.0 filesrc location="02 - ABBA - Knowing Me, Knowing You.ogg" !
# decodebin ! audioconvert ! audioresample ! lamemp3enc target=bitrate bitrate=128 ! # decodebin ! audioconvert ! audioresample ! lamemp3enc target=bitrate bitrate=128 !
@@ -242,15 +244,15 @@ class CoverArtExport(GObject.Object):
convert = Gst.ElementFactory.make('audioconvert', 'convert') convert = Gst.ElementFactory.make('audioconvert', 'convert')
sample = Gst.ElementFactory.make('audioresample', 'sample') sample = Gst.ElementFactory.make('audioresample', 'sample')
encoder = Gst.ElementFactory.make('lamemp3enc', 'encoder') encoder = Gst.ElementFactory.make('lamemp3enc', 'encoder')
encoder.set_property('target', 'bitrate') encoder.set_property('target', 'bitrate')
encoder.set_property('bitrate', self.TARGET_BITRATE) encoder.set_property('bitrate', self.TARGET_BITRATE)
xing = Gst.ElementFactory.make('xingmux', 'xing') # needed to make bitrate more accurate xing = Gst.ElementFactory.make('xingmux', 'xing') # needed to make bitrate more accurate
mux = Gst.ElementFactory.make('id3v2mux', 'mux') mux = Gst.ElementFactory.make('id3v2mux', 'mux')
if not mux: if not mux:
# use id3mux where not available # use id3mux where not available
mux = Gst.ElementFactory.make('id3mux', 'mux') mux = Gst.ElementFactory.make('id3mux', 'mux')
sink = Gst.ElementFactory.make('filesink', 'sink') sink = Gst.ElementFactory.make('filesink', 'sink')
converter.add(source) converter.add(source)
@@ -267,33 +269,33 @@ class CoverArtExport(GObject.Object):
#it doesnt have source-pads (http://stackoverflow.com/questions/2993777/gstreamer-of-pythons-gst-linkerror-problem) #it doesnt have source-pads (http://stackoverflow.com/questions/2993777/gstreamer-of-pythons-gst-linkerror-problem)
decoder.connect("pad-added", on_new_decoded_pad) decoder.connect("pad-added", on_new_decoded_pad)
Gst.Element.link(convert, sample) Gst.Element.link(convert, sample)
Gst.Element.link(sample, encoder) Gst.Element.link(sample, encoder)
Gst.Element.link(encoder, xing) Gst.Element.link(encoder, xing)
Gst.Element.link(xing, mux) Gst.Element.link(xing, mux)
Gst.Element.link(mux, sink) Gst.Element.link(mux, sink)
self.converter=converter self.converter = converter
self.source=source self.source = source
self.sink=sink self.sink = sink
self.encoder=encoder self.encoder = encoder
def _calc_mp3_filename(self, filename, save_folder): def _calc_mp3_filename(self, filename, save_folder):
finalname = os.path.basename(filename) finalname = os.path.basename(filename)
finalname = finalname.rsplit('.')[0] + ".mp3" finalname = finalname.rsplit('.')[0] + ".mp3"
return save_folder + "/" + finalname return save_folder + "/" + finalname
def convert_to_mp3(self, filename, save_folder, bitrate): def convert_to_mp3(self, filename, save_folder, bitrate):
self.source.set_property('location', filename) self.source.set_property('location', filename)
self.sink.set_property('location', self._calc_mp3_filename(filename, save_folder)) self.sink.set_property('location', self._calc_mp3_filename(filename, save_folder))
print (bitrate) print(bitrate)
if bitrate < 32: if bitrate < 32:
bitrate = self.TARGET_BITRATE bitrate = self.TARGET_BITRATE
self.encoder.set_property('bitrate', int(bitrate)) self.encoder.set_property('bitrate', int(bitrate))
print (bitrate) print(bitrate)
# Start playing # Start playing
ret = self.converter.set_state(Gst.State.PLAYING) ret = self.converter.set_state(Gst.State.PLAYING)
@@ -311,7 +313,7 @@ class CoverArtExport(GObject.Object):
# for some reason in ubuntu 12.04 Gst.CLOCK_TIME_NONE fails # for some reason in ubuntu 12.04 Gst.CLOCK_TIME_NONE fails
msg = bus.timed_pop_filtered( msg = bus.timed_pop_filtered(
18446744073709551615, Gst.MessageType.ERROR | Gst.MessageType.EOS) 18446744073709551615, Gst.MessageType.ERROR | Gst.MessageType.EOS)
# Parse message # Parse message
if (msg): if (msg):
if msg.type == Gst.MessageType.ERROR: if msg.type == Gst.MessageType.ERROR:
+37 -32
Ver Arquivo
@@ -29,10 +29,12 @@ from coverart_rb3compat import ApplicationShell
from coverart_rb3compat import Menu from coverart_rb3compat import Menu
from coverart_utils import CaseInsensitiveDict from coverart_utils import CaseInsensitiveDict
class ExternalPlugin(GObject.Object): class ExternalPlugin(GObject.Object):
''' '''
class for all supported ExternalPlugins class for all supported ExternalPlugins
''' '''
def __init__(self, **kargs): def __init__(self, **kargs):
super(ExternalPlugin, self).__init__(**kargs) super(ExternalPlugin, self).__init__(**kargs)
@@ -50,7 +52,7 @@ class ExternalPlugin(GObject.Object):
:param key: `str` name of attribute :param key: `str` name of attribute
:param val: `str` value of attribute :param val: `str` value of attribute
''' '''
if key == 'is_album_menu': if key == 'is_album_menu':
if val == 'yes': if val == 'yes':
self.attributes[key] = True self.attributes[key] = True
@@ -67,16 +69,16 @@ class ExternalPlugin(GObject.Object):
loaded_plugins = peas.get_loaded_plugins() loaded_plugins = peas.get_loaded_plugins()
if self.attributes['plugin_name'] in CaseInsensitiveDict(loaded_plugins): if self.attributes['plugin_name'] in CaseInsensitiveDict(loaded_plugins):
print ("found %s" % self.attributes['plugin_name']) print("found %s" % self.attributes['plugin_name'])
return True return True
print ("search for %s" % self.attributes['plugin_name']) print("search for %s" % self.attributes['plugin_name'])
print (loaded_plugins) print(loaded_plugins)
return False return False
def create_menu_item(self, menubar, section_name, at_position, def create_menu_item(self, menubar, section_name, at_position,
save_actiongroup, save_menu, for_album = False): save_actiongroup, save_menu, for_album=False):
''' '''
method to create the menu item appropriate to the plugin. method to create the menu item appropriate to the plugin.
A plugin can have many menu items - all menuitems are enclosed A plugin can have many menu items - all menuitems are enclosed
@@ -92,34 +94,35 @@ class ExternalPlugin(GObject.Object):
''' '''
if for_album and not self.attributes['is_album_menu']: if for_album and not self.attributes['is_album_menu']:
return False return False
if not self.is_activated(): if not self.is_activated():
return False return False
action = ApplicationShell(save_menu.shell).lookup_action(self.attributes['action_group_name'], action = ApplicationShell(save_menu.shell).lookup_action(self.attributes['action_group_name'],
self.attributes['action_name'], self.attributes['action_type']) self.attributes['action_name'],
self.attributes['action_type'])
if action: if action:
self.attributes['action']=action self.attributes['action'] = action
if self.attributes['new_menu_name'] != '': if self.attributes['new_menu_name'] != '':
self.attributes['label'] = self.attributes['new_menu_name'] self.attributes['label'] = self.attributes['new_menu_name']
else: else:
self.attributes['label']=action.label self.attributes['label'] = action.label
#self.attributes['sensitive']=action.get_sensitive() #self.attributes['sensitive']=action.get_sensitive()
else: else:
print ("action not found") print("action not found")
print (self.attributes) print(self.attributes)
return False return False
action = save_actiongroup.add_action(func=self.menuitem_callback, action = save_actiongroup.add_action(func=self.menuitem_callback,
action_name=self.attributes['action_name'], album=for_album, action_name=self.attributes['action_name'], album=for_album,
shell=save_menu.shell, label=self.attributes['label']) shell=save_menu.shell, label=self.attributes['label'])
new_menu_item = save_menu.insert_menu_item(menubar, section_name, new_menu_item = save_menu.insert_menu_item(menubar, section_name,
at_position, action) at_position, action)
return new_menu_item return new_menu_item
def do_deactivate(self): def do_deactivate(self):
pass pass
@@ -149,9 +152,10 @@ class ExternalPlugin(GObject.Object):
shell = args['shell'] shell = args['shell']
if for_album: if for_album:
self.set_entry_view_selected_entries(shell) self.set_entry_view_selected_entries(shell)
self.attributes['action'].activate() self.attributes['action'].activate()
class CreateExternalPluginMenu(GObject.Object): class CreateExternalPluginMenu(GObject.Object):
''' '''
This is the key class called to initialise all supported plugins This is the key class called to initialise all supported plugins
@@ -160,22 +164,23 @@ class CreateExternalPluginMenu(GObject.Object):
:param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99 :param at_position: `int` position within the GtkMenu to create menu - ignored for RB2.99
:param popup: `Menu` whole popupmenu including sub-menus :param popup: `Menu` whole popupmenu including sub-menus
''' '''
def __init__(self, section_name, at_position, popup, **kargs): def __init__(self, section_name, at_position, popup, **kargs):
super(CreateExternalPluginMenu, self).__init__(**kargs) super(CreateExternalPluginMenu, self).__init__(**kargs)
self.menu = popup self.menu = popup
self.section_name = section_name self.section_name = section_name
self.at_position = at_position self.at_position = at_position
self._actiongroup = ActionGroup(popup.shell, section_name + '_externalplugins') self._actiongroup = ActionGroup(popup.shell, section_name + '_externalplugins')
# all supported plugins will be defined in the following array by parsing # all supported plugins will be defined in the following array by parsing
# the plugins XML file for the definition. Supported plugins are split between # the plugins XML file for the definition. Supported plugins are split between
# rb2.99 and later and rb2.98 and earlier due to the likelihood that earlier # rb2.99 and later and rb2.98 and earlier due to the likelihood that earlier
# plugins may never be updated by their authors # plugins may never be updated by their authors
self.supported_plugins = [] self.supported_plugins = []
extplugins = rb.find_plugin_file(popup.plugin, 'ui/coverart_external_plugins.xml') extplugins = rb.find_plugin_file(popup.plugin, 'ui/coverart_external_plugins.xml')
root = ET.parse(open(extplugins)).getroot() root = ET.parse(open(extplugins)).getroot()
@@ -188,7 +193,7 @@ class CreateExternalPluginMenu(GObject.Object):
pluginname = elem.attrib['name'] pluginname = elem.attrib['name']
basemenu = base + "[@name='" + pluginname + "']/menu" basemenu = base + "[@name='" + pluginname + "']/menu"
for menuelem in root.xpath(basemenu): for menuelem in root.xpath(basemenu):
ext = ExternalPlugin() ext = ExternalPlugin()
ext.appendattribute('plugin_name', pluginname) ext.appendattribute('plugin_name', pluginname)
@@ -206,8 +211,8 @@ class CreateExternalPluginMenu(GObject.Object):
ext.appendattribute(key, val) ext.appendattribute(key, val)
self.supported_plugins.append(ext) self.supported_plugins.append(ext)
def create_menu(self, menu_name, for_album = False): def create_menu(self, menu_name, for_album=False):
''' '''
method to create the menu items for all supported plugins method to create the menu items for all supported plugins
@@ -217,18 +222,18 @@ class CreateExternalPluginMenu(GObject.Object):
EntryView EntryView
''' '''
self.menu_name = menu_name self.menu_name = menu_name
self._actiongroup.remove_actions() self._actiongroup.remove_actions()
self.menu.remove_menu_items(self.menu_name, self.section_name) self.menu.remove_menu_items(self.menu_name, self.section_name)
items_added = False items_added = False
for plugin in self.supported_plugins: for plugin in self.supported_plugins:
new_menu_item = plugin.create_menu_item(self.menu_name, self.section_name, new_menu_item = plugin.create_menu_item(self.menu_name, self.section_name,
self.at_position, self._actiongroup, self.menu, for_album) self.at_position, self._actiongroup, self.menu, for_album)
if (not items_added) and new_menu_item: if (not items_added) and new_menu_item:
items_added = True items_added = True
if items_added: if items_added:
self.menu.insert_separator(self.menu_name, self.at_position) self.menu.insert_separator(self.menu_name, self.at_position)
+11 -10
Ver Arquivo
@@ -21,6 +21,7 @@ from coverart_widgets import AbstractView
from gi.repository import GObject from gi.repository import GObject
from gi.repository import GLib from gi.repository import GLib
class ListShowingPolicy(GObject.Object): class ListShowingPolicy(GObject.Object):
''' '''
Policy that mostly takes care of how and when things should be showed on Policy that mostly takes care of how and when things should be showed on
@@ -38,37 +39,37 @@ class ListShowingPolicy(GObject.Object):
return return
self._has_initialised = True self._has_initialised = True
class ListView(AbstractView): class ListView(AbstractView):
__gtype_name__ = "ListView" __gtype_name__ = "ListView"
name = 'listview' name = 'listview'
use_plugin_window = False use_plugin_window = False
def __init__(self): def __init__(self):
super(ListView, self).__init__() super(ListView, self).__init__()
self.view = self self.view = self
self._has_initialised = False self._has_initialised = False
self.show_policy = ListShowingPolicy(self) self.show_policy = ListShowingPolicy(self)
def initialise(self, source): def initialise(self, source):
if self._has_initialised: if self._has_initialised:
return return
self._has_initialised = True self._has_initialised = True
self.view_name = "list_view" self.view_name = "list_view"
super(ListView, self).initialise(source) super(ListView, self).initialise(source)
#self.album_manager = source.album_manager #self.album_manager = source.album_manager
self.shell = source.shell self.shell = source.shell
def switch_to_view(self, source, album): def switch_to_view(self, source, album):
self.initialise(source) self.initialise(source)
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.library_source) self.shell.props.library_source)
def get_selected_objects(self): def get_selected_objects(self):
''' '''
finds what has been selected finds what has been selected
+115 -114
Ver Arquivo
@@ -28,14 +28,15 @@ import random
LOAD_CHUNK = 50 LOAD_CHUNK = 50
class WebPlaylist(object): class WebPlaylist(object):
MAX_TRACKS_TO_ADD = 3 # number of tracks to add to a source for each fetch MAX_TRACKS_TO_ADD = 3 # number of tracks to add to a source for each fetch
MIN_TRACKS_TO_FETCH = 5 # number of tracks in source before a fetch will be required MIN_TRACKS_TO_FETCH = 5 # number of tracks in source before a fetch will be required
TOTAL_TRACKS_REMEMBERED = 25 # total number of tracks for all artists before a fetch is allowed TOTAL_TRACKS_REMEMBERED = 25 # total number of tracks for all artists before a fetch is allowed
MAX_TRACKS_PER_ARTIST = 3 # number of tracks allowed to be remembered per artist MAX_TRACKS_PER_ARTIST = 3 # number of tracks allowed to be remembered per artist
def __init__(self, shell, source, playlist_name): def __init__(self, shell, source, playlist_name):
self.shell = shell self.shell = shell
#lets fill up the queue with artists #lets fill up the queue with artists
self.candidate_artist = {} self.candidate_artist = {}
@@ -47,54 +48,54 @@ class WebPlaylist(object):
self.tracks_not_played = 0 self.tracks_not_played = 0
# cache for artist information: valid for a month, can be used indefinitely # cache for artist information: valid for a month, can be used indefinitely
# if offline, discarded if unused for six months # if offline, discarded if unused for six months
self.info_cache = rb.URLCache(name = playlist_name, self.info_cache = rb.URLCache(name=playlist_name,
path = os.path.join('coverart_browser', playlist_name), path=os.path.join('coverart_browser', playlist_name),
refresh = 30, refresh=30,
discard = 180) discard=180)
self.info_cache.clean() self.info_cache.clean()
def playing_song_changed(self, player, entry): def playing_song_changed(self, player, entry):
if not entry: if not entry:
return return
if player.get_playing_source() != self.source: if player.get_playing_source() != self.source:
self.playlist_started = False self.playlist_started = False
self.played_artist.clear() self.played_artist.clear()
self.tracks_not_played = 0 self.tracks_not_played = 0
if self.playlist_started and len(self.source.props.query_model) < self.MIN_TRACKS_TO_FETCH: if self.playlist_started and len(self.source.props.query_model) < self.MIN_TRACKS_TO_FETCH:
self.start(entry) self.start(entry)
def start(self, seed_entry, reinitialise = False): def start(self, seed_entry, reinitialise=False):
artist = seed_entry.get_string(RB.RhythmDBPropType.ARTIST) artist = seed_entry.get_string(RB.RhythmDBPropType.ARTIST)
if reinitialise: if reinitialise:
self.played_artist.clear() self.played_artist.clear()
self.tracks_not_played = 0 self.tracks_not_played = 0
self.playlist_started = False self.playlist_started = False
player = self.shell.props.shell_player player = self.shell.props.shell_player
_, is_playing = player.get_playing() _, is_playing = player.get_playing()
if is_playing: if is_playing:
player.stop() player.stop()
for row in self.source.props.query_model: for row in self.source.props.query_model:
self.source.props.query_model.remove_entry(row[0]) self.source.props.query_model.remove_entry(row[0])
if self.tracks_not_played > self.TOTAL_TRACKS_REMEMBERED: if self.tracks_not_played > self.TOTAL_TRACKS_REMEMBERED:
print(("we have plenty of tracks to play yet - no need to fetch more %d", self.tracks_not_played)) print(("we have plenty of tracks to play yet - no need to fetch more %d", self.tracks_not_played))
self.add_tracks_to_source() self.add_tracks_to_source()
return return
search_artist = urllib.parse.quote(artist.encode("utf8")) search_artist = urllib.parse.quote(artist.encode("utf8"))
if search_artist in self.played_artist: if search_artist in self.played_artist:
print ("we have already searched for that artist") print("we have already searched for that artist")
return return
self.search_entry = seed_entry self.search_entry = seed_entry
self.played_artist[search_artist] = True self.played_artist[search_artist] = True
self.playlist_started = True self.playlist_started = True
self._running = False self._running = False
self._start_process() self._start_process()
@@ -103,14 +104,14 @@ class WebPlaylist(object):
if not self._running: if not self._running:
self._running = True self._running = True
self.search_website() self.search_website()
def search_website(self): def search_website(self):
pass pass
def _clear_next(self): def _clear_next(self):
self.search_artists = "" self.search_artists = ""
self._running = False self._running = False
@idle_iterator @idle_iterator
def _load_albums(self): def _load_albums(self):
def process(row, data): def process(row, data):
@@ -120,8 +121,8 @@ class WebPlaylist(object):
lookup_title = entry.get_string(RB.RhythmDBPropType.TITLE_FOLDED) lookup_title = entry.get_string(RB.RhythmDBPropType.TITLE_FOLDED)
if lookup in self.artist and \ if lookup in self.artist and \
lookup_title in \ lookup_title in \
self.artist[lookup]: self.artist[lookup]:
if lookup not in self.candidate_artist: if lookup not in self.candidate_artist:
self.candidate_artist[lookup] = [] self.candidate_artist[lookup] = []
@@ -129,16 +130,16 @@ class WebPlaylist(object):
# N.B. every artist has an array of dicts with a known format of track & add-to-source elements # N.B. every artist has an array of dicts with a known format of track & add-to-source elements
# the following extracts the track-title and add-to-source to form a dict of track-title and a value # the following extracts the track-title and add-to-source to form a dict of track-title and a value
# of the add-to-source # of the add-to-source
d=dict((i['track-title'], i['add-to-source']) for i in self.candidate_artist[lookup]) d = dict((i['track-title'], i['add-to-source']) for i in self.candidate_artist[lookup])
if len(d) < self.MAX_TRACKS_PER_ARTIST and lookup_title not in d: if len(d) < self.MAX_TRACKS_PER_ARTIST and lookup_title not in d:
# we only append a max of three tracks to each artist # we only append a max of three tracks to each artist
self.candidate_artist[lookup].append({ self.candidate_artist[lookup].append({
'track':entry, 'track': entry,
'add-to-source':False, 'add-to-source': False,
'track-title':lookup_title}) 'track-title': lookup_title})
self.tracks_not_played = self.tracks_not_played + 1 self.tracks_not_played = self.tracks_not_played + 1
def after(data): def after(data):
# update the progress # update the progress
pass pass
@@ -147,40 +148,40 @@ class WebPlaylist(object):
print(('Error processing entries: ' + str(exception))) print(('Error processing entries: ' + str(exception)))
def finish(data): def finish(data):
self.add_tracks_to_source() self.add_tracks_to_source()
self._clear_next() self._clear_next()
return LOAD_CHUNK, process, after, error, finish return LOAD_CHUNK, process, after, error, finish
def display_error_message(self): def display_error_message(self):
dialog = Gtk.MessageDialog(None, dialog = Gtk.MessageDialog(None,
Gtk.DialogFlags.MODAL, Gtk.DialogFlags.MODAL,
Gtk.MessageType.INFO, Gtk.MessageType.INFO,
Gtk.ButtonsType.OK, Gtk.ButtonsType.OK,
_("No matching tracks have been found")) _("No matching tracks have been found"))
dialog.run() dialog.run()
dialog.destroy() dialog.destroy()
def add_tracks_to_source(self): def add_tracks_to_source(self):
entries = [] entries = []
for artist in self.candidate_artist: for artist in self.candidate_artist:
d=dict((i['track'], (self.candidate_artist[artist].index(i), d = dict((i['track'], (self.candidate_artist[artist].index(i),
i['add-to-source'], i['add-to-source'],
artist)) for i in self.candidate_artist[artist]) artist)) for i in self.candidate_artist[artist])
for entry, elements in d.items(): for entry, elements in d.items():
element_pos, add_to_source, artist = elements element_pos, add_to_source, artist = elements
if not add_to_source: if not add_to_source:
entries.append({entry: elements}) entries.append({entry: elements})
random.shuffle(entries) random.shuffle(entries)
count = 0 count = 0
for row in entries: for row in entries:
print (row) print(row)
entry, elements = list(row.items())[0] entry, elements = list(row.items())[0]
element_pos, add_to_source, artist = elements element_pos, add_to_source, artist = elements
self.source.add_entry(entry, -1) self.source.add_entry(entry, -1)
@@ -190,24 +191,24 @@ class WebPlaylist(object):
self.tracks_not_played = self.tracks_not_played - 1 self.tracks_not_played = self.tracks_not_played - 1
if count == self.MAX_TRACKS_TO_ADD: if count == self.MAX_TRACKS_TO_ADD:
break break
player = self.shell.props.shell_player player = self.shell.props.shell_player
_, is_playing = player.get_playing() _, is_playing = player.get_playing()
if len(self.source.props.query_model) > 0 and not is_playing: if len(self.source.props.query_model) > 0 and not is_playing:
player.play_entry(self.source.props.query_model[0][0], self.source) player.play_entry(self.source.props.query_model[0][0], self.source)
class LastFMTrackPlaylist(WebPlaylist): class LastFMTrackPlaylist(WebPlaylist):
def __init__(self, shell, source): def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "lastfm_trackplaylist") WebPlaylist.__init__(self, shell, source, "lastfm_trackplaylist")
def search_website(self): def search_website(self):
# unless already cached - directly fetch from lastfm similar track information # unless already cached - directly fetch from lastfm similar track information
apikey = "844353bce568b93accd9ca47674d6c3e" apikey = "844353bce568b93accd9ca47674d6c3e"
url = "http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&api_key={0}&artist={1}&track={2}&format=json" url = "http://ws.audioscrobbler.com/2.0/?method=track.getsimilar&api_key={0}&artist={1}&track={2}&format=json"
artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST) artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST)
title = self.search_entry.get_string(RB.RhythmDBPropType.TITLE) title = self.search_entry.get_string(RB.RhythmDBPropType.TITLE)
artist = urllib.parse.quote(artist.encode("utf8")) artist = urllib.parse.quote(artist.encode("utf8"))
@@ -216,25 +217,25 @@ class LastFMTrackPlaylist(WebPlaylist):
artist, artist,
title) title)
print (formatted_url) print(formatted_url)
cachekey = "artist:%s:title:%s" % (artist, title) cachekey = "artist:%s:title:%s" % (artist, title)
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None) self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _): def similar_info_cb(self, data, _):
if not data: if not data:
print ("nothing to do") print("nothing to do")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
similar = json.loads(data.decode('utf-8')) similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned # loop through the response and find all titles for the artists returned
self.artist = {} self.artist = {}
if 'similartracks' not in similar: if 'similartracks' not in similar:
print ("No matching data returned from LastFM") print("No matching data returned from LastFM")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
@@ -242,56 +243,56 @@ class LastFMTrackPlaylist(WebPlaylist):
name = RB.search_fold(song['artist']['name']) name = RB.search_fold(song['artist']['name'])
if name not in self.artist: if name not in self.artist:
self.artist[name] = [] self.artist[name] = []
self.artist[name].append(RB.search_fold(song['name'])) self.artist[name].append(RB.search_fold(song['name']))
if len(self.artist) == 0: if len(self.artist) == 0:
print ("no artists returned") print("no artists returned")
self._clear_next() self._clear_next()
return return
# loop through every track - see if the track contains the artist & title # loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember # if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model, self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.) total=len(query_model), progress=0.)
class EchoNestPlaylist(WebPlaylist): class EchoNestPlaylist(WebPlaylist):
def __init__(self, shell, source): def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "echonest_playlist") WebPlaylist.__init__(self, shell, source, "echonest_playlist")
def search_website(self): def search_website(self):
# unless already cached - directly fetch from echonest similar artist information # unless already cached - directly fetch from echonest similar artist information
apikey = "N685TONJGZSHBDZMP" apikey = "N685TONJGZSHBDZMP"
url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&artist={1}&format=json&results=100&type=artist-radio&limited_interactivity=true" url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&artist={1}&format=json&results=100&type=artist-radio&limited_interactivity=true"
artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST) artist = self.search_entry.get_string(RB.RhythmDBPropType.ARTIST)
artist = urllib.parse.quote(artist.encode("utf8")) artist = urllib.parse.quote(artist.encode("utf8"))
formatted_url = url.format(urllib.parse.quote(apikey), formatted_url = url.format(urllib.parse.quote(apikey),
artist) artist)
print (formatted_url) print(formatted_url)
cachekey = "artist:%s" % artist cachekey = "artist:%s" % artist
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None) self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _): def similar_info_cb(self, data, _):
if not data: if not data:
print ("nothing to do") print("nothing to do")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
similar = json.loads(data.decode('utf-8')) similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned # loop through the response and find all titles for the artists returned
self.artist = {} self.artist = {}
if 'songs' not in similar['response']: if 'songs' not in similar['response']:
print ("No matching data returned from EchoNest") print("No matching data returned from EchoNest")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
@@ -299,56 +300,56 @@ class EchoNestPlaylist(WebPlaylist):
name = RB.search_fold(song['artist_name']) name = RB.search_fold(song['artist_name'])
if name not in self.artist: if name not in self.artist:
self.artist[name] = [] self.artist[name] = []
self.artist[name].append(RB.search_fold(song['title'])) self.artist[name].append(RB.search_fold(song['title']))
if len(self.artist) == 0: if len(self.artist) == 0:
print ("no artists returned") print("no artists returned")
self._clear_next() self._clear_next()
return return
# loop through every track - see if the track contains the artist & title # loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember # if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model, self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.) total=len(query_model), progress=0.)
class EchoNestGenrePlaylist(WebPlaylist): class EchoNestGenrePlaylist(WebPlaylist):
def __init__(self, shell, source): def __init__(self, shell, source):
WebPlaylist.__init__(self, shell, source, "echonest_genre_playlist") WebPlaylist.__init__(self, shell, source, "echonest_genre_playlist")
def search_website(self): def search_website(self):
# unless already cached - directly fetch from echonest similar artist information # unless already cached - directly fetch from echonest similar artist information
apikey = "N685TONJGZSHBDZMP" apikey = "N685TONJGZSHBDZMP"
url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&genre={1}&format=json&results=100&type=genre-radio&limited_interactivity=true" url = "http://developer.echonest.com/api/v4/playlist/basic?api_key={0}&genre={1}&format=json&results=100&type=genre-radio&limited_interactivity=true"
genre = self.search_entry.get_string(RB.RhythmDBPropType.GENRE).lower() genre = self.search_entry.get_string(RB.RhythmDBPropType.GENRE).lower()
genre = urllib.parse.quote(genre.encode("utf8")) genre = urllib.parse.quote(genre.encode("utf8"))
formatted_url = url.format(urllib.parse.quote(apikey), formatted_url = url.format(urllib.parse.quote(apikey),
genre) genre)
print (formatted_url) print(formatted_url)
cachekey = "genre:%s" % genre cachekey = "genre:%s" % genre
self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None) self.info_cache.fetch(cachekey, formatted_url, self.similar_info_cb, None)
def similar_info_cb(self, data, _): def similar_info_cb(self, data, _):
if not data: if not data:
print ("nothing to do") print("nothing to do")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
similar = json.loads(data.decode('utf-8')) similar = json.loads(data.decode('utf-8'))
# loop through the response and find all titles for the artists returned # loop through the response and find all titles for the artists returned
self.artist = {} self.artist = {}
if 'songs' not in similar['response']: if 'songs' not in similar['response']:
print ("No matching data returned from EchoNest") print("No matching data returned from EchoNest")
self.display_error_message() self.display_error_message()
self._clear_next() self._clear_next()
return return
@@ -356,18 +357,18 @@ class EchoNestGenrePlaylist(WebPlaylist):
name = RB.search_fold(song['artist_name']) name = RB.search_fold(song['artist_name'])
if name not in self.artist: if name not in self.artist:
self.artist[name] = [] self.artist[name] = []
self.artist[name].append(RB.search_fold(song['title'])) self.artist[name].append(RB.search_fold(song['title']))
if len(self.artist) == 0: if len(self.artist) == 0:
print ("no artists returned") print("no artists returned")
self._clear_next() self._clear_next()
return return
# loop through every track - see if the track contains the artist & title # loop through every track - see if the track contains the artist & title
# if yes then this is a candidate similar track to remember # if yes then this is a candidate similar track to remember
query_model = self.shell.props.library_source.props.base_query_model query_model = self.shell.props.library_source.props.base_query_model
self._load_albums(iter(query_model), albums={}, model=query_model, self._load_albums(iter(query_model), albums={}, model=query_model,
total=len(query_model), progress=0.) total=len(query_model), progress=0.)
+11 -10
Ver Arquivo
@@ -21,6 +21,7 @@ from coverart_widgets import AbstractView
from gi.repository import GObject from gi.repository import GObject
from gi.repository import GLib from gi.repository import GLib
class QueueShowingPolicy(GObject.Object): class QueueShowingPolicy(GObject.Object):
''' '''
Policy that mostly takes care of how and when things should be showed on Policy that mostly takes care of how and when things should be showed on
@@ -38,37 +39,37 @@ class QueueShowingPolicy(GObject.Object):
return return
self._has_initialised = True self._has_initialised = True
class QueueView(AbstractView): class QueueView(AbstractView):
__gtype_name__ = "QueueView" __gtype_name__ = "QueueView"
name = 'queueview' name = 'queueview'
use_plugin_window = False use_plugin_window = False
def __init__(self): def __init__(self):
super(QueueView, self).__init__() super(QueueView, self).__init__()
self.view = self self.view = self
self._has_initialised = False self._has_initialised = False
self.show_policy = QueueShowingPolicy(self) self.show_policy = QueueShowingPolicy(self)
def initialise(self, source): def initialise(self, source):
if self._has_initialised: if self._has_initialised:
return return
self._has_initialised = True self._has_initialised = True
self.view_name = "queue_view" self.view_name = "queue_view"
super(QueueView, self).initialise(source) super(QueueView, self).initialise(source)
#self.album_manager = source.album_manager #self.album_manager = source.album_manager
self.shell = source.shell self.shell = source.shell
def switch_to_view(self, source, album): def switch_to_view(self, source, album):
self.initialise(source) self.initialise(source)
GLib.idle_add(self.shell.props.display_page_tree.select, GLib.idle_add(self.shell.props.display_page_tree.select,
self.shell.props.queue_source) self.shell.props.queue_source)
def get_selected_objects(self): def get_selected_objects(self):
''' '''
finds what has been selected finds what has been selected
+158 -138
Ver Arquivo
@@ -31,37 +31,40 @@ import sys
import rb import rb
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
def pygobject_version(): def pygobject_version():
''' '''
returns float of the major and minor parts of a pygobject version returns float of the major and minor parts of a pygobject version
e.g. version (3, 9, 5) return float(3.9) e.g. version (3, 9, 5) return float(3.9)
''' '''
to_number = lambda t: ".".join(str(v) for v in t) to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version) str_version = to_number(GObject.pygobject_version)
return float(str_version.rsplit('.',1)[0]) return float(str_version.rsplit('.', 1)[0])
def compare_pygobject_version(version): def compare_pygobject_version(version):
''' '''
return True if version is less than pygobject_version return True if version is less than pygobject_version
i.e. 3.9 < 3.11 i.e. 3.9 < 3.11
''' '''
to_number = lambda t: ".".join(str(v) for v in t) to_number = lambda t: ".".join(str(v) for v in t)
str_version = to_number(GObject.pygobject_version) str_version = to_number(GObject.pygobject_version)
split = str_version.rsplit('.',2) split = str_version.rsplit('.', 2)
split_compare = version.rsplit('.',2) split_compare = version.rsplit('.', 2)
if int(split_compare[0])<int(split[0]): if int(split_compare[0]) < int(split[0]):
return True return True
if int(split_compare[1])<int(split[1]): if int(split_compare[1]) < int(split[1]):
return True return True
return False return False
PYVER = sys.version_info[0] PYVER = sys.version_info[0]
if PYVER >= 3: if PYVER >= 3:
@@ -74,65 +77,75 @@ if PYVER >= 3:
import http.client import http.client
else: else:
import httplib import httplib
def responses(): def responses():
if PYVER >=3: if PYVER >= 3:
return http.client.responses return http.client.responses
else: else:
return httplib.responses return httplib.responses
def unicodestr(param, charset): def unicodestr(param, charset):
if PYVER >=3: if PYVER >= 3:
return param#str(param, charset) return param #str(param, charset)
else: else:
return unicode(param, charset) return unicode(param, charset)
def unicodeencode(param, charset): def unicodeencode(param, charset):
if PYVER >=3: if PYVER >= 3:
return param#str(param).encode(charset) return param #str(param).encode(charset)
else: else:
return unicode(param).encode(charset) return unicode(param).encode(charset)
def unicodedecode(param, charset): def unicodedecode(param, charset):
if PYVER >=3: if PYVER >= 3:
return param return param
else: else:
return param.decode(charset) return param.decode(charset)
def urlparse(uri): def urlparse(uri):
if PYVER >=3: if PYVER >= 3:
return urllib.parse.urlparse(uri) return urllib.parse.urlparse(uri)
else: else:
return rb2urlparse(uri) return rb2urlparse(uri)
def url2pathname(url): def url2pathname(url):
if PYVER >=3: if PYVER >= 3:
return urllib.request.url2pathname(url) return urllib.request.url2pathname(url)
else: else:
return urllib.url2pathname(url) return urllib.url2pathname(url)
def urlopen(filename): def urlopen(filename):
if PYVER >=3: if PYVER >= 3:
return urllib.request.urlopen(filename) return urllib.request.urlopen(filename)
else: else:
return urllib.urlopen(filename) return urllib.urlopen(filename)
def pathname2url(filename): def pathname2url(filename):
if PYVER >=3: if PYVER >= 3:
return urllib.request.pathname2url(filename) return urllib.request.pathname2url(filename)
else: else:
return urllib.pathname2url(filename) return urllib.pathname2url(filename)
def unquote(uri): def unquote(uri):
if PYVER >=3: if PYVER >= 3:
return urllib.parse.unquote(uri) return urllib.parse.unquote(uri)
else: else:
return urllib.unquote(uri) return urllib.unquote(uri)
def quote(uri, safe=None): def quote(uri, safe=None):
if PYVER >=3: if PYVER >= 3:
if safe: if safe:
return urllib.parse.quote(uri,safe=safe) return urllib.parse.quote(uri, safe=safe)
else: else:
return urllib.parse.quote(uri) return urllib.parse.quote(uri)
else: else:
@@ -140,27 +153,30 @@ def quote(uri, safe=None):
return urllib.quote(uri, safe=safe) return urllib.quote(uri, safe=safe)
else: else:
return urllib.quote(uri) return urllib.quote(uri)
def quote_plus(uri): def quote_plus(uri):
if PYVER >=3: if PYVER >= 3:
return urllib.parse.quote_plus(uri) return urllib.parse.quote_plus(uri)
else: else:
return urllib.quote_plus(uri) return urllib.quote_plus(uri)
def is_rb3(*args): def is_rb3(*args):
if hasattr(RB.Shell.props, 'ui_manager'): if hasattr(RB.Shell.props, 'ui_manager'):
return False return False
else: else:
return True return True
class Menu(GObject.Object): class Menu(GObject.Object):
''' '''
Menu object used to create window popup menus Menu object used to create window popup menus
''' '''
__gsignals__ = { __gsignals__ = {
'pre-popup': (GObject.SIGNAL_RUN_LAST, None, ()) 'pre-popup': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self, plugin, shell): def __init__(self, plugin, shell):
''' '''
Initializes the menu. Initializes the menu.
@@ -169,10 +185,10 @@ class Menu(GObject.Object):
self.plugin = plugin self.plugin = plugin
self.shell = shell self.shell = shell
self._unique_num = 0 self._unique_num = 0
self._rbmenu_items = {} self._rbmenu_items = {}
self._rbmenu_objects = {} self._rbmenu_objects = {}
def add_menu_item(self, menubar, section_name, action): def add_menu_item(self, menubar, section_name, action):
''' '''
add a new menu item to the popup add a new menu item to the popup
@@ -191,7 +207,7 @@ class Menu(GObject.Object):
:param action: `Action` to associate with the menu item :param action: `Action` to associate with the menu item
''' '''
label = action.label label = action.label
if is_rb3(self.shell): if is_rb3(self.shell):
app = self.shell.props.application app = self.shell.props.application
item = Gio.MenuItem() item = Gio.MenuItem()
@@ -201,14 +217,14 @@ class Menu(GObject.Object):
if not section_name in self._rbmenu_items: if not section_name in self._rbmenu_items:
self._rbmenu_items[section_name] = [] self._rbmenu_items[section_name] = []
self._rbmenu_items[section_name].append(label) self._rbmenu_items[section_name].append(label)
app.add_plugin_menu_item(section_name, label, item) app.add_plugin_menu_item(section_name, label, item)
else: else:
item = Gtk.MenuItem(label=label) item = Gtk.MenuItem(label=label)
action.associate_menuitem(item) action.associate_menuitem(item)
self._rbmenu_items[label] = item self._rbmenu_items[label] = item
bar = self.get_menu_object(menubar) bar = self.get_menu_object(menubar)
if position == -1: if position == -1:
bar.append(item) bar.append(item)
else: else:
@@ -245,15 +261,15 @@ class Menu(GObject.Object):
if is_rb3(self.shell): if is_rb3(self.shell):
if not section_name in self._rbmenu_items: if not section_name in self._rbmenu_items:
return return
app = self.shell.props.application app = self.shell.props.application
for menu_item in self._rbmenu_items[section_name]: for menu_item in self._rbmenu_items[section_name]:
app.remove_plugin_menu_item(section_name, menu_item) app.remove_plugin_menu_item(section_name, menu_item)
if self._rbmenu_items[section_name]: if self._rbmenu_items[section_name]:
del self._rbmenu_items[section_name][:] del self._rbmenu_items[section_name][:]
else: else:
if not self._rbmenu_items: if not self._rbmenu_items:
@@ -267,8 +283,8 @@ class Menu(GObject.Object):
bar.show_all() bar.show_all()
uim.ensure_update() uim.ensure_update()
def load_from_file(self, rb2_ui_filename, rb3_ui_filename ): def load_from_file(self, rb2_ui_filename, rb3_ui_filename):
''' '''
utility function to load the menu structure utility function to load the menu structure
:param rb2_ui_filename: `str` RB2.98 and below UI file :param rb2_ui_filename: `str` RB2.98 and below UI file
@@ -277,21 +293,22 @@ class Menu(GObject.Object):
self.builder = Gtk.Builder() self.builder = Gtk.Builder()
try: try:
from coverart_browser_prefs import CoverLocale from coverart_browser_prefs import CoverLocale
cl = CoverLocale() cl = CoverLocale()
self.builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN) self.builder.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
except: except:
pass pass
if is_rb3(self.shell): if is_rb3(self.shell):
ui_filename = rb3_ui_filename ui_filename = rb3_ui_filename
else: else:
ui_filename = rb2_ui_filename ui_filename = rb2_ui_filename
self.ui_filename = ui_filename self.ui_filename = ui_filename
self.builder.add_from_file(rb.find_plugin_file(self.plugin, self.builder.add_from_file(rb.find_plugin_file(self.plugin,
ui_filename)) ui_filename))
def _connect_rb3_signals(self, signals): def _connect_rb3_signals(self, signals):
def _menu_connect(action_name, func): def _menu_connect(action_name, func):
@@ -299,29 +316,29 @@ class Menu(GObject.Object):
action.connect('activate', func) action.connect('activate', func)
action.set_enabled(True) action.set_enabled(True)
self.shell.props.window.add_action(action) self.shell.props.window.add_action(action)
for key,value in signals.items(): for key, value in signals.items():
_menu_connect( key, value) _menu_connect(key, value)
def _connect_rb2_signals(self, signals): def _connect_rb2_signals(self, signals):
def _menu_connect(menu_item_name, func): def _menu_connect(menu_item_name, func):
menu_item = self.get_menu_object(menu_item_name) menu_item = self.get_menu_object(menu_item_name)
menu_item.connect('activate', func) menu_item.connect('activate', func)
for key,value in signals.items(): for key, value in signals.items():
_menu_connect( key, value) _menu_connect(key, value)
def connect_signals(self, signals): def connect_signals(self, signals):
''' '''
connect all signal handlers with their menuitem counterparts connect all signal handlers with their menuitem counterparts
:param signals: `dict` key is the name of the menuitem :param signals: `dict` key is the name of the menuitem
and value is the function callback when the menu is activated and value is the function callback when the menu is activated
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
self._connect_rb3_signals(signals) self._connect_rb3_signals(signals)
else: else:
self._connect_rb2_signals(signals) self._connect_rb2_signals(signals)
def get_gtkmenu(self, source, popup_name): def get_gtkmenu(self, source, popup_name):
''' '''
utility function to obtain the GtkMenu from the menu UI file utility function to obtain the GtkMenu from the menu UI file
@@ -330,7 +347,7 @@ class Menu(GObject.Object):
if popup_name in self._rbmenu_objects: if popup_name in self._rbmenu_objects:
return self._rbmenu_objects[popup_name] return self._rbmenu_objects[popup_name]
item = self.builder.get_object(popup_name) item = self.builder.get_object(popup_name)
if is_rb3(self.shell): if is_rb3(self.shell):
app = self.shell.props.application app = self.shell.props.application
app.link_shared_menus(item) app.link_shared_menus(item)
@@ -338,11 +355,11 @@ class Menu(GObject.Object):
popup_menu.attach_to_widget(source, None) popup_menu.attach_to_widget(source, None)
else: else:
popup_menu = item popup_menu = item
self._rbmenu_objects[popup_name] = popup_menu self._rbmenu_objects[popup_name] = popup_menu
return popup_menu return popup_menu
def get_menu_object(self, menu_name_or_link): def get_menu_object(self, menu_name_or_link):
''' '''
utility function returns the GtkMenuItem/Gio.MenuItem utility function returns the GtkMenuItem/Gio.MenuItem
@@ -359,9 +376,9 @@ class Menu(GObject.Object):
popup_menu = app.get_plugin_menu(menu_name_or_link) popup_menu = app.get_plugin_menu(menu_name_or_link)
else: else:
popup_menu = item popup_menu = item
print (menu_name_or_link) print(menu_name_or_link)
self._rbmenu_objects[menu_name_or_link] = popup_menu self._rbmenu_objects[menu_name_or_link] = popup_menu
return popup_menu return popup_menu
def set_sensitive(self, menu_or_action_item, enable): def set_sensitive(self, menu_or_action_item, enable):
@@ -371,14 +388,14 @@ class Menu(GObject.Object):
that is to be enabled/disabled that is to be enabled/disabled
:param enable: `bool` value to enable/disable :param enable: `bool` value to enable/disable
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
item = self.shell.props.window.lookup_action(menu_or_action_item) item = self.shell.props.window.lookup_action(menu_or_action_item)
item.set_enabled(enable) item.set_enabled(enable)
else: else:
item = self.get_menu_object(menu_or_action_item) item = self.get_menu_object(menu_or_action_item)
item.set_sensitive(enable) item.set_sensitive(enable)
def popup(self, source, menu_name, button, time): def popup(self, source, menu_name, button, time):
''' '''
utility function to show the popup menu utility function to show the popup menu
@@ -386,16 +403,17 @@ class Menu(GObject.Object):
self.emit('pre-popup') self.emit('pre-popup')
menu = self.get_gtkmenu(source, menu_name) menu = self.get_gtkmenu(source, menu_name)
menu.popup(None, None, None, None, button, time) menu.popup(None, None, None, None, button, time)
class ActionGroup(object): class ActionGroup(object):
''' '''
container for all Actions used to associate with menu items container for all Actions used to associate with menu items
''' '''
# action_state # action_state
STANDARD=0 STANDARD = 0
TOGGLE=1 TOGGLE = 1
def __init__(self, shell, group_name): def __init__(self, shell, group_name):
''' '''
constructor constructor
@@ -404,12 +422,12 @@ class ActionGroup(object):
''' '''
self.group_name = group_name self.group_name = group_name
self.shell = shell self.shell = shell
self._actions = {} self._actions = {}
if is_rb3(self.shell): if is_rb3(self.shell):
self.actiongroup = Gio.SimpleActionGroup() self.actiongroup = Gio.SimpleActionGroup()
else: else:
self.actiongroup = Gtk.ActionGroup(group_name) self.actiongroup = Gtk.ActionGroup(group_name)
uim = self.shell.props.ui_manager uim = self.shell.props.ui_manager
uim.insert_action_group(self.actiongroup) uim.insert_action_group(self.actiongroup)
@@ -417,14 +435,14 @@ class ActionGroup(object):
@property @property
def name(self): def name(self):
return self.group_name return self.group_name
def remove_actions(self): def remove_actions(self):
''' '''
utility function to remove all actions associated with the ActionGroup utility function to remove all actions associated with the ActionGroup
''' '''
for action in self.actiongroup.list_actions(): for action in self.actiongroup.list_actions():
self.actiongroup.remove_action(action) self.actiongroup.remove_action(action)
def get_action(self, action_name): def get_action(self, action_name):
''' '''
utility function to obtain the Action from the ActionGroup utility function to obtain the Action from the ActionGroup
@@ -447,8 +465,8 @@ class ActionGroup(object):
''' '''
args['accel'] = accel args['accel'] = accel
return self.add_action(func, action_name, **args) return self.add_action(func, action_name, **args)
def add_action(self, func, action_name, **args ): def add_action(self, func, action_name, **args):
''' '''
Creates an Action and adds it to the ActionGroup Creates an Action and adds it to the ActionGroup
@@ -465,21 +483,21 @@ class ActionGroup(object):
if 'label' in args: if 'label' in args:
label = args['label'] label = args['label']
else: else:
label=action_name label = action_name
if 'accel' in args: if 'accel' in args:
accel = args['accel'] accel = args['accel']
else: else:
accel = None accel = None
state = ActionGroup.STANDARD state = ActionGroup.STANDARD
if 'action_state' in args: if 'action_state' in args:
state = args['action_state'] state = args['action_state']
if is_rb3(self.shell): if is_rb3(self.shell):
if state == ActionGroup.TOGGLE: if state == ActionGroup.TOGGLE:
action = Gio.SimpleAction.new_stateful(action_name, None, action = Gio.SimpleAction.new_stateful(action_name, None,
GLib.Variant('b', False)) GLib.Variant('b', False))
else: else:
action = Gio.SimpleAction.new(action_name, None) action = Gio.SimpleAction.new(action_name, None)
@@ -489,7 +507,7 @@ class ActionGroup(object):
action_type = 'app' action_type = 'app'
app = Gio.Application.get_default() app = Gio.Application.get_default()
if action_type == 'app': if action_type == 'app':
app.add_action(action) app.add_action(action)
else: else:
@@ -497,56 +515,58 @@ class ActionGroup(object):
self.actiongroup.add_action(action) self.actiongroup.add_action(action)
if accel: if accel:
app.add_accelerator(accel, action_type+"."+action_name, None) app.add_accelerator(accel, action_type + "." + action_name, None)
else: else:
if 'stock_id' in args: if 'stock_id' in args:
stock_id = args['stock_id'] stock_id = args['stock_id']
else: else:
stock_id = Gtk.STOCK_CLEAR stock_id = Gtk.STOCK_CLEAR
if state == ActionGroup.TOGGLE: if state == ActionGroup.TOGGLE:
action = Gtk.ToggleAction(label=label, action = Gtk.ToggleAction(label=label,
name=action_name, name=action_name,
tooltip='', stock_id=stock_id) tooltip='', stock_id=stock_id)
else: else:
action = Gtk.Action(label=label, action = Gtk.Action(label=label,
name=action_name, name=action_name,
tooltip='', stock_id=stock_id) tooltip='', stock_id=stock_id)
if accel: if accel:
self.actiongroup.add_action_with_accel(action, accel) self.actiongroup.add_action_with_accel(action, accel)
else: else:
self.actiongroup.add_action(action) self.actiongroup.add_action(action)
act = Action(self.shell, action) act = Action(self.shell, action)
act.connect('activate', func, args) act.connect('activate', func, args)
act.label = label act.label = label
act.accel = accel act.accel = accel
self._actions[action_name] = act self._actions[action_name] = act
return act return act
class ApplicationShell(object): class ApplicationShell(object):
''' '''
Unique class that mirrors RB.Application & RB.Shell menu functionality Unique class that mirrors RB.Application & RB.Shell menu functionality
''' '''
# storage for the instance reference # storage for the instance reference
__instance = None __instance = None
class __impl: class __impl:
""" Implementation of the singleton interface """ """ Implementation of the singleton interface """
def __init__(self, shell): def __init__(self, shell):
self.shell = shell self.shell = shell
if is_rb3(self.shell): if is_rb3(self.shell):
self._uids = {} self._uids = {}
else: else:
self._uids = [] self._uids = []
self._action_groups = {} self._action_groups = {}
def insert_action_group(self, action_group): def insert_action_group(self, action_group):
''' '''
Adds an ActionGroup to the ApplicationShell Adds an ActionGroup to the ApplicationShell
@@ -554,7 +574,7 @@ class ApplicationShell(object):
:param action_group: `ActionGroup` to add :param action_group: `ActionGroup` to add
''' '''
self._action_groups[action_group.name] = action_group self._action_groups[action_group.name] = action_group
def lookup_action(self, action_group_name, action_name, action_type='app'): def lookup_action(self, action_group_name, action_name, action_type='app'):
''' '''
looks up (finds) an action created by another plugin. If found returns looks up (finds) an action created by another plugin. If found returns
@@ -564,7 +584,7 @@ class ApplicationShell(object):
:param action_name: `str` unique name for the action to look for :param action_name: `str` unique name for the action to look for
:param action_type: `str` RB2.99+ action type ("win" or "app") :param action_type: `str` RB2.99+ action type ("win" or "app")
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
if action_type == "app": if action_type == "app":
action = self.shell.props.application.lookup_action(action_name) action = self.shell.props.application.lookup_action(action_name)
@@ -582,7 +602,7 @@ class ApplicationShell(object):
action = None action = None
if actiongroup: if actiongroup:
action = actiongroup.get_action(action_name) action = actiongroup.get_action(action_name)
if action: if action:
return Action(self.shell, action) return Action(self.shell, action)
else: else:
@@ -611,24 +631,24 @@ class ApplicationShell(object):
for elem in root.findall(".//menuitem"): for elem in root.findall(".//menuitem"):
action_name = elem.attrib['action'] action_name = elem.attrib['action']
item_name = elem.attrib['name'] item_name = elem.attrib['name']
group = self._action_groups[group_name] group = self._action_groups[group_name]
act = group.get_action(action_name) act = group.get_action(action_name)
item = Gio.MenuItem() item = Gio.MenuItem()
item.set_detailed_action('app.' + action_name) item.set_detailed_action('app.' + action_name)
item.set_label(act.label) item.set_label(act.label)
item.set_attribute_value("accel", GLib.Variant("s", act.accel)) item.set_attribute_value("accel", GLib.Variant("s", act.accel))
app = Gio.Application.get_default() app = Gio.Application.get_default()
index = menu+action_name index = menu + action_name
app.add_plugin_menu_item(menu, app.add_plugin_menu_item(menu,
index, item) index, item)
self._uids[index] = menu self._uids[index] = menu
else: else:
uim = self.shell.props.ui_manager uim = self.shell.props.ui_manager
self._uids.append(uim.add_ui_from_string(ui_string)) self._uids.append(uim.add_ui_from_string(ui_string))
uim.ensure_update() uim.ensure_update()
def add_browser_menuitems(self, ui_string, group_name): def add_browser_menuitems(self, ui_string, group_name):
''' '''
utility function to add popup menu items to existing browser popups utility function to add popup menu items to existing browser popups
@@ -648,19 +668,19 @@ class ApplicationShell(object):
root = ET.fromstring(ui_string) root = ET.fromstring(ui_string)
for elem in root.findall("./popup"): for elem in root.findall("./popup"):
popup_name = elem.attrib['name'] popup_name = elem.attrib['name']
menuelem = elem.find('.//menuitem') menuelem = elem.find('.//menuitem')
action_name = menuelem.attrib['action'] action_name = menuelem.attrib['action']
item_name = menuelem.attrib['name'] item_name = menuelem.attrib['name']
group = self._action_groups[group_name] group = self._action_groups[group_name]
act = group.get_action(action_name) act = group.get_action(action_name)
item = Gio.MenuItem() item = Gio.MenuItem()
item.set_detailed_action('win.' + action_name) item.set_detailed_action('win.' + action_name)
item.set_label(act.label) item.set_label(act.label)
app = Gio.Application.get_default() app = Gio.Application.get_default()
if popup_name == 'QueuePlaylistViewPopup': if popup_name == 'QueuePlaylistViewPopup':
plugin_type = 'queue-popup' plugin_type = 'queue-popup'
elif popup_name == 'BrowserSourceViewPopup': elif popup_name == 'BrowserSourceViewPopup':
@@ -670,11 +690,11 @@ class ApplicationShell(object):
elif popup_name == 'PodcastViewPopup': elif popup_name == 'PodcastViewPopup':
plugin_type = 'podcast-episode-popup' plugin_type = 'podcast-episode-popup'
else: else:
print ("unknown type %s" % plugin_type) print("unknown type %s" % plugin_type)
index = plugin_type+action_name index = plugin_type + action_name
app.add_plugin_menu_item(plugin_type, index, item) app.add_plugin_menu_item(plugin_type, index, item)
self._uids[index]=plugin_type self._uids[index] = plugin_type
else: else:
uim = self.shell.props.ui_manager uim = self.shell.props.ui_manager
self._uids.append(uim.add_ui_from_string(ui_string)) self._uids.append(uim.add_ui_from_string(ui_string))
@@ -686,9 +706,8 @@ class ApplicationShell(object):
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
for uid in self._uids: for uid in self._uids:
Gio.Application.get_default().remove_plugin_menu_item(self._uids[uid],
Gio.Application.get_default().remove_plugin_menu_item(self._uids[uid], uid)
uid)
else: else:
uim = self.shell.props.ui_manager uim = self.shell.props.ui_manager
for uid in self._uids: for uid in self._uids:
@@ -713,11 +732,12 @@ class ApplicationShell(object):
""" Delegate access to implementation """ """ Delegate access to implementation """
return setattr(self.__instance, attr, value) return setattr(self.__instance, attr, value)
class Action(object): class Action(object):
''' '''
class that wraps around either a Gio.Action or a Gtk.Action class that wraps around either a Gio.Action or a Gtk.Action
''' '''
def __init__(self, shell, action): def __init__(self, shell, action):
''' '''
constructor. constructor.
@@ -727,19 +747,19 @@ class Action(object):
''' '''
self.shell = shell self.shell = shell
self.action = action self.action = action
self._label = '' self._label = ''
self._accel = '' self._accel = ''
self._current_state = False self._current_state = False
self._do_update_state = True self._do_update_state = True
def connect(self, address, func, args): def connect(self, address, func, args):
self._connect_func = func self._connect_func = func
self._connect_args = args self._connect_args = args
if address == 'activate': if address == 'activate':
func = self._activate func = self._activate
if is_rb3(self.shell): if is_rb3(self.shell):
self.action.connect(address, func, args) self.action.connect(address, func, args)
else: else:
@@ -749,9 +769,9 @@ class Action(object):
if self._do_update_state: if self._do_update_state:
self._current_state = not self._current_state self._current_state = not self._current_state
self.set_state(self._current_state) self.set_state(self._current_state)
self._connect_func(action, None, self._connect_args) self._connect_func(action, None, self._connect_args)
@property @property
def label(self): def label(self):
''' '''
@@ -764,21 +784,21 @@ class Action(object):
return self.action.get_label() return self.action.get_label()
else: else:
return self._label return self._label
@label.setter @label.setter
def label(self, new_label): def label(self, new_label):
if not is_rb3(self.shell): if not is_rb3(self.shell):
self.action.set_label(new_label) self.action.set_label(new_label)
self._label = new_label self._label = new_label
@property @property
def accel(self): def accel(self):
''' '''
get the accelerator associated with the Action get the accelerator associated with the Action
''' '''
return self._accel return self._accel
@accel.setter @accel.setter
def accel(self, new_accelerator): def accel(self, new_accelerator):
if new_accelerator: if new_accelerator:
@@ -796,7 +816,7 @@ class Action(object):
return self.action.get_enabled() return self.action.get_enabled()
else: else:
return self.action.get_sensitive() return self.action.get_sensitive()
def set_state(self, value): def set_state(self, value):
''' '''
set the state of a stateful action - this is applicable only set the state of a stateful action - this is applicable only
@@ -813,7 +833,7 @@ class Action(object):
self.action.activate(None) self.action.activate(None)
else: else:
self.action.activate() self.action.activate()
def set_active(self, value): def set_active(self, value):
''' '''
activate or deactivate a stateful action signal activate or deactivate a stateful action signal
@@ -822,7 +842,7 @@ class Action(object):
:param value: `boolean` state value :param value: `boolean` state value
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
self.action.change_state(GLib.Variant('b', value)) self.action.change_state(GLib.Variant('b', value))
self._current_state = value self._current_state = value
@@ -831,7 +851,7 @@ class Action(object):
self._do_update_state = True self._do_update_state = True
else: else:
self.action.set_active(value) self.action.set_active(value)
def get_active(self): def get_active(self):
''' '''
get the state of the action get the state of the action
@@ -851,7 +871,7 @@ class Action(object):
''' '''
if is_rb3(self.shell): if is_rb3(self.shell):
menuitem.set_detailed_action('win.'+self.action.get_name()) menuitem.set_detailed_action('win.' + self.action.get_name())
else: else:
menuitem.set_related_action(self.action) menuitem.set_related_action(self.action)
+30 -27
Ver Arquivo
@@ -25,6 +25,7 @@ import coverart_rb3compat as rb3compat
from coverart_album import Album from coverart_album import Album
from coverart_browser_prefs import webkit_support from coverart_browser_prefs import webkit_support
class CoverSearchPane(Gtk.Box): class CoverSearchPane(Gtk.Box):
''' '''
This UI represents a pane where different covers can be presented This UI represents a pane where different covers can be presented
@@ -32,6 +33,7 @@ class CoverSearchPane(Gtk.Box):
customize the default search and select covers from the pane and use them customize the default search and select covers from the pane and use them
as the covers (either with a double click or dragging them). as the covers (either with a double click or dragging them).
''' '''
def __init__(self, plugin, selection_color): def __init__(self, plugin, selection_color):
''' '''
Initializes the pane, loading it's html templates and it's ui. Initializes the pane, loading it's html templates and it's ui.
@@ -54,26 +56,26 @@ class CoverSearchPane(Gtk.Box):
''' '''
Loads the templates and stylesheets to be used by the pane. Loads the templates and stylesheets to be used by the pane.
''' '''
# input_encoding='utf-8', # input_encoding='utf-8',
path = rb.find_plugin_file(plugin, path = rb.find_plugin_file(plugin,
'tmpl/albumartsearch-tmpl.html') 'tmpl/albumartsearch-tmpl.html')
self.template = Template(filename=path, self.template = Template(filename=path,
default_filters=['decode.utf8'], default_filters=['decode.utf8'],
module_directory='/tmp/', module_directory='/tmp/',
encoding_errors='replace') encoding_errors='replace')
path = rb.find_plugin_file(plugin, path = rb.find_plugin_file(plugin,
'tmpl/albumartsearchempty-tmpl.html') 'tmpl/albumartsearchempty-tmpl.html')
self.empty_template = Template(filename=path, self.empty_template = Template(filename=path,
default_filters=['decode.utf8'], default_filters=['decode.utf8'],
module_directory='/tmp/', module_directory='/tmp/',
encoding_errors='replace') encoding_errors='replace')
path = rb.find_plugin_file(plugin, path = rb.find_plugin_file(plugin,
'tmpl/artistartsearch-tmpl.html') 'tmpl/artistartsearch-tmpl.html')
self.artist_template = Template(filename=path, self.artist_template = Template(filename=path,
default_filters=['decode.utf8'], default_filters=['decode.utf8'],
module_directory='/tmp/', module_directory='/tmp/',
encoding_errors='replace') encoding_errors='replace')
self.styles = rb.find_plugin_file(plugin, 'tmpl/main.css') self.styles = rb.find_plugin_file(plugin, 'tmpl/main.css')
def init_gui(self): def init_gui(self):
@@ -82,6 +84,7 @@ class CoverSearchPane(Gtk.Box):
''' '''
#---- set up webkit pane -----# #---- set up webkit pane -----#
from gi.repository import WebKit from gi.repository import WebKit
self.webview = WebKit.WebView() self.webview = WebKit.WebView()
settings = self.webview.get_settings() settings = self.webview.get_settings()
settings.set_property('enable-default-context-menu', False) settings.set_property('enable-default-context-menu', False)
@@ -102,13 +105,13 @@ class CoverSearchPane(Gtk.Box):
of the album or artist passed. of the album or artist passed.
''' '''
print ("coverart-search do_search") print("coverart-search do_search")
if coverobject is self.current_searchobject: if coverobject is self.current_searchobject:
return return
self.current_searchobject = coverobject self.current_searchobject = coverobject
self.callback = callback self.callback = callback
if isinstance(coverobject, Album): if isinstance(coverobject, Album):
artist = coverobject.artist artist = coverobject.artist
album_name = coverobject.name album_name = coverobject.name
@@ -119,9 +122,9 @@ class CoverSearchPane(Gtk.Box):
if artist.upper() == "UNKNOWN": if artist.upper() == "UNKNOWN":
artist = "" artist = ""
if not(album_name == "" and artist == ""): if not (album_name == "" and artist == ""):
artist = rb3compat.unicodestr(artist.replace('&', '&amp;'), artist = rb3compat.unicodestr(artist.replace('&', '&amp;'),
'utf-8') 'utf-8')
album_name = rb3compat.unicodestr(album_name.replace('&', '&amp;'), 'utf-8') album_name = rb3compat.unicodestr(album_name.replace('&', '&amp;'), 'utf-8')
self.render_album_art_search(artist, album_name) self.render_album_art_search(artist, album_name)
else: else:
@@ -130,9 +133,9 @@ class CoverSearchPane(Gtk.Box):
if artist_name.upper() == "UNKNOWN": if artist_name.upper() == "UNKNOWN":
artist_name = "" artist_name = ""
if not(artist_name == ""): if not (artist_name == ""):
artist = rb3compat.unicodestr(artist_name.replace('&', '&amp;'), artist = rb3compat.unicodestr(artist_name.replace('&', '&amp;'),
'utf-8') 'utf-8')
self.render_artist_art_search(artist) self.render_artist_art_search(artist)
@@ -141,23 +144,23 @@ class CoverSearchPane(Gtk.Box):
Renders the template on the webview. Renders the template on the webview.
''' '''
temp_file = self.template.render(artist=artist, album=album_name, temp_file = self.template.render(artist=artist, album=album_name,
stylesheet=self.styles, selection_color=self.selection_color) stylesheet=self.styles, selection_color=self.selection_color)
print ("here") print("here")
self.webview.load_string(temp_file, 'text/html', 'utf-8', self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath) self.basepath)
def render_artist_art_search(self, artist): def render_artist_art_search(self, artist):
''' '''
Renders the template on the webview. Renders the template on the webview.
''' '''
temp_file = self.artist_template.render(artist=artist, temp_file = self.artist_template.render(artist=artist,
stylesheet=self.styles, selection_color=self.selection_color) stylesheet=self.styles, selection_color=self.selection_color)
print ("here") print("here")
self.webview.load_string(temp_file, 'text/html', 'utf-8', self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath) self.basepath)
def clear(self): def clear(self):
''' '''
Clears the webview of any specific info/covers. Clears the webview of any specific info/covers.
@@ -166,7 +169,7 @@ class CoverSearchPane(Gtk.Box):
temp_file = self.empty_template.render(stylesheet=self.styles) temp_file = self.empty_template.render(stylesheet=self.styles)
self.webview.load_string(temp_file, 'text/html', 'utf-8', self.webview.load_string(temp_file, 'text/html', 'utf-8',
self.basepath) self.basepath)
def set_cover(self, webview, arg): def set_cover(self, webview, arg):
''' '''
+33 -30
Ver Arquivo
@@ -39,6 +39,7 @@ from coverart_browser_prefs import webkit_support
import rb import rb
class Toolbar(GObject.Object): class Toolbar(GObject.Object):
def __init__(self, plugin, mainbox, controllers): def __init__(self, plugin, mainbox, controllers):
super(Toolbar, self).__init__() super(Toolbar, self).__init__()
@@ -81,10 +82,10 @@ class Toolbar(GObject.Object):
search_entry.controller = controllers['search'] search_entry.controller = controllers['search']
Theme(self.plugin).connect('theme_changed', self._theme_changed, Theme(self.plugin).connect('theme_changed', self._theme_changed,
controllers) controllers)
self.builder = builder.get_object('toolbar') self.builder = builder.get_object('toolbar')
#now theme the toolbar including child objects such as the button popups #now theme the toolbar including child objects such as the button popups
style_context = self.builder.get_style_context() style_context = self.builder.get_style_context()
style_context.add_class(Gtk.STYLE_CLASS_TOOLBAR) style_context.add_class(Gtk.STYLE_CLASS_TOOLBAR)
@@ -93,6 +94,7 @@ class Toolbar(GObject.Object):
for controller in list(controllers.values()): for controller in list(controllers.values()):
controller.update_images(True) controller.update_images(True)
class TopToolbar(Toolbar): class TopToolbar(Toolbar):
ui = 'ui/coverart_topbar.ui' ui = 'ui/coverart_topbar.ui'
name = 'main' name = 'main'
@@ -115,11 +117,11 @@ class LeftToolbar(Toolbar):
if self.builder.get_visible(): if self.builder.get_visible():
self.builder.hide() self.builder.hide()
self.plugin.shell.remove_widget(self.builder, self.plugin.shell.remove_widget(self.builder,
RB.ShellUILocation.SIDEBAR) RB.ShellUILocation.SIDEBAR)
def show(self): def show(self):
self.plugin.shell.add_widget(self.builder, self.plugin.shell.add_widget(self.builder,
RB.ShellUILocation.SIDEBAR, expand=False, fill=False) RB.ShellUILocation.SIDEBAR, expand=False, fill=False)
self.builder.show() self.builder.show()
@@ -131,32 +133,33 @@ class RightToolbar(Toolbar):
if self.builder.get_visible(): if self.builder.get_visible():
self.builder.hide() self.builder.hide()
self.plugin.shell.remove_widget(self.builder, self.plugin.shell.remove_widget(self.builder,
RB.ShellUILocation.RIGHT_SIDEBAR) RB.ShellUILocation.RIGHT_SIDEBAR)
def show(self): def show(self):
self.plugin.shell.add_widget(self.builder, self.plugin.shell.add_widget(self.builder,
RB.ShellUILocation.RIGHT_SIDEBAR, expand=False, fill=False) RB.ShellUILocation.RIGHT_SIDEBAR, expand=False, fill=False)
self.builder.show() self.builder.show()
class ToolbarObject(object): class ToolbarObject(object):
#properties #properties
PROPERTIES='properties_button' PROPERTIES = 'properties_button'
SORT_BY='sort_by' SORT_BY = 'sort_by'
SORT_ORDER='sort_order' SORT_ORDER = 'sort_order'
SORT_BY_ARTIST='sort_by_artist' SORT_BY_ARTIST = 'sort_by_artist'
SORT_ORDER_ARTIST='sort_order_artist' SORT_ORDER_ARTIST = 'sort_order_artist'
GENRE='genre_button' GENRE = 'genre_button'
PLAYLIST='playlist_button' PLAYLIST = 'playlist_button'
DECADE='decade_button' DECADE = 'decade_button'
SEARCH='search' SEARCH = 'search'
VIEW='view_button' VIEW = 'view_button'
class ToolbarManager(GObject.Object): class ToolbarManager(GObject.Object):
# properties # properties
toolbar_pos = GObject.property(type=str, default=TopToolbar.name) toolbar_pos = GObject.property(type=str, default=TopToolbar.name)
def __init__(self, plugin, main_box, viewmgr): def __init__(self, plugin, main_box, viewmgr):
super(ToolbarManager, self).__init__() super(ToolbarManager, self).__init__()
self.plugin = plugin self.plugin = plugin
@@ -166,19 +169,19 @@ class ToolbarManager(GObject.Object):
# initialize toolbars # initialize toolbars
self._bars = {} self._bars = {}
self._bars[TopToolbar.name] = TopToolbar(plugin, main_box, self._bars[TopToolbar.name] = TopToolbar(plugin, main_box,
controllers) controllers)
self._bars[LeftToolbar.name] = LeftToolbar(plugin, main_box, self._bars[LeftToolbar.name] = LeftToolbar(plugin, main_box,
controllers) controllers)
self._bars[RightToolbar.name] = RightToolbar(plugin, main_box, self._bars[RightToolbar.name] = RightToolbar(plugin, main_box,
controllers) controllers)
self.last_toolbar_pos = None self.last_toolbar_pos = None
# connect signal and properties # connect signal and properties
self._connect_signals() self._connect_signals()
self._connect_properties() self._connect_properties()
self._controllers = controllers self._controllers = controllers
def set_enabled(self, enabled, toolbar_object=None): def set_enabled(self, enabled, toolbar_object=None):
''' '''
enable or disable the toolbar object. enable or disable the toolbar object.
@@ -193,7 +196,7 @@ class ToolbarManager(GObject.Object):
else: else:
for controller in self._controllers: for controller in self._controllers:
self._controllers[controller].enabled = enabled self._controllers[controller].enabled = enabled
def _connect_signals(self): def _connect_signals(self):
self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos) self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
@@ -201,12 +204,12 @@ class ToolbarManager(GObject.Object):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos', setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
Gio.SettingsBindFlags.GET) Gio.SettingsBindFlags.GET)
def _create_controllers(self, plugin, viewmgr): def _create_controllers(self, plugin, viewmgr):
controllers = {} controllers = {}
album_model=viewmgr.source.album_manager.model album_model = viewmgr.source.album_manager.model
controllers[ToolbarObject.PROPERTIES] = \ controllers[ToolbarObject.PROPERTIES] = \
PropertiesMenuController(plugin, viewmgr.source) PropertiesMenuController(plugin, viewmgr.source)
controllers[ToolbarObject.SORT_BY] = \ controllers[ToolbarObject.SORT_BY] = \
@@ -225,7 +228,7 @@ class ToolbarManager(GObject.Object):
DecadePopupController(plugin, album_model) DecadePopupController(plugin, album_model)
controllers[ToolbarObject.SEARCH] = \ controllers[ToolbarObject.SEARCH] = \
AlbumSearchEntryController(album_model) AlbumSearchEntryController(album_model)
controllers[ToolbarObject.VIEW] = viewmgr.controller controllers[ToolbarObject.VIEW] = viewmgr.controller
return controllers return controllers
+60 -41
Ver Arquivo
@@ -35,14 +35,17 @@ from coverart_search_providers import lastfm_connected
from coverart_search_providers import get_search_providers from coverart_search_providers import get_search_providers
from collections import namedtuple from collections import namedtuple
class FauxTb(object): class FauxTb(object):
def __init__(self, tb_frame, tb_lineno, tb_next): def __init__(self, tb_frame, tb_lineno, tb_next):
self.tb_frame = tb_frame self.tb_frame = tb_frame
self.tb_lineno = tb_lineno self.tb_lineno = tb_lineno
self.tb_next = tb_next self.tb_next = tb_next
def current_stack(skip=0): def current_stack(skip=0):
try: 1/0 try:
1 / 0
except ZeroDivisionError: except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame f = sys.exc_info()[2].tb_frame
for i in range(skip + 2): for i in range(skip + 2):
@@ -53,6 +56,7 @@ def current_stack(skip=0):
f = f.f_back f = f.f_back
return lst return lst
def extend_traceback(tb, stack): def extend_traceback(tb, stack):
"""Extend traceback with stack info.""" """Extend traceback with stack info."""
head = tb head = tb
@@ -60,17 +64,20 @@ def extend_traceback(tb, stack):
head = FauxTb(tb_frame, tb_lineno, head) head = FauxTb(tb_frame, tb_lineno, head)
return head return head
def full_exc_info(): def full_exc_info():
"""Like sys.exc_info, but includes the full traceback.""" """Like sys.exc_info, but includes the full traceback."""
t, v, tb = sys.exc_info() t, v, tb = sys.exc_info()
full_tb = extend_traceback(tb, current_stack(1)) full_tb = extend_traceback(tb, current_stack(1))
return t, v, full_tb return t, v, full_tb
def dumpstack(message): def dumpstack(message):
''' dumps the current stack - useful of debugging ''' dumps the current stack - useful of debugging
''' '''
logging.error(message, exc_info=full_exc_info()) logging.error(message, exc_info=full_exc_info())
def uniquify_and_sort(iterable): def uniquify_and_sort(iterable):
''' Removes duplicates of an iterables and returns a list of unique ''' Removes duplicates of an iterables and returns a list of unique
elements. elements.
@@ -86,6 +93,7 @@ def uniquify_and_sort(iterable):
GenreType = namedtuple("GenreType", ["name", "genre_type"]) GenreType = namedtuple("GenreType", ["name", "genre_type"])
class NaturalString(str): class NaturalString(str):
''' '''
this class implements an object that can naturally compare this class implements an object that can naturally compare
@@ -97,7 +105,7 @@ class NaturalString(str):
super(NaturalString, self).__init__() super(NaturalString, self).__init__()
convert = lambda text: int(text) if text.isdigit() else text.lower() convert = lambda text: int(text) if text.isdigit() else text.lower()
alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)',
key)] key)]
self._string_elements = alphanum_key(string) self._string_elements = alphanum_key(string)
@@ -298,7 +306,6 @@ class SortedCollection(object):
class ReversedSortedCollection(object): class ReversedSortedCollection(object):
def __init__(self, sorted_collection): def __init__(self, sorted_collection):
self._sorted_collection = sorted_collection self._sorted_collection = sorted_collection
@@ -354,7 +361,6 @@ class ReversedSortedCollection(object):
class IdleCallIterator(object): class IdleCallIterator(object):
def __init__(self, chunk, process, after=None, error=None, finish=None): def __init__(self, chunk, process, after=None, error=None, finish=None):
default = lambda *_: None default = lambda *_: None
@@ -403,6 +409,7 @@ def idle_iterator(func):
return iter_function return iter_function
class Theme: class Theme:
''' '''
This class manages the theme details This class manages the theme details
@@ -421,7 +428,7 @@ class Theme:
''' '''
__gsignals__ = { __gsignals__ = {
'theme_changed': (GObject.SIGNAL_RUN_LAST, None, ()) 'theme_changed': (GObject.SIGNAL_RUN_LAST, None, ())
} }
# below public variables and methods that can be called for Theme # below public variables and methods that can be called for Theme
def __init__(self, plugin): def __init__(self, plugin):
''' '''
@@ -453,11 +460,11 @@ class Theme:
def _connect_properties(self): def _connect_properties(self):
self.setting.bind(self.gs.PluginKey.THEME, self, self.setting.bind(self.gs.PluginKey.THEME, self,
'theme', Gio.SettingsBindFlags.GET) 'theme', Gio.SettingsBindFlags.GET)
def _connect_signals(self): def _connect_signals(self):
self.connect('notify::theme', self._on_theme_changed, self.connect('notify::theme', self._on_theme_changed,
None) None)
def _on_theme_changed(self, *args): def _on_theme_changed(self, *args):
self.emit('theme_changed') self.emit('theme_changed')
@@ -480,11 +487,11 @@ class Theme:
""" Delegate access to implementation """ """ Delegate access to implementation """
return setattr(self.__instance, attr, value) return setattr(self.__instance, attr, value)
class SpriteSheet(object):
class SpriteSheet(object):
def __init__(self, image, icon_width, icon_height, x_spacing, y_spacing, def __init__(self, image, icon_width, icon_height, x_spacing, y_spacing,
x_start, y_start, across_dimension, down_dimension, x_start, y_start, across_dimension, down_dimension,
alpha_color=None, size=None): alpha_color=None, size=None):
# load the image # load the image
base_image = GdkPixbuf.Pixbuf.new_from_file(image) base_image = GdkPixbuf.Pixbuf.new_from_file(image)
@@ -499,15 +506,15 @@ class SpriteSheet(object):
for y in range(0, down_dimension): for y in range(0, down_dimension):
for x in range(0, across_dimension): for x in range(0, across_dimension):
sprite = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, sprite = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True,
8, icon_width, icon_height) 8, icon_width, icon_height)
base_image.copy_area(x_start + (x * delta_x), base_image.copy_area(x_start + (x * delta_x),
y_start + (y * delta_y), icon_width, icon_height, y_start + (y * delta_y), icon_width, icon_height,
sprite, 0, 0) sprite, 0, 0)
if size: if size:
sprite = sprite.scale_simple(size[0], size[1], sprite = sprite.scale_simple(size[0], size[1],
GdkPixbuf.InterpType.BILINEAR) GdkPixbuf.InterpType.BILINEAR)
self._sprites.append(sprite) self._sprites.append(sprite)
@@ -517,14 +524,15 @@ class SpriteSheet(object):
def __getitem__(self, index): def __getitem__(self, index):
return self._sprites[index] return self._sprites[index]
class ConfiguredSpriteSheet(object): class ConfiguredSpriteSheet(object):
def __init__(self, plugin, sprite_name, size=None): def __init__(self, plugin, sprite_name, size=None):
popups = rb.find_plugin_file(plugin, 'img/popups.xml') popups = rb.find_plugin_file(plugin, 'img/popups.xml')
root = ET.parse(open(popups)).getroot() root = ET.parse(open(popups)).getroot()
base = 'theme/theme[@folder_name="' + Theme(plugin).current\ base = 'theme/theme[@folder_name="' + Theme(plugin).current \
+ '"]/spritesheet[@name="' + sprite_name + '"]/' + '"]/spritesheet[@name="' + sprite_name + '"]/'
image = rb.find_plugin_file(plugin, 'img/' + Theme(plugin).current\ image = rb.find_plugin_file(plugin, 'img/' + Theme(plugin).current \
+ '/' + root.xpath(base + 'image')[0].text) + '/' + root.xpath(base + 'image')[0].text)
icon_width = int(root.xpath(base + 'icon')[0].attrib['width']) icon_width = int(root.xpath(base + 'icon')[0].attrib['width'])
icon_height = int(root.xpath(base + 'icon')[0].attrib['height']) icon_height = int(root.xpath(base + 'icon')[0].attrib['height'])
x_spacing = int(root.xpath(base + 'spacing')[0].attrib['x']) x_spacing = int(root.xpath(base + 'spacing')[0].attrib['x'])
@@ -536,7 +544,7 @@ class ConfiguredSpriteSheet(object):
try: try:
alpha_color = list(map(int, alpha_color = list(map(int,
root.xpath(base + 'alpha')[0].text.split(' '))) root.xpath(base + 'alpha')[0].text.split(' ')))
except: except:
alpha_color = None alpha_color = None
@@ -547,7 +555,7 @@ class ConfiguredSpriteSheet(object):
lang = cl.get_locale() lang = cl.get_locale()
base = sprite_name + '/' + sprite_name + \ base = sprite_name + '/' + sprite_name + \
'[@spritesheet="' + sprite_name + '"]' '[@spritesheet="' + sprite_name + '"]'
for elem in root.xpath(base + '[not(@xml:lang)]'): for elem in root.xpath(base + '[not(@xml:lang)]'):
self.names.append(elem.text) self.names.append(elem.text)
@@ -557,12 +565,12 @@ class ConfiguredSpriteSheet(object):
if (not self.locale_names) and len(lang) > 2: if (not self.locale_names) and len(lang) > 2:
for elem in root.xpath(base + '[@xml:lang="' + \ for elem in root.xpath(base + '[@xml:lang="' + \
lang[0:2] + '"]'): lang[0:2] + '"]'):
self.locale_names[elem.text] = elem.attrib['name'] self.locale_names[elem.text] = elem.attrib['name']
self._sheet = SpriteSheet(image, icon_width, icon_height, x_spacing, self._sheet = SpriteSheet(image, icon_width, icon_height, x_spacing,
y_spacing, x_start, y_start, across_dimension, down_dimension, y_spacing, x_start, y_start, across_dimension, down_dimension,
alpha_color, size) alpha_color, size)
self._genre_db = RB.ExtDB(name='cb_genre') self._genre_db = RB.ExtDB(name='cb_genre')
@@ -581,6 +589,7 @@ class ConfiguredSpriteSheet(object):
def keys(self): def keys(self):
return self.names return self.names
class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet): class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
''' '''
A sprite-sheet of genres. Creates a pixbuf representation of a picture A sprite-sheet of genres. Creates a pixbuf representation of a picture
@@ -602,7 +611,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
def __init__(self, plugin, sprite_name, size=None): def __init__(self, plugin, sprite_name, size=None):
super(GenreConfiguredSpriteSheet, self).__init__(plugin, sprite_name, super(GenreConfiguredSpriteSheet, self).__init__(plugin, sprite_name,
size) size)
self.genre_alternate = {} # contains GenreType tuples self.genre_alternate = {} # contains GenreType tuples
self._alt_icons = {} self._alt_icons = {}
self._sprite_name = sprite_name self._sprite_name = sprite_name
@@ -626,7 +635,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
sprite = GdkPixbuf.Pixbuf.new_from_file(icon_location) sprite = GdkPixbuf.Pixbuf.new_from_file(icon_location)
if self._size: if self._size:
sprite = sprite.scale_simple(self._size[0], self._size[1], sprite = sprite.scale_simple(self._size[0], self._size[1],
GdkPixbuf.InterpType.BILINEAR) GdkPixbuf.InterpType.BILINEAR)
self._alt_icons[str(index)] = sprite self._alt_icons[str(index)] = sprite
self.names.append(str(index)) self.names.append(str(index))
@@ -654,7 +663,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
# if (not self.locale_alternate) and len(lang) > 2: # if (not self.locale_alternate) and len(lang) > 2:
if len(lang) > 2: if len(lang) > 2:
for elem in root.xpath(base + '[@xml:lang="' + \ for elem in root.xpath(base + '[@xml:lang="' + \
lang[0:2] + '"]/alt'): lang[0:2] + '"]/alt'):
self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_LOCALE)] = elem.attrib['genre'] self.genre_alternate[GenreType(name=elem.text, genre_type=self.GENRE_LOCALE)] = elem.attrib['genre']
def add_genre_icon(self, filename): def add_genre_icon(self, filename):
@@ -667,7 +676,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
key = RB.ExtDBKey.create_storage('icon', str(next_index)) key = RB.ExtDBKey.create_storage('icon', str(next_index))
uri = "file://" + rb3compat.pathname2url(filename) uri = "file://" + rb3compat.pathname2url(filename)
self._genre_db.store_uri(key, RB.ExtDBSourceType.USER_EXPLICIT, uri) self._genre_db.store_uri(key, RB.ExtDBSourceType.USER_EXPLICIT, uri)
pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename) pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename)
@@ -675,7 +684,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
if self._size: if self._size:
pixbuf = pixbuf.scale_simple(self._size[0], self._size[1], pixbuf = pixbuf.scale_simple(self._size[0], self._size[1],
GdkPixbuf.InterpType.BILINEAR) GdkPixbuf.InterpType.BILINEAR)
self._alt_icons[new_genre.name] = pixbuf self._alt_icons[new_genre.name] = pixbuf
self.names.append(new_genre.name) self.names.append(new_genre.name)
@@ -731,6 +740,7 @@ class GenreConfiguredSpriteSheet(ConfiguredSpriteSheet):
print("nothing found to amend") print("nothing found to amend")
return None return None
def get_stock_size(): def get_stock_size():
what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.BUTTON) what, width, height = Gtk.icon_size_lookup(Gtk.IconSize.BUTTON)
@@ -742,30 +752,38 @@ def create_pixbuf_from_file_at_size(filename, width, height):
if pixbuf.get_width() != width or pixbuf.get_height() != height: if pixbuf.get_width() != width or pixbuf.get_height() != height:
pixbuf = pixbuf.scale_simple(width, height, pixbuf = pixbuf.scale_simple(width, height,
GdkPixbuf.InterpType.BILINEAR) GdkPixbuf.InterpType.BILINEAR)
return pixbuf return pixbuf
''' '''
class to search through a dict without case-sensitivity nor class to search through a dict without case-sensitivity nor
unicode vs string issues unicode vs string issues
''' '''
class CaseInsensitiveDict(collections.Mapping): class CaseInsensitiveDict(collections.Mapping):
def __init__(self, d): def __init__(self, d):
self._d = d self._d = d
self._s = dict((RB.search_fold(k), k) for k in d) self._s = dict((RB.search_fold(k), k) for k in d)
def __contains__(self, k): def __contains__(self, k):
return RB.search_fold(k) in self._s return RB.search_fold(k) in self._s
def __len__(self): def __len__(self):
return len(self._s) return len(self._s)
def __iter__(self): def __iter__(self):
return iter(self._s) return iter(self._s)
def __getitem__(self, k): def __getitem__(self, k):
return self._d[self._s[RB.search_fold(k)]] return self._d[self._s[RB.search_fold(k)]]
def actual_key_case(self, k): def actual_key_case(self, k):
return self._s.get(RB.search_fold(k)) return self._s.get(RB.search_fold(k))
def check_lastfm(force_check=False): def check_lastfm(force_check=False):
''' '''
check validity of lastfm connection check validity of lastfm connection
@@ -774,26 +792,27 @@ def check_lastfm(force_check=False):
Also returns True if lastFM is not in the list of search providers Also returns True if lastFM is not in the list of search providers
''' '''
providers = get_search_providers() providers = get_search_providers()
print (providers) print(providers)
print (force_check) print(force_check)
if force_check or 'lastfm-search' in providers: if force_check or 'lastfm-search' in providers:
connected = lastfm_connected() connected = lastfm_connected()
print (connected) print(connected)
return connected return connected
elif not 'lastfm-search' in providers: elif not 'lastfm-search' in providers:
print ("not lastm-search") print("not lastm-search")
return True return True
else: else:
print ("returning default") print("returning default")
return False return False
def create_button_image(plugin, icon_name): def create_button_image(plugin, icon_name):
'create a pixbuf for the given icon_name sized according to the stock icon size' 'create a pixbuf for the given icon_name sized according to the stock icon size'
path = 'img/' path = 'img/'
return create_pixbuf_from_file_at_size( return create_pixbuf_from_file_at_size(
rb.find_plugin_file(plugin, path + icon_name), rb.find_plugin_file(plugin, path + icon_name),
*get_stock_size()) *get_stock_size())
+103 -99
Ver Arquivo
@@ -30,9 +30,11 @@ from coverart_browser_prefs import GSetting
import rb import rb
def enum(**enums): def enum(**enums):
return type('Enum', (object,), enums) return type('Enum', (object,), enums)
class OptionsWidget(Gtk.Widget): class OptionsWidget(Gtk.Widget):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(OptionsWidget, self).__init__(*args, **kwargs) super(OptionsWidget, self).__init__(*args, **kwargs)
@@ -54,7 +56,7 @@ class OptionsWidget(Gtk.Widget):
# connect signals # connect signals
self._options_changed_id = self._controller.connect('notify::options', self._options_changed_id = self._controller.connect('notify::options',
self._update_options) self._update_options)
self._current_key_changed_id = self._controller.connect( self._current_key_changed_id = self._controller.connect(
'notify::current-key', self._update_current_key) 'notify::current-key', self._update_current_key)
self._update_image_changed_id = self._controller.connect( self._update_image_changed_id = self._controller.connect(
@@ -68,7 +70,7 @@ class OptionsWidget(Gtk.Widget):
def _update_visibility(self, *args): def _update_visibility(self, *args):
self.set_visible(self._controller.enabled) self.set_visible(self._controller.enabled)
def _update_options(self, *args): def _update_options(self, *args):
self.update_options() self.update_options()
@@ -86,14 +88,14 @@ class OptionsWidget(Gtk.Widget):
def update_image(self): def update_image(self):
pass pass
def calc_popup_position(self, widget): def calc_popup_position(self, widget):
# this calculates the popup positioning - algorithm taken # this calculates the popup positioning - algorithm taken
# from Gtk3.8 gtk/gtkmenubutton.c # from Gtk3.8 gtk/gtkmenubutton.c
toplevel = self.get_toplevel() toplevel = self.get_toplevel()
toplevel.set_type_hint(Gdk.WindowTypeHint.DROPDOWN_MENU) toplevel.set_type_hint(Gdk.WindowTypeHint.DROPDOWN_MENU)
menu_req, pref_req = widget.get_preferred_size() menu_req, pref_req = widget.get_preferred_size()
align = widget.get_halign() align = widget.get_halign()
direction = self.get_direction() direction = self.get_direction()
@@ -107,7 +109,7 @@ class OptionsWidget(Gtk.Widget):
allocation = self.get_allocation() allocation = self.get_allocation()
ret, x,y = window.get_origin() ret, x, y = window.get_origin()
x += allocation.x x += allocation.x
y += allocation.y y += allocation.y
@@ -120,15 +122,15 @@ class OptionsWidget(Gtk.Widget):
y -= menu_req.height y -= menu_req.height
else: else:
y -= menu_req.height y -= menu_req.height
return x, y return x, y
class OptionsPopupWidget(OptionsWidget):
class OptionsPopupWidget(OptionsWidget):
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
OptionsWidget.__init__(self, *args, **kwargs) OptionsWidget.__init__(self, *args, **kwargs)
@@ -189,31 +191,30 @@ class OptionsPopupWidget(OptionsWidget):
if self._controller: if self._controller:
# inform the controller # inform the controller
self._controller.option_selected(key) self._controller.option_selected(key)
def _popup_callback(self, *args): def _popup_callback(self, *args):
x, y = self.calc_popup_position(self._popup_menu) x, y = self.calc_popup_position(self._popup_menu)
return x, y, False, None return x, y, False, None
def show_popup(self, align=True): def show_popup(self, align=True):
''' '''
show the current popup menu show the current popup menu
''' '''
if align: if align:
self._popup_menu.popup(None, None, self._popup_callback, self, 0, self._popup_menu.popup(None, None, self._popup_callback, self, 0,
Gtk.get_current_event_time()) Gtk.get_current_event_time())
else: else:
self._popup_menu.popup(None, None, None, None, 0, self._popup_menu.popup(None, None, None, None, 0,
Gtk.get_current_event_time()) Gtk.get_current_event_time())
def do_delete_thyself(self): def do_delete_thyself(self):
self.clear_popupmenu() self.clear_popupmenu()
del self._popupmenu del self._popupmenu
class EnhancedButton(Gtk.ToggleButton): class EnhancedButton(Gtk.ToggleButton):
button_relief = GObject.property(type=bool, default=False) button_relief = GObject.property(type=bool, default=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -222,10 +223,10 @@ class EnhancedButton(Gtk.ToggleButton):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.BUTTON_RELIEF, self, setting.bind(gs.PluginKey.BUTTON_RELIEF, self,
'button_relief', Gio.SettingsBindFlags.GET) 'button_relief', Gio.SettingsBindFlags.GET)
self.connect('notify::button-relief', self.connect('notify::button-relief',
self.on_notify_button_relief) self.on_notify_button_relief)
def on_notify_button_relief(self, *arg): def on_notify_button_relief(self, *arg):
if self.button_relief: if self.button_relief:
@@ -235,7 +236,6 @@ class EnhancedButton(Gtk.ToggleButton):
class PixbufButton(EnhancedButton): class PixbufButton(EnhancedButton):
button_relief = GObject.property(type=bool, default=False) button_relief = GObject.property(type=bool, default=False)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -250,7 +250,7 @@ class PixbufButton(EnhancedButton):
if hasattr(self, "controller.enabled") and not self.controller.enabled: if hasattr(self, "controller.enabled") and not self.controller.enabled:
pixbuf = self._getBlendedPixbuf(pixbuf) pixbuf = self._getBlendedPixbuf(pixbuf)
self.get_image().set_from_pixbuf(pixbuf) self.get_image().set_from_pixbuf(pixbuf)
self.on_notify_button_relief() self.on_notify_button_relief()
@@ -259,12 +259,12 @@ class PixbufButton(EnhancedButton):
"""Turn a pixbuf into a blended version of the pixbuf by drawing a """Turn a pixbuf into a blended version of the pixbuf by drawing a
transparent alpha blend on it.""" transparent alpha blend on it."""
pixbuf = pixbuf.copy() pixbuf = pixbuf.copy()
w,h = pixbuf.get_width(), pixbuf.get_height() w, h = pixbuf.get_width(), pixbuf.get_height()
surface = cairo.ImageSurface( surface = cairo.ImageSurface(
cairo.FORMAT_ARGB32, pixbuf.get_width(), pixbuf.get_height()) cairo.FORMAT_ARGB32, pixbuf.get_width(), pixbuf.get_height())
context = cairo.Context(surface) context = cairo.Context(surface)
Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0) Gdk.cairo_set_source_pixbuf(context, pixbuf, 0, 0)
context.paint() context.paint()
@@ -284,7 +284,7 @@ class PopupButton(PixbufButton, OptionsPopupWidget):
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
''' '''
@@ -292,13 +292,13 @@ class PopupButton(PixbufButton, OptionsPopupWidget):
''' '''
PixbufButton.__init__(self, *args, **kwargs) PixbufButton.__init__(self, *args, **kwargs)
OptionsPopupWidget.__init__(self, *args, **kwargs) OptionsPopupWidget.__init__(self, *args, **kwargs)
self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works
self._popup_menu.connect('deactivate', self.popup_deactivate) self._popup_menu.connect('deactivate', self.popup_deactivate)
# initialise some variables # initialise some variables
self._first_menu_item = None self._first_menu_item = None
def popup_deactivate(self, *args): def popup_deactivate(self, *args):
self.set_active(False) self.set_active(False)
@@ -321,14 +321,15 @@ class PopupButton(PixbufButton, OptionsPopupWidget):
if (event.button == Gdk.BUTTON_PRIMARY): if (event.button == Gdk.BUTTON_PRIMARY):
self.show_popup() self.show_popup()
self.set_active(True) self.set_active(True)
class TextPopupButton(EnhancedButton, OptionsPopupWidget): class TextPopupButton(EnhancedButton, OptionsPopupWidget):
__gtype_name__ = "TextPopupButton" __gtype_name__ = "TextPopupButton"
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
''' '''
@@ -336,8 +337,8 @@ class TextPopupButton(EnhancedButton, OptionsPopupWidget):
''' '''
EnhancedButton.__init__(self, *args, **kwargs) EnhancedButton.__init__(self, *args, **kwargs)
OptionsPopupWidget.__init__(self, *args, **kwargs) OptionsPopupWidget.__init__(self, *args, **kwargs)
self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works
self._popup_menu.connect('deactivate', self.popup_deactivate) self._popup_menu.connect('deactivate', self.popup_deactivate)
# initialise some variables # initialise some variables
@@ -362,7 +363,7 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
''' '''
@@ -370,11 +371,11 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
''' '''
PixbufButton.__init__(self, *args, **kwargs) PixbufButton.__init__(self, *args, **kwargs)
OptionsPopupWidget.__init__(self, *args, **kwargs) OptionsPopupWidget.__init__(self, *args, **kwargs)
self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works self._popup_menu.attach_to_widget(self, None) #critical to ensure theming works
self._popup_menu.connect('deactivate', self.popup_deactivate) self._popup_menu.connect('deactivate', self.popup_deactivate)
self._states = {} self._states = {}
def popup_deactivate(self, *args): def popup_deactivate(self, *args):
self.set_active(False) self.set_active(False)
@@ -382,11 +383,11 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
''' '''
add a new menu item to the popup add a new menu item to the popup
''' '''
label = key.label label = key.label
menutype = key.menutype menutype = key.menutype
typevalue = key.typevalue typevalue = key.typevalue
if menutype and menutype == 'separator': if menutype and menutype == 'separator':
new_menu_item = Gtk.SeparatorMenuItem().new() new_menu_item = Gtk.SeparatorMenuItem().new()
elif menutype and menutype == 'check': elif menutype and menutype == 'check':
@@ -399,7 +400,7 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
new_menu_item.show() new_menu_item.show()
self._popup_menu.append(new_menu_item) self._popup_menu.append(new_menu_item)
def clear_popupmenu(self): def clear_popupmenu(self):
''' '''
reinitialises/clears the current popup menu and associated actions reinitialises/clears the current popup menu and associated actions
@@ -416,7 +417,7 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
for key in self._controller.options: for key in self._controller.options:
self.add_menuitem(key) self.add_menuitem(key)
self._states = {} self._states = {}
def _fire_item_clicked(self, menu_item): def _fire_item_clicked(self, menu_item):
@@ -426,7 +427,7 @@ class MenuButton(PixbufButton, OptionsPopupWidget):
value of the selected item. value of the selected item.
''' '''
self.emit('item-clicked', menu_item.get_label()) self.emit('item-clicked', menu_item.get_label())
def update_image(self): def update_image(self):
super(MenuButton, self).update_image() super(MenuButton, self).update_image()
self.set_image(self._controller.get_current_image()) self.set_image(self._controller.get_current_image())
@@ -484,8 +485,8 @@ class ImageToggleButton(PixbufButton, OptionsWidget):
class ImageRadioButton(Gtk.RadioButton, OptionsWidget): class ImageRadioButton(Gtk.RadioButton, OptionsWidget):
# this is legacy code that will not as yet work with # this is legacy code that will not as yet work with
# the new toolbar - consider removing this later # the new toolbar - consider removing this later
__gtype_name__ = "ImageRadioButton" __gtype_name__ = "ImageRadioButton"
@@ -501,10 +502,10 @@ class ImageRadioButton(Gtk.RadioButton, OptionsWidget):
gs = GSetting() gs = GSetting()
setting = gs.get_setting(gs.Path.PLUGIN) setting = gs.get_setting(gs.Path.PLUGIN)
setting.bind(gs.PluginKey.BUTTON_RELIEF, self, setting.bind(gs.PluginKey.BUTTON_RELIEF, self,
'button_relief', Gio.SettingsBindFlags.GET) 'button_relief', Gio.SettingsBindFlags.GET)
self.connect('notify::button-relief', self.connect('notify::button-relief',
self.on_notify_button_relief) self.on_notify_button_relief)
# initialise some variables # initialise some variables
self.image_display = False self.image_display = False
@@ -545,9 +546,10 @@ class ImageRadioButton(Gtk.RadioButton, OptionsWidget):
def update_current_key(self): def update_current_key(self):
# update the current image and tooltip # update the current image and tooltip
#self.set_image(self._controller.get_current_image(Gtk.Buildable.get_name(self))) #self.set_image(self._controller.get_current_image(Gtk.Buildable.get_name(self)))
self.set_tooltip_text("") #self._controller.get_current_description()) self.set_tooltip_text("") #self._controller.get_current_description())
from gi.repository import Gdk from gi.repository import Gdk
if self.controller.current_key == Gtk.Buildable.get_name(self): if self.controller.current_key == Gtk.Buildable.get_name(self):
self.set_active(True) self.set_active(True)
self._set_colour(Gtk.StateFlags.NORMAL) self._set_colour(Gtk.StateFlags.NORMAL)
@@ -555,14 +557,14 @@ class ImageRadioButton(Gtk.RadioButton, OptionsWidget):
self._set_colour(Gtk.StateFlags.INSENSITIVE) self._set_colour(Gtk.StateFlags.INSENSITIVE)
def _set_colour(self, state_flag): def _set_colour(self, state_flag):
if len(self.get_children()) == 0: if len(self.get_children()) == 0:
return return
def get_standard_colour(label, state_flag): def get_standard_colour(label, state_flag):
context = label.get_style_context() context = label.get_style_context()
return context.get_color(state_flag) return context.get_color(state_flag)
label0 = self.get_children()[0] label0 = self.get_children()[0]
if not self._not_active_colour: if not self._not_active_colour:
@@ -571,24 +573,25 @@ class ImageRadioButton(Gtk.RadioButton, OptionsWidget):
if not self._active_colour: if not self._active_colour:
self._active_colour = get_standard_colour(label0, Gtk.StateFlags.NORMAL) self._active_colour = get_standard_colour(label0, Gtk.StateFlags.NORMAL)
if state_flag == Gtk.StateFlags.INSENSITIVE: if state_flag == Gtk.StateFlags.INSENSITIVE:
label0.override_color(Gtk.StateType.NORMAL, self._not_active_colour) label0.override_color(Gtk.StateType.NORMAL, self._not_active_colour)
else: else:
label0.override_color(Gtk.StateType.NORMAL, self._active_colour) label0.override_color(Gtk.StateType.NORMAL, self._active_colour)
class SearchEntry(RB.SearchEntry, OptionsPopupWidget): class SearchEntry(RB.SearchEntry, OptionsPopupWidget):
__gtype_name__ = "SearchEntry" __gtype_name__ = "SearchEntry"
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
RB.SearchEntry.__init__(self, *args, **kwargs) RB.SearchEntry.__init__(self, *args, **kwargs)
OptionsPopupWidget.__init__(self) OptionsPopupWidget.__init__(self)
#self.props.explicit_mode = True #self.props.explicit_mode = True
@OptionsPopupWidget.controller.setter @OptionsPopupWidget.controller.setter
def controller(self, controller): def controller(self, controller):
if self._controller: if self._controller:
@@ -613,7 +616,7 @@ class SearchEntry(RB.SearchEntry, OptionsPopupWidget):
super(SearchEntry, self).update_current_key() super(SearchEntry, self).update_current_key()
self.set_placeholder(self._controller.get_current_description()) self.set_placeholder(self._controller.get_current_description())
def do_show_popup(self): def do_show_popup(self):
''' '''
Callback called by the search entry when the magnifier is clicked. Callback called by the search entry when the magnifier is clicked.
@@ -637,7 +640,7 @@ class QuickSearchEntry(Gtk.Frame):
__gsignals__ = { __gsignals__ = {
'quick-search': (GObject.SIGNAL_RUN_LAST, None, (str,)), 'quick-search': (GObject.SIGNAL_RUN_LAST, None, (str,)),
'arrow-pressed': (GObject.SIGNAL_RUN_LAST, None, (object,)) 'arrow-pressed': (GObject.SIGNAL_RUN_LAST, None, (object,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(QuickSearchEntry, self).__init__(*args, **kwargs) super(QuickSearchEntry, self).__init__(*args, **kwargs)
@@ -645,7 +648,7 @@ class QuickSearchEntry(Gtk.Frame):
# text entry for the quick search input # text entry for the quick search input
text_entry = Gtk.Entry(halign='center', valign='center', text_entry = Gtk.Entry(halign='center', valign='center',
margin=5) margin=5)
self.add(text_entry) self.add(text_entry)
@@ -677,7 +680,7 @@ class QuickSearchEntry(Gtk.Frame):
return False return False
Gdk.threads_add_timeout_seconds(GLib.PRIORITY_DEFAULT_IDLE, 4, Gdk.threads_add_timeout_seconds(GLib.PRIORITY_DEFAULT_IDLE, 4,
hide_on_timeout, None) hide_on_timeout, None)
def do_parent_set(self, old_parent, *args): def do_parent_set(self, old_parent, *args):
if old_parent: if old_parent:
@@ -685,12 +688,12 @@ class QuickSearchEntry(Gtk.Frame):
parent = self.get_parent() parent = self.get_parent()
self._on_parent_key_press_id = parent.connect('key-press-event', self._on_parent_key_press_id = parent.connect('key-press-event',
self._on_parent_key_press, self.get_child()) self._on_parent_key_press, self.get_child())
def _on_parent_key_press(self, parent, event, entry): def _on_parent_key_press(self, parent, event, entry):
if not self.get_visible() and \ if not self.get_visible() and \
event.keyval not in [Gdk.KEY_Shift_L, Gdk.KEY_Shift_R, event.keyval not in [Gdk.KEY_Shift_L, Gdk.KEY_Shift_R,
Gdk.KEY_Control_L, Gdk.KEY_Control_R, Gdk.KEY_Escape]: Gdk.KEY_Control_L, Gdk.KEY_Control_R, Gdk.KEY_Escape]:
# grab focus, redirect the pressed key and make the quick search # grab focus, redirect the pressed key and make the quick search
# entry visible # entry visible
entry.set_text('') entry.set_text('')
@@ -758,12 +761,11 @@ class ProxyPopupButton(Gtk.Frame):
class OptionsListViewWidget(OptionsWidget): class OptionsListViewWidget(OptionsWidget):
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)), 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)),
'deactivate': (GObject.SIGNAL_RUN_LAST, None, ()) 'deactivate': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
OptionsWidget.__init__(self, *args, **kwargs) OptionsWidget.__init__(self, *args, **kwargs)
@@ -773,7 +775,7 @@ class OptionsListViewWidget(OptionsWidget):
def controller(self, controller): def controller(self, controller):
ui = Gtk.Builder() ui = Gtk.Builder()
ui.add_from_file(rb.find_plugin_file(controller.plugin, ui.add_from_file(rb.find_plugin_file(controller.plugin,
'ui/coverart_listwindow.ui')) 'ui/coverart_listwindow.ui'))
ui.connect_signals(self) ui.connect_signals(self)
self._listwindow = ui.get_object('listwindow') self._listwindow = ui.get_object('listwindow')
self._liststore = ui.get_object('liststore') self._liststore = ui.get_object('liststore')
@@ -838,10 +840,10 @@ class OptionsListViewWidget(OptionsWidget):
if self._increment: if self._increment:
if button is self._scrolldown_button: if button is self._scrolldown_button:
adjustment.set_value(adjustment.get_value() adjustment.set_value(adjustment.get_value()
+ self._step) + self._step)
else: else:
adjustment.set_value(adjustment.get_value() adjustment.set_value(adjustment.get_value()
- self._step) - self._step)
return self._increment return self._increment
@@ -851,7 +853,7 @@ class OptionsListViewWidget(OptionsWidget):
self.on_scroll_button_released() self.on_scroll_button_released()
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50,
scroll, None) scroll, None)
def on_scroll_button_leave(self, *args): def on_scroll_button_leave(self, *args):
self._increment = False self._increment = False
@@ -884,7 +886,7 @@ class ListViewButton(PixbufButton, OptionsListViewWidget):
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)), 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (str,)),
'deactivate': (GObject.SIGNAL_RUN_LAST, None, ()) 'deactivate': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
''' '''
@@ -892,19 +894,19 @@ class ListViewButton(PixbufButton, OptionsListViewWidget):
''' '''
PixbufButton.__init__(self, *args, **kwargs) PixbufButton.__init__(self, *args, **kwargs)
OptionsListViewWidget.__init__(self, *args, **kwargs) OptionsListViewWidget.__init__(self, *args, **kwargs)
self._popup.connect('deactivate', self.popup_deactivate) self._popup.connect('deactivate', self.popup_deactivate)
def popup_deactivate(self, *args): def popup_deactivate(self, *args):
# add a slight delay to allow the click of button to occur # add a slight delay to allow the click of button to occur
# before the deactivation of the button - this will allow # before the deactivation of the button - this will allow
# us to toggle the popup via the button correctly # us to toggle the popup via the button correctly
def deactivate(*args): def deactivate(*args):
self.set_active(False) self.set_active(False)
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50, deactivate, None) Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50, deactivate, None)
def update_image(self): def update_image(self):
super(ListViewButton, self).update_image() super(ListViewButton, self).update_image()
self.set_image(self._controller.get_current_image()) self.set_image(self._controller.get_current_image())
@@ -934,9 +936,9 @@ class EnhancedIconView(Gtk.IconView):
# signals # signals
__gsignals__ = { __gsignals__ = {
'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (object, object)) 'item-clicked': (GObject.SIGNAL_RUN_LAST, None, (object, object))
} }
object_column = GObject.property(type=int, default= -1) object_column = GObject.property(type=int, default=-1)
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(EnhancedIconView, self).__init__(*args, **kwargs) super(EnhancedIconView, self).__init__(*args, **kwargs)
@@ -957,7 +959,7 @@ class EnhancedIconView(Gtk.IconView):
# don't need to reaccommodate if it's a vertical change # don't need to reaccommodate if it's a vertical change
self._reallocate_count += 1 self._reallocate_count += 1
Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 500, Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 500,
self._reallocate_columns, None) self._reallocate_columns, None)
Gtk.IconView.do_size_allocate(self, allocation) Gtk.IconView.do_size_allocate(self, allocation)
@@ -983,7 +985,7 @@ class EnhancedIconView(Gtk.IconView):
# if the item being clicked isn't selected, we should clear # if the item being clicked isn't selected, we should clear
# the current selection # the current selection
if len(self.get_selected_objects()) > 0 and \ if len(self.get_selected_objects()) > 0 and \
not self.path_is_selected(current_path): not self.path_is_selected(current_path):
self.unselect_all() self.unselect_all()
self.select_path(current_path) self.select_path(current_path)
@@ -1011,7 +1013,7 @@ class EnhancedIconView(Gtk.IconView):
model = self.get_model() model = self.get_model()
selected_objects = list(reversed([model[selected][self.object_column] selected_objects = list(reversed([model[selected][self.object_column]
for selected in selected_items])) for selected in selected_items]))
return selected_objects return selected_objects
@@ -1037,7 +1039,7 @@ class PanedCollapsible(Gtk.Paned):
# values for expand method # values for expand method
Paned = enum(DEFAULT=1, EXPAND=2, COLLAPSE=3) Paned = enum(DEFAULT=1, EXPAND=2, COLLAPSE=3)
# this indicates the latest position for the handle before a child was # this indicates the latest position for the handle before a child was
# collapsed # collapsed
collapsible_y = GObject.property(type=int, default=0) collapsible_y = GObject.property(type=int, default=0)
@@ -1048,7 +1050,7 @@ class PanedCollapsible(Gtk.Paned):
# signals # signals
__gsignals__ = { __gsignals__ = {
'expanded': (GObject.SIGNAL_RUN_LAST, None, (bool,)) 'expanded': (GObject.SIGNAL_RUN_LAST, None, (bool,))
} }
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PanedCollapsible, self).__init__(*args, **kwargs) super(PanedCollapsible, self).__init__(*args, **kwargs)
@@ -1059,7 +1061,7 @@ class PanedCollapsible(Gtk.Paned):
self.connect('notify::collapsible1', self._on_collapsible1_changed) self.connect('notify::collapsible1', self._on_collapsible1_changed)
self.connect('notify::collapsible2', self._on_collapsible2_changed) self.connect('notify::collapsible2', self._on_collapsible2_changed)
self.connect('notify::collapsible_label', self.connect('notify::collapsible_label',
self._on_collapsible_label_changed) self._on_collapsible_label_changed)
def _on_collapsible1_changed(self, *args): def _on_collapsible1_changed(self, *args):
if self.collapsible1 and self.collapsible2: if self.collapsible1 and self.collapsible2:
@@ -1072,7 +1074,7 @@ class PanedCollapsible(Gtk.Paned):
def _on_collapsible2_changed(self, *args): def _on_collapsible2_changed(self, *args):
if self.collapsible1 and self.collapsible2: if self.collapsible1 and self.collapsible2:
# check consistency, only one collapsible at a time # check consistency, only one collapsible at a time
self.collapsible1 = False self.collapsible1 = False
child = self.get_child2() child = self.get_child2()
@@ -1193,16 +1195,16 @@ class PanedCollapsible(Gtk.Paned):
def _create_expander(self, widget): def _create_expander(self, widget):
self._expander = Gtk.Expander(label=self.collapsible_label, self._expander = Gtk.Expander(label=self.collapsible_label,
visible=True) visible=True)
self._expander.add(widget) self._expander.add(widget)
# connect the expanded signal # connect the expanded signal
self._expander.connect('notify::expanded', self._expander.connect('notify::expanded',
self._on_collapsible_expanded) self._on_collapsible_expanded)
# connect the initial collapse # connect the initial collapse
self._allocate_id = self._expander.connect('size-allocate', self._allocate_id = self._expander.connect('size-allocate',
self._initial_collapse) self._initial_collapse)
return self._expander return self._expander
@@ -1213,8 +1215,8 @@ class PanedCollapsible(Gtk.Paned):
def _collapse(self): def _collapse(self):
new_y = self.get_allocated_height() - \ new_y = self.get_allocated_height() - \
self.get_handle_window().get_height() - \ self.get_handle_window().get_height() - \
self._expander.get_label_widget().get_allocated_height() self._expander.get_label_widget().get_allocated_height()
self.set_position(new_y) self.set_position(new_y)
@@ -1228,9 +1230,9 @@ class PanedCollapsible(Gtk.Paned):
self._expander.set_expanded(True) self._expander.set_expanded(True)
elif force == PanedCollapsible.Paned.COLLAPSE: elif force == PanedCollapsible.Paned.COLLAPSE:
self._expander.set_expanded(False) self._expander.set_expanded(False)
elif force==PanedCollapsible.Paned.DEFAULT: elif force == PanedCollapsible.Paned.DEFAULT:
self._expander.set_expanded(not self._expander.get_expanded()) self._expander.set_expanded(not self._expander.get_expanded())
def get_expansion_status(self): def get_expansion_status(self):
''' '''
returns the position of the expander i.e. expanded or not returns the position of the expander i.e. expanded or not
@@ -1241,6 +1243,7 @@ class PanedCollapsible(Gtk.Paned):
return value return value
class AbstractView(GObject.Object): class AbstractView(GObject.Object):
''' '''
intention is to document 'the must have' methods all views should define intention is to document 'the must have' methods all views should define
@@ -1255,28 +1258,29 @@ class AbstractView(GObject.Object):
# where abstractview is part of multiple inheritance # where abstractview is part of multiple inheritance
__gsignals__ = { __gsignals__ = {
'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ()) 'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
} }
def __init__(self): def __init__(self):
super(AbstractView, self).__init__() super(AbstractView, self).__init__()
def initialise(self, source): def initialise(self, source):
self.source = source self.source = source
self.plugin = source.plugin self.plugin = source.plugin
self.connect('update-toolbar', self.do_update_toolbar) self.connect('update-toolbar', self.do_update_toolbar)
def do_update_toolbar(self, *args): def do_update_toolbar(self, *args):
''' '''
called when update-toolbar signal is emitted called when update-toolbar signal is emitted
by default the toolbar objects are made visible by default the toolbar objects are made visible
''' '''
from coverart_toolbar import ToolbarObject from coverart_toolbar import ToolbarObject
self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_BY) self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_BY)
self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_ORDER) self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_ORDER)
self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_BY_ARTIST) self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_BY_ARTIST)
self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_ORDER_ARTIST) self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_ORDER_ARTIST)
def resize_icon(self, cover_size): def resize_icon(self, cover_size):
''' '''
resize the view main picture icon resize the view main picture icon
@@ -1304,7 +1308,7 @@ class AbstractView(GObject.Object):
find a path and highlight (select) that object find a path and highlight (select) that object
''' '''
pass pass
def scroll_to_album(self, album): def scroll_to_album(self, album):
''' '''
scroll to the album in the view scroll to the album in the view
@@ -1332,33 +1336,33 @@ class AbstractView(GObject.Object):
consistent consistent
''' '''
pass pass
def get_view_icon_name(self): def get_view_icon_name(self):
''' '''
every view should have an icon - subject to removal every view should have an icon - subject to removal
since we'll probably just have text buttons for the view since we'll probably just have text buttons for the view
''' '''
return "" return ""
def get_default_manager(self): def get_default_manager(self):
''' '''
every view should have a default manager every view should have a default manager
for example an AlbumManager or ArtistManager for example an AlbumManager or ArtistManager
by default - use the AlbumManager from the source by default - use the AlbumManager from the source
''' '''
return self.source.album_manager return self.source.album_manager
def switch_to_coverpane(self, cover_search_pane): def switch_to_coverpane(self, cover_search_pane):
''' '''
called from the source to update the coverpane when called from the source to update the coverpane when
it is switched from the track pane it is switched from the track pane
''' '''
selected = self.get_selected_objects() selected = self.get_selected_objects()
if selected: if selected:
manager = self.get_default_manager() manager = self.get_default_manager()
cover_search_pane.do_search(selected[0], cover_search_pane.do_search(selected[0],
manager.cover_man.update_cover) manager.cover_man.update_cover)
+1
Ver Arquivo
@@ -1,6 +1,7 @@
import gi import gi
from gi.repository import Pango from gi.repository import Pango
from gi.repository import Gtk from gi.repository import Gtk
gi.require_version("Gtk", "3.0") gi.require_version("Gtk", "3.0")
import logging import logging
+14 -16
Ver Arquivo
@@ -57,6 +57,7 @@ class ShapeStar():
coords = [] coords = []
from math import cos, pi, sin from math import cos, pi, sin
step = pi / points step = pi / points
for i in range(2 * points): for i in range(2 * points):
@@ -72,7 +73,7 @@ class ShapeStar():
def layout(self, cr, x, y, w, h): def layout(self, cr, x, y, w, h):
points = [(sx_sy[0] * w + x, sx_sy[1] * h + y) points = [(sx_sy[0] * w + x, sx_sy[1] * h + y)
for sx_sy in self.coords] for sx_sy in self.coords]
cr.move_to(*points[0]) cr.move_to(*points[0])
for p in points[1:]: for p in points[1:]:
@@ -82,7 +83,6 @@ class ShapeStar():
class StarRenderer(ShapeStar): class StarRenderer(ShapeStar):
def __init__(self): def __init__(self):
ShapeStar.__init__(self, 5, 0.6) ShapeStar.__init__(self, 5, 0.6)
@@ -107,7 +107,7 @@ class StarRenderer(ShapeStar):
# public # public
def create_normal_surfaces(self, def create_normal_surfaces(self,
context, vis_width, vis_height, star_width): context, vis_width, vis_height, star_width):
rgba1 = context.get_border_color(Gtk.StateFlags.NORMAL) rgba1 = context.get_border_color(Gtk.StateFlags.NORMAL)
rgba0 = context.get_color(Gtk.StateFlags.ACTIVE) rgba0 = context.get_color(Gtk.StateFlags.ACTIVE)
@@ -118,7 +118,7 @@ class StarRenderer(ShapeStar):
# paint full # paint full
full_surf = cairo.ImageSurface( full_surf = cairo.ImageSurface(
cairo.FORMAT_ARGB32, vis_width, vis_height) cairo.FORMAT_ARGB32, vis_width, vis_height)
cr = cairo.Context(full_surf) cr = cairo.Context(full_surf)
cr.set_source(lin) cr.set_source(lin)
@@ -136,7 +136,7 @@ class StarRenderer(ShapeStar):
# paint empty # paint empty
empty_surf = cairo.ImageSurface( empty_surf = cairo.ImageSurface(
cairo.FORMAT_ARGB32, vis_width, vis_height) cairo.FORMAT_ARGB32, vis_width, vis_height)
cr = cairo.Context(empty_surf) cr = cairo.Context(empty_surf)
cr.set_source(lin) cr.set_source(lin)
@@ -154,11 +154,11 @@ class StarRenderer(ShapeStar):
return full_surf, empty_surf return full_surf, empty_surf
def create_reactive_surfaces(self, def create_reactive_surfaces(self,
context, vis_width, vis_height, star_width): context, vis_width, vis_height, star_width):
# paint full # paint full
full_surf = cairo.ImageSurface( full_surf = cairo.ImageSurface(
cairo.FORMAT_ARGB32, vis_width, vis_height) cairo.FORMAT_ARGB32, vis_width, vis_height)
cr = cairo.Context(full_surf) cr = cairo.Context(full_surf)
if self.rounded: if self.rounded:
@@ -196,7 +196,7 @@ class StarRenderer(ShapeStar):
# paint empty # paint empty
empty_surf = cairo.ImageSurface( empty_surf = cairo.ImageSurface(
cairo.FORMAT_ARGB32, vis_width, vis_height) cairo.FORMAT_ARGB32, vis_width, vis_height)
cr = cairo.Context(empty_surf) cr = cairo.Context(empty_surf)
if self.rounded: if self.rounded:
@@ -230,8 +230,8 @@ class StarRenderer(ShapeStar):
elif self.hints == StarRenderHints.REACTIVE: elif self.hints == StarRenderHints.REACTIVE:
surfs = self.create_reactive_surfaces( surfs = self.create_reactive_surfaces(
context, vis_width, context, vis_width,
vis_height, star_width) vis_height, star_width)
# dict keys # dict keys
full_key, empty_key = self._get_mangled_keys(size) full_key, empty_key = self._get_mangled_keys(size)
@@ -319,13 +319,13 @@ class Star(Gtk.EventBox, StarRenderer):
self.yalign = yalign self.yalign = yalign
self.queue_draw() self.queue_draw()
#~ def set_padding(*args): #~ def set_padding(*args):
#~ return #~ return
def get_alignment(self): def get_alignment(self):
return self.xalign, self.yalign return self.xalign, self.yalign
#~ def get_padding(*args): #~ def get_padding(*args):
#~ return #~ return
def on_style_updated(self, widget): def on_style_updated(self, widget):
@@ -396,7 +396,6 @@ class Star(Gtk.EventBox, StarRenderer):
class StarRatingsWidget(Gtk.HBox): class StarRatingsWidget(Gtk.HBox):
def __init__(self): def __init__(self):
Gtk.Box.__init__(self) Gtk.Box.__init__(self)
self.set_spacing(StockEms.SMALL) self.set_spacing(StockEms.SMALL)
@@ -423,12 +422,11 @@ class StarRatingsWidget(Gtk.HBox):
class ReactiveStar(Star): class ReactiveStar(Star):
__gsignals__ = { __gsignals__ = {
"changed": (GObject.SignalFlags.RUN_LAST, "changed": (GObject.SignalFlags.RUN_LAST,
None, None,
(),) (),)
} }
def __init__(self, size=StarSize.SMALL): def __init__(self, size=StarSize.SMALL):
Star.__init__(self, size) Star.__init__(self, size)
@@ -469,7 +467,7 @@ class ReactiveStar(Star):
if self.get_rating() == 1 and star_index == 1: if self.get_rating() == 1 and star_index == 1:
star_index = 0 star_index = 0
self.set_rating(star_index) self.set_rating(star_index)
self.emit('changed') self.emit('changed')