コード例 #1
0
    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_one = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_two = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)

        self._paned_one.connect("notify::position", self.__on_paned_position)
        self._paned_two.connect("notify::position", self.__on_paned_position)

        self.__progress = ProgressBar()
        self.__progress.get_style_context().add_class("progress-bottom")
        self.__progress.set_property("valign", Gtk.Align.END)
        self.add_overlay(self.__progress)

        self._paned_two.add2(self._stack)
        self._paned_one.add2(self._paned_two)
        position = App().settings.get_value(
            "paned-mainlist-width").get_int32()
        self._paned_one.set_position(position)
        self._paned_one.show()
        self._paned_two.show()
        search_action = App().lookup_action("search")
        search_action.connect("activate", self.__on_search_activate)
コード例 #2
0
 def __init__(self):
     """
         Init container
     """
     self.__pulse_timeout = None
     self._progress = ProgressBar()
     self._progress.set_property("hexpand", True)
コード例 #3
0
 def setup(self):
     """
         Setup container
     """
     self.__widget = Handy.Leaflet()
     self.__widget.show()
     self.__sub_widget = Handy.Leaflet()
     self.__sub_widget.show()
     self.__focused_view = None
     self._stack = StackContainer()
     self._stack.show()
     ListsContainer.__init__(self)
     self.__progress = ProgressBar()
     self.__progress.get_style_context().add_class("progress-bottom")
     self.__progress.set_property("valign", Gtk.Align.END)
     self.add_overlay(self.__progress)
     search_action = App().lookup_action("search")
     search_action.connect("activate", self.__on_search_activate)
     self.__widget.add(self.sidebar)
     self.__grid_view = Grid()
     self.__grid_view.set_orientation(Gtk.Orientation.VERTICAL)
     self.__grid_view.show()
     self.__sub_widget.add(self.left_list)
     self.__sub_widget.add(self.__grid_view)
     self.__grid_view.attach(self._stack, 0, 0, 1, 1)
     self.__widget.add(self.__sub_widget)
     self.__widget.set_visible_child(self.__sub_widget)
     self.__sub_widget.set_visible_child(self.__grid_view)
     self.add(self.__widget)
     FilterContainer.__init__(self)
コード例 #4
0
ファイル: container.py プロジェクト: digitalseraph/lollypop
    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_main_list = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_list_view = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        vgrid = Gtk.Grid()
        vgrid.set_orientation(Gtk.Orientation.VERTICAL)

        self.__list_one = SelectionList()
        if Lp().settings.get_value("show-navigation-list"):
            self.__list_one.show()
        self.__list_two = SelectionList()
        self.__list_one.connect("item-selected", self.__on_list_one_selected)
        self.__list_one.connect("populated", self.__on_list_populated)
        self.__list_one.connect("pass-focus", self.__on_pass_focus)
        self.__list_two.connect("item-selected", self.__on_list_two_selected)
        self.__list_two.connect("pass-focus", self.__on_pass_focus)

        self.__progress = ProgressBar()
        self.__progress.set_property("hexpand", True)

        vgrid.add(self.__stack)
        vgrid.add(self.__progress)
        vgrid.show()

        self._paned_list_view.add1(self.__list_two)
        self._paned_list_view.add2(vgrid)
        self._paned_main_list.add1(self.__list_one)
        self._paned_main_list.add2(self._paned_list_view)
        self._paned_main_list.set_position(
            Lp().settings.get_value("paned-mainlist-width").get_int32())
        self._paned_list_view.set_position(
            Lp().settings.get_value("paned-listview-width").get_int32())
        self._paned_main_list.show()
        self._paned_list_view.show()
コード例 #5
0
    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_main_list = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_list_view = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        vgrid = Gtk.Grid()
        vgrid.set_orientation(Gtk.Orientation.VERTICAL)

        self.__list_one = SelectionList(SelectionMode.LIMITED)
        self.__list_one.show()
        self.__list_two = SelectionList(SelectionMode.NORMAL)
        self.__list_one.connect('item-selected', self.__on_list_one_selected)
        self.__list_one.connect('populated', self.__on_list_populated)
        self.__list_two.connect('item-selected', self.__on_list_two_selected)

        self.__progress = ProgressBar()
        self.__progress.set_property('hexpand', True)

        vgrid.add(self.__stack)
        vgrid.add(self.__progress)
        vgrid.show()

        self._paned_list_view.add1(self.__list_two)
        self._paned_list_view.add2(vgrid)
        self._paned_main_list.add1(self.__list_one)
        self._paned_main_list.add2(self._paned_list_view)
        self._paned_main_list.set_position(
            Lp().settings.get_value('paned-mainlist-width').get_int32())
        self._paned_list_view.set_position(
            Lp().settings.get_value('paned-listview-width').get_int32())
        self._paned_main_list.show()
        self._paned_list_view.show()
コード例 #6
0
ファイル: container.py プロジェクト: TainakaDrums/lollypop
    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_main_list = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_list_view = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        vgrid = Gtk.Grid()
        vgrid.set_orientation(Gtk.Orientation.VERTICAL)

        self.__list_one = SelectionList()
        if Lp().settings.get_value('show-navigation-list'):
            self.__list_one.show()
        self.__list_two = SelectionList()
        self.__list_one.connect('item-selected', self.__on_list_one_selected)
        self.__list_one.connect('populated', self.__on_list_populated)
        self.__list_two.connect('item-selected', self.__on_list_two_selected)

        self.__progress = ProgressBar()
        self.__progress.set_property('hexpand', True)

        vgrid.add(self.__stack)
        vgrid.add(self.__progress)
        vgrid.show()

        self._paned_list_view.add1(self.__list_two)
        self._paned_list_view.add2(vgrid)
        self._paned_main_list.add1(self.__list_one)
        self._paned_main_list.add2(self._paned_list_view)
        self._paned_main_list.set_position(
            Lp().settings.get_value('paned-mainlist-width').get_int32())
        self._paned_list_view.set_position(
            Lp().settings.get_value('paned-listview-width').get_int32())
        self._paned_main_list.show()
        self._paned_list_view.show()
