Ejemplo n.º 1
0
    def __init__(self, player, parent_view):
        """Initialize the AlbumWidget.

        :param player: The player object
        :param parent_view: The view this widget is part of
        """
        Gtk.EventBox.__init__(self)

        self._tracks = []

        scale = self.get_scale_factor()
        self._cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.large)

        self._player = player
        self._iter_to_clean = None

        self._selection_mode = False

        self._builder = Gtk.Builder()
        self._builder.add_from_resource('/org/gnome/Music/AlbumWidget.ui')
        self._create_model()
        self._album = None
        self._header_bar = None
        self._selection_mode_allowed = True

        self._composer_label = self._builder.get_object('composer_label')
        self._composer_info = self._builder.get_object('composer_info')

        view_box = self._builder.get_object('view')
        self._disc_listbox = DiscListBox()
        self._disc_listbox.set_selection_mode_allowed(True)
        # TODO: The top of the coverart is the same vertical
        # position as the top of the album songs, however
        # since we set a top margins for the discbox
        # subtract that margin here. A cleaner solution is
        # appreciated.
        self._disc_listbox.set_margin_top(64 - 16)
        self._disc_listbox.set_margin_bottom(64)
        self._disc_listbox.set_margin_end(32)
        self._disc_listbox.connect('selection-changed',
                                   self._on_selection_changed)
        view_box.add(self._disc_listbox)

        # FIXME: Assigned to appease searchview
        # get_selected_tracks
        self.view = self._disc_listbox

        self.add(self._builder.get_object('AlbumWidget'))
        self.get_style_context().add_class('view')
        self.get_style_context().add_class('content-view')

        self.show_all()
Ejemplo n.º 2
0
    def __init__(self, media, player, model, header_bar,
                 selection_mode_allowed, size_group=None,
                 cover_size_group=None):
        super().__init__(self, orientation=Gtk.Orientation.HORIZONTAL)

        self._size_group = size_group
        self._cover_size_group = cover_size_group
        scale = self.get_scale_factor()
        self._cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading,
            ArtSize.medium)

        self._media = media
        self._player = player
        self._artist = utils.get_artist_name(self._media)
        self._album_title = utils.get_album_title(self._media)
        self._model = model
        self._header_bar = header_bar
        self._selection_mode = False
        self._selection_mode_allowed = selection_mode_allowed

        self._songs = []

        self._header_bar._select_button.connect(
            'toggled', self._on_header_select_button_toggled)

        ui = Gtk.Builder()
        ui.add_from_resource('/org/gnome/Music/ArtistAlbumWidget.ui')

        self.cover = ui.get_object('cover')
        self.cover.set_from_surface(self._loading_icon_surface)

        self._disc_listbox = ui.get_object('disclistbox')
        self._disc_listbox.set_selection_mode_allowed(
            self._selection_mode_allowed)

        ui.get_object('title').set_label(self._album_title)
        creation_date = self._media.get_creation_date()
        if creation_date:
            year = creation_date.get_year()
            ui.get_object('year').set_markup(
                '<span color=\'grey\'>{}</span>'.format(year))

        if self._size_group:
            self._size_group.add_widget(ui.get_object('box1'))

        if self._cover_size_group:
            self._cover_size_group.add_widget(self.cover)

        self.pack_start(ui.get_object('ArtistAlbumWidget'), True, True, 0)

        GLib.idle_add(self._update_album_art)
        grilo.populate_album_songs(self._media, self._add_item)
Ejemplo n.º 3
0
    def __init__(self, window, player):
        BaseView.__init__(self, 'search', None, window, Gd.MainViewType.LIST)
        self._items = {}
        self.isStarred = None
        self.iter_to_clean = None

        scale = self.get_scale_factor()
        loading_icon_surface = DefaultIcon(scale).get(DefaultIcon.Type.loading,
                                                      ArtSize.small)
        self._loading_icon = Gdk.pixbuf_get_from_surface(
            loading_icon_surface,
            0,
            0,
            loading_icon_surface.get_width(),
            loading_icon_surface.get_height())

        self._add_list_renderers()
        self.player = player
        self.head_iters = [None, None, None, None]
        self.songs_model = self.model
        self.previous_view = None
        self.connect('no-music-found', self._no_music_found_callback)

        self.albums_selected = []
        self._albums = {}
        self._albumWidget = AlbumWidget(player, self)
        self.add(self._albumWidget)

        self.artists_albums_selected = []
        self._artists = {}
        self._artistAlbumsWidget = None

        self.view.get_generic_view().set_show_expanders(False)
        self.items_selected = []
        self.items_selected_callback = None

        self.found_items_number = None
Ejemplo n.º 4
0
    def __init__(self, window, player):
        BaseView.__init__(self, 'search', None, window, Gd.MainViewType.LIST)
        self._items = {}
        self.isStarred = None
        self.iter_to_clean = None

        scale = self.get_scale_factor()
        loading_icon_surface = DefaultIcon(scale).get(DefaultIcon.Type.loading,
                                                      ArtSize.small)
        self._loading_icon = Gdk.pixbuf_get_from_surface(
            loading_icon_surface,
            0,
            0,
            loading_icon_surface.get_width(),
            loading_icon_surface.get_height())

        self._add_list_renderers()
        self.player = player
        self.head_iters = [None, None, None, None]
        self.songs_model = self.model
        self.previous_view = None
        self.connect('no-music-found', self._no_music_found_callback)

        self.albums_selected = []
        self._albums = {}
        self._albumWidget = AlbumWidget(player, self)
        self.add(self._albumWidget)

        self.artists_albums_selected = []
        self._artists = {}
        self._artistAlbumsWidget = None

        self.view.get_generic_view().set_show_expanders(False)
        self.items_selected = []
        self.items_selected_callback = None

        self.found_items_number = None
