1# Copyright (c) 2016 The GNOME Music Developers
2#
3# GNOME Music is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 2 of the License, or
6# (at your option) any later version.
7#
8# GNOME Music is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
13# You should have received a copy of the GNU General Public License along
14# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16#
17# The GNOME Music authors hereby grant permission for non-GPL compatible
18# GStreamer plugins to be used and distributed together with GStreamer
19# and GNOME Music.  This permission is above and beyond the permissions
20# granted by the GPL license by which GNOME Music is covered.  If you
21# modify this code, you may extend this exception to your version of the
22# code, but you are not obligated to do so.  If you do not wish to do so,
23# delete this exception statement from your version.
24
25from enum import IntEnum
26
27from gettext import gettext as _
28from gi.repository import GLib, GObject, Gtk, Tracker
29
30
31@Gtk.Template(resource_path="/org/gnome/Music/ui/EmptyView.ui")
32class EmptyView(Gtk.Stack):
33    """Empty view when there is no music to display
34
35    This view can have several states
36
37    EMPTY: No music has been found at startup (default)
38    SEARCH: No music found with a user search
39    NO_TRACKER: Tracker is unavailable
40    TRACKER_OUTDATED: Tracker version is too old
41    """
42
43    class State(IntEnum):
44        """Enum for EmptyView state."""
45        EMPTY = 0
46        SEARCH = 1
47        NO_TRACKER = 2
48        TRACKER_OUTDATED = 3
49
50    __gtype_name__ = "EmptyView"
51
52    _description_label = Gtk.Template.Child()
53    _initial_state = Gtk.Template.Child()
54    _status_page = Gtk.Template.Child()
55
56    def __init__(self):
57        super().__init__()
58
59        # FIXME: This is now duplicated here and in GrlTrackerWrapper.
60        try:
61            music_folder = GLib.get_user_special_dir(
62                GLib.UserDirectory.DIRECTORY_MUSIC)
63            assert music_folder is not None
64        except (TypeError, AssertionError):
65            self._content_text = _("Your XDG Music directory is not set.")
66            return
67
68        music_folder = Tracker.sparql_escape_string(
69            GLib.filename_to_uri(music_folder))
70
71        href_text = "<a href='{}'>{}</a>".format(
72            music_folder, _("Music Folder"))
73
74        # TRANSLATORS: This is a label to display a link to open user's music
75        # folder. {} will be replaced with the translated text 'Music folder'
76        folder_text = _("The contents of your {} will appear here.")
77        self._content_text = folder_text.format(href_text)
78
79        # Hack to get to HdyClamp, so it can be hidden for the
80        # initial state.
81        child_of_child = self._status_page.get_child().get_child()
82        self._hdy_clamp = child_of_child.get_child().get_children()[0]
83
84        self._status_page.add(self._initial_state)
85
86        self._state = EmptyView.State.EMPTY
87
88    @GObject.Property(type=int, default=0, minimum=0, maximum=4)
89    def state(self):
90        """Get the state of the empty view
91
92        :returns: The view state
93        :rtype: int
94        """
95        return self._state
96
97    @state.setter  # type: ignore
98    def state(self, value):
99        """Set the state of the empty view
100
101        :param int value: new state
102        """
103        self._state = value
104
105        self._hdy_clamp.props.visible = True
106        self._initial_state.props.visible = False
107
108        if self._state == EmptyView.State.EMPTY:
109            self._set_empty_state()
110        elif self._state == EmptyView.State.SEARCH:
111            self._set_search_state()
112        elif self._state == EmptyView.State.NO_TRACKER:
113            self._set_no_tracker_state()
114        elif self._state == EmptyView.State.TRACKER_OUTDATED:
115            self._set_tracker_outdated_state()
116
117    def _set_empty_state(self):
118        self._hdy_clamp.props.visible = False
119        self._initial_state.props.visible = True
120
121        self._description_label.props.label = self._content_text
122
123    def _set_search_state(self):
124        self._status_page.props.title = _("No Music Found")
125        self._status_page.props.description = _("Try a Different Search")
126
127    def _set_no_tracker_state(self):
128        self._status_page.props.title = _(
129            "GNOME Music could not connect to Tracker.")
130        self._status_page.props.description = _(
131            "Your music files cannot be indexed without Tracker running.")
132
133        self._status_page.props.icon_name = "dialog-error-symbolic"
134
135    def _set_tracker_outdated_state(self):
136        self._status_page.props.title = _(
137            "Your system Tracker version seems outdated.")
138        self._status_page.props.description = _(
139            "Music needs Tracker version 3.0.0 or higher.")
140
141        self._status_page.props.icon_name = "dialog-error-symbolic"
142
143    def select_all(self):
144        """Cannot select songs from EmptyView."""
145        pass
146
147    def deselect_all(self):
148        """Cannot select songs from EmptyView."""
149        pass
150