コード例 #7
0
class Container:
    """
        Container for main view
    """
    def __init__(self):
        """
            Init container
        """
        self.__pulse_timeout = None
        # Index will start at -VOLUMES
        self.__devices = {}
        self.__devices_index = Type.DEVICES
        self.__show_genres = Lp().settings.get_value('show-genres')
        self.__stack = ViewContainer(500)
        self.__stack.show()

        self.__setup_view()
        self.__setup_scanner()

        (list_one_ids, list_two_ids) = self.__get_saved_view_state()
        if list_one_ids and list_one_ids[0] != Type.NONE:
            self.__list_one.select_ids(list_one_ids)
        if list_two_ids and list_two_ids[0] != Type.NONE:
            self.__list_two.select_ids(list_two_ids)

        # Volume manager
        self.__vm = Gio.VolumeMonitor.get()
        self.__vm.connect('mount-added', self.__on_mount_added)
        self.__vm.connect('mount-removed', self.__on_mount_removed)
        for mount in self.__vm.get_mounts():
            self.__add_device(mount, False)

        Lp().playlists.connect('playlists-changed', self.__update_playlists)

    def update_db(self):
        """
            Update db at startup only if needed
        """
        # Stop previous scan
        if Lp().scanner.is_locked():
            Lp().scanner.stop()
            GLib.timeout_add(250, self.update_db)
        else:
            Lp().scanner.update()

    def get_genre_id(self):
        """
            Return current selected genre
            @return genre id as int
        """
        if self.__show_genres:
            return self.__list_one.get_selected_id()
        else:
            return None

    def init_list_one(self):
        """
            Init list one
        """
        self.__update_list_one(None)

    def save_view_state(self):
        """
            Save view state
        """
        Lp().settings.set_value(
            "list-one-ids", GLib.Variant('ai', self.__list_one.selected_ids))
        Lp().settings.set_value(
            "list-two-ids", GLib.Variant('ai', self.__list_two.selected_ids))

    def show_playlist_manager(self, object_id, genre_ids, artist_ids,
                              is_album):
        """
            Show playlist manager for object_id
            Current view stay present in ViewContainer
            @param object id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param is_album as bool
        """
        from lollypop.view_playlists import PlaylistsManageView
        current = self.__stack.get_visible_child()
        view = PlaylistsManageView(object_id, genre_ids, artist_ids, is_album)
        view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        current.disable_overlay()

    def show_playlist_editor(self, playlist_id):
        """
            Show playlist editor for playlist
            Current view stay present in ViewContainer
            @param playlist id as int
            @param playlist name as str
        """
        from lollypop.view_playlists import PlaylistEditView
        view = PlaylistEditView(playlist_id)
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)
        view.populate()

    def get_view_width(self):
        """
            Return view width
            @return width as int
        """
        return self.__stack.get_allocation().width

    def stop_all(self):
        """
            Stop current view from processing
        """
        view = self.__stack.get_visible_child()
        if view is not None:
            self.__stack.clean_old_views(None)

    def show_genres(self, show):
        """
            Show/Hide genres
            @param bool
        """
        self.__show_genres = show
        self.__list_one.clear()
        self.__list_two.clear()
        self.__list_two.hide()
        self.__update_list_one(None)
        self.__list_one.select_ids([Type.POPULARS])

    def destroy_current_view(self):
        """
            Destroy current view
        """
        view = self.__stack.get_visible_child()
        for child in self.__stack.get_children():
            if child != view:
                self.__stack.set_visible_child(child)
                self.__stack.clean_old_views(child)
                break

    @property
    def view(self):
        """
            Disable overlays
        """
        return self.__stack.get_visible_child()

    @property
    def progress(self):
        """
            Progress bar
            @return ProgressBar
        """
        return self.__progress

    def add_remove_from(self, value, list_one, add):
        """
            Add or remove value to list
            @param value as (int, str)
            @param list one as bool
            @param add as bool
        """
        if list_one:
            l = self.__list_one
        else:
            l = self.__list_two
        if add:
            l.add_value(value)
        else:
            l.remove_value(value[0])

    def reload_view(self):
        """
            Reload current view
        """
        values_two = self.__list_two.selected_ids
        values_one = self.__list_one.selected_ids
        if not values_one:
            values_one = [Type.POPULARS]
        self.__list_one.select_ids([])
        self.__list_one.clear()
        self.__update_list_one(None)
        self.__list_one.select_ids(values_one)
        if self.__list_two.is_visible():
            self.__list_two.select_ids([])
            self.__list_two.clear()
            self.__update_list_two(None)
            self.__list_two.select_ids(values_two)

    def pulse(self, pulse):
        """
            Make progress bar visible/pulse if pulse is True
            @param pulse as bool
        """
        if pulse and not self.__progress.is_visible():
            self.__progress.show()
            if self.__pulse_timeout is None:
                self.__pulse_timeout = GLib.timeout_add(500, self.__pulse)
        else:
            if self.__pulse_timeout is not None:
                GLib.source_remove(self.__pulse_timeout)
                self.__pulse_timeout = None
                self.__progress.hide()

    def on_scan_finished(self, scanner):
        """
            Mark force scan as False, update lists
            @param scanner as CollectionScanner
        """
        self.__update_lists(scanner)

    def add_fake_phone(self):
        """
            Emulate an Android Phone
        """
        self.__devices_index -= 1
        dev = Device()
        dev.id = self.__devices_index
        dev.name = "Android phone"
        dev.uri = "file:///tmp/android/"
        d = Gio.File.new_for_uri(dev.uri + "Internal Memory")
        if not d.query_exists():
            d.make_directory_with_parents()
        d = Gio.File.new_for_uri(dev.uri + "SD Card")
        if not d.query_exists():
            d.make_directory_with_parents()
        self.__devices[self.__devices_index] = dev

    def show_artists_albums(self, artist_ids):
        """
            Show albums from artists
        """
        self.__update_view_artists([], artist_ids)
        GLib.idle_add(self.__list_two.hide)
        GLib.idle_add(self.__list_one.select_ids, [])

