1# Copyright (c) 2014-2021 Cedric Bellegarde <cedric.bellegarde@adishatz.org>
2# This program is free software: you can redistribute it and/or modify
3# it under the terms of the GNU General Public License as published by
4# the Free Software Foundation, either version 3 of the License, or
5# (at your option) any later version.
6# This program is distributed in the hope that it will be useful,
7# but WITHOUT ANY WARRANTY; without even the implied warranty of
8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9# GNU General Public License for more details.
10# You should have received a copy of the GNU General Public License
11# along with this program. If not, see <http://www.gnu.org/licenses/>.
12
13from gi.repository import Gtk, GLib, GObject, Handy
14
15from lollypop.define import App, Type
16from lollypop.utils import emit_signal
17from lollypop.view import View
18from lollypop.container_stack import StackContainer
19from lollypop.container_notification import NotificationContainer
20from lollypop.container_scanner import ScannerContainer
21from lollypop.container_playlists import PlaylistsContainer
22from lollypop.container_lists import ListsContainer
23from lollypop.container_views import ViewsContainer
24from lollypop.container_filter import FilterContainer
25from lollypop.progressbar import ProgressBar
26
27
28class Grid(Gtk.Grid):
29    def do_get_preferred_width(self):
30        return 200, 700
31
32
33class Container(Gtk.Overlay, NotificationContainer,
34                ScannerContainer, PlaylistsContainer,
35                ListsContainer, ViewsContainer, FilterContainer):
36    """
37        Main view management
38    """
39
40    __gsignals__ = {
41        "can-go-back-changed": (GObject.SignalFlags.RUN_FIRST, None, (bool,)),
42    }
43
44    def __init__(self):
45        """
46            Init container
47            @param view_type as ViewType, will be appended to any created view
48        """
49        Gtk.Overlay.__init__(self)
50        NotificationContainer.__init__(self)
51        ScannerContainer.__init__(self)
52        PlaylistsContainer.__init__(self)
53        ViewsContainer.__init__(self)
54
55    def setup(self):
56        """
57            Setup container
58        """
59        self.__widget = Handy.Leaflet()
60        self.__widget.show()
61        self.__widget.connect("notify::folded", self.__on_folded)
62        self.__sub_widget = Handy.Leaflet()
63        self.__sub_widget.show()
64        self.__focused_view = None
65        self._stack = StackContainer()
66        self._stack.show()
67        ListsContainer.__init__(self)
68        self.__progress = ProgressBar()
69        self.__progress.get_style_context().add_class("progress-bottom")
70        self.__progress.set_property("valign", Gtk.Align.END)
71        self.add_overlay(self.__progress)
72        search_action = App().lookup_action("search")
73        search_action.connect("activate", self.__on_search_activate)
74        self.__widget.add(self.sidebar)
75        self.__grid_view = Grid()
76        self.__grid_view.set_orientation(Gtk.Orientation.VERTICAL)
77        self.__grid_view.show()
78        self.__sub_widget.add(self.left_list)
79        self.__sub_widget.add(self.__grid_view)
80        self.__grid_view.attach(self._stack, 0, 0, 1, 1)
81        self.__widget.add(self.__sub_widget)
82        self.__widget.set_visible_child(self.__sub_widget)
83        self.__sub_widget.set_visible_child(self.__grid_view)
84        self.add(self.__widget)
85        FilterContainer.__init__(self)
86
87    def stop(self):
88        """
89            Stop current view from processing
90        """
91        view = self._stack.get_visible_child()
92        if view is not None:
93            view.stop()
94
95    def reload_view(self):
96        """
97            Reload current view
98        """
99        view = self._stack.get_visible_child()
100        if view is not None and view.args is not None:
101            cls = view.__class__
102            new_view = cls(**view.args)
103            new_view.populate()
104            new_view.show()
105            self._stack.add(new_view)
106            self._stack.set_visible_child(new_view)
107        else:
108            App().lookup_action("reload").change_state(GLib.Variant("b", True))
109
110    def set_focused_view(self, view):
111        """
112            Set focused view
113            @param view as View
114        """
115        self.__focused_view = view
116
117    def go_home(self):
118        """
119            Go back to first page
120        """
121        self.__widget.set_visible_child(self.sidebar)
122        self._stack.clear()
123        emit_signal(self, "can-go-back-changed", False)
124
125    def go_back(self):
126        """
127            Go back in history
128        """
129        if self._stack.history.count > 0:
130            self._stack.go_back()
131            self.set_focused_view(self._stack.get_visible_child())
132        elif self.__sub_widget.get_folded() and\
133                self.__sub_widget.get_visible_child() != self.left_list:
134            self.__sub_widget.set_visible_child(self.left_list)
135            self._stack.clear()
136        elif self.__widget.get_folded() and\
137                self.__widget.get_visible_child() != self.sidebar:
138            self.__widget.set_visible_child(self.sidebar)
139            self._stack.clear()
140        emit_signal(self, "can-go-back-changed", self.can_go_back)
141
142    @property
143    def can_go_back(self):
144        """
145            True if can go back
146            @return bool
147        """
148        if self.__widget.get_folded():
149            return self.__widget.get_visible_child() != self._sidebar
150        else:
151            return self._stack.history.count > 0
152
153    @property
154    def widget(self):
155        """
156            Get main widget
157            @return Handy.Leaflet
158        """
159        return self.__widget
160
161    @property
162    def sub_widget(self):
163        """
164            Get sub widget
165            @return Handy.Leaflet
166        """
167        return self.__sub_widget
168
169    @property
170    def grid_view(self):
171        """
172            Get grid view
173            @return Gtk.Grid
174        """
175        return self.__grid_view
176
177    @property
178    def focused_view(self):
179        """
180            Get focused view
181            @return View
182        """
183        return self.__focused_view
184
185    @property
186    def view(self):
187        """
188            Get current view
189            @return View
190        """
191        view = self._stack.get_visible_child()
192        if view is not None and isinstance(view, View):
193            return view
194        return None
195
196    @property
197    def stack(self):
198        """
199            Container stack
200            @return stack as Gtk.Stack
201        """
202        return self._stack
203
204    @property
205    def progress(self):
206        """
207            Progress bar
208            @return ProgressBar
209        """
210        return self.__progress
211
212############
213# PRIVATE  #
214############
215    def __on_folded(self, *ignore):
216        """
217            Reload main view if needed
218        """
219        if not App().window.folded and self.view is None:
220            self.show_view(self.sidebar.selected_ids)
221
222    def __on_search_activate(self, action, variant):
223        """
224            @param action as Gio.SimpleAction
225            @param variant as GLib.Variant
226        """
227        if App().window.folded:
228            search = variant.get_string()
229            App().window.container.show_view([Type.SEARCH], search)
230