Example #1
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)
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))