############
# Private  #
############

    def __pulse(self):
        """
            Make progress bar pulse while visible
            @param pulse as bool
        """
        if self.__progress.is_visible() and not Lp().scanner.is_locked():
            self.__progress.pulse()
            return True
        else:
            self.__progress.set_fraction(0.0, self)
            return False

    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_main_list = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_list_view = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        vgrid = Gtk.Grid()
        vgrid.set_orientation(Gtk.Orientation.VERTICAL)

        self.__list_one = SelectionList(True)
        self.__list_one.show()
        self.__list_two = SelectionList(False)
        self.__list_one.connect('item-selected', self.__on_list_one_selected)
        self.__list_one.connect('populated', self.__on_list_populated)
        self.__list_two.connect('item-selected', self.__on_list_two_selected)

        self.__progress = ProgressBar()
        self.__progress.set_property('hexpand', True)

        vgrid.add(self.__stack)
        vgrid.add(self.__progress)
        vgrid.show()

        self._paned_list_view.add1(self.__list_two)
        self._paned_list_view.add2(vgrid)
        self._paned_main_list.add1(self.__list_one)
        self._paned_main_list.add2(self._paned_list_view)
        self._paned_main_list.set_position(
            Lp().settings.get_value('paned-mainlist-width').get_int32())
        self._paned_list_view.set_position(
            Lp().settings.get_value('paned-listview-width').get_int32())
        self._paned_main_list.show()
        self._paned_list_view.show()

    def __get_saved_view_state(self):
        """
            Get save view state
            @return (list one id, list two id)
        """
        list_one_ids = [Type.POPULARS]
        list_two_ids = [Type.NONE]
        if Lp().settings.get_value('save-state'):
            list_one_ids = []
            list_two_ids = []
            ids = Lp().settings.get_value('list-one-ids')
            for i in ids:
                if isinstance(i, int):
                    list_one_ids.append(i)
            ids = Lp().settings.get_value('list-two-ids')
            for i in ids:
                if isinstance(i, int):
                    list_two_ids.append(i)
        return (list_one_ids, list_two_ids)

    def __setup_scanner(self):
        """
            Run collection update if needed
            @return True if hard scan is running
        """
        Lp().scanner.connect('scan-finished', self.on_scan_finished)
        Lp().scanner.connect('genre-updated', self.__on_genre_updated)
        Lp().scanner.connect('artist-updated', self.__on_artist_updated)

    def __update_playlists(self, playlists, playlist_id):
        """
            Update playlists in second list
            @param playlists as Playlists
            @param playlist_id as int
        """
        ids = self.__list_one.selected_ids
        if ids and ids[0] == Type.PLAYLISTS:
            if Lp().playlists.exists(playlist_id):
                self.__list_two.update_value(
                    playlist_id,
                    Lp().playlists.get_name(playlist_id))
            else:
                self.__list_two.remove_value(playlist_id)

    def __update_lists(self, updater=None):
        """
            Update lists
            @param updater as GObject
        """
        self.__update_list_one(updater)
        self.__update_list_two(updater)

    def __update_list_one(self, updater):
        """
            Update list one
            @param updater as GObject
        """
        update = updater is not None
        if self.__show_genres:
            self.__setup_list_genres(self.__list_one, update)
        else:
            self.__setup_list_artists(self.__list_one, [Type.ALL], update)

    def __update_list_two(self, updater):
        """
            Update list two
            @param updater as GObject
        """
        update = updater is not None
        ids = self.__list_one.selected_ids
        if ids and ids[0] == Type.PLAYLISTS:
            self.__setup_list_playlists(update)
        elif self.__show_genres and ids:
            self.__setup_list_artists(self.__list_two, ids, update)

    def __setup_list_genres(self, selection_list, update):
        """
            Setup list for genres
            @param list as SelectionList
            @param update as bool, if True, just update entries
            @thread safe
        """
        def load():
            genres = Lp().genres.get()
            return genres

        def setup(genres):
            items = selection_list.get_headers()
            items.append((Type.SEPARATOR, ''))
            items += genres
            selection_list.mark_as_artists(False)
            if update:
                selection_list.update_values(items)
            else:
                selection_list.populate(items)

        loader = Loader(target=load, view=selection_list, on_finished=setup)
        loader.start()

    def __setup_list_artists(self, selection_list, genre_ids, update):
        """
            Setup list for artists
            @param list as SelectionList
            @param genre ids as [int]
            @param update as bool, if True, just update entries
            @thread safe
        """
        def load():
            artists = Lp().artists.get(genre_ids)
            compilations = Lp().albums.get_compilation_ids(genre_ids)
            return (artists, compilations)

        def setup(artists, compilations):
            if selection_list == self.__list_one:
                items = selection_list.get_headers()
                if not compilations:
                    items.append((Type.SEPARATOR, ''))
            else:
                items = []
            if compilations:
                items.append((Type.COMPILATIONS, _("Compilations")))
                items.append((Type.SEPARATOR, ''))
            items += artists
            selection_list.mark_as_artists(True)
            if update:
                selection_list.update_values(items)
            else:
                selection_list.populate(items)

        if selection_list == self.__list_one:
            if self.__list_two.is_visible():
                self.__list_two.hide()
            self.__list_two_restore = Type.NONE
        loader = Loader(target=load,
                        view=selection_list,
                        on_finished=lambda r: setup(*r))
        loader.start()

    def __setup_list_playlists(self, update):
        """
            Setup list for playlists
            @param update as bool
            @thread safe
        """
        playlists = [(Type.LOVED, Lp().playlists.LOVED)]
        playlists.append((Type.POPULARS, _("Popular tracks")))
        playlists.append((Type.RECENTS, _("Recently played")))
        playlists.append((Type.NEVER, _("Never played")))
        playlists.append((Type.RANDOMS, _("Random tracks")))
        playlists.append((Type.SEPARATOR, ''))
        playlists += Lp().playlists.get()
        if update:
            self.__list_two.update_values(playlists)
        else:
            self.__list_two.mark_as_artists(False)
            self.__list_two.populate(playlists)

    def __stop_current_view(self):
        """
            Stop current view
        """
        child = self.__stack.get_visible_child()
        if child is not None:
            if hasattr(child, "stop"):
                child.stop()

    def __update_view_device(self, device_id):
        """
            Update current view with device view,
            Use existing view if available
            @param device id as int
        """
        from lollypop.view_device import DeviceView, DeviceLocked
        self.__stop_current_view()
        device = self.__devices[device_id]
        child = self.__stack.get_child_by_name(device.uri)
        if child is None:
            files = DeviceView.get_files(device.uri)
            if files:
                if child is None:
                    child = DeviceView(device)
                    self.__stack.add_named(child, device.uri)
            else:
                child = DeviceLocked()
                self.__stack.add(child)
            child.show()
        child.populate()
        self.__stack.set_visible_child(child)
        self.__stack.clean_old_views(child)

    def __update_view_artists(self, genre_ids, artist_ids):
        """
            Update current view with artists view
            @param genre ids as [int]
            @param artist ids as [int]
        """
        def load():
            if genre_ids and genre_ids[0] == Type.ALL:
                albums = Lp().albums.get_ids(artist_ids, [])
            else:
                albums = []
                if artist_ids and artist_ids[0] == Type.COMPILATIONS:
                    albums += Lp().albums.get_compilation_ids(genre_ids)
                albums += Lp().albums.get_ids(artist_ids, genre_ids)
            return albums

        from lollypop.view_artist import ArtistView
        self.__stop_current_view()
        view = ArtistView(artist_ids, genre_ids)
        loader = Loader(target=load, view=view)
        loader.start()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_albums(self, genre_ids, artist_ids):
        """
            Update current view with albums view
            @param genre ids as [int]
            @param is compilation as bool
        """
        def load():
            albums = []
            is_compilation = artist_ids and artist_ids[0] == Type.COMPILATIONS
            if genre_ids and genre_ids[0] == Type.ALL:
                if is_compilation or\
                        Lp().settings.get_value('show-compilations'):
                    albums = Lp().albums.get_compilation_ids()
                if not is_compilation:
                    albums += Lp().albums.get_ids()
            elif genre_ids and genre_ids[0] == Type.POPULARS:
                albums = Lp().albums.get_populars()
            elif genre_ids and genre_ids[0] == Type.RECENTS:
                albums = Lp().albums.get_recents()
            elif genre_ids and genre_ids[0] == Type.RANDOMS:
                albums = Lp().albums.get_randoms()
            else:
                if is_compilation or\
                        Lp().settings.get_value('show-compilations'):
                    albums = Lp().albums.get_compilation_ids(genre_ids)
                if not is_compilation:
                    albums += Lp().albums.get_ids([], genre_ids)
            return albums

        from lollypop.view_albums import AlbumsView
        self.__stop_current_view()
        view = AlbumsView(genre_ids, artist_ids)
        loader = Loader(target=load, view=view)
        loader.start()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_playlists(self, playlist_ids=[]):
        """
            Update current view with playlist view
            @param playlist ids as [int]
        """
        def load():
            track_ids = []
            for playlist_id in playlist_ids:
                if playlist_id == Type.POPULARS:
                    tracks = Lp().tracks.get_populars()
                elif playlist_id == Type.RECENTS:
                    tracks = Lp().tracks.get_recently_listened_to()
                elif playlist_id == Type.NEVER:
                    tracks = Lp().tracks.get_never_listened_to()
                elif playlist_id == Type.RANDOMS:
                    tracks = Lp().tracks.get_randoms()
                else:
                    tracks = Lp().playlists.get_track_ids(playlist_id)
                for track_id in tracks:
                    if track_id not in track_ids:
                        track_ids.append(track_id)
            return track_ids

        self.__stop_current_view()
        view = None
        if playlist_ids:
            from lollypop.view_playlists import PlaylistsView
            view = PlaylistsView(playlist_ids)
            loader = Loader(target=load, view=view)
            loader.start()
        else:
            from lollypop.view_playlists import PlaylistsManageView
            view = PlaylistsManageView(Type.NONE, [], [], False)
            view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_radios(self):
        """
            Update current view with radios view
        """
        from lollypop.view_radios import RadiosView
        self.__stop_current_view()
        view = RadiosView()
        view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __add_device(self, mount, show=False):
        """
            Add a device
            @param mount as Gio.Mount
            @param show as bool
        """
        if mount.get_volume() is None:
            return
        name = mount.get_name()
        uri = mount.get_default_location().get_uri()
        if uri is not None and (mount.can_eject() or uri.startswith('mtp')):
            self.__devices_index -= 1
            dev = Device()
            dev.id = self.__devices_index
            dev.name = name
            dev.uri = uri
            self.__devices[self.__devices_index] = dev
            if show:
                self.__list_one.add_value((dev.id, dev.name))

    def __remove_device(self, mount):
        """
            Remove volume from device list
            @param mount as Gio.Mount
        """
        uri = mount.get_default_location().get_uri()
        for dev in self.__devices.values():
            if dev.uri == uri:
                self.__list_one.remove_value(dev.id)
                child = self.__stack.get_child_by_name(uri)
                if child is not None:
                    child.destroy()
                del self.__devices[dev.id]
            break

    def __on_list_one_selected(self, selection_list):
        """
            Update view based on selected object
            @param list as SelectionList
        """
        selected_ids = self.__list_one.selected_ids
        if not selected_ids:
            return
        self.__list_two.clear()
        if selected_ids[0] == Type.PLAYLISTS:
            self.__list_two.show()
            if not self.__list_two.will_be_selected():
                self.__update_view_playlists()
            self.__setup_list_playlists(False)
        elif Type.DEVICES - 999 < selected_ids[0] < Type.DEVICES:
            self.__list_two.hide()
            if not self.__list_two.will_be_selected():
                self.__update_view_device(selected_ids[0])
        elif selected_ids[0] in [
                Type.POPULARS, Type.RECENTS, Type.RANDOMS, Type.CHARTS
        ]:
            self.__list_two.hide()
            self.__update_view_albums(selected_ids, [])
        elif selected_ids[0] == Type.RADIOS:
            self.__list_two.hide()
            self.__update_view_radios()
        elif selection_list.is_marked_as_artists():
            self.__list_two.hide()
            if selected_ids[0] == Type.ALL:
                self.__update_view_albums(selected_ids, [])
            elif selected_ids[0] == Type.COMPILATIONS:
                self.__update_view_albums([], selected_ids)
            else:
                self.__update_view_artists([], selected_ids)
        else:
            self.__setup_list_artists(self.__list_two, selected_ids, False)
            self.__list_two.show()
            if not self.__list_two.will_be_selected():
                self.__update_view_albums(selected_ids, [])

    def __on_list_populated(self, selection_list):
        """
            Add device to list one and update db
            @param selection list as SelectionList
        """
        for dev in self.__devices.values():
            self.__list_one.add_value((dev.id, dev.name))

    def __on_list_two_selected(self, selection_list):
        """
            Update view based on selected object
            @param list as SelectionList
        """
        genre_ids = self.__list_one.selected_ids
        selected_ids = self.__list_two.selected_ids
        if not selected_ids or not genre_ids:
            return
        if genre_ids[0] == Type.PLAYLISTS:
            self.__update_view_playlists(selected_ids)
        elif selected_ids[0] == Type.COMPILATIONS:
            self.__update_view_albums(genre_ids, selected_ids)
        else:
            self.__update_view_artists(genre_ids, selected_ids)

    def __on_genre_updated(self, scanner, genre_id, add):
        """
            Add genre to genre list
            @param scanner as CollectionScanner
            @param genre id as int
            @param add as bool
        """
        if self.__show_genres:
            if add:
                genre_name = Lp().genres.get_name(genre_id)
                self.__list_one.add_value((genre_id, genre_name))
            else:
                genre_ids = Lp().genres.get_ids()
                if genre_id not in genre_ids:
                    self.__list_one.remove_value(genre_id)

    def __on_artist_updated(self, scanner, artist_id, add):
        """
            Add artist to artist list
            @param scanner as CollectionScanner
            @param artist id as int
            @param add as bool
        """
        artist_name = Lp().artists.get_name(artist_id)
        if self.__show_genres:
            l = self.__list_two
            artist_ids = Lp().artists.get_ids(self.__list_one.selected_ids)
        else:
            l = self.__list_one
            artist_ids = Lp().artists.get_ids()
        if add:
            if artist_id in artist_ids:
                l.add_value((artist_id, artist_name))
        else:
            if artist_id not in artist_ids:
                l.remove_value(artist_id)

    def __on_mount_added(self, vm, mount):
        """
            On volume mounter
            @param vm as Gio.VolumeMonitor
            @param mount as Gio.Mount
        """
        self.__add_device(mount, True)

    def __on_mount_removed(self, vm, mount):
        """
            On volume removed, clean selection list
            @param vm as Gio.VolumeMonitor
            @param mount as Gio.Mount
        """
        self.__remove_device(mount)
