Example #1
0
    def __init__(self, playlist_name):
        Gtk.Bin.__init__(self)
        self._playlist_name = playlist_name
        self._tracks = []

        self._main_widget = Gtk.Grid()
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget2.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self.add(self._main_widget)
Example #2
0
    def __init__(self, playlist_id):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        main_widget = Gtk.Grid()
        main_widget.set_property('margin', 10)
        main_widget.set_property('column-spacing', 10)
        main_widget.show()

        loved = playlist_id != Type.LOVED
        self._tracks_widget1 = TracksWidget(False, loved)
        self._tracks_widget2 = TracksWidget(False, loved)
        self._tracks_widget1.connect('activated',
                                     self._on_activated)
        self._tracks_widget2.connect('activated',
                                     self._on_activated)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        main_widget.add(self._tracks_widget1)
        main_widget.add(self._tracks_widget2)
        self.add(main_widget)
Example #3
0
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Bin.__init__(self)
        self._playlist_ids = playlist_ids
        self._tracks1 = []
        self._tracks2 = []
        self._width = None
        self._orientation = None
        self._stop = False
        # Used to block widget2 populate while showing one column
        self._locked_widget2 = True

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget()
        self._tracks_widget_right = TracksWidget()
        self._tracks_widget_left.connect('activated', self._on_activated)
        self._tracks_widget_right.connect('activated', self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.add(self._box)
Example #4
0
    def __init__(self, playlist_name):
        Gtk.Bin.__init__(self)
        self._playlist_name = playlist_name
        self._tracks = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget2.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self.add(self._main_widget)
Example #5
0
    def __init__(self, playlist_id):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        main_widget = Gtk.Grid()
        main_widget.set_property('margin', 10)
        main_widget.set_property('column-spacing', 10)
        main_widget.show()

        loved = playlist_id != Type.LOVED
        self._tracks_widget1 = TracksWidget(False, loved)
        self._tracks_widget2 = TracksWidget(False, loved)
        self._tracks_widget1.connect('activated', self._on_activated)
        self._tracks_widget2.connect('activated', self._on_activated)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        main_widget.add(self._tracks_widget1)
        main_widget.add(self._tracks_widget2)
        self.add(main_widget)
Example #6
0
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Bin.__init__(self)
        self._playlist_ids = playlist_ids
        self._tracks1 = []
        self._tracks2 = []
        self._width = None
        self._orientation = None
        self._stop = False
        # Used to block widget2 populate while showing one column
        self._locked_widget2 = True

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget()
        self._tracks_widget_right = TracksWidget()
        self._tracks_widget_left.connect('activated',
                                         self._on_activated)
        self._tracks_widget_right.connect('activated',
                                          self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.add(self._box)
Example #7
0
 def __add_disc_container(self, disc_number):
     """
         Add disc container to box
         @param disc_number as int
     """
     self._tracks_left[disc_number] = TracksWidget()
     self._tracks_right[disc_number] = TracksWidget()
     self._tracks_left[disc_number].connect("activated",
                                            self.__on_activated)
     self._tracks_right[disc_number].connect("activated",
                                             self.__on_activated)
     self._tracks_left[disc_number].show()
     self._tracks_right[disc_number].show()
Example #8
0
    def __init__(self, playlist_id, playlist_name):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._playlist_name = playlist_name
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        loved = playlist_name != Lp.playlists._LOVED
        self._tracks_widget1 = TracksWidget(False, loved)
        self._tracks_widget2 = TracksWidget(False, loved)
        self._tracks_widget1.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget2.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(250)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

        spinner = Gtk.Spinner()
        spinner.start()
        spinner.show()
        self._stack.add(spinner)
        self._stack.add(self._main_widget)
        self._stack.set_visible_child(spinner)

        self.add(self._stack)
Example #9
0
 def _add_disc_container(self, disc_number):
     """
         Add disc container to box
         @param disc_number as int
     """
     self._tracks_left[disc_number] = TracksWidget()
     self._tracks_right[disc_number] = TracksWidget()
     self._tracks_left[disc_number].connect('activated', self._on_activated)
     self._tracks_left[disc_number].connect('button-press-event',
                                            self._on_button_press_event)
     self._tracks_right[disc_number].connect('activated',
                                             self._on_activated)
     self._tracks_right[disc_number].connect('button-press-event',
                                             self._on_button_press_event)
     self._tracks_left[disc_number].show()
     self._tracks_right[disc_number].show()
Example #10
0
    def __init__(self, playlist_id, playlist_name):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._playlist_name = playlist_name
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget2.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(250)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

        spinner = Gtk.Spinner()
        spinner.start()
        spinner.show()
        self._stack.add(spinner)
        self._stack.add(self._main_widget)
        self._stack.set_visible_child(spinner)

        self.add(self._stack)
Example #11
0
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_ids = playlist_ids
        self._tracks1 = []
        self._tracks2 = []
        self._width = None
        self._stop = False
        # Used to block widget2 populate while showing one column
        self._locked_widget2 = True

        self._box = FlowBox()
        self._box.set_selection_mode(Gtk.SelectionMode.NONE)
        self._box.set_hexpand(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        loved = playlist_ids and playlist_ids[0] != Type.LOVED
        self._tracks_widget_left = TracksWidget(loved)
        self._tracks_widget_right = TracksWidget(loved)
        self._tracks_widget_left.connect('track-moved', self._on_track_moved)
        self._tracks_widget_right.connect('track-moved', self._on_track_moved)
        self._tracks_widget_left.connect('activated',
                                         self._on_activated)
        self._tracks_widget_right.connect('activated',
                                          self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget_left)
        size_group.add_widget(self._tracks_widget_right)

        self._box.add(self._tracks_widget_left)
        self._box.add(self._tracks_widget_right)
        self.add(self._box)
Example #12
0
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Grid.__init__(self)
        self.set_row_spacing(5)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.__playlist_ids = playlist_ids
        self.__tracks_left = []
        self.__tracks_right = []
        self.__width = None
        self.__orientation = None
        self.__loading = Loading.NONE
        # Used to block widget2 populate while showing one column
        self.__locked_widget_right = True

        self.__grid = Gtk.Grid()
        self.__grid.set_vexpand(True)
        self.__grid.set_column_homogeneous(True)
        self.__grid.show()

        self.connect("size-allocate", self.__on_size_allocate)

        self.__tracks_widget_left = TracksWidget(True)
        self.__tracks_widget_left.set_vexpand(True)
        self.__tracks_widget_right = TracksWidget(True)
        self.__tracks_widget_right.set_vexpand(True)
        self.__tracks_widget_left.connect("activated",
                                          self.__on_activated)
        self.__tracks_widget_right.connect("activated",
                                           self.__on_activated)
        self.__tracks_widget_left.show()
        self.__tracks_widget_right.show()

        self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
                           [], Gdk.DragAction.MOVE)
        self.drag_dest_add_text_targets()
        self.connect("drag-data-received", self.__on_drag_data_received)

        self.add(self.__grid)
Example #13
0
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Grid.__init__(self)
        self.set_row_spacing(5)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self._playlist_ids = playlist_ids
        self._tracks_left = []
        self._tracks_right = []
        self._width = None
        self._orientation = None
        self._loading = Loading.NONE
        # Used to block widget2 populate while showing one column
        self._locked_widget_right = True

        self._box = Gtk.Grid()
        self._box.set_vexpand(True)
        self._box.set_column_homogeneous(True)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget(True)
        self._tracks_widget_left.set_vexpand(True)
        self._tracks_widget_right = TracksWidget(True)
        self._tracks_widget_right.set_vexpand(True)
        self._tracks_widget_left.connect('activated',
                                         self._on_activated)
        self._tracks_widget_right.connect('activated',
                                          self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
                           [], Gdk.DragAction.MOVE)
        self.drag_dest_add_text_targets()
        self.connect('drag-data-received', self._on_drag_data_received)

        self.add(self._box)
Example #14
0
    def __init__(self, album_id, genre_id, pop_allowed, scrolled, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre id as int
            @param parent width as int
            @param pop_allowed as bool if widget can show popovers
            @param scrolled as bool
            @param size group as Gtk.SizeGroup
        """
        AlbumWidget.__init__(self, album_id, genre_id=genre_id)

        builder = Gtk.Builder()
        if scrolled:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumContextWidget.ui')
        else:
            builder.add_from_resource(
                '/org/gnome/Lollypop/AlbumDetailedWidget.ui')

        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        if scrolled:
            builder.get_object('artist').set_text(self._album.artist_name)
            builder.get_object('artist').show()

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
                sep = Gtk.Separator()
                sep.set_property('margin-bottom', 2)
                sep.show()
                grid.attach(sep, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(pop_allowed)
            self._tracks_right[index] = TracksWidget(pop_allowed)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated', self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()

        builder.get_object('title').set_label(self._album.name)
        builder.get_object('year').set_label(self._album.year)
        self.add(builder.get_object('AlbumDetailedWidget'))

        if pop_allowed:
            self._menu = builder.get_object('menu')
            self._eventbox = builder.get_object('eventbox')
            self._eventbox.connect('realize', self._on_eventbox_realize)
            self._eventbox.connect("button-press-event",
                                   self._on_cover_press_event)
            self._menu.connect('clicked', self._pop_menu)
            self._menu.show()
        else:
            self._eventbox = None
Example #15
0
    def __init__(self, album_id, genre_id, show_menu, scrolled, size_group):
        AlbumWidget.__init__(self, album_id)

        self._artist_id = Objects.albums.get_artist_id(album_id)
        self._album_id = album_id
        self._genre_id = genre_id

        builder = Gtk.Builder()
        if scrolled:
            builder.add_from_resource(
                    '/org/gnome/Lollypop/AlbumContextWidget.ui')
        else:
            builder.add_from_resource(
                    '/org/gnome/Lollypop/AlbumDetailedWidget.ui')
        builder.connect_signals(self)

        self._stars = []
        self._stars.append(builder.get_object('star0'))
        self._stars.append(builder.get_object('star1'))
        self._stars.append(builder.get_object('star2'))
        self._stars.append(builder.get_object('star3'))
        self._stars.append(builder.get_object('star4'))
        self._on_leave_notify(None, None)

        grid = builder.get_object('tracks')
        self._discs = Objects.albums.get_discs(album_id, genre_id)
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % disc)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
                sep = Gtk.Separator()
                sep.show()
                grid.attach(sep, 0, i ,2 ,1)
                i += 1
            self._tracks_left[disc] = TracksWidget(show_menu)
            self._tracks_right[disc] = TracksWidget(show_menu)
            grid.attach(self._tracks_left[disc], 0, i, 1, 1)
            grid.attach(self._tracks_right[disc], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[disc])
            size_group.add_widget(self._tracks_right[disc])

            self._tracks_left[disc].connect('activated', self._on_activated)
            self._tracks_left[disc].connect('button-press-event',
                                         self._on_button_press_event)
            self._tracks_right[disc].connect('activated', self._on_activated)
            self._tracks_right[disc].connect('button-press-event',
                                     self._on_button_press_event)
       
            self._tracks_left[disc].show()
            self._tracks_right[disc].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()

        builder.get_object('title').set_label(
                                            Objects.albums.get_name(album_id))
        builder.get_object('year').set_label(
                                            Objects.albums.get_year(album_id))
        self.add(builder.get_object('AlbumDetailedWidget'))

        if show_menu:
            self._menu = builder.get_object('menu')
            self._eventbox = builder.get_object('eventbox')
            self._eventbox.connect('realize', self._on_eventbox_realize)
            self._eventbox.connect("button-press-event",
                                   self._show_web_art)
            self._menu.connect('clicked',
                               self._pop_menu)
            self._menu.show()
        else:
            self._eventbox = None
Example #16
0
class PlaylistWidget(Gtk.Bin):
    """
        Init playlist Widget
        @param playlist name as str
    """
    def __init__(self, playlist_name):
        Gtk.Bin.__init__(self)
        self._playlist_name = playlist_name
        self._tracks = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget2.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self.add(self._main_widget)

    """
        Populate list one, thread safe
        @param track's ids as array of int
        @param track position as int
    """
    def populate_list_one(self, tracks, pos):
        self._stop = False
        self._tracks = list(tracks)
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget1,
                      pos)

    """
        Populate list two, thread safe
        @param track's ids as array of int
        @param track position as int
    """
    def populate_list_two(self, tracks, pos):
        self._stop = False
        self._tracks += list(tracks)
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget2,
                      pos)

    """
        Update playing indicator
    """
    def update_playing_indicator(self):
        self._tracks_widget1.update_playing(Lp.player.current_track.id)
        self._tracks_widget2.update_playing(Lp.player.current_track.id)

    """
        Stop loading
    """
    def stop(self):
        self._stop = True

    """
        Clear tracks
    """
    def clear(self):
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()

#######################
# PRIVATE             #
#######################
    """
        Add tracks to list
        @param tracks id as array of [int]
        @param widget TracksWidget
        @param track position as int
        @param previous album id as int
    """
    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        if not tracks or self._stop:
            return

        track_id = tracks.pop(0)
        if track_id == -1:
            return

        (title, filepath, length, album_id) =\
            Lp.tracks.get_infos(track_id)
        if title is None:
            return
        else:
            title = escape(title)

        artist_id = Lp.albums.get_artist_id(album_id)
        artist_ids = Lp.tracks.get_artist_ids(track_id)
        # If we are listening to a compilation, prepend artist name
        if artist_id == Type.COMPILATIONS or\
           len(artist_ids) > 1 or\
           artist_id not in artist_ids:
            artist_name = ""
            for artist_id in artist_ids:
                artist_name += translate_artist_name(
                    Lp.artists.get_name(artist_id)) + ", "
            title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]),
                                       title)

        if album_id != previous_album_id:
            widget.add_album(track_id, album_id, pos, title, length, None)
        else:
            widget.add_track(track_id, pos, title, length, None)
        GLib.idle_add(self._add_tracks, tracks, widget, pos+1, album_id)

    """
        On track activation, play track
        @param widget as TracksWidget
        @param track id as int
        @param playlist name as str
    """
    def _on_activated(self, widget, track_id, playlist_name):
        if not Lp.player.is_party():
            track = Lp.player.set_user_playlist(self._tracks, track_id)
            if track is not None:
                Lp.player.load(track)
        else:
            Lp.player.load(Track(track_id))
Example #17
0
class PlaylistWidget(Gtk.Bin):
    """
        Init playlist Widget
        @param playlist name as str
    """
    def __init__(self, playlist_name):
        Gtk.Bin.__init__(self)
        self._playlist_name = playlist_name
        self._tracks = []

        self._main_widget = Gtk.Grid()
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget2.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self.add(self._main_widget)

    """
        Populate list one, thread safe
        @param track's ids as array of int
        @param track position as int
    """

    def populate_list_one(self, tracks, pos):
        GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos)

    """
        Populate list two, thread safe
        @param track's ids as array of int
        @param track position as int
    """

    def populate_list_two(self, tracks, pos):
        GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos)

    """
        Update playing indicator
    """

    def update_playing_indicator(self):
        self._tracks_widget1.update_playing(Objects.player.current.id)
        self._tracks_widget2.update_playing(Objects.player.current.id)

    """
        Clear tracks
    """

    def clear(self):
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()

#######################
# PRIVATE             #
#######################

    """
        Add tracks to list
        @param tracks id as array of [int]
        @param widget TracksWidget
        @param track position as int
    """
    def _add_tracks(self, tracks, widget, pos):
        if not tracks:
            return

        track_id = tracks.pop(0)
        if track_id == -1:
            return

        (title, filepath, length, album_id) =\
            Objects.tracks.get_infos(track_id)

        artist_name = ""
        for artist_id in Objects.tracks.get_artist_ids(track_id):
            artist_name += translate_artist_name(
                Objects.artists.get_name(artist_id)) + ", "
        title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]), escape(title))

        widget.add_track(track_id, pos, title, length, None, True)
        GLib.idle_add(self._add_tracks, tracks, widget, pos + 1)

    """
        On track activation, play track
        @param widget as TracksWidget
        @param track id as int
        @param playlist name as str
    """

    def _on_activated(self, widget, track_id, playlist_name):
        if not Objects.player.is_party():
            if not self._tracks:
                self._tracks = Objects.playlists.get_tracks_id(playlist_name)
            Objects.player.set_user_playlist(self._tracks, track_id)
        Objects.player.load(track_id)
Example #18
0
class PlaylistsWidget(Gtk.Bin):
    """
        Show playlist tracks/albums
    """
    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Bin.__init__(self)
        self._playlist_ids = playlist_ids
        self._tracks1 = []
        self._tracks2 = []
        self._width = None
        self._orientation = None
        self._stop = False
        # Used to block widget2 populate while showing one column
        self._locked_widget2 = True

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget()
        self._tracks_widget_right = TracksWidget()
        self._tracks_widget_left.connect('activated', self._on_activated)
        self._tracks_widget_right.connect('activated', self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.add(self._box)

    def get_id(self):
        """
            Return playlist widget id
            @return int
        """
        return Type.PLAYLISTS

    def update_overlay(self):
        """
            No overlay here now
        """
        pass

    def update_state(self):
        """
            No state to update
        """
        pass

    def update_cover(self):
        """
            No update cover for now
        """
        pass

    def get_current_ordinate(self):
        """
            If current track in widget, return it ordinate,
            @return y as int
        """
        ordinate = None
        for child in self._tracks_widget_left.get_children() + \
                self._tracks_widget_right.get_children():
            if child.get_id() == Lp().player.current_track.id:
                ordinate = child.translate_coordinates(self._box, 0, 0)[1]
        return ordinate

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        # We reset width here to allow size allocation code to run
        self._width = None
        self._tracks1 = list(tracks)
        GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_left, pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        self._tracks2 = list(tracks)
        # If we are showing only one column, wait for widget1
        if self._orientation == Gtk.Orientation.VERTICAL and\
           self._locked_widget2:
            GLib.timeout_add(100, self.populate_list_right, tracks, pos)
        else:
            # We reset width here to allow size allocation code to run
            self._width = None
            GLib.idle_add(self._add_tracks, tracks, self._tracks_widget_right,
                          pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget_left.update_playing(Lp().player.current_track.id)
        self._tracks_widget_right.update_playing(Lp().player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._stop = True

    def append(self, track_id):
        """
            Add track to widget
            @param track id as int
        """
        self._add_tracks([track_id], self._tracks_widget_right, -1)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)

    def remove(self, track_id):
        """
            Del track from widget
            @param track id as int
        """
        children = self._tracks_widget_left.get_children() + \
            self._tracks_widget_right.get_children()
        # Clear the widget
        if track_id is None:
            for child in children:
                child.destroy()
            self._update_tracks()
        else:
            for child in children:
                if child.get_id() == track_id:
                    child.destroy()
                    break
            self._update_tracks()
            self._update_position()
            self._update_headers()
            self._tracks_widget_left.update_indexes(1)
            self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)


#######################
# PRIVATE             #
#######################

    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param pos as int
            @param previous album id as int
        """
        if not tracks or self._stop:
            if widget == self._tracks_widget_right:
                self._stop = False
            else:
                self._locked_widget2 = False
            return

        track = Track(tracks.pop(0))
        row = PlaylistRow(track.id, pos, track.album.id != previous_album_id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        widget.insert(row, pos)
        GLib.idle_add(self._add_tracks, tracks, widget, pos + 1,
                      track.album.id)

    def _update_tracks(self):
        """
            Update tracks based on current widget
        """
        # Recalculate tracks
        self._tracks1 = []
        self._tracks2 = []
        for child in self._tracks_widget_left.get_children():
            self._tracks1.append(child.get_id())
        for child in self._tracks_widget_right.get_children():
            self._tracks2.append(child.get_id())

    def _update_position(self):
        """
            Update widget position
        """
        len_tracks1 = len(self._tracks1)
        len_tracks2 = len(self._tracks2)
        # Take first track from tracks2 and put it at the end of tracks1
        if len_tracks2 > len_tracks1:
            src = self._tracks2[0]
            if self._tracks1:
                dst = self._tracks1[-1]
            else:
                dst = -1
            self._move_track(dst, src, False)
        # Take last track of tracks1 and put it at the bottom of tracks2
        elif len_tracks1 - 1 > len_tracks2:
            src = self._tracks1[-1]
            if self._tracks2:
                dst = self._tracks2[0]
            else:
                dst = -1
            self._move_track(dst, src, True)
        self._update_tracks()

    def _update_headers(self):
        """
            Update headers for all tracks
        """
        self._tracks_widget_left.update_headers()
        prev_album_id = None
        if self._orientation == Gtk.Orientation.VERTICAL:
            if self._tracks1:
                prev_album_id = Track(self._tracks1[-1]).album.id
        self._tracks_widget_right.update_headers(prev_album_id)

    def _move_track(self, dst, src, up):
        """
            Move track from src to row
            @param dst as int
            @param src as int
            @param up as bool
            @return (dst_widget as TracksWidget,
                     src index as int, dst index as int)
        """
        tracks1_len = len(self._tracks1)
        tracks2_len = len(self._tracks2)
        if src in self._tracks1:
            src_widget = self._tracks_widget_left
            src_index = self._tracks1.index(src) - 1
        else:
            src_widget = self._tracks_widget_right
            src_index = self._tracks2.index(src) - 1
        if tracks1_len == 0 or dst in self._tracks1:
            dst_widget = self._tracks_widget_left
            dst_tracks = self._tracks1
        elif tracks2_len == 0 or dst in self._tracks2:
            dst_widget = self._tracks_widget_right
            dst_tracks = self._tracks2
        else:
            return
        # Remove src from src_widget
        for child in src_widget.get_children():
            if child.get_id() == src:
                child.destroy()
                break
        src_track = Track(src)
        prev_track = Track()
        name = escape(src_track.name)
        index = 0
        # Get previous track
        if dst != -1:
            for child in dst_widget.get_children():
                if child.get_id() == dst:
                    break
                index += 1
            if not up:
                index += 1
            # Get previous track (in dst context)
            prev_index = dst_tracks.index(dst)
            if up:
                prev_index -= 1
            prev_track = Track(dst_tracks[prev_index])
            # If we are listening to a compilation, prepend artist name
            if (src_track.album.artist_id == Type.COMPILATIONS
                    or len(src_track.artist_ids) > 1
                    or src_track.album.artist_id not in src_track.artist_ids):
                name = "<b>%s</b>\n%s" % (escape(", ".join(
                    src_track.artists)), name)
            self._tracks1.insert(index, src_track.id)
        row = PlaylistRow(
            src_track.id, index, index == 0
            or src_track.album.id != prev_track.album.id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        dst_widget.insert(row, index)
        return (src_widget, dst_widget, src_index, index)

    def _on_track_moved(self, widget, dst, src, up):
        """
            Move track from src to row
            Recalculate track position
            @param widget as TracksWidget
            @param dst as int
            @param src as int
            @param up as bool
        """
        (src_widget, dst_widget, src_index, dst_index) = \
            self._move_track(dst, src, up)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)
        # Save playlist in db only if one playlist visible
        if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0:
            Lp().playlists.clear(self._playlist_ids[0], False)
            tracks = []
            for track_id in self._tracks1 + self._tracks2:
                tracks.append(Track(track_id))
            Lp().playlists.add_tracks(self._playlist_ids[0], tracks, False)
        if Lp().player.get_user_playlist_ids() == self._playlist_ids:
            Lp().player.populate_user_playlist_by_tracks(
                self._tracks1 + self._tracks2, self._playlist_ids)

    def _on_size_allocate(self, widget, allocation):
        """
            Change box max/min children
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if self._width == allocation.width:
            return
        self._width = allocation.width
        redraw = False
        if allocation.width < WindowSize.MONSTER:
            orientation = Gtk.Orientation.VERTICAL
        else:
            orientation = Gtk.Orientation.HORIZONTAL
        if orientation != self._orientation:
            self._orientation = orientation
            redraw = True
        self._box.set_orientation(orientation)
        if redraw:
            for child in self._box.get_children():
                self._box.remove(child)
            GLib.idle_add(self._box.add, self._tracks_widget_left)
            GLib.idle_add(self._box.add, self._tracks_widget_right)
        self._update_headers()

    def _on_activated(self, widget, track_id):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
        """
        Lp().player.load(Track(track_id))
        if not Lp().player.is_party():
            Lp().player.populate_user_playlist_by_tracks(
                self._tracks1 + self._tracks2, self._playlist_ids)
Example #19
0
    def __init__(self, album_id, genre_ids, artist_ids, popover, size_group):
        """
            Init detailed album widget
            @param album id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param popover as bool
            @param size group as Gtk.SizeGroup
        """
        Gtk.Bin.__init__(self)
        AlbumWidget.__init__(self, album_id, genre_ids)
        self._artist_ids = artist_ids
        self._pop_allowed = not popover or Gtk.get_minor_version() > 16
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Lollypop/%s.ui' %
                                  type(self).__name__)
        self._color = builder.get_object('color')
        rating = RatingWidget(self._album)
        rating.show()
        builder.get_object('coverbox').add(rating)
        builder.connect_signals(self)

        self._artist_label = builder.get_object('artist')
        if len(artist_ids) > 1:
            self._artist_label.set_text(self._album.artist_name)
            self._artist_label.show()
        label = builder.get_object('duration')
        duration = Lp().albums.get_duration(album_id, genre_ids)
        hours = int(duration / 3600)
        mins = int(duration / 60)
        if hours > 0:
            mins -= hours * 60
            if mins > 0:
                label.set_text(_("%s h  %s m") % (hours, mins))
            else:
                label.set_text(_("%s h") % hours)
        else:
            label.set_text(_("%s m") % mins)

        grid = builder.get_object('tracks')
        self._discs = self._album.discs
        self._tracks_left = {}
        self._tracks_right = {}
        show_label = len(self._discs) > 1
        i = 0
        for disc in self._discs:
            index = disc.number
            if show_label:
                label = Gtk.Label()
                label.set_text(_("Disc %s") % index)
                label.set_property('halign', Gtk.Align.START)
                label.get_style_context().add_class('dim-label')
                if i:
                    label.set_property('margin-top', 30)
                label.show()
                grid.attach(label, 0, i, 2, 1)
                i += 1
            self._tracks_left[index] = TracksWidget(self._pop_allowed, True)
            self._tracks_right[index] = TracksWidget(self._pop_allowed, True)
            grid.attach(self._tracks_left[index], 0, i, 1, 1)
            grid.attach(self._tracks_right[index], 1, i, 1, 1)
            size_group.add_widget(self._tracks_left[index])
            size_group.add_widget(self._tracks_right[index])

            self._tracks_left[index].connect('activated', self._on_activated)
            self._tracks_left[index].connect('button-press-event',
                                             self._on_button_press_event)
            self._tracks_right[index].connect('activated', self._on_activated)
            self._tracks_right[index].connect('button-press-event',
                                              self._on_button_press_event)

            self._tracks_left[index].show()
            self._tracks_right[index].show()
            i += 1

        self._cover = builder.get_object('cover')
        self.set_cover()
        self.update_state()

        builder.get_object('title').set_label(self._album.name)
        if self._album.year:
            year = builder.get_object('year')
            year.set_label(self._album.year)
            year.show()

        self.add(builder.get_object('widget'))

        # TODO: Remove this test later
        if self._pop_allowed:
            self._menu = builder.get_object('menu')
            self._menu.connect('clicked', self._pop_menu)
            self._menu.show()
Example #20
0
class PlaylistWidget(Gtk.Bin):
    """
        Show playlist tracks/albums
    """

    def __init__(self, playlist_id, playlist_name):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._playlist_name = playlist_name
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget2.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(250)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

        spinner = Gtk.Spinner()
        spinner.start()
        spinner.show()
        self._stack.add(spinner)
        self._stack.add(self._main_widget)
        self._stack.set_visible_child(spinner)

        self.add(self._stack)

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        GLib.idle_add(self._stack.set_visible_child, self._main_widget)
        self._stop = False
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget1,
                      pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        self._stop = False
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget2,
                      pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget1.update_playing(Lp.player.current_track.id)
        self._tracks_widget2.update_playing(Lp.player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._stop = True

    def clear(self):
        """
            Clear tracks
        """
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()

#######################
# PRIVATE             #
#######################
    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param previous album id as int
        """
        if not tracks or self._stop:
            return

        track_id = tracks.pop(0)
        if track_id == -1:
            return

        (title, filepath, length, album_id) =\
            Lp.tracks.get_infos(track_id)
        if title is None:
            return
        else:
            title = escape(title)

        artist_id = Lp.albums.get_artist_id(album_id)
        artist_ids = Lp.tracks.get_artist_ids(track_id)
        # If we are listening to a compilation, prepend artist name
        if artist_id == Type.COMPILATIONS or\
           len(artist_ids) > 1 or\
           artist_id not in artist_ids:
            artist_name = ""
            for artist_id in artist_ids:
                if artist_name != "":
                    artist_name += ", "
                artist_name += Lp.artists.get_name(artist_id)
            title = "<b>%s</b>\n%s" % (escape(artist_name),
                                       title)

        if widget == self._tracks_widget1:
            self._tracks1.append(Track(track_id))
        else:
            self._tracks2.append(Track(track_id))

        if album_id != previous_album_id:
            widget.add_album(track_id, album_id, pos, title, length, None)
        else:
            widget.add_album(track_id, None, pos, title, length, None)
        GLib.idle_add(self._add_tracks, tracks, widget, pos+1, album_id)

    def _on_activated(self, widget, track_id, playlist_name):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
            @param playlist name as str
        """
        if Lp.player.is_party():
            Lp.player.load(Track(track_id))
        else:
            track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2,
                                                track_id)
            Lp.player.set_user_playlist_id(self._playlist_id)
            if track is not None:
                Lp.player.load(track)
Example #21
0
class PlaylistWidget(Gtk.Bin):
    """
        Show playlist tracks/albums
    """

    def __init__(self, playlist_id):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        main_widget = Gtk.Grid()
        main_widget.set_property('margin', 10)
        main_widget.set_property('column-spacing', 10)
        main_widget.show()

        loved = playlist_id != Type.LOVED
        self._tracks_widget1 = TracksWidget(False, loved)
        self._tracks_widget2 = TracksWidget(False, loved)
        self._tracks_widget1.connect('activated',
                                     self._on_activated)
        self._tracks_widget2.connect('activated',
                                     self._on_activated)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        main_widget.add(self._tracks_widget1)
        main_widget.add(self._tracks_widget2)
        self.add(main_widget)

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        self._stop = False
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget1,
                      pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        self._stop = False
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget2,
                      pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget1.update_playing(Lp.player.current_track.id)
        self._tracks_widget2.update_playing(Lp.player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._stop = True

    def clear(self):
        """
            Clear tracks
        """
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()

#######################
# PRIVATE             #
#######################
    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param previous album id as int
        """
        if not tracks or self._stop:
            return

        track = Track(tracks.pop(0))
        name = escape(track.name)
        album = track.album

        if track.id is None:
            GLib.idle_add(self._add_tracks, tracks,
                          widget, pos + 1, previous_album_id)
            return

        # If we are listening to a compilation, prepend artist name
        if (album.artist_id == Type.COMPILATIONS or
                len(track.artist_ids) > 1 or
                album.artist_id not in track.artist_ids):
            name = "<b>%s</b>\n%s" % (escape(track.artist_names), name)

        if widget == self._tracks_widget1:
            self._tracks1.append(track)
        else:
            self._tracks2.append(track)

        if album.id != previous_album_id:
            widget.add_album(track.id, album, pos,
                             name, track.duration, None)
        else:
            widget.add_album(track.id, None, pos, name, track.duration, None)
        GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, album.id)

    def _on_activated(self, widget, track_id):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
        """
        if Lp.player.is_party():
            Lp.player.load(Track(track_id))
        else:
            track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2,
                                                track_id)
            Lp.player.set_user_playlist_id(self._playlist_id)
            if track is not None:
                Lp.player.load(track)
Example #22
0
class PlaylistsWidget(Gtk.Grid):
    """
        Show playlist tracks/albums
    """
    __gsignals__ = {
        'populated': (GObject.SignalFlags.RUN_FIRST, None, ())
    }

    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Grid.__init__(self)
        self.set_row_spacing(5)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self._playlist_ids = playlist_ids
        self._tracks_left = []
        self._tracks_right = []
        self._width = None
        self._orientation = None
        self._loading = Loading.NONE
        # Used to block widget2 populate while showing one column
        self._locked_widget_right = True

        self._box = Gtk.Grid()
        self._box.set_vexpand(True)
        self._box.set_column_homogeneous(True)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget(True)
        self._tracks_widget_left.set_vexpand(True)
        self._tracks_widget_right = TracksWidget(True)
        self._tracks_widget_right.set_vexpand(True)
        self._tracks_widget_left.connect('activated',
                                         self._on_activated)
        self._tracks_widget_right.connect('activated',
                                          self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION,
                           [], Gdk.DragAction.MOVE)
        self.drag_dest_add_text_targets()
        self.connect('drag-data-received', self._on_drag_data_received)

        self.add(self._box)

    def get_id(self):
        """
            Return playlist widget id
            @return int
        """
        return Type.PLAYLISTS

    def show_overlay(self, bool):
        """
            No overlay here now
        """
        pass

    def update_state(self):
        """
            No state to update
        """
        pass

    def update_cover(self):
        """
            No update cover for now
        """
        pass

    def get_current_ordinate(self):
        """
            If current track in widget, return it ordinate,
            @return y as int
        """
        ordinate = None
        for child in self._tracks_widget_left.get_children() + \
                self._tracks_widget_right.get_children():
            if child.get_id() == Lp().player.current_track.id:
                ordinate = child.translate_coordinates(self._box, 0, 0)[1]
        return ordinate

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        # We reset width here to allow size allocation code to run
        self._width = None
        self._tracks_left = list(tracks)
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget_left,
                      pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        self._tracks_right = list(tracks)
        # If we are showing only one column, wait for widget1
        if self._orientation == Gtk.Orientation.VERTICAL and\
           self._locked_widget_right:
            GLib.timeout_add(100, self.populate_list_right, tracks, pos)
        else:
            # We reset width here to allow size allocation code to run
            self._width = None
            GLib.idle_add(self._add_tracks,
                          tracks,
                          self._tracks_widget_right,
                          pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget_left.update_playing(Lp().player.current_track.id)
        self._tracks_widget_right.update_playing(Lp().player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._loading = Loading.STOP

    def append(self, track_id):
        """
            Add track to widget
            @param track id as int
        """
        self._add_tracks([track_id],
                         self._tracks_widget_right,
                         -1)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks_left) + 1)

    def remove(self, track_id):
        """
            Del track from widget
            @param track id as int
        """
        children = self._tracks_widget_left.get_children() + \
            self._tracks_widget_right.get_children()
        # Clear the widget
        if track_id is None:
            for child in children:
                child.destroy()
            self._update_tracks()
        else:
            for child in children:
                if child.get_id() == track_id:
                    child.destroy()
                    break
            self._update_tracks()
            self._update_position()
            self._update_headers()
            self._tracks_widget_left.update_indexes(1)
            self._tracks_widget_right.update_indexes(
                                                    len(self._tracks_left) + 1)

#######################
# PRIVATE             #
#######################
    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param pos as int
            @param previous album id as int
        """
        if self._loading == Loading.STOP:
            self._loading = Loading.NONE
            return
        if not tracks:
            if widget == self._tracks_widget_right:
                self._loading |= Loading.RIGHT
            elif widget == self._tracks_widget_left:
                self._loading |= Loading.LEFT
            if self._loading == Loading.ALL:
                self.emit('populated')
            self._locked_widget_right = False
            return

        track = Track(tracks.pop(0))
        row = PlaylistRow(track.id, pos,
                          track.album.id != previous_album_id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        widget.insert(row, pos)
        GLib.idle_add(self._add_tracks, tracks, widget,
                      pos + 1, track.album.id)

    def _update_tracks(self):
        """
            Update tracks based on current widget
        """
        # Recalculate tracks
        self._tracks_left = []
        self._tracks_right = []
        for child in self._tracks_widget_left.get_children():
            self._tracks_left.append(child.get_id())
        for child in self._tracks_widget_right.get_children():
            self._tracks_right.append(child.get_id())

    def _update_position(self):
        """
            Update widget position
        """
        len_tracks1 = len(self._tracks_left)
        len_tracks2 = len(self._tracks_right)
        # Take first track from tracks2 and put it at the end of tracks1
        if len_tracks2 > len_tracks1:
            src = self._tracks_right[0]
            if self._tracks_left:
                dst = self._tracks_left[-1]
            else:
                dst = -1
            self._move_track(dst, src, False)
        # Take last track of tracks1 and put it at the bottom of tracks2
        elif len_tracks1 - 1 > len_tracks2:
            src = self._tracks_left[-1]
            if self._tracks_right:
                dst = self._tracks_right[0]
            else:
                dst = -1
            self._move_track(dst, src, True)
        self._update_tracks()

    def _update_headers(self):
        """
            Update headers for all tracks
        """
        self._tracks_widget_left.update_headers()
        prev_album_id = None
        if self._orientation == Gtk.Orientation.VERTICAL:
            if self._tracks_left:
                prev_album_id = Track(self._tracks_left[-1]).album.id
        self._tracks_widget_right.update_headers(prev_album_id)

    def _move_track(self, dst, src, up):
        """
            Move track from src to row
            @param dst as int
            @param src as int
            @param up as bool
            @return (dst_widget as TracksWidget,
                     src index as int, dst index as int)
        """
        tracks1_len = len(self._tracks_left)
        tracks2_len = len(self._tracks_right)
        if src in self._tracks_left:
            src_widget = self._tracks_widget_left
            src_index = self._tracks_left.index(src) - 1
        else:
            src_widget = self._tracks_widget_right
            src_index = self._tracks_right.index(src) - 1
        if tracks1_len == 0 or dst in self._tracks_left:
            dst_widget = self._tracks_widget_left
            dst_tracks = self._tracks_left
        elif tracks2_len == 0 or dst in self._tracks_right:
            dst_widget = self._tracks_widget_right
            dst_tracks = self._tracks_right
        else:
            return
        # Remove src from src_widget
        for child in src_widget.get_children():
            if child.get_id() == src:
                child.destroy()
                break
        src_track = Track(src)
        prev_track = Track()
        name = escape(src_track.name)
        index = 0
        # Get previous track
        if dst != -1:
            for child in dst_widget.get_children():
                if child.get_id() == dst:
                    break
                index += 1
            if not up:
                index += 1
            # Get previous track (in dst context)
            prev_index = dst_tracks.index(dst)
            if up:
                prev_index -= 1
            prev_track = Track(dst_tracks[prev_index])
            # If we are listening to a compilation, prepend artist name
            if (src_track.album.artist_id == Type.COMPILATIONS or
                    len(src_track.artist_ids) > 1 or
                    src_track.album.artist_id not in src_track.artist_ids):
                name = "<b>%s</b>\n%s" % (escape(", ".join(src_track.artists)),
                                          name)
            self._tracks_left.insert(index, src_track.id)
        row = PlaylistRow(src_track.id,
                          index,
                          index == 0 or
                          src_track.album.id != prev_track.album.id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        dst_widget.insert(row, index)
        return (src_widget, dst_widget, src_index, index)

    def _on_drag_data_received(self, widget, context, x, y, data, info, time):
        """
            ONLY HAPPEN IN VERTICAL ORIENTATION
            Horizontal orientation is handled by TracksWidget
            @param widget as Gtk.Widget
            @param context as Gdk.DragContext
            @param x as int
            @param y as int
            @param data as Gtk.SelectionData
            @param info as int
            @param time as int
        """
        try:
            try:
                child = self._tracks_widget_right.get_children()[-1]
            except:
                child = self._tracks_widget_left.get_children()[-1]
            self._on_track_moved(widget, child.get_id(),
                                 int(data.get_text()), False)
        except:
            pass

    def _on_track_moved(self, widget, dst, src, up):
        """
            Move track from src to row
            Recalculate track position
            @param widget as TracksWidget
            @param dst as int
            @param src as int
            @param up as bool
        """
        def update_playlist():
            # Save playlist in db only if one playlist visible
            if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0:
                Lp().playlists.clear(self._playlist_ids[0], False)
                tracks = []
                for track_id in self._tracks_left + self._tracks_right:
                    tracks.append(Track(track_id))
                Lp().playlists.add_tracks(self._playlist_ids[0],
                                          tracks,
                                          False)
            if not (set(self._playlist_ids) -
               set(Lp().player.get_user_playlist_ids())):
                Lp().player.update_user_playlist(self._tracks_left +
                                                 self._tracks_right)

        (src_widget, dst_widget, src_index, dst_index) = \
            self._move_track(dst, src, up)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks_left) + 1)
        t = Thread(target=update_playlist)
        t.daemon = True
        t.start()

    def _on_size_allocate(self, widget, allocation):
        """
            Change box max/min children
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if self._width == allocation.width:
            return
        self._width = allocation.width
        redraw = False
        if allocation.width < WindowSize.MONSTER:
            self._box.set_property('valign', Gtk.Align.START)
            orientation = Gtk.Orientation.VERTICAL
        else:
            self._box.set_property('valign', Gtk.Align.FILL)
            orientation = Gtk.Orientation.HORIZONTAL
        if orientation != self._orientation:
            self._orientation = orientation
            redraw = True
        self._box.set_orientation(orientation)
        if redraw:
            for child in self._box.get_children():
                self._box.remove(child)
            GLib.idle_add(self._box.add, self._tracks_widget_left)
            GLib.idle_add(self._box.add, self._tracks_widget_right)
        self._update_headers()

    def _on_activated(self, widget, track_id):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
        """
        # Add to queue by default
        if Lp().player.locked or Lp().player.queued:
            if track_id in Lp().player.get_queue():
                Lp().player.del_from_queue(track_id)
            else:
                Lp().player.append_to_queue(track_id)
        else:
            Lp().player.load(Track(track_id))
            if not Lp().player.is_party():
                Lp().player.populate_user_playlist_by_tracks(
                                                            self._tracks_left +
                                                            self._tracks_right,
                                                            self._playlist_ids)
Example #23
0
class PlaylistsWidget(Gtk.Grid):
    """
        Show playlist tracks/albums
    """
    __gsignals__ = {"populated": (GObject.SignalFlags.RUN_FIRST, None, ())}

    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Grid.__init__(self)
        self.set_row_spacing(5)
        self.set_orientation(Gtk.Orientation.VERTICAL)
        self.__playlist_ids = playlist_ids
        self.__tracks_left = []
        self.__tracks_right = []
        self.__width = None
        self.__orientation = None
        self.__loading = Loading.NONE
        # Used to block widget2 populate while showing one column
        self.__locked_widget_right = True

        self.__grid = Gtk.Grid()
        self.__grid.set_vexpand(True)
        self.__grid.set_column_homogeneous(True)
        self.__grid.show()

        self.connect("size-allocate", self.__on_size_allocate)

        self.__tracks_widget_left = TracksWidget(True)
        self.__tracks_widget_left.set_vexpand(True)
        self.__tracks_widget_right = TracksWidget(True)
        self.__tracks_widget_right.set_vexpand(True)
        self.__tracks_widget_left.connect("activated", self.__on_activated)
        self.__tracks_widget_right.connect("activated", self.__on_activated)
        self.__tracks_widget_left.show()
        self.__tracks_widget_right.show()

        self.drag_dest_set(Gtk.DestDefaults.DROP | Gtk.DestDefaults.MOTION, [],
                           Gdk.DragAction.MOVE)
        self.drag_dest_add_text_targets()
        self.connect("drag-data-received", self.__on_drag_data_received)

        self.add(self.__grid)

    @property
    def id(self):
        """
            Return playlist widget id
            @return int
        """
        return Type.PLAYLISTS

    @property
    def boxes(self):
        """
            @return [Gtk.ListBox]
        """
        return [self.__tracks_widget_left, self.__tracks_widget_right]

    def set_filter_func(self, func):
        """
            Set filter function
        """
        self.__tracks_widget_left.set_filter_func(func)
        self.__tracks_widget_right.set_filter_func(func)

    def show_overlay(self, bool):
        """
            No overlay here now
        """
        pass

    def update_state(self):
        """
            No state to update
        """
        pass

    def update_cover(self):
        """
            No update cover for now
        """
        pass

    def update_allocation(self):
        """
            Update widget allocation
        """
        self.__width = 0
        self.__on_size_allocate(self, self.get_allocation())

    def get_current_ordinate(self):
        """
            If current track in widget, return it ordinate,
            @return y as int
        """
        ordinate = None
        for child in self.__tracks_widget_left.get_children() + \
                self.__tracks_widget_right.get_children():
            if child.id == Lp().player.current_track.id:
                ordinate = child.translate_coordinates(self.__grid, 0, 0)[1]
        return ordinate

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track"s ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        # We reset width here to allow size allocation code to run
        self.__width = None
        self.__tracks_left = list(tracks)
        GLib.idle_add(self.__add_tracks, tracks, self.__tracks_widget_left,
                      pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track"s ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        self.__tracks_right = list(tracks)
        # If we are showing only one column, wait for widget1
        if self.__orientation == Gtk.Orientation.VERTICAL and\
           self.__locked_widget_right:
            GLib.timeout_add(100, self.populate_list_right, tracks, pos)
        else:
            # We reset width here to allow size allocation code to run
            self.__width = None
            GLib.idle_add(self.__add_tracks, tracks,
                          self.__tracks_widget_right, pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self.__tracks_widget_left.update_playing(Lp().player.current_track.id)
        self.__tracks_widget_right.update_playing(Lp().player.current_track.id)

    def update_duration(self, track_id):
        """
            Update duration for current track
            @param track id as int
        """
        self.__tracks_widget_left.update_duration(track_id)
        self.__tracks_widget_right.update_duration(track_id)

    def stop(self):
        """
            Stop loading
        """
        self.__loading = Loading.STOP

    def insert(self, track_id, pos=-1):
        """
            Add track to widget
            @param track id as int
            @param pos as int
        """
        children_len = len(self.__tracks_widget_left.get_children() +
                           self.__tracks_widget_right.get_children())
        if pos > children_len / 2:
            widget = self.__tracks_widget_right
            pos -= len(self.__tracks_widget_left.get_children())
        else:
            widget = self.__tracks_widget_left
        self.__add_tracks([track_id], widget, pos)
        self.__update_tracks()
        self.__update_position()
        self.__update_headers()
        self.__tracks_widget_left.update_indexes(1)
        self.__tracks_widget_right.update_indexes(len(self.__tracks_left) + 1)

    def remove(self, track_id):
        """
            Del track from widget
            @param track id as int
        """
        children = self.__tracks_widget_left.get_children() + \
            self.__tracks_widget_right.get_children()
        # Clear the widget
        if track_id is None:
            for child in children:
                child.destroy()
            self.__update_tracks()
        else:
            for child in children:
                if child.id == track_id:
                    child.destroy()
                    break
            self.__update_tracks()
            self.__update_position()
            self.__update_headers()
            self.__tracks_widget_left.update_indexes(1)
            self.__tracks_widget_right.update_indexes(
                len(self.__tracks_left) + 1)


#######################
# PRIVATE             #
#######################

    def __add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param pos as int
            @param previous album id as int
        """
        if self.__loading == Loading.STOP:
            self.__loading = Loading.NONE
            return
        if not tracks:
            if widget == self.__tracks_widget_right:
                self.__loading |= Loading.RIGHT
            elif widget == self.__tracks_widget_left:
                self.__loading |= Loading.LEFT
            if self.__loading == Loading.ALL:
                self.emit("populated")
            self.__locked_widget_right = False
            return

        track = Track(tracks.pop(0))
        row = PlaylistRow(track.id, pos, track.album.id != previous_album_id)
        row.connect("track-moved", self.__on_track_moved)
        row.show()
        widget.insert(row, pos)
        GLib.idle_add(self.__add_tracks, tracks, widget, pos + 1,
                      track.album.id)

    def __update_tracks(self):
        """
            Update tracks based on current widget
        """
        # Recalculate tracks
        self.__tracks_left = []
        self.__tracks_right = []
        for child in self.__tracks_widget_left.get_children():
            self.__tracks_left.append(child.id)
        for child in self.__tracks_widget_right.get_children():
            self.__tracks_right.append(child.id)

    def __update_position(self):
        """
            Update widget position
        """
        len_tracks1 = len(self.__tracks_left)
        len_tracks2 = len(self.__tracks_right)
        # Take first track from tracks2 and put it at the end of tracks1
        if len_tracks2 > len_tracks1:
            src = self.__tracks_right[0]
            if self.__tracks_left:
                dst = self.__tracks_left[-1]
            else:
                dst = -1
            self.__move_track(dst, src, False)
        # Take last track of tracks1 and put it at the bottom of tracks2
        elif len_tracks1 - 1 > len_tracks2:
            src = self.__tracks_left[-1]
            if self.__tracks_right:
                dst = self.__tracks_right[0]
            else:
                dst = -1
            self.__move_track(dst, src, True)
        self.__update_tracks()

    def __update_headers(self):
        """
            Update headers for all tracks
        """
        self.__tracks_widget_left.update_headers()
        prev_album_id = None
        if self.__orientation == Gtk.Orientation.VERTICAL:
            if self.__tracks_left:
                prev_album_id = Track(self.__tracks_left[-1]).album.id
        self.__tracks_widget_right.update_headers(prev_album_id)

    def __show_spinner(self, widget, track_id):
        """
            Show spinner for widget
            @param widget as TracksWidget
            @param track id as int
        """
        track = Track(track_id)
        if track.is_web:
            widget.show_spinner(track_id)

    def __move_track(self, dst, src, up):
        """
            Move track from src to row
            @param dst as int
            @param src as int
            @param up as bool
            @return (dst_widget as TracksWidget,
                     src index as int, dst index as int)
        """
        tracks1_len = len(self.__tracks_left)
        tracks2_len = len(self.__tracks_right)
        if src in self.__tracks_left:
            src_widget = self.__tracks_widget_left
            src_index = self.__tracks_left.index(src) - 1
        else:
            src_widget = self.__tracks_widget_right
            src_index = self.__tracks_right.index(src) - 1
        if tracks1_len == 0 or dst in self.__tracks_left:
            dst_widget = self.__tracks_widget_left
            dst_tracks = self.__tracks_left
        elif tracks2_len == 0 or dst in self.__tracks_right:
            dst_widget = self.__tracks_widget_right
            dst_tracks = self.__tracks_right
        else:
            return
        # Remove src from src_widget
        for child in src_widget.get_children():
            if child.id == src:
                child.destroy()
                break
        src_track = Track(src)
        prev_track = Track()
        name = GLib.markup_escape_text(src_track.name)
        index = 0
        # Get previous track
        if dst != -1:
            for child in dst_widget.get_children():
                if child.id == dst:
                    break
                index += 1
            if not up:
                index += 1
            # Get previous track (in dst context)
            prev_index = dst_tracks.index(dst)
            if up:
                prev_index -= 1
            prev_track = Track(dst_tracks[prev_index])
            # If we are listening to a compilation, prepend artist name
            if (src_track.album.artist_id == Type.COMPILATIONS
                    or len(src_track.artist_ids) > 1
                    or src_track.album.artist_id not in src_track.artist_ids):
                name = "<b>%s</b>\n%s" % (GLib.markup_escape_text(", ".join(
                    src_track.artists)), name)
            self.__tracks_left.insert(index, src_track.id)
        row = PlaylistRow(
            src_track.id, index, index == 0
            or src_track.album.id != prev_track.album.id)
        row.connect("track-moved", self.__on_track_moved)
        row.show()
        dst_widget.insert(row, index)
        return (src_widget, dst_widget, src_index, index)

    def __on_drag_data_received(self, widget, context, x, y, data, info, time):
        """
            ONLY HAPPEN IN VERTICAL ORIENTATION
            Horizontal orientation is handled by TracksWidget
            @param widget as Gtk.Widget
            @param context as Gdk.DragContext
            @param x as int
            @param y as int
            @param data as Gtk.SelectionData
            @param info as int
            @param time as int
        """
        try:
            value = int(data.get_text())
            try:
                child = self.__tracks_widget_right.get_children()[-1]
            except:
                child = self.__tracks_widget_left.get_children()[-1]
            self.__on_track_moved(widget, child.id, value, False)
        except:
            if len(self.__playlist_ids) == 1:
                Lp().playlists.import_uri(self.__playlist_ids[0],
                                          data.get_text())

    def __on_track_moved(self, widget, dst, src, up):
        """
            Move track from src to row
            Recalculate track position
            @param widget as TracksWidget
            @param dst as int
            @param src as int
            @param up as bool
        """
        def update_playlist():
            # Save playlist in db only if one playlist visible
            if len(self.__playlist_ids) == 1 and self.__playlist_ids[0] >= 0:
                Lp().playlists.clear(self.__playlist_ids[0], False)
                tracks = []
                for track_id in self.__tracks_left + self.__tracks_right:
                    tracks.append(Track(track_id))
                Lp().playlists.add_tracks(self.__playlist_ids[0], tracks,
                                          False)
            if not (set(self.__playlist_ids) -
                    set(Lp().player.get_user_playlist_ids())):
                Lp().player.update_user_playlist(self.__tracks_left +
                                                 self.__tracks_right)

        (src_widget, dst_widget, src_index, dst_index) = \
            self.__move_track(dst, src, up)
        self.__update_tracks()
        self.__update_position()
        self.__update_headers()
        self.__tracks_widget_left.update_indexes(1)
        self.__tracks_widget_right.update_indexes(len(self.__tracks_left) + 1)
        t = Thread(target=update_playlist)
        t.daemon = True
        t.start()

    def __on_size_allocate(self, widget, allocation):
        """
            Change box max/min children
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if self.__width == allocation.width:
            return
        self.__width = allocation.width
        redraw = False
        if allocation.width < WindowSize.MONSTER or\
                not Lp().settings.get_value("split-view"):
            self.__grid.set_property("valign", Gtk.Align.START)
            orientation = Gtk.Orientation.VERTICAL
        else:
            self.__grid.set_property("valign", Gtk.Align.FILL)
            orientation = Gtk.Orientation.HORIZONTAL
        if orientation != self.__orientation:
            self.__orientation = orientation
            redraw = True
        self.__grid.set_orientation(orientation)
        if redraw:
            for child in self.__grid.get_children():
                self.__grid.remove(child)
            GLib.idle_add(self.__grid.add, self.__tracks_widget_left)
            GLib.idle_add(self.__grid.add, self.__tracks_widget_right)
        self.__update_headers()

    def __on_activated(self, widget, track_id):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
        """
        # Add to queue by default
        if Lp().player.locked:
            if track_id in Lp().player.queue:
                Lp().player.del_from_queue(track_id)
            else:
                Lp().player.append_to_queue(track_id)
        else:
            self.__show_spinner(widget, track_id)
            Lp().player.load(Track(track_id))
            if not Lp().player.is_party:
                Lp().player.populate_user_playlist_by_tracks(
                    self.__tracks_left + self.__tracks_right,
                    self.__playlist_ids)
Example #24
0
class PlaylistsWidget(Gtk.Bin):
    """
        Show playlist tracks/albums
    """

    def __init__(self, playlist_ids):
        """
            Init playlist Widget
            @param playlist ids as [int]
        """
        Gtk.Bin.__init__(self)
        self._playlist_ids = playlist_ids
        self._tracks1 = []
        self._tracks2 = []
        self._width = None
        self._orientation = None
        self._stop = False
        # Used to block widget2 populate while showing one column
        self._locked_widget2 = True

        self._box = Gtk.Grid()
        self._box.set_column_homogeneous(True)
        self._box.set_property('valign', Gtk.Align.START)
        self._box.show()

        self.connect('size-allocate', self._on_size_allocate)

        self._tracks_widget_left = TracksWidget()
        self._tracks_widget_right = TracksWidget()
        self._tracks_widget_left.connect('activated',
                                         self._on_activated)
        self._tracks_widget_right.connect('activated',
                                          self._on_activated)
        self._tracks_widget_left.show()
        self._tracks_widget_right.show()

        self.add(self._box)

    def get_id(self):
        """
            Return playlist widget id
            @return int
        """
        return Type.PLAYLISTS

    def show_overlay(self, bool):
        """
            No overlay here now
        """
        pass

    def update_state(self):
        """
            No state to update
        """
        pass

    def update_cover(self):
        """
            No update cover for now
        """
        pass

    def get_current_ordinate(self):
        """
            If current track in widget, return it ordinate,
            @return y as int
        """
        ordinate = None
        for child in self._tracks_widget_left.get_children() + \
                self._tracks_widget_right.get_children():
            if child.get_id() == Lp().player.current_track.id:
                ordinate = child.translate_coordinates(self._box, 0, 0)[1]
        return ordinate

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        # We reset width here to allow size allocation code to run
        self._width = None
        self._tracks1 = list(tracks)
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget_left,
                      pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int (not null)
            @param track position as int
            @thread safe
        """
        self._tracks2 = list(tracks)
        # If we are showing only one column, wait for widget1
        if self._orientation == Gtk.Orientation.VERTICAL and\
           self._locked_widget2:
            GLib.timeout_add(100, self.populate_list_right, tracks, pos)
        else:
            # We reset width here to allow size allocation code to run
            self._width = None
            GLib.idle_add(self._add_tracks,
                          tracks,
                          self._tracks_widget_right,
                          pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget_left.update_playing(Lp().player.current_track.id)
        self._tracks_widget_right.update_playing(Lp().player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._stop = True

    def append(self, track_id):
        """
            Add track to widget
            @param track id as int
        """
        self._add_tracks([track_id],
                         self._tracks_widget_right,
                         -1)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)

    def remove(self, track_id):
        """
            Del track from widget
            @param track id as int
        """
        children = self._tracks_widget_left.get_children() + \
            self._tracks_widget_right.get_children()
        # Clear the widget
        if track_id is None:
            for child in children:
                child.destroy()
            self._update_tracks()
        else:
            for child in children:
                if child.get_id() == track_id:
                    child.destroy()
                    break
            self._update_tracks()
            self._update_position()
            self._update_headers()
            self._tracks_widget_left.update_indexes(1)
            self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)

#######################
# PRIVATE             #
#######################
    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param pos as int
            @param previous album id as int
        """
        if not tracks or self._stop:
            if widget == self._tracks_widget_right:
                self._stop = False
            else:
                self._locked_widget2 = False
            return

        track = Track(tracks.pop(0))
        row = PlaylistRow(track.id, pos,
                          track.album.id != previous_album_id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        widget.insert(row, pos)
        GLib.idle_add(self._add_tracks, tracks, widget,
                      pos + 1, track.album.id)

    def _update_tracks(self):
        """
            Update tracks based on current widget
        """
        # Recalculate tracks
        self._tracks1 = []
        self._tracks2 = []
        for child in self._tracks_widget_left.get_children():
            self._tracks1.append(child.get_id())
        for child in self._tracks_widget_right.get_children():
            self._tracks2.append(child.get_id())

    def _update_position(self):
        """
            Update widget position
        """
        len_tracks1 = len(self._tracks1)
        len_tracks2 = len(self._tracks2)
        # Take first track from tracks2 and put it at the end of tracks1
        if len_tracks2 > len_tracks1:
            src = self._tracks2[0]
            if self._tracks1:
                dst = self._tracks1[-1]
            else:
                dst = -1
            self._move_track(dst, src, False)
        # Take last track of tracks1 and put it at the bottom of tracks2
        elif len_tracks1 - 1 > len_tracks2:
            src = self._tracks1[-1]
            if self._tracks2:
                dst = self._tracks2[0]
            else:
                dst = -1
            self._move_track(dst, src, True)
        self._update_tracks()

    def _update_headers(self):
        """
            Update headers for all tracks
        """
        self._tracks_widget_left.update_headers()
        prev_album_id = None
        if self._orientation == Gtk.Orientation.VERTICAL:
            if self._tracks1:
                prev_album_id = Track(self._tracks1[-1]).album.id
        self._tracks_widget_right.update_headers(prev_album_id)

    def _move_track(self, dst, src, up):
        """
            Move track from src to row
            @param dst as int
            @param src as int
            @param up as bool
            @return (dst_widget as TracksWidget,
                     src index as int, dst index as int)
        """
        tracks1_len = len(self._tracks1)
        tracks2_len = len(self._tracks2)
        if src in self._tracks1:
            src_widget = self._tracks_widget_left
            src_index = self._tracks1.index(src) - 1
        else:
            src_widget = self._tracks_widget_right
            src_index = self._tracks2.index(src) - 1
        if tracks1_len == 0 or dst in self._tracks1:
            dst_widget = self._tracks_widget_left
            dst_tracks = self._tracks1
        elif tracks2_len == 0 or dst in self._tracks2:
            dst_widget = self._tracks_widget_right
            dst_tracks = self._tracks2
        else:
            return
        # Remove src from src_widget
        for child in src_widget.get_children():
            if child.get_id() == src:
                child.destroy()
                break
        src_track = Track(src)
        prev_track = Track()
        name = escape(src_track.name)
        index = 0
        # Get previous track
        if dst != -1:
            for child in dst_widget.get_children():
                if child.get_id() == dst:
                    break
                index += 1
            if not up:
                index += 1
            # Get previous track (in dst context)
            prev_index = dst_tracks.index(dst)
            if up:
                prev_index -= 1
            prev_track = Track(dst_tracks[prev_index])
            # If we are listening to a compilation, prepend artist name
            if (src_track.album.artist_id == Type.COMPILATIONS or
                    len(src_track.artist_ids) > 1 or
                    src_track.album.artist_id not in src_track.artist_ids):
                name = "<b>%s</b>\n%s" % (escape(", ".join(src_track.artists)),
                                          name)
            self._tracks1.insert(index, src_track.id)
        row = PlaylistRow(src_track.id,
                          index,
                          index == 0 or
                          src_track.album.id != prev_track.album.id)
        row.connect('track-moved', self._on_track_moved)
        row.show()
        dst_widget.insert(row, index)
        return (src_widget, dst_widget, src_index, index)

    def _on_track_moved(self, widget, dst, src, up):
        """
            Move track from src to row
            Recalculate track position
            @param widget as TracksWidget
            @param dst as int
            @param src as int
            @param up as bool
        """
        def update_playlist():
            # Save playlist in db only if one playlist visible
            if len(self._playlist_ids) == 1 and self._playlist_ids[0] >= 0:
                Lp().playlists.clear(self._playlist_ids[0], False)
                tracks = []
                for track_id in self._tracks1 + self._tracks2:
                    tracks.append(Track(track_id))
                Lp().playlists.add_tracks(self._playlist_ids[0],
                                          tracks,
                                          False)
            if not (set(self._playlist_ids) -
               set(Lp().player.get_user_playlist_ids())):
                Lp().player.update_user_playlist(self._tracks1 + self._tracks2)

        (src_widget, dst_widget, src_index, dst_index) = \
            self._move_track(dst, src, up)
        self._update_tracks()
        self._update_position()
        self._update_headers()
        self._tracks_widget_left.update_indexes(1)
        self._tracks_widget_right.update_indexes(len(self._tracks1) + 1)
        t = Thread(target=update_playlist)
        t.daemon = True
        t.start()

    def _on_size_allocate(self, widget, allocation):
        """
            Change box max/min children
            @param widget as Gtk.Widget
            @param allocation as Gtk.Allocation
        """
        if self._width == allocation.width:
            return
        self._width = allocation.width
        redraw = False
        if allocation.width < WindowSize.MONSTER:
            orientation = Gtk.Orientation.VERTICAL
        else:
            orientation = Gtk.Orientation.HORIZONTAL
        if orientation != self._orientation:
            self._orientation = orientation
            redraw = True
        self._box.set_orientation(orientation)
        if redraw:
            for child in self._box.get_children():
                self._box.remove(child)
            GLib.idle_add(self._box.add, self._tracks_widget_left)
            GLib.idle_add(self._box.add, self._tracks_widget_right)
        self._update_headers()

    def _on_activated(self, widget, track_id):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
        """
        Lp().player.load(Track(track_id))
        if not Lp().player.is_party():
            Lp().player.populate_user_playlist_by_tracks(self._tracks1 +
                                                         self._tracks2,
                                                         self._playlist_ids)
Example #25
0
class PlaylistWidget(Gtk.Bin):
    """
        Show playlist tracks/albums
    """
    def __init__(self, playlist_id, playlist_name):
        """
            Init playlist Widget
            @param playlist id as int
            @param playlist name as str
        """
        Gtk.Bin.__init__(self)
        self._playlist_id = playlist_id
        self._playlist_name = playlist_name
        self._tracks1 = []
        self._tracks2 = []
        self._stop = False

        self._main_widget = Gtk.Grid()
        self._main_widget.set_property('margin', 10)
        self._main_widget.set_property('column-spacing', 10)
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget2.connect('activated', self._on_activated,
                                     playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self._stack = Gtk.Stack()
        self._stack.set_transition_duration(250)
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._stack.show()

        spinner = Gtk.Spinner()
        spinner.start()
        spinner.show()
        self._stack.add(spinner)
        self._stack.add(self._main_widget)
        self._stack.set_visible_child(spinner)

        self.add(self._stack)

    def populate_list_left(self, tracks, pos):
        """
            Populate left list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        GLib.idle_add(self._stack.set_visible_child, self._main_widget)
        self._stop = False
        GLib.idle_add(self._add_tracks, tracks, self._tracks_widget1, pos)

    def populate_list_right(self, tracks, pos):
        """
            Populate right list
            @param track's ids as array of int
            @param track position as int
            @thread safe
        """
        self._stop = False
        GLib.idle_add(self._add_tracks, tracks, self._tracks_widget2, pos)

    def update_playing_indicator(self):
        """
            Update playing indicator
        """
        self._tracks_widget1.update_playing(Lp.player.current_track.id)
        self._tracks_widget2.update_playing(Lp.player.current_track.id)

    def stop(self):
        """
            Stop loading
        """
        self._stop = True

    def clear(self):
        """
            Clear tracks
        """
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()


#######################
# PRIVATE             #
#######################

    def _add_tracks(self, tracks, widget, pos, previous_album_id=None):
        """
            Add tracks to list
            @param tracks id as array of [int]
            @param widget TracksWidget
            @param track position as int
            @param previous album id as int
        """
        if not tracks or self._stop:
            return

        track = Track(tracks.pop(0))
        name = escape(track.name)
        album = track.album

        if track.id is None:
            GLib.idle_add(self._add_tracks, tracks, widget, pos + 1,
                          previous_album_id)
            return

        # If we are listening to a compilation, prepend artist name
        if (album.artist_id == Type.COMPILATIONS or len(track.artist_ids) > 1
                or album.artist_id not in track.artist_ids):
            name = "<b>%s</b>\n%s" % (escape(track.artist_names), name)

        if widget == self._tracks_widget1:
            self._tracks1.append(track)
        else:
            self._tracks2.append(track)

        if album.id != previous_album_id:
            widget.add_album(track.id, album.id, pos, name, track.duration,
                             None)
        else:
            widget.add_album(track.id, None, pos, name, track.duration, None)
        GLib.idle_add(self._add_tracks, tracks, widget, pos + 1, album.id)

    def _on_activated(self, widget, track_id, playlist_name):
        """
            On track activation, play track
            @param widget as TracksWidget
            @param track as Track
            @param playlist name as str
        """
        if Lp.player.is_party():
            Lp.player.load(Track(track_id))
        else:
            track = Lp.player.set_user_playlist(self._tracks1 + self._tracks2,
                                                track_id)
            Lp.player.set_user_playlist_id(self._playlist_id)
            if track is not None:
                Lp.player.load(track)
Example #26
0
class PlaylistWidget(Gtk.Bin):
    """
        Init playlist Widget
        @param playlist name as str
    """
    def __init__(self, playlist_name):
        Gtk.Bin.__init__(self)
        self._playlist_name = playlist_name
        self._tracks = []

        self._main_widget = Gtk.Grid()
        self._main_widget.show()

        self._tracks_widget1 = TracksWidget(False)
        self._tracks_widget2 = TracksWidget(False)
        self._tracks_widget1.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget2.connect('activated',
                                     self._on_activated, playlist_name)
        self._tracks_widget1.show()
        self._tracks_widget2.show()

        size_group = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL)
        size_group.add_widget(self._tracks_widget1)
        size_group.add_widget(self._tracks_widget2)

        self._main_widget.add(self._tracks_widget1)
        self._main_widget.add(self._tracks_widget2)

        self.add(self._main_widget)

    """
        Populate list one, thread safe
        @param track's ids as array of int
        @param track position as int
    """
    def populate_list_one(self, tracks, pos):
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget1,
                      pos)

    """
        Populate list two, thread safe
        @param track's ids as array of int
        @param track position as int
    """
    def populate_list_two(self, tracks, pos):
        GLib.idle_add(self._add_tracks,
                      tracks,
                      self._tracks_widget2,
                      pos)

    """
        Update playing indicator
    """
    def update_playing_indicator(self):
        self._tracks_widget1.update_playing(Objects.player.current.id)
        self._tracks_widget2.update_playing(Objects.player.current.id)

    """
        Clear tracks
    """
    def clear(self):
        self._tracks = []
        for child in self._tracks_widget1.get_children():
            child.destroy()
        for child in self._tracks_widget2.get_children():
            child.destroy()

#######################
# PRIVATE             #
#######################
    """
        Add tracks to list
        @param tracks id as array of [int]
        @param widget TracksWidget
        @param track position as int
    """
    def _add_tracks(self, tracks, widget, pos):
        if not tracks:
            return

        track_id = tracks.pop(0)
        if track_id == -1:
            return

        (title, filepath, length, album_id) =\
            Objects.tracks.get_infos(track_id)

        artist_name = ""
        for artist_id in Objects.tracks.get_artist_ids(track_id):
            artist_name += translate_artist_name(
                            Objects.artists.get_name(artist_id)) + ", "
        title = "<b>%s</b>\n%s" % (escape(artist_name[:-2]),
                                   escape(title))

        widget.add_track(track_id, pos, title, length, None, True)
        GLib.idle_add(self._add_tracks, tracks, widget, pos+1)

    """
        On track activation, play track
        @param widget as TracksWidget
        @param track id as int
        @param playlist name as str
    """
    def _on_activated(self, widget, track_id, playlist_name):
        if not Objects.player.is_party():
            if not self._tracks:
                self._tracks = Objects.playlists.get_tracks_id(playlist_name)
            Objects.player.set_user_playlist(self._tracks, track_id)
        Objects.player.load(track_id)