reformat code according to pycharm
Esse commit está contido em:
+176
-176
@@ -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
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+262
-255
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+57
-54
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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('&', '&'),
|
artist = rb3compat.unicodestr(artist.replace('&', '&'),
|
||||||
'utf-8')
|
'utf-8')
|
||||||
album_name = rb3compat.unicodestr(album_name.replace('&', '&'), 'utf-8')
|
album_name = rb3compat.unicodestr(album_name.replace('&', '&'), '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('&', '&'),
|
artist = rb3compat.unicodestr(artist_name.replace('&', '&'),
|
||||||
'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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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')
|
||||||
|
|
||||||
|
|||||||
Referência em uma Nova Issue
Bloquear um usuário