コード例 #8
0
class Container:
    """
        Container for main view
    """
    def __init__(self):
        """
            Init container
        """
        self.__pulse_timeout = None
        # Index will start at -VOLUMES
        self.__devices = {}
        self.__devices_index = Type.DEVICES
        self.__show_genres = Lp().settings.get_value('show-genres')
        self.__stack = ViewContainer(500)
        self.__stack.show()

        self.__setup_view()
        self.__setup_scanner()

        (list_one_ids, list_two_ids) = self.__get_saved_view_state()
        if list_one_ids and list_one_ids[0] != Type.NONE:
            self.__list_one.select_ids(list_one_ids)
        if list_two_ids and list_two_ids[0] != Type.NONE:
            self.__list_two.select_ids(list_two_ids)

        # Volume manager
        self.__vm = Gio.VolumeMonitor.get()
        self.__vm.connect('mount-added', self.__on_mount_added)
        self.__vm.connect('mount-removed', self.__on_mount_removed)
        for mount in self.__vm.get_mounts():
            self.__add_device(mount, False)

        Lp().playlists.connect('playlists-changed',
                               self.__update_playlists)

    def update_db(self):
        """
            Update db at startup only if needed
        """
        # Stop previous scan
        if Lp().scanner.is_locked():
            Lp().scanner.stop()
            GLib.timeout_add(250, self.update_db)
        else:
            Lp().scanner.update()

    def get_genre_id(self):
        """
            Return current selected genre
            @return genre id as int
        """
        if self.__show_genres:
            return self.__list_one.get_selected_id()
        else:
            return None

    def init_list_one(self):
        """
            Init list one
        """
        self.__update_list_one(None)

    def save_view_state(self):
        """
            Save view state
        """
        Lp().settings.set_value(
                            "list-one-ids",
                            GLib.Variant('ai',
                                         self.__list_one.selected_ids))
        Lp().settings.set_value(
                            "list-two-ids",
                            GLib.Variant('ai',
                                         self.__list_two.selected_ids))

    def show_playlist_manager(self, object_id, genre_ids,
                              artist_ids, is_album):
        """
            Show playlist manager for object_id
            Current view stay present in ViewContainer
            @param object id as int
            @param genre ids as [int]
            @param artist ids as [int]
            @param is_album as bool
        """
        from lollypop.view_playlists import PlaylistsManageView
        current = self.__stack.get_visible_child()
        view = PlaylistsManageView(object_id, genre_ids, artist_ids, is_album)
        view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        current.disable_overlay()

    def show_playlist_editor(self, playlist_id):
        """
            Show playlist editor for playlist
            Current view stay present in ViewContainer
            @param playlist id as int
            @param playlist name as str
        """
        from lollypop.view_playlists import PlaylistEditView
        view = PlaylistEditView(playlist_id)
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)
        view.populate()

    def get_view_width(self):
        """
            Return view width
            @return width as int
        """
        return self.__stack.get_allocation().width

    def stop_all(self):
        """
            Stop current view from processing
        """
        view = self.__stack.get_visible_child()
        if view is not None:
            self.__stack.clean_old_views(None)

    def show_genres(self, show):
        """
            Show/Hide genres
            @param bool
        """
        self.__show_genres = show
        self.__list_one.clear()
        self.__list_two.clear()
        self.__list_two.hide()
        self.__update_list_one(None)
        self.__list_one.select_ids([Type.POPULARS])

    def destroy_current_view(self):
        """
            Destroy current view
        """
        view = self.__stack.get_visible_child()
        for child in self.__stack.get_children():
            if child != view:
                self.__stack.set_visible_child(child)
                self.__stack.clean_old_views(child)
                break

    @property
    def view(self):
        """
            Disable overlays
        """
        return self.__stack.get_visible_child()

    @property
    def progress(self):
        """
            Progress bar
            @return ProgressBar
        """
        return self.__progress

    def add_remove_from(self, value, list_one, add):
        """
            Add or remove value to list
            @param value as (int, str)
            @param list one as bool
            @param add as bool
        """
        if list_one:
            l = self.__list_one
        else:
            l = self.__list_two
        if add:
            l.add_value(value)
        else:
            l.remove_value(value[0])

    def reload_view(self):
        """
            Reload current view
        """
        values_two = self.__list_two.selected_ids
        values_one = self.__list_one.selected_ids
        if not values_one:
            values_one = [Type.POPULARS]
        self.__list_one.select_ids([])
        self.__list_one.clear()
        self.__update_list_one(None)
        self.__list_one.select_ids(values_one)
        if self.__list_two.is_visible():
            self.__list_two.select_ids([])
            self.__list_two.clear()
            self.__update_list_two(None)
            self.__list_two.select_ids(values_two)

    def pulse(self, pulse):
        """
            Make progress bar visible/pulse if pulse is True
            @param pulse as bool
        """
        if pulse and not self.__progress.is_visible():
            self.__progress.show()
            if self.__pulse_timeout is None:
                self.__pulse_timeout = GLib.timeout_add(500, self.__pulse)
        else:
            if self.__pulse_timeout is not None:
                GLib.source_remove(self.__pulse_timeout)
                self.__pulse_timeout = None
                self.__progress.hide()

    def on_scan_finished(self, scanner):
        """
            Mark force scan as False, update lists
            @param scanner as CollectionScanner
        """
        self.__update_lists(scanner)

    def add_fake_phone(self):
        """
            Emulate an Android Phone
        """
        self.__devices_index -= 1
        dev = Device()
        dev.id = self.__devices_index
        dev.name = "Android phone"
        dev.uri = "file:///tmp/android/"
        d = Gio.File.new_for_uri(dev.uri+"Internal Memory")
        if not d.query_exists():
            d.make_directory_with_parents()
        d = Gio.File.new_for_uri(dev.uri+"SD Card")
        if not d.query_exists():
            d.make_directory_with_parents()
        self.__devices[self.__devices_index] = dev

    def show_artists_albums(self, artist_ids):
        """
            Show albums from artists
        """
        self.__update_view_artists([], artist_ids)
        GLib.idle_add(self.__list_two.hide)
        GLib.idle_add(self.__list_one.select_ids, [])