Ejemplo n.º 5
0
    def __init__(self, parent_window):
        GObject.GObject.__init__(self)
        self._parent_window = parent_window
        self.playlist = None
        self.playlistType = None
        self.playlistId = None
        self.playlistField = None
        self.currentTrack = None
        self.currentTrackUri = None
        self._lastState = Gst.State.PAUSED
        scale = parent_window.get_scale_factor()
        self.cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.xsmall)
        self._missingPluginMessages = []

        Gst.init(None)
        GstPbutils.pb_utils_init()

        self.discoverer = GstPbutils.Discoverer()
        self.discoverer.connect('discovered', self._on_discovered)
        self.discoverer.start()
        self._discovering_urls = {}

        self.player = Gst.ElementFactory.make('playbin', 'player')
        self.bus = self.player.get_bus()
        self.bus.add_signal_watch()
        self.setup_replaygain()

        self._settings = Gio.Settings.new('org.gnome.Music')
        self._settings.connect('changed::repeat',
                               self._on_repeat_setting_changed)
        self._settings.connect('changed::replaygain',
                               self._on_replaygain_setting_changed)
        self.repeat = self._settings.get_enum('repeat')
        self.replaygain = self._settings.get_value('replaygain') is not None
        self.toggle_replaygain(self.replaygain)

        self.bus.connect('message::state-changed', self._on_bus_state_changed)
        self.bus.connect('message::error', self._onBusError)
        self.bus.connect('message::element', self._on_bus_element)
        self.bus.connect('message::eos', self._on_bus_eos)
        self._setup_view()

        self.playlist_insert_handler = 0
        self.playlist_delete_handler = 0

        self._check_last_fm()
Ejemplo n.º 6
0
    def __init__(self, player, parent_view):
        """Initialize the AlbumWidget.

        :param player: The player object
        :param parent_view: The view this widget is part of
        """
        Gtk.EventBox.__init__(self)

        scale = self.get_scale_factor()
        self._cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.large)

        self._player = player
        self._iter_to_clean = None

        self._ui = Gtk.Builder()
        self._ui.add_from_resource('/org/gnome/Music/AlbumWidget.ui')
        self._create_model()
        self.view = Gd.MainView(shadow_type=Gtk.ShadowType.NONE)
        self.view.set_view_type(Gd.MainViewType.LIST)
        self._album = None
        self._header_bar = None
        self.view.connect('item-activated', self._on_item_activated)

        view_box = self._ui.get_object('view')
        self._ui.get_object('scrolledWindow').set_placement(
            Gtk.CornerType.TOP_LEFT)
        self.view.connect('selection-mode-request',
                          self._on_selection_mode_request)
        child_view = self.view.get_children()[0]
        child_view.set_margin_top(64)
        child_view.set_margin_bottom(64)
        child_view.set_margin_end(32)
        self.view.remove(child_view)
        view_box.add(child_view)

        self.add(self._ui.get_object('AlbumWidget'))
        self._star_handler = StarHandlerWidget(self, 9)
        self._add_list_renderers()
        self.get_style_context().add_class('view')
        self.get_style_context().add_class('content-view')
        self.view.get_generic_view().get_style_context().remove_class('view')
        self.show_all()
Ejemplo n.º 7
0
    def __init__(self, name, title, window, view_type, use_sidebar=False, sidebar=None):
        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self._adjustmentValueId = 0
        self._adjustmentChangedId = 0
        self._scrollbarVisibleId = 0
        self.old_vsbl_range = None
        self.model = Gtk.ListStore(
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GdkPixbuf.Pixbuf,
            GObject.TYPE_OBJECT,
            GObject.TYPE_BOOLEAN,
            GObject.TYPE_INT,
            GObject.TYPE_STRING,
            GObject.TYPE_INT,
            GObject.TYPE_BOOLEAN,
            GObject.TYPE_INT
        )

        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT,
            )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self.star_handler = StarHandlerWidget(self, 9)
        self._cursor = None
        self.window = window
        self.header_bar = window.toolbar
        self.selection_toolbar = window.selection_toolbar
        self.header_bar._select_button.connect(
            'toggled', self._on_header_bar_toggled)
        self.header_bar._cancel_button.connect(
            'clicked', self._on_cancel_button_clicked)

        self.name = name
        self.title = title
        self.add(self._grid)

        self.show_all()
        self.view.hide()
        self._items = []

        scale = self.get_scale_factor()
        self.cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading,
            ArtSize.medium)


        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self.selection_socket = None
        self.header_bar.connect('selection-mode-changed',
                                self._on_selection_mode_changed)

        self._discovering_urls = {}
        grilo.connect('changes-pending', self._on_changes_pending)