############
# Private  #
############
    def __pulse(self):
        """
            Make progress bar pulse while visible
            @param pulse as bool
        """
        if self.__progress.is_visible() and not Lp().scanner.is_locked():
            self.__progress.pulse()
            return True
        else:
            self.__progress.set_fraction(0.0, self)
            return False

    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_main_list = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_list_view = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        vgrid = Gtk.Grid()
        vgrid.set_orientation(Gtk.Orientation.VERTICAL)

        self.__list_one = SelectionList(True)
        self.__list_one.show()
        self.__list_two = SelectionList(False)
        self.__list_one.connect('item-selected', self.__on_list_one_selected)
        self.__list_one.connect('populated', self.__on_list_populated)
        self.__list_two.connect('item-selected', self.__on_list_two_selected)

        self.__progress = ProgressBar()
        self.__progress.set_property('hexpand', True)

        vgrid.add(self.__stack)
        vgrid.add(self.__progress)
        vgrid.show()

        self._paned_list_view.add1(self.__list_two)
        self._paned_list_view.add2(vgrid)
        self._paned_main_list.add1(self.__list_one)
        self._paned_main_list.add2(self._paned_list_view)
        self._paned_main_list.set_position(
            Lp().settings.get_value('paned-mainlist-width').get_int32())
        self._paned_list_view.set_position(
            Lp().settings.get_value('paned-listview-width').get_int32())
        self._paned_main_list.show()
        self._paned_list_view.show()

    def __get_saved_view_state(self):
        """
            Get save view state
            @return (list one id, list two id)
        """
        list_one_ids = [Type.POPULARS]
        list_two_ids = [Type.NONE]
        if Lp().settings.get_value('save-state'):
            list_one_ids = []
            list_two_ids = []
            ids = Lp().settings.get_value('list-one-ids')
            for i in ids:
                if isinstance(i, int):
                    list_one_ids.append(i)
            ids = Lp().settings.get_value('list-two-ids')
            for i in ids:
                if isinstance(i, int):
                    list_two_ids.append(i)
        return (list_one_ids, list_two_ids)

    def __setup_scanner(self):
        """
            Run collection update if needed
            @return True if hard scan is running
        """
        Lp().scanner.connect('scan-finished', self.on_scan_finished)
        Lp().scanner.connect('genre-updated', self.__on_genre_updated)
        Lp().scanner.connect('artist-updated', self.__on_artist_updated)

    def __update_playlists(self, playlists, playlist_id):
        """
            Update playlists in second list
            @param playlists as Playlists
            @param playlist_id as int
        """
        ids = self.__list_one.selected_ids
        if ids and ids[0] == Type.PLAYLISTS:
            if Lp().playlists.exists(playlist_id):
                self.__list_two.update_value(playlist_id,
                                             Lp().playlists.get_name(
                                                                  playlist_id))
            else:
                self.__list_two.remove_value(playlist_id)

    def __update_lists(self, updater=None):
        """
            Update lists
            @param updater as GObject
        """
        self.__update_list_one(updater)
        self.__update_list_two(updater)

    def __update_list_one(self, updater):
        """
            Update list one
            @param updater as GObject
        """
        update = updater is not None
        if self.__show_genres:
            self.__setup_list_genres(self.__list_one, update)
        else:
            self.__setup_list_artists(self.__list_one, [Type.ALL], update)

    def __update_list_two(self, updater):
        """
            Update list two
            @param updater as GObject
        """
        update = updater is not None
        ids = self.__list_one.selected_ids
        if ids and ids[0] == Type.PLAYLISTS:
            self.__setup_list_playlists(update)
        elif self.__show_genres and ids:
            self.__setup_list_artists(self.__list_two, ids, update)

    def __setup_list_genres(self, selection_list, update):
        """
            Setup list for genres
            @param list as SelectionList
            @param update as bool, if True, just update entries
            @thread safe
        """
        def load():
            genres = Lp().genres.get()
            return genres

        def setup(genres):
            items = selection_list.get_headers()
            items.append((Type.SEPARATOR, ''))
            items += genres
            selection_list.mark_as_artists(False)
            if update:
                selection_list.update_values(items)
            else:
                selection_list.populate(items)

        loader = Loader(target=load, view=selection_list, on_finished=setup)
        loader.start()

    def __setup_list_artists(self, selection_list, genre_ids, update):
        """
            Setup list for artists
            @param list as SelectionList
            @param genre ids as [int]
            @param update as bool, if True, just update entries
            @thread safe
        """
        def load():
            artists = Lp().artists.get(genre_ids)
            compilations = Lp().albums.get_compilation_ids(genre_ids)
            return (artists, compilations)

        def setup(artists, compilations):
            if selection_list == self.__list_one:
                items = selection_list.get_headers()
                if not compilations:
                    items.append((Type.SEPARATOR, ''))
            else:
                items = []
            if compilations:
                items.append((Type.COMPILATIONS, _("Compilations")))
                items.append((Type.SEPARATOR, ''))
            items += artists
            selection_list.mark_as_artists(True)
            if update:
                selection_list.update_values(items)
            else:
                selection_list.populate(items)

        if selection_list == self.__list_one:
            if self.__list_two.is_visible():
                self.__list_two.hide()
            self.__list_two_restore = Type.NONE
        loader = Loader(target=load, view=selection_list,
                        on_finished=lambda r: setup(*r))
        loader.start()

    def __setup_list_playlists(self, update):
        """
            Setup list for playlists
            @param update as bool
            @thread safe
        """
        playlists = [(Type.LOVED, Lp().playlists.LOVED)]
        playlists.append((Type.POPULARS, _("Popular tracks")))
        playlists.append((Type.RECENTS, _("Recently played")))
        playlists.append((Type.NEVER, _("Never played")))
        playlists.append((Type.RANDOMS, _("Random tracks")))
        playlists.append((Type.SEPARATOR, ''))
        playlists += Lp().playlists.get()
        if update:
            self.__list_two.update_values(playlists)
        else:
            self.__list_two.mark_as_artists(False)
            self.__list_two.populate(playlists)

    def __stop_current_view(self):
        """
            Stop current view
        """
        child = self.__stack.get_visible_child()
        if child is not None:
            if hasattr(child, "stop"):
                child.stop()

    def __update_view_device(self, device_id):
        """
            Update current view with device view,
            Use existing view if available
            @param device id as int
        """
        from lollypop.view_device import DeviceView, DeviceLocked
        self.__stop_current_view()
        device = self.__devices[device_id]
        child = self.__stack.get_child_by_name(device.uri)
        if child is None:
            files = DeviceView.get_files(device.uri)
            if files:
                if child is None:
                    child = DeviceView(device)
                    self.__stack.add_named(child, device.uri)
            else:
                child = DeviceLocked()
                self.__stack.add(child)
            child.show()
        child.populate()
        self.__stack.set_visible_child(child)
        self.__stack.clean_old_views(child)

    def __update_view_artists(self, genre_ids, artist_ids):
        """
            Update current view with artists view
            @param genre ids as [int]
            @param artist ids as [int]
        """
        def load():
            if genre_ids and genre_ids[0] == Type.ALL:
                albums = Lp().albums.get_ids(artist_ids, [])
            else:
                albums = []
                if artist_ids and artist_ids[0] == Type.COMPILATIONS:
                    albums += Lp().albums.get_compilation_ids(genre_ids)
                albums += Lp().albums.get_ids(artist_ids, genre_ids)
            return albums
        from lollypop.view_artist import ArtistView
        self.__stop_current_view()
        view = ArtistView(artist_ids, genre_ids)
        loader = Loader(target=load, view=view)
        loader.start()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_albums(self, genre_ids, artist_ids):
        """
            Update current view with albums view
            @param genre ids as [int]
            @param is compilation as bool
        """
        def load():
            albums = []
            is_compilation = artist_ids and artist_ids[0] == Type.COMPILATIONS
            if genre_ids and genre_ids[0] == Type.ALL:
                if is_compilation or\
                        Lp().settings.get_value('show-compilations'):
                    albums = Lp().albums.get_compilation_ids()
                if not is_compilation:
                    albums += Lp().albums.get_ids()
            elif genre_ids and genre_ids[0] == Type.POPULARS:
                albums = Lp().albums.get_populars()
            elif genre_ids and genre_ids[0] == Type.RECENTS:
                albums = Lp().albums.get_recents()
            elif genre_ids and genre_ids[0] == Type.RANDOMS:
                albums = Lp().albums.get_randoms()
            else:
                if is_compilation or\
                        Lp().settings.get_value('show-compilations'):
                    albums = Lp().albums.get_compilation_ids(genre_ids)
                if not is_compilation:
                    albums += Lp().albums.get_ids([], genre_ids)
            return albums

        from lollypop.view_albums import AlbumsView
        self.__stop_current_view()
        view = AlbumsView(genre_ids, artist_ids)
        loader = Loader(target=load, view=view)
        loader.start()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_playlists(self, playlist_ids=[]):
        """
            Update current view with playlist view
            @param playlist ids as [int]
        """
        def load():
            track_ids = []
            for playlist_id in playlist_ids:
                if playlist_id == Type.POPULARS:
                    tracks = Lp().tracks.get_populars()
                elif playlist_id == Type.RECENTS:
                    tracks = Lp().tracks.get_recently_listened_to()
                elif playlist_id == Type.NEVER:
                    tracks = Lp().tracks.get_never_listened_to()
                elif playlist_id == Type.RANDOMS:
                    tracks = Lp().tracks.get_randoms()
                else:
                    tracks = Lp().playlists.get_track_ids(playlist_id)
                for track_id in tracks:
                    if track_id not in track_ids:
                        track_ids.append(track_id)
            return track_ids

        self.__stop_current_view()
        view = None
        if playlist_ids:
            from lollypop.view_playlists import PlaylistsView
            view = PlaylistsView(playlist_ids)
            loader = Loader(target=load, view=view)
            loader.start()
        else:
            from lollypop.view_playlists import PlaylistsManageView
            view = PlaylistsManageView(Type.NONE, [], [], False)
            view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __update_view_radios(self):
        """
            Update current view with radios view
        """
        from lollypop.view_radios import RadiosView
        self.__stop_current_view()
        view = RadiosView()
        view.populate()
        view.show()
        self.__stack.add(view)
        self.__stack.set_visible_child(view)
        self.__stack.clean_old_views(view)

    def __add_device(self, mount, show=False):
        """
            Add a device
            @param mount as Gio.Mount
            @param show as bool
        """
        if mount.get_volume() is None:
            return
        name = mount.get_name()
        uri = mount.get_default_location().get_uri()
        if uri is not None and (
                mount.can_eject() or uri.startswith('mtp')):
            self.__devices_index -= 1
            dev = Device()
            dev.id = self.__devices_index
            dev.name = name
            dev.uri = uri
            self.__devices[self.__devices_index] = dev
            if show:
                self.__list_one.add_value((dev.id, dev.name))

    def __remove_device(self, mount):
        """
            Remove volume from device list
            @param mount as Gio.Mount
        """
        uri = mount.get_default_location().get_uri()
        for dev in self.__devices.values():
            if dev.uri == uri:
                self.__list_one.remove_value(dev.id)
                child = self.__stack.get_child_by_name(uri)
                if child is not None:
                    child.destroy()
                del self.__devices[dev.id]
            break

    def __on_list_one_selected(self, selection_list):
        """
            Update view based on selected object
            @param list as SelectionList
        """
        selected_ids = self.__list_one.selected_ids
        if not selected_ids:
            return
        self.__list_two.clear()
        if selected_ids[0] == Type.PLAYLISTS:
            self.__list_two.show()
            if not self.__list_two.will_be_selected():
                self.__update_view_playlists()
            self.__setup_list_playlists(False)
        elif Type.DEVICES - 999 < selected_ids[0] < Type.DEVICES:
            self.__list_two.hide()
            if not self.__list_two.will_be_selected():
                self.__update_view_device(selected_ids[0])
        elif selected_ids[0] in [Type.POPULARS,
                                 Type.RECENTS,
                                 Type.RANDOMS,
                                 Type.CHARTS]:
            self.__list_two.hide()
            self.__update_view_albums(selected_ids, [])
        elif selected_ids[0] == Type.RADIOS:
            self.__list_two.hide()
            self.__update_view_radios()
        elif selection_list.is_marked_as_artists():
            self.__list_two.hide()
            if selected_ids[0] == Type.ALL:
                self.__update_view_albums(selected_ids, [])
            elif selected_ids[0] == Type.COMPILATIONS:
                self.__update_view_albums([], selected_ids)
            else:
                self.__update_view_artists([], selected_ids)
        else:
            self.__setup_list_artists(self.__list_two, selected_ids, False)
            self.__list_two.show()
            if not self.__list_two.will_be_selected():
                self.__update_view_albums(selected_ids, [])

    def __on_list_populated(self, selection_list):
        """
            Add device to list one and update db
            @param selection list as SelectionList
        """
        for dev in self.__devices.values():
            self.__list_one.add_value((dev.id, dev.name))

    def __on_list_two_selected(self, selection_list):
        """
            Update view based on selected object
            @param list as SelectionList
        """
        genre_ids = self.__list_one.selected_ids
        selected_ids = self.__list_two.selected_ids
        if not selected_ids or not genre_ids:
            return
        if genre_ids[0] == Type.PLAYLISTS:
            self.__update_view_playlists(selected_ids)
        elif selected_ids[0] == Type.COMPILATIONS:
            self.__update_view_albums(genre_ids, selected_ids)
        else:
            self.__update_view_artists(genre_ids, selected_ids)

    def __on_genre_updated(self, scanner, genre_id, add):
        """
            Add genre to genre list
            @param scanner as CollectionScanner
            @param genre id as int
            @param add as bool
        """
        # Ignore static genres, can happend with Charts
        if genre_id < 0:
            return
        if self.__show_genres:
            if add:
                genre_name = Lp().genres.get_name(genre_id)
                self.__list_one.add_value((genre_id, genre_name))
            else:
                genre_ids = Lp().genres.get_ids()
                if genre_id not in genre_ids:
                    self.__list_one.remove_value(genre_id)

    def __on_artist_updated(self, scanner, artist_id, add):
        """
            Add artist to artist list
            @param scanner as CollectionScanner
            @param artist id as int
            @param add as bool
        """
        artist_name = Lp().artists.get_name(artist_id)
        if self.__show_genres:
            l = self.__list_two
            artist_ids = Lp().artists.get_ids(self.__list_one.selected_ids)
        else:
            l = self.__list_one
            artist_ids = Lp().artists.get_ids()
        if add:
            if artist_id in artist_ids:
                l.add_value((artist_id, artist_name))
        else:
            if artist_id not in artist_ids:
                l.remove_value(artist_id)

    def __on_mount_added(self, vm, mount):
        """
            On volume mounter
            @param vm as Gio.VolumeMonitor
            @param mount as Gio.Mount
        """
        self.__add_device(mount, True)

    def __on_mount_removed(self, vm, mount):
        """
            On volume removed, clean selection list
            @param vm as Gio.VolumeMonitor
            @param mount as Gio.Mount
        """
        self.__remove_device(mount)