Ejemplo n.º 8
0
class BaseView(Gtk.Stack):
    nowPlayingIconName = 'media-playback-start-symbolic'
    errorIconName = 'dialog-error-symbolic'

    selection_mode = GObject.Property(type=bool, default=False)

    def __repr__(self):
        return '<BaseView>'

    @log
    def __init__(self, name, title, window, view_type, use_sidebar=False, sidebar=None):
        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self._adjustmentValueId = 0
        self._adjustmentChangedId = 0
        self._scrollbarVisibleId = 0
        self.old_vsbl_range = None
        self.model = Gtk.ListStore(
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GObject.TYPE_STRING,
            GdkPixbuf.Pixbuf,
            GObject.TYPE_OBJECT,
            GObject.TYPE_BOOLEAN,
            GObject.TYPE_INT,
            GObject.TYPE_STRING,
            GObject.TYPE_INT,
            GObject.TYPE_BOOLEAN,
            GObject.TYPE_INT
        )

        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT,
            )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self.star_handler = StarHandlerWidget(self, 9)
        self._cursor = None
        self.window = window
        self.header_bar = window.toolbar
        self.selection_toolbar = window.selection_toolbar
        self.header_bar._select_button.connect(
            'toggled', self._on_header_bar_toggled)
        self.header_bar._cancel_button.connect(
            'clicked', self._on_cancel_button_clicked)

        self.name = name
        self.title = title
        self.add(self._grid)

        self.show_all()
        self.view.hide()
        self._items = []

        scale = self.get_scale_factor()
        self.cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading,
            ArtSize.medium)


        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self.selection_socket = None
        self.header_bar.connect('selection-mode-changed',
                                self._on_selection_mode_changed)

        self._discovering_urls = {}
        grilo.connect('changes-pending', self._on_changes_pending)

    @log
    def _on_changes_pending(self, data=None):
        pass

    @log
    def _setup_view(self, view_type):
        self.view = Gd.MainView(shadow_type=Gtk.ShadowType.NONE)
        self.view.set_view_type(view_type)

        self.view.click_handler = self.view.connect('item-activated', self._on_item_activated)
        self.view.connect('selection-mode-request', self._on_selection_mode_request)

        self.view.bind_property('selection-mode', self, 'selection_mode',
                                GObject.BindingFlags.BIDIRECTIONAL)

        self.view.connect('view-selection-changed', self._on_view_selection_changed)

        self._box.pack_start(self.view, True, True, 0)

    @log
    def _on_header_bar_toggled(self, button):
        self.selection_mode = button.get_active()

        if self.selection_mode:
            self.header_bar.set_selection_mode(True)
            self.player.actionbar.set_visible(False)
            self.selection_toolbar.actionbar.set_visible(True)
            self.selection_toolbar._add_to_playlist_button.set_sensitive(False)
            self.selection_toolbar._remove_from_playlist_button.set_sensitive(False)
        else:
            self.header_bar.set_selection_mode(False)
            self.player.actionbar.set_visible(self.player.currentTrack is not None)
            self.selection_toolbar.actionbar.set_visible(False)
            self.unselect_all()

    @log
    def _on_cancel_button_clicked(self, button):
        self.view.set_selection_mode(False)
        self.header_bar.set_selection_mode(False)

    @log
    def _on_grilo_ready(self, data=None):
        # FIXME: with async changes in Window this seems never to be
        # called anymore. Fix it proper or remove.
        if (self.header_bar.get_stack().get_visible_child() == self and not self._init):
            self._populate()
        self.header_bar.get_stack().connect('notify::visible-child',
                                            self._on_headerbar_visible)

    @log
    def _on_headerbar_visible(self, widget, param):
        if self == widget.get_visible_child() and not self._init:
            self._populate()

    @log
    def _on_view_selection_changed(self, widget):
        if not self.selection_mode:
            return

        items = self.view.get_selection()
        self.update_header_from_selection(len(items))

    @log
    def update_header_from_selection(self, n_items):
        self.selection_toolbar._add_to_playlist_button.\
            set_sensitive(n_items > 0)
        self.selection_toolbar._remove_from_playlist_button.\
            set_sensitive(n_items > 0)
        if n_items > 0:
            self.header_bar._selection_menu_label.set_text(
                ngettext("Selected %d item", "Selected %d items", n_items) % n_items)
        else:
            self.header_bar._selection_menu_label.set_text(_("Click on items to select them"))

    @log
    def _populate(self, data=None):
        self._init = True
        self.populate()

    @log
    def _on_selection_mode_changed(self, widget, data=None):
        pass

    @log
    def populate(self):
        pass

    @log
    def _add_item(self, source, param, item, remaining=0, data=None):
        if not item:
            if remaining == 0:
                self.view.set_model(self.model)
                self.window.pop_loading_notification()
                self.view.show()
            return

        self._offset += 1
        artist = utils.get_artist_name(item)
        title = utils.get_media_title(item)

        _iter = self.model.append(None)

        loading_icon = Gdk.pixbuf_get_from_surface(
            self._loadin_icon_surface, 0, 0,
            self._loading_icon_surface.get_width(),
            self._loading_icon_surface.get_height())

        self.model[_iter][0, 1, 2, 3, 4, 5, 7, 9] = [
            str(item.get_id()),
            '',
            title,
            artist,
            loading_icon,
            item,
            0,
            False
        ]
        self.cache.lookup(item, self._iconWidth, self._iconHeight,
                          self._on_lookup_ready, _iter)

    @log
    def _on_lookup_ready(self, surface, _iter):
        if surface:
            pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
                                                 surface.get_width(),
                                                 surface.get_height())

            self.model[_iter][4] = pixbuf

    @log
    def _add_list_renderers(self):
        pass

    @log
    def _on_item_activated(self, widget, id, path):
        pass

    @log
    def _on_selection_mode_request(self, *args):
        self.header_bar._select_button.clicked()

    @log
    def get_selected_tracks(self, callback):
        callback([])

    @log
    def _set_selection(self, value, parent=None):
        count = 0
        _iter = self.model.iter_children(parent)
        while _iter is not None:
            if self.model.iter_has_child(_iter):
                count += self._set_selection(value, _iter)
            if self.model[_iter][5]:
                self.model[_iter][6] = value
                count += 1
            _iter = self.model.iter_next(_iter)
        return count

    @log
    def select_all(self):
        """Select all the available tracks."""
        count = self._set_selection(True)

        if count > 0:
            self.selection_toolbar._add_to_playlist_button.set_sensitive(True)
            self.selection_toolbar._remove_from_playlist_button.set_sensitive(True)

        self.update_header_from_selection(count)
        self.view.queue_draw()

    @log
    def unselect_all(self):
        """Unselects all the selected tracks."""
        self._set_selection(False)
        self.selection_toolbar._add_to_playlist_button.set_sensitive(False)
        self.selection_toolbar._remove_from_playlist_button.set_sensitive(False)
        self.header_bar._selection_menu_label.set_text(_("Click on items to select them"))
        self.queue_draw()