コード例 #9
0
class ProgressContainer:
    """
        Progress bar management for main view
    """
    def __init__(self):
        """
            Init container
        """
        self.__pulse_timeout = None
        self._progress = ProgressBar()
        self._progress.set_property("hexpand", True)

    def pulse(self, pulse):
        """
            Make progress bar visible/pulse if pulse is True
            @param pulse as bool
        """
        if pulse and not self._progress.is_visible():
            self._progress.show()
            if self.__pulse_timeout is None:
                self.__pulse_timeout = GLib.timeout_add(500, self.__pulse)
        else:
            if self.__pulse_timeout is not None:
                GLib.source_remove(self.__pulse_timeout)
                self.__pulse_timeout = None
                self._progress.hide()

    @property
    def progress(self):
        """
            Progress bar
            @return ProgressBar
        """
        return self._progress

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

    def __pulse(self):
        """
            Make progress bar pulse while visible
            @param pulse as bool
        """
        if self._progress.is_visible() and not App().scanner.is_locked():
            self._progress.pulse()
            return True
        else:
            self._progress.set_fraction(0.0, self)
            self.__pulse_timeout = None
            return False
コード例 #10
0
class Container(Gtk.Overlay, NotificationContainer, ScannerContainer,
                PlaylistsContainer, ListsContainer, ViewsContainer,
                FilterContainer):
    """
        Main view management
    """

    __gsignals__ = {
        "can-go-back-changed": (GObject.SignalFlags.RUN_FIRST, None, (bool, )),
    }

    def __init__(self):
        """
            Init container
            @param view_type as ViewType, will be appended to any created view
        """
        Gtk.Overlay.__init__(self)
        NotificationContainer.__init__(self)
        ScannerContainer.__init__(self)
        PlaylistsContainer.__init__(self)
        ViewsContainer.__init__(self)

    def setup(self):
        """
            Setup container
        """
        self.__widget = Handy.Leaflet()
        self.__widget.show()
        self.__sub_widget = Handy.Leaflet()
        self.__sub_widget.show()
        self.__focused_view = None
        self._stack = StackContainer()
        self._stack.show()
        ListsContainer.__init__(self)
        self.__progress = ProgressBar()
        self.__progress.get_style_context().add_class("progress-bottom")
        self.__progress.set_property("valign", Gtk.Align.END)
        self.add_overlay(self.__progress)
        search_action = App().lookup_action("search")
        search_action.connect("activate", self.__on_search_activate)
        self.__widget.add(self.sidebar)
        self.__grid_view = Grid()
        self.__grid_view.set_orientation(Gtk.Orientation.VERTICAL)
        self.__grid_view.show()
        self.__sub_widget.add(self.left_list)
        self.__sub_widget.add(self.__grid_view)
        self.__grid_view.attach(self._stack, 0, 0, 1, 1)
        self.__widget.add(self.__sub_widget)
        self.__widget.set_visible_child(self.__sub_widget)
        self.__sub_widget.set_visible_child(self.__grid_view)
        self.add(self.__widget)
        FilterContainer.__init__(self)

    def stop(self):
        """
            Stop current view from processing
        """
        view = self._stack.get_visible_child()
        if view is not None:
            view.stop()

    def reload_view(self):
        """
            Reload current view
        """
        view = self._stack.get_visible_child()
        if view is not None and view.args is not None:
            from lollypop.view_artist_box import ArtistViewBox
            from lollypop.view_artist_list import ArtistViewList
            show_tracks = App().settings.get_value("show-artist-tracks")
            if view.__class__ == ArtistViewBox and show_tracks:
                cls = ArtistViewList
            elif view.__class__ == ArtistViewList and not show_tracks:
                cls = ArtistViewBox
            else:
                cls = view.__class__
            new_view = cls(**view.args)
            new_view.populate()
            new_view.show()
            self._stack.add(new_view)
            self._stack.set_visible_child(new_view)
        else:
            App().lookup_action("reload").change_state(GLib.Variant("b", True))

    def set_focused_view(self, view):
        """
            Set focused view
            @param view as View
        """
        self.__focused_view = view

    def go_home(self):
        """
            Go back to first page
        """
        self.__widget.set_visible_child(self.sidebar)
        self._stack.clear()
        emit_signal(self, "can-go-back-changed", False)

    def go_back(self):
        """
            Go back in history
        """
        if self._stack.history.count > 0:
            self._stack.go_back()
        elif self.__sub_widget.get_folded() and\
                self.__sub_widget.get_visible_child() != self.left_list:
            self.__sub_widget.set_visible_child(self.left_list)
            self._stack.clear()
        elif self.__widget.get_folded() and\
                self.__widget.get_visible_child() != self.sidebar:
            self.__widget.set_visible_child(self.sidebar)
            self._stack.clear()
        emit_signal(self, "can-go-back-changed", self.can_go_back)

    @property
    def can_go_back(self):
        """
            True if can go back
            @return bool
        """
        if self.__widget.get_folded():
            return self.__widget.get_visible_child() != self._sidebar
        else:
            return self._stack.history.count > 0

    @property
    def widget(self):
        """
            Get main widget
            @return Handy.Leaflet
        """
        return self.__widget

    @property
    def sub_widget(self):
        """
            Get sub widget
            @return Handy.Leaflet
        """
        return self.__sub_widget

    @property
    def grid_view(self):
        """
            Get grid view
            @return Gtk.Grid
        """
        return self.__grid_view

    @property
    def focused_view(self):
        """
            Get focused view
            @return View
        """
        return self.__focused_view

    @property
    def view(self):
        """
            Get current view
            @return View
        """
        view = self._stack.get_visible_child()
        if view is not None and isinstance(view, View):
            return view
        return None

    @property
    def stack(self):
        """
            Container stack
            @return stack as Gtk.Stack
        """
        return self._stack

    @property
    def progress(self):
        """
            Progress bar
            @return ProgressBar
        """
        return self.__progress

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

    def __on_search_activate(self, action, variant):
        """
            @param action as Gio.SimpleAction
            @param variant as GLib.Variant
        """
        if App().window.folded:
            search = variant.get_string()
            App().window.container.show_view([Type.SEARCH], search)
コード例 #11
0
class Container(Gtk.Overlay, NotificationContainer,
                ScannerContainer, PlaylistsContainer,
                ListsContainer, ViewsContainer):
    """
        Main view management
    """

    def __init__(self, view_type=ViewType.DEFAULT):
        """
            Init container
            @param view_type as ViewType, will be appended to any created view
        """
        Gtk.Overlay.__init__(self)
        NotificationContainer.__init__(self)
        ScannerContainer.__init__(self)
        PlaylistsContainer.__init__(self)
        ListsContainer.__init__(self)
        ViewsContainer.__init__(self)
        self._view_type = view_type
        self._rounded_artists_view = None
        self._stack = AdaptiveStack()
        self._stack.show()
        self.__setup_view()
        self.add(self._paned_one)

    def stop_all(self):
        """
            Stop current view from processing
        """
        view = self._stack.get_visible_child()
        if view is not None:
            view.stop()

    def reload_view(self):
        """
            Reload current view
        """
        if App().settings.get_value("show-sidebar"):
            ListsContainer._restore_state(self)
        else:
            ViewsContainer._restore_state(self)

    def show_sidebar(self, show):
        """
            Show/Hide navigation sidebar
            @param show as bool
        """
        def select_list_one(selection_list):
            ListsContainer._restore_state(self)
            self._list_one.disconnect_by_func(select_list_one)

        if self._rounded_artists_view is not None:
            self._rounded_artists_view.destroy()
            self._rounded_artists_view = None

        if show:
            self._setup_lists()
            self._list_one.show()
            if len(self._stack.get_children()) == 1:
                App().window.emit("can-go-back-changed", False)
            self._list_one.connect("populated", select_list_one)
            self.update_list_one()
            self.__show_settings_dialog()
        else:
            if self._list_one is not None:
                self._list_one.destroy()
                self._list_two.destroy()
                self._list_one = self._list_two = None
            App().window.emit("show-can-go-back", True)
            empty = len(self._stack.get_children()) == 0
            App().window.emit("can-go-back-changed", not empty)
            # Remove any existing child
            children = self._stack.get_children()
            for child in children:
                self._stack.remove(child)
            # Be sure to have an initial artist view
            if self._rounded_artists_view is None:
                self._rounded_artists_view = self._get_view_artists_rounded(
                    True)
                self._stack.set_visible_child(self._rounded_artists_view)
            if empty:
                ViewsContainer._restore_state(self)
            else:
                # Add children now we have an initial artist view
                for child in children:
                    self._stack.add(child)
                    self._stack.set_visible_child(child)

    def show_artists_albums(self, artist_ids):
        """
            Show albums from artists
            @param artist_ids as [int]
        """
        # FIXME nécessaire?
        def select_list_two(selection_list, artist_ids):
            self._list_two.select_ids(artist_ids)
            self._list_two.disconnect_by_func(select_list_two)
        sidebar_content = App().settings.get_enum("sidebar-content")
        if sidebar_content == SidebarContent.GENRES:
            # Get artist genres
            genre_ids = []
            for artist_id in artist_ids:
                album_ids = App().artists.get_albums(artist_ids)
                for album_id in album_ids:
                    for genre_id in App().albums.get_genre_ids(album_id):
                        if genre_id not in genre_ids:
                            genre_ids.append(genre_id)
            self.show_lists(genre_ids, artist_ids)
        elif sidebar_content == SidebarContent.ARTISTS:
            # Select artists on list one
            self.show_lists(artist_ids, [])
        else:
            self.show_view(artist_ids)

    @property
    def view(self):
        """
            Get current view
            @return View
        """
        view = self._stack.get_visible_child()
        if view is not None and isinstance(view, View):
            return view
        return None

    @property
    def stack(self):
        """
            Container stack
            @return stack as Gtk.Stack
        """
        return self._stack

    @property
    def progress(self):
        """
            Progress bar
            @return ProgressBar
        """
        return self.__progress

    @property
    def rounded_artists_view(self):
        """
            Get rounder artists view
            @return RoundedArtistsView
        """
        return self._rounded_artists_view