Ejemplo n.º 9
0
    def __init__(self,
                 name,
                 title,
                 window,
                 view_type,
                 use_sidebar=False,
                 sidebar=None):
        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self._adjustmentValueId = 0
        self._adjustmentChangedId = 0
        self._scrollbarVisibleId = 0
        self.old_vsbl_range = None
        self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GdkPixbuf.Pixbuf, GObject.TYPE_OBJECT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT,
                                   GObject.TYPE_STRING, GObject.TYPE_INT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT)

        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT, )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self.star_handler = StarHandlerWidget(self, 9)
        self._cursor = None
        self.window = window
        self.header_bar = window.toolbar
        self.selection_toolbar = window.selection_toolbar
        self.header_bar._select_button.connect('toggled',
                                               self._on_header_bar_toggled)
        self.header_bar._cancel_button.connect('clicked',
                                               self._on_cancel_button_clicked)

        self.name = name
        self.title = title
        self.add(self._grid)

        self.show_all()
        self.view.hide()
        self._items = []

        scale = self.get_scale_factor()
        self.cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.medium)

        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self.selection_socket = None
        self.header_bar.connect('selection-mode-changed',
                                self._on_selection_mode_changed)

        self._discovering_urls = {}
        grilo.connect('changes-pending', self._on_changes_pending)