############
# PRIVATE  #
############
    def __setup_view(self):
        """
            Setup window main view:
                - genre list
                - artist list
                - main view as artist view or album view
        """
        self._paned_one = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)
        self._paned_two = Gtk.Paned.new(Gtk.Orientation.HORIZONTAL)

        self._paned_one.connect("notify::position", self.__on_paned_position)
        self._paned_two.connect("notify::position", self.__on_paned_position)

        self.__progress = ProgressBar()
        self.__progress.get_style_context().add_class("progress-bottom")
        self.__progress.set_property("valign", Gtk.Align.END)
        self.add_overlay(self.__progress)

        self._paned_two.add2(self._stack)
        self._paned_one.add2(self._paned_two)
        position = App().settings.get_value(
            "paned-mainlist-width").get_int32()
        self._paned_one.set_position(position)
        self._paned_one.show()
        self._paned_two.show()
        search_action = App().lookup_action("search")
        search_action.connect("activate", self.__on_search_activate)

    def __show_settings_dialog(self):
        """
            Show settings dialog if view exists in stack
        """
        from lollypop.view_settings import SettingsChildView
        from lollypop.view_settings import SettingsView
        if isinstance(self.view, SettingsChildView) or\
                isinstance(self.view, SettingsView):
            action = App().lookup_action("settings")
            GLib.idle_add(action.activate,
                          GLib.Variant("i", self.view.type))

    def __on_search_activate(self, action, variant):
        """
            @param action as Gio.SimpleAction
            @param variant as GLib.Variant
        """
        if App().window.is_adaptive:
            search = variant.get_string()
            App().window.container.show_view([Type.SEARCH], search)

    def __on_paned_position(self, paned, param):
        """
            Save paned position
            @param paned as Gtk.Paned
            @param param as GParamSpec
        """
        position = paned.get_property(param.name)
        # We do not want to save position while adaptive mode is set
        # Not a good a fix but a working one
        if position < 100:
            return
        if paned == self._paned_one:
            setting = "paned-mainlist-width"
        else:
            setting = "paned-listview-width"
        App().settings.set_value(setting,
                                 GLib.Variant("i",
                                              position))