Ejemplo n.º 10
0
class BaseView(Gtk.Stack):
    nowPlayingIconName = 'media-playback-start-symbolic'
    errorIconName = 'dialog-error-symbolic'

    selection_mode = GObject.Property(type=bool, default=False)

    def __repr__(self):
        return '<BaseView>'

    @log
    def __init__(self,
                 name,
                 title,
                 window,
                 view_type,
                 use_sidebar=False,
                 sidebar=None):
        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self._adjustmentValueId = 0
        self._adjustmentChangedId = 0
        self._scrollbarVisibleId = 0
        self.old_vsbl_range = None
        self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GdkPixbuf.Pixbuf, GObject.TYPE_OBJECT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT,
                                   GObject.TYPE_STRING, GObject.TYPE_INT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT)

        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT, )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self.star_handler = StarHandlerWidget(self, 9)
        self._cursor = None
        self.window = window
        self.header_bar = window.toolbar
        self.selection_toolbar = window.selection_toolbar
        self.header_bar._select_button.connect('toggled',
                                               self._on_header_bar_toggled)
        self.header_bar._cancel_button.connect('clicked',
                                               self._on_cancel_button_clicked)

        self.name = name
        self.title = title
        self.add(self._grid)

        self.show_all()
        self.view.hide()
        self._items = []

        scale = self.get_scale_factor()
        self.cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.medium)

        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self.selection_socket = None
        self.header_bar.connect('selection-mode-changed',
                                self._on_selection_mode_changed)

        self._discovering_urls = {}
        grilo.connect('changes-pending', self._on_changes_pending)

    @log
    def _on_changes_pending(self, data=None):
        pass

    @log
    def _setup_view(self, view_type):
        self.view = Gd.MainView(shadow_type=Gtk.ShadowType.NONE)
        self.view.set_view_type(view_type)

        self.view.click_handler = self.view.connect('item-activated',
                                                    self._on_item_activated)
        self.view.connect('selection-mode-request',
                          self._on_selection_mode_request)

        self.view.bind_property('selection-mode', self, 'selection_mode',
                                GObject.BindingFlags.BIDIRECTIONAL)

        self.view.connect('view-selection-changed',
                          self._on_view_selection_changed)

        self._box.pack_start(self.view, True, True, 0)

    @log
    def _on_header_bar_toggled(self, button):
        self.selection_mode = button.get_active()

        if self.selection_mode:
            self.header_bar.set_selection_mode(True)
            self.player.actionbar.set_visible(False)
            self.selection_toolbar.actionbar.set_visible(True)
            self.selection_toolbar._add_to_playlist_button.set_sensitive(False)
            self.selection_toolbar._remove_from_playlist_button.set_sensitive(
                False)
        else:
            self.header_bar.set_selection_mode(False)
            self.player.actionbar.set_visible(
                self.player.currentTrack is not None)
            self.selection_toolbar.actionbar.set_visible(False)
            self.unselect_all()

    @log
    def _on_cancel_button_clicked(self, button):
        self.view.set_selection_mode(False)
        self.header_bar.set_selection_mode(False)

    @log
    def _on_grilo_ready(self, data=None):
        if (self.header_bar.get_stack().get_visible_child() == self
                and not self._init):
            self._populate()
        self.header_bar.get_stack().connect('notify::visible-child',
                                            self._on_headerbar_visible)

    @log
    def _on_headerbar_visible(self, widget, param):
        if self == widget.get_visible_child() and not self._init:
            self._populate()

    @log
    def _on_view_selection_changed(self, widget):
        if not self.selection_mode:
            return

        items = self.view.get_selection()
        self.update_header_from_selection(len(items))

    @log
    def update_header_from_selection(self, n_items):
        self.selection_toolbar._add_to_playlist_button.\
            set_sensitive(n_items > 0)
        self.selection_toolbar._remove_from_playlist_button.\
            set_sensitive(n_items > 0)
        if n_items > 0:
            self.header_bar._selection_menu_label.set_text(
                ngettext("Selected %d item", "Selected %d items", n_items) %
                n_items)
        else:
            self.header_bar._selection_menu_label.set_text(
                _("Click on items to select them"))

    @log
    def _populate(self, data=None):
        self._init = True
        self.populate()

    @log
    def _on_selection_mode_changed(self, widget, data=None):
        pass

    @log
    def populate(self):
        print('populate')

    @log
    def _add_item(self, source, param, item, remaining=0, data=None):
        self.window.notification.set_timeout(0)
        if not item:
            if remaining == 0:
                self.view.set_model(self.model)
                self.window.notification.dismiss()
                self.view.show()
            return

        self._offset += 1
        artist = utils.get_artist_name(item)
        title = utils.get_media_title(item)

        _iter = self.model.append(None)

        loading_icon = Gdk.pixbuf_get_from_surface(
            self._loadin_icon_surface, 0, 0,
            self._loading_icon_surface.get_width(),
            self._loading_icon_surface.get_height())

        self.model[_iter][0, 1, 2, 3, 4, 5, 7, 9] = [
            str(item.get_id()), '', title, artist, loading_icon, item, 0, False
        ]
        self.cache.lookup(item, self._iconWidth, self._iconHeight,
                          self._on_lookup_ready, _iter)

    @log
    def _on_lookup_ready(self, surface, _iter):
        if surface:
            pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
                                                 surface.get_width(),
                                                 surface.get_height())

            self.model[_iter][4] = pixbuf

    @log
    def _add_list_renderers(self):
        pass

    @log
    def _on_item_activated(self, widget, id, path):
        pass

    @log
    def _on_selection_mode_request(self, *args):
        self.header_bar._select_button.clicked()

    @log
    def get_selected_tracks(self, callback):
        callback([])

    def _on_list_widget_star_render(self, col, cell, model, _iter, data):
        pass

    @log
    def _set_selection(self, value, parent=None):
        count = 0
        _iter = self.model.iter_children(parent)
        while _iter is not None:
            if self.model.iter_has_child(_iter):
                count += self._set_selection(value, _iter)
            if self.model[_iter][5]:
                self.model[_iter][6] = value
                count += 1
            _iter = self.model.iter_next(_iter)
        return count

    @log
    def select_all(self):
        """Select all the available tracks."""
        count = self._set_selection(True)

        if count > 0:
            self.selection_toolbar._add_to_playlist_button.set_sensitive(True)
            self.selection_toolbar._remove_from_playlist_button.set_sensitive(
                True)

        self.update_header_from_selection(count)
        self.view.queue_draw()

    @log
    def unselect_all(self):
        """Unselects all the selected tracks."""
        self._set_selection(False)
        self.selection_toolbar._add_to_playlist_button.set_sensitive(False)
        self.selection_toolbar._remove_from_playlist_button.set_sensitive(
            False)
        self.header_bar._selection_menu_label.set_text(
            _("Click on items to select them"))
        self.queue_draw()
Ejemplo n.º 11
0
class CoverStack(GObject.GObject):
    """Provides a smooth transition between image states

    Uses a Gtk.Stack to provide an in-situ transition between an image
    state. Either between the 'loading' state versus the 'loaded' state
    or in between songs.
    """

    __gsignals__ = {'updated': (GObject.SignalFlags.RUN_FIRST, None, ())}

    _default_icon = DefaultIcon()

    @log
    def __init__(self, stack, size):
        super().__init__()

        self._size = size
        self._stack = stack
        self._stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE)
        self._scale = self._stack.get_scale_factor()
        self._handler_id = None

        self._loading_icon = self._default_icon.get(DefaultIcon.Type.LOADING,
                                                    self._size, self._scale)

        self._loading_cover = Gtk.Image.new_from_surface(self._loading_icon)

        self._cover_a = Gtk.Image()
        self._cover_b = Gtk.Image()

        self._stack.add_named(self._loading_cover, "loading")
        self._stack.add_named(self._cover_a, "A")
        self._stack.add_named(self._cover_b, "B")

        self._stack.set_visible_child_name("loading")
        self._stack.show_all()

    @log
    def update(self, media):
        """Update the stack with the given media

        Update the stack with the art retrieved from the given media.
        :param Grl.Media media: The media object
        """
        self._active_child = self._stack.get_visible_child_name()

        art = Art(self._size, media, self._scale)
        self._handler_id = art.connect('finished', self._art_retrieved)
        art.lookup()

    @log
    def _art_retrieved(self, klass):
        klass.disconnect(self._handler_id)
        if self._active_child == "B":
            self._cover_a.set_from_surface(klass.surface)
            self._stack.set_visible_child_name("A")
        else:
            self._cover_b.set_from_surface(klass.surface)
            self._stack.set_visible_child_name("B")

        self.emit('updated')
Ejemplo n.º 12
0
class CoverStack(Gtk.Stack):
    """Provides a smooth transition between image states

    Uses a Gtk.Stack to provide an in-situ transition between an image
    state. Either between the 'loading' state versus the 'loaded' state
    or in between songs.
    """

    __gtype_name__ = 'CoverStack'

    __gsignals__ = {
        'updated': (GObject.SignalFlags.RUN_FIRST, None, ())
    }

    _default_icon = DefaultIcon()

    def __repr__(self):
        return '<CoverStack>'

    @log
    def __init__(self, size=Art.Size.MEDIUM):
        """Initialize the CoverStack

        :param Art.Size size: The size of the art used for the cover
        """
        super().__init__()

        self._size = None
        self._handler_id = None

        self._loading_cover = Gtk.Image()
        self._cover_a = Gtk.Image()
        self._cover_b = Gtk.Image()

        self.add_named(self._loading_cover, "loading")
        self.add_named(self._cover_a, "A")
        self.add_named(self._cover_b, "B")

        self.props.size = size
        self.props.transition_type = Gtk.StackTransitionType.CROSSFADE
        self.props.visible_child_name = "loading"

        self.show_all()

    @GObject.Property(type=object, flags=GObject.ParamFlags.READWRITE)
    def size(self):
        """Size of the cover

        :returns: The size used
        :rtype: Art.Size
        """
        return self._size

    @size.setter
    def size(self, value):
        """Set the cover size

        :param Art.Size value: The size to use for the cover
        """
        self._size = value

        icon = self._default_icon.get(
            DefaultIcon.Type.LOADING, self.props.size, self.props.scale_factor)
        self._loading_cover.props.surface = icon

    @log
    def update(self, media):
        """Update the stack with the given media

        Update the stack with the art retrieved from the given media.
        :param Grl.Media media: The media object
        """
        self._active_child = self.props.visible_child_name

        art = Art(self.props.size, media, self.props.scale_factor)
        self._handler_id = art.connect('finished', self._art_retrieved)
        art.lookup()

    @log
    def _art_retrieved(self, klass):
        klass.disconnect(self._handler_id)
        if self._active_child == "B":
            self._cover_a.props.surface = klass.surface
            self.props.visible_child_name = "A"
        else:
            self._cover_b.props.surface = klass.surface
            self.props.visible_child_name = "B"

        self.emit('updated')
Ejemplo n.º 13
0
class CoverStack(Gtk.Stack):
    """Provides a smooth transition between image states

    Uses a Gtk.Stack to provide an in-situ transition between an image
    state. Either between the 'loading' state versus the 'loaded' state
    or in between songs.
    """

    __gtype_name__ = 'CoverStack'

    __gsignals__ = {'updated': (GObject.SignalFlags.RUN_FIRST, None, ())}

    _default_icon = DefaultIcon()

    def __repr__(self):
        return '<CoverStack>'

    @log
    def __init__(self, size=Art.Size.MEDIUM):
        """Initialize the CoverStack

        :param Art.Size size: The size of the art used for the cover
        """
        super().__init__()

        self._art = None
        self._handler_id = None
        self._size = None
        self._timeout = None

        self._loading_cover = Gtk.Image()
        self._cover_a = Gtk.Image()
        self._cover_b = Gtk.Image()

        self.add_named(self._loading_cover, "loading")
        self.add_named(self._cover_a, "A")
        self.add_named(self._cover_b, "B")

        self.props.size = size
        self.props.transition_type = Gtk.StackTransitionType.CROSSFADE
        self.props.visible_child_name = "loading"

        self.show_all()

    @GObject.Property(type=object, flags=GObject.ParamFlags.READWRITE)
    def size(self):
        """Size of the cover

        :returns: The size used
        :rtype: Art.Size
        """
        return self._size

    @size.setter
    def size(self, value):
        """Set the cover size

        :param Art.Size value: The size to use for the cover
        """
        self._size = value

        icon = self._default_icon.get(DefaultIcon.Type.LOADING,
                                      self.props.size, self.props.scale_factor)
        self._loading_cover.props.surface = icon

    @log
    def update(self, coresong):
        """Update the stack with the given CoreSong

        Update the stack with the art retrieved from the given Coresong.
        :param CoreSong coresong: The CoreSong object
        """
        if self._handler_id and self._art:
            # Remove a possible dangling 'finished' callback if update
            # is called again, but it is still looking for the previous
            # art.
            self._art.disconnect(self._handler_id)
            # Set the loading state only after a delay to make between
            # song transitions smooth if loading time is negligible.
            self._timeout = GLib.timeout_add(100, self._set_loading_child)

        self._active_child = self.props.visible_child_name

        self._art = Art(self.props.size, coresong, self.props.scale_factor)
        self._handler_id = self._art.connect('finished', self._art_retrieved)
        self._art.lookup()

    @log
    def _set_loading_child(self):
        self.props.visible_child_name = "loading"
        self._active_child = self.props.visible_child_name
        self._timeout = None

        return GLib.SOURCE_REMOVE

    @log
    def _art_retrieved(self, klass):
        if self._timeout:
            GLib.source_remove(self._timeout)
            self._timeout = None

        if self._active_child == "B":
            self._cover_a.props.surface = klass.surface
            self.props.visible_child_name = "A"
        else:
            self._cover_b.props.surface = klass.surface
            self.props.visible_child_name = "B"

        self._active_child = self.props.visible_child_name
        self._art = None

        self.emit('updated')
Ejemplo n.º 14
0
    def __init__(self,
                 name,
                 title,
                 window,
                 view_type,
                 use_sidebar=False,
                 sidebar=None):
        """Initialize
        :param name: The view name
        :param title: The view title
        :param GtkWidget window: The main window
        :param view_type: The Gtk view type
        :param use_sidebar: Whether to use sidebar
        :param sidebar: The sidebar object (Default: Gtk.Box)
        """

        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GdkPixbuf.Pixbuf, GObject.TYPE_OBJECT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT,
                                   GObject.TYPE_STRING, GObject.TYPE_INT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT)
        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT, )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self._star_handler = StarHandlerWidget(self, 9)
        self._window = window
        self._header_bar = window.toolbar
        self._selection_toolbar = window.selection_toolbar
        self._header_bar._select_button.connect('toggled',
                                                self._on_header_bar_toggled)
        self._header_bar._cancel_button.connect('clicked',
                                                self._on_cancel_button_clicked)

        self.name = name
        self.title = title

        self.add(self._grid)
        self.show_all()
        self._view.hide()

        scale = self.get_scale_factor()
        self._cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.medium)

        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self._header_bar.connect('selection-mode-changed',
                                 self._on_selection_mode_changed)
        grilo.connect('changes-pending', self._on_changes_pending)
Ejemplo n.º 15
0
class BaseView(Gtk.Stack):
    """Base Class for all view classes"""

    _now_playing_icon_name = 'media-playback-start-symbolic'
    _error_icon_name = 'dialog-error-symbolic'
    selection_mode = GObject.Property(type=bool, default=False)

    def __repr__(self):
        return '<BaseView>'

    @log
    def __init__(self,
                 name,
                 title,
                 window,
                 view_type,
                 use_sidebar=False,
                 sidebar=None):
        """Initialize
        :param name: The view name
        :param title: The view title
        :param GtkWidget window: The main window
        :param view_type: The Gtk view type
        :param use_sidebar: Whether to use sidebar
        :param sidebar: The sidebar object (Default: Gtk.Box)
        """

        Gtk.Stack.__init__(self,
                           transition_type=Gtk.StackTransitionType.CROSSFADE)
        self._grid = Gtk.Grid(orientation=Gtk.Orientation.HORIZONTAL)
        self._offset = 0
        self.model = Gtk.ListStore(GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GObject.TYPE_STRING, GObject.TYPE_STRING,
                                   GdkPixbuf.Pixbuf, GObject.TYPE_OBJECT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT,
                                   GObject.TYPE_STRING, GObject.TYPE_INT,
                                   GObject.TYPE_BOOLEAN, GObject.TYPE_INT)
        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)

        # Setup the main view
        self._setup_view(view_type)

        if use_sidebar:
            self.stack = Gtk.Stack(
                transition_type=Gtk.StackTransitionType.SLIDE_RIGHT, )
            dummy = Gtk.Frame(visible=False)
            self.stack.add_named(dummy, 'dummy')
            if sidebar:
                self.stack.add_named(sidebar, 'sidebar')
            else:
                self.stack.add_named(self._box, 'sidebar')
            self.stack.set_visible_child_name('dummy')
            self._grid.add(self.stack)
        if not use_sidebar or sidebar:
            self._grid.add(self._box)

        self._star_handler = StarHandlerWidget(self, 9)
        self._window = window
        self._header_bar = window.toolbar
        self._selection_toolbar = window.selection_toolbar
        self._header_bar._select_button.connect('toggled',
                                                self._on_header_bar_toggled)
        self._header_bar._cancel_button.connect('clicked',
                                                self._on_cancel_button_clicked)

        self.name = name
        self.title = title

        self.add(self._grid)
        self.show_all()
        self._view.hide()

        scale = self.get_scale_factor()
        self._cache = AlbumArtCache(scale)
        self._loading_icon_surface = DefaultIcon(scale).get(
            DefaultIcon.Type.loading, ArtSize.medium)

        self._init = False
        grilo.connect('ready', self._on_grilo_ready)
        self._header_bar.connect('selection-mode-changed',
                                 self._on_selection_mode_changed)
        grilo.connect('changes-pending', self._on_changes_pending)

    @log
    def _on_changes_pending(self, data=None):
        pass

    @log
    def _setup_view(self, view_type):
        """Instantiate and set up the view object"""
        self._view = Gd.MainView(shadow_type=Gtk.ShadowType.NONE)
        self._view.set_view_type(view_type)

        self._view.click_handler = self._view.connect('item-activated',
                                                      self._on_item_activated)
        self._view.connect('selection-mode-request',
                           self._on_selection_mode_request)

        self._view.bind_property('selection-mode', self, 'selection_mode',
                                 GObject.BindingFlags.BIDIRECTIONAL)

        self._view.connect('view-selection-changed',
                           self._on_view_selection_changed)

        self._box.pack_start(self._view, True, True, 0)

    @log
    def _on_header_bar_toggled(self, button):
        self.selection_mode = button.get_active()

        if self.selection_mode:
            self._header_bar.set_selection_mode(True)
            self.player.actionbar.set_visible(False)
            select_toolbar = self._selection_toolbar
            select_toolbar.actionbar.set_visible(True)
            select_toolbar._add_to_playlist_button.set_sensitive(False)
            select_toolbar._remove_from_playlist_button.set_sensitive(False)
        else:
            self._header_bar.set_selection_mode(False)
            track_playing = self.player.currentTrack is not None
            self.player.actionbar.set_visible(track_playing)
            self._selection_toolbar.actionbar.set_visible(False)
            self.unselect_all()

    @log
    def _on_cancel_button_clicked(self, button):
        self._view.set_selection_mode(False)
        self._header_bar.set_selection_mode(False)

    @log
    def _on_grilo_ready(self, data=None):
        if (self._header_bar.get_stack().get_visible_child() == self
                and not self._init):
            self._populate()
        self._header_bar.get_stack().connect('notify::visible-child',
                                             self._on_headerbar_visible)

    @log
    def _on_headerbar_visible(self, widget, param):
        if (self == widget.get_visible_child() and not self._init):
            self._populate()

    @log
    def _on_view_selection_changed(self, widget):
        if not self.selection_mode:
            return
        items = self._view.get_selection()
        self.update_header_from_selection(len(items))

    @log
    def update_header_from_selection(self, n_items):
        """Updates header during item selection."""
        select_toolbar = self._selection_toolbar
        select_toolbar._add_to_playlist_button.set_sensitive(n_items > 0)
        select_toolbar._remove_from_playlist_button.set_sensitive(n_items > 0)
        if n_items > 0:
            self._header_bar._selection_menu_label.set_text(
                ngettext("Selected {} item", "Selected {} items",
                         n_items).format(n_items))
        else:
            self._header_bar._selection_menu_label.set_text(
                _("Click on items to select them"))

    @log
    def _populate(self, data=None):
        self._init = True
        self.populate()

    @log
    def _on_selection_mode_changed(self, widget, data=None):
        pass

    @log
    def populate(self):
        pass

    @log
    def _add_item(self, source, param, item, remaining=0, data=None):
        if not item:
            if remaining == 0:
                self._view.set_model(self.model)
                self._window.pop_loading_notification()
                self._view.show()
            return
        self._offset += 1
        artist = utils.get_artist_name(item)
        title = utils.get_media_title(item)

        itr = self.model.append(None)
        loading_icon = Gdk.pixbuf_get_from_surface(
            self._loadin_icon_surface, 0, 0,
            self._loading_icon_surface.get_width(),
            self._loading_icon_surface.get_height())

        self.model[itr][0, 1, 2, 3, 4, 5, 7, 9] = [
            str(item.get_id()), '', title, artist, loading_icon, item, 0, False
        ]

    @log
    def _on_lookup_ready(self, surface, itr):
        if surface:
            pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0,
                                                 surface.get_width(),
                                                 surface.get_height())
            self.model[itr][4] = pixbuf

    @log
    def _add_list_renderers(self):
        pass

    @log
    def _on_item_activated(self, widget, id, path):
        pass

    @log
    def _on_selection_mode_request(self, *args):
        self._header_bar._select_button.clicked()

    @log
    def get_selected_songs(self, callback):
        callback([])

    @log
    def _set_selection(self, value, parent=None):
        count = 0
        itr = self.model.iter_children(parent)
        while itr != None:
            if self.model.iter_has_child(itr):
                count += self._set_selection(value, itr)
            if self.model[itr][5] != None:
                self.model[itr][6] = value
                count += 1
            itr = self.model.iter_next(itr)
        return count

    @log
    def select_all(self):
        """Select all the available songs."""
        count = self._set_selection(True)

        if count > 0:
            select_toolbar = self._selection_toolbar
            select_toolbar._add_to_playlist_button.set_sensitive(True)
            select_toolbar._remove_from_playlist_button.set_sensitive(True)

        self.update_header_from_selection(count)
        self._view.queue_draw()

    @log
    def unselect_all(self):
        """Unselects all the selected songs."""
        self._set_selection(False)
        select_toolbar = self._selection_toolbar
        select_toolbar._add_to_playlist_button.set_sensitive(False)
        select_toolbar._remove_from_playlist_button.set_sensitive(False)
        self._header_bar._selection_menu_label.set_text(
            _("Click on items to select them"))
        self.queue_draw()