コード例 #1
0
    def __init__(self, *args, **kwargs):
        '''
        Initializes the button.
        '''
        Gtk.RadioButton.__init__(self, *args, **kwargs)
        OptionsWidget.__init__(self, *args, **kwargs)

        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)
        setting.bind(gs.PluginKey.BUTTON_RELIEF, self,
            'button_relief', Gio.SettingsBindFlags.GET)

        self.connect('notify::button-relief',
            self.on_notify_button_relief)

        # initialise some variables
        self.image_display = False
        self.initialised = False

        #ensure button appearance rather than standard radio toggle
        self.set_mode(False)

        #label colours
        self._not_active_colour = None
        self._active_colour = None
コード例 #2
0
    def __init__(self, plugin, viewmgr):
        super(ArtistSortPopupController, self).__init__()

        self._viewmgr = viewmgr
        self.plugin = plugin
        # sorts dictionary
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        self.values = OrderedDict([(_('Sort by album name'), 'name_artist'),
            (_('Sort by year'), 'year_artist'),
            (_('Sort by rating'), 'rating_artist')])

        self.options = list(self.values.keys())
        
        # get the current sort key and initialise the superclass
        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        value = source_settings[gs.PluginKey.SORT_BY_ARTIST]
        
        if value not in list(self.values.values()):
            print ("here")
            value = 'name_artist'
            source_settings[gs.PluginKey.SORT_BY_ARTIST]=value

        self._spritesheet = None
        self.update_images(False)
        
        self.current_key = list(self.values.keys())[
            list(self.values.values()).index(value)]
        print (self.current_key)
コード例 #3
0
    def sort(self):

        albums = SortedCollection(key=lambda album: getattr(album, 'name'))

        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        key = source_settings[gs.PluginKey.SORT_BY_ARTIST]
        order = source_settings[gs.PluginKey.SORT_ORDER_ARTIST]

        sort_keys = {
            'name_artist': ('album_sort', 'album_sort'),
            'year_artist': ('real_year', 'calc_year_sort'),
            'rating_artist': ('rating', 'album_sort')
        }

        props = sort_keys[key]

        def key_function(album):
            keys = [getattr(album, prop) for prop in props]
            return keys

        # remember the current sort then remove the sort order
        # because sorting will only work in unsorted lists
        sortSettings = self.store.get_sort_column_id()

        self.store.set_sort_column_id(-1, Gtk.SortType.ASCENDING)

        for artist in self._iters:
            albums.clear()
            albums.key = key_function

            if 'album' in self._iters[artist] and len(
                    self._iters[artist]['album']) > 1:
                # we only need to sort an artists albums if there is more than one album

                # sort all the artists albums
                for album_iter in self._iters[artist]['album']:
                    albums.insert(self._tree_store[album_iter][
                        self.columns['artist_album']])

                if not order:
                    albums = reversed(albums)

                # now we iterate through the sorted artist albums.  Look and swap iters
                # according to where they are in the tree store

                artist_iter = self._iters[artist]['iter']
                next_iter = self._tree_store.iter_children(artist_iter)

                for album in albums:
                    if self._tree_store[next_iter][
                            self.columns['artist_album']] != album:
                        self._tree_store.swap(next_iter,
                                              self._albumiters[album]['iter'])
                        next_iter = self._albumiters[album]['iter']
                    next_iter = self._tree_store.iter_next(next_iter)

        # now we have finished sorting, reapply the sort
        if sortSettings[0]:
            self.store.set_sort_column_id(*sortSettings)
コード例 #4
0
    def __init__(self, plugin, album_model):
        super(SortPopupController, self).__init__()

        self._album_model = album_model
        self.plugin = plugin
        # sorts dictionary
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        self.values = OrderedDict([(_('Sort by album name'), 'name'),
                                   (_('Sort by album artist'), 'artist'),
                                   (_('Sort by year'), 'year'),
                                   (_('Sort by rating'), 'rating')])

        self.options = self.values.keys()

        # get the current sort key and initialise the superclass
        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        value = source_settings[gs.PluginKey.SORT_BY]

        self._spritesheet = None
        self.update_images(False)

        self.current_key = self.values.keys()[self.values.values().index(
            value)]
コード例 #5
0
    def initialise(self, plugin, shell, callback):
        '''
        extend the default initialise function
        because we need to also resize the picture
        associated with the sort button as well as find the
        saved sort order
        '''
        if self.is_initialised:
            return

        self._spritesheet = ConfiguredSpriteSheet(plugin, 'sort')

        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        source_settings.bind(gs.PluginKey.SORT_BY,
            self, 'sort_by', Gio.SettingsBindFlags.DEFAULT)

        super(SortPopupButton, self).initialise(shell, callback,
            self.sorts[self.sort_by])

        # create the pop up menu
        for key, text in sorted(self.sorts.iteritems()):
            self.add_menuitem(text, self._sort_changed, key)

        self._sort_changed(None, self.sort_by)
コード例 #6
0
    def display_columns(self):

        self.col_map = OrderedDict([
            ('track-number', RB.EntryViewColumn.TRACK_NUMBER),
            ('title', RB.EntryViewColumn.TITLE),
            ('genre', RB.EntryViewColumn.GENRE),
            ('artist', RB.EntryViewColumn.ARTIST),
            ('album', RB.EntryViewColumn.ALBUM),
            ('composer', RB.EntryViewColumn.COMPOSER),
            ('date', RB.EntryViewColumn.YEAR),
            ('duration', RB.EntryViewColumn.DURATION),
            ('bitrate', RB.EntryViewColumn.QUALITY),
            ('play-count', RB.EntryViewColumn.PLAY_COUNT),
            ('beats-per-minute', RB.EntryViewColumn.BPM),
            ('comment', RB.EntryViewColumn.COMMENT),
            ('location', RB.EntryViewColumn.LOCATION),
            ('rating', RB.EntryViewColumn.RATING),
            ('last-played', RB.EntryViewColumn.LAST_PLAYED),
            ('first-seen', RB.EntryViewColumn.FIRST_SEEN)
        ])

        for entry in self.col_map:
            visible = True if entry == 'title' else False
            self.append_column(self.col_map[entry], visible)

        # connect the visible-columns global setting to update our entryview
        gs = GSetting()
        rhythm_settings = gs.get_setting(gs.Path.RBSOURCE)
        rhythm_settings.connect('changed::visible-columns',
                                self.on_visible_columns_changed)
        self.on_visible_columns_changed(rhythm_settings, 'visible-columns')
コード例 #7
0
    def display_columns(self):

        self.col_map = OrderedDict([
            ('track-number', RB.EntryViewColumn.TRACK_NUMBER),
            ('title', RB.EntryViewColumn.TITLE),
            ('genre', RB.EntryViewColumn.GENRE),
            ('artist', RB.EntryViewColumn.ARTIST),
            ('album', RB.EntryViewColumn.ALBUM),
            ('composer', RB.EntryViewColumn.COMPOSER),
            ('date', RB.EntryViewColumn.YEAR),
            ('duration', RB.EntryViewColumn.DURATION),
            ('bitrate', RB.EntryViewColumn.QUALITY),
            ('play-count', RB.EntryViewColumn.PLAY_COUNT),
            ('beats-per-minute', RB.EntryViewColumn.BPM),
            ('comment', RB.EntryViewColumn.COMMENT),
            ('location', RB.EntryViewColumn.LOCATION),
            ('rating', RB.EntryViewColumn.RATING),
            ('last-played', RB.EntryViewColumn.LAST_PLAYED),
            ('first-seen', RB.EntryViewColumn.FIRST_SEEN)
        ])

        for entry in self.col_map:
            visible = True if entry == 'title' else False
            self.append_column(self.col_map[entry], visible)

        # connect the visible-columns global setting to update our entryview
        gs = GSetting()
        rhythm_settings = gs.get_setting(gs.Path.RBSOURCE)
        rhythm_settings.connect('changed::visible-columns',
                                self.on_visible_columns_changed)
        self.on_visible_columns_changed(rhythm_settings, 'visible-columns')
コード例 #8
0
    def __init__(self, plugin, viewmgr):
        super(SortPopupController, self).__init__()

        self._viewmgr = viewmgr
        self.plugin = plugin
        # sorts dictionary
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        self.values = OrderedDict(
            [
                (_("Sort by album name"), "name"),
                (_("Sort by album artist"), "artist"),
                (_("Sort by year"), "year"),
                (_("Sort by rating"), "rating"),
            ]
        )

        self.options = list(self.values.keys())

        # get the current sort key and initialise the superclass
        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        value = source_settings[gs.PluginKey.SORT_BY]

        self._spritesheet = None
        self.update_images(False)

        self.current_key = list(self.values.keys())[list(self.values.values()).index(value)]
コード例 #9
0
    def on_notify_view_name(self, *args):
        if self._lastview and self.view_name != self._lastview:

            selected = self._views[self._lastview].get_selected_objects()
            current_album = None
            if len(selected) > 0:
                current_album = self._views[self._lastview].get_selected_objects()[0]
                
            self.window.remove(self._views[self._lastview].view)
            self.window.add(self._views[self.view_name].view)
            self.window.show_all()
            self.click_count = 0
            
            self._views[self._lastview].panedposition = self.source.paned.get_expansion_status()
            self._views[self.view_name].switch_to_view(self.source, current_album)
            self.source.paned.expand(self._views[self.view_name].panedposition)
            
            self._lastview = self.view_name
            self.current_view.set_popup_menu(self.source.popup_menu)
            self.source.album_manager.current_view = self.current_view
            
            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            setting[gs.PluginKey.VIEW_NAME] = self.view_name

        self.emit('new-view')
コード例 #10
0
    def __init__(self, plugin, viewmgr):
        super(ArtistSortPopupController, self).__init__()

        self._viewmgr = viewmgr
        self.plugin = plugin
        # sorts dictionary
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        self.values = OrderedDict([(_('Sort by album name'), 'name_artist'),
                                   (_('Sort by year'), 'year_artist'),
                                   (_('Sort by rating'), 'rating_artist')])

        self.options = list(self.values.keys())

        # get the current sort key and initialise the superclass
        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        value = source_settings[gs.PluginKey.SORT_BY_ARTIST]

        if value not in list(self.values.values()):
            print("here")
            value = 'name_artist'
            source_settings[gs.PluginKey.SORT_BY_ARTIST] = value

        self._spritesheet = None
        self.update_images(False)

        self.current_key = list(self.values.keys())[
            list(self.values.values()).index(value)]
        print(self.current_key)
コード例 #11
0
    def __init__(self, *args, **kwargs):
        '''
        Initializes the button.
        '''
        Gtk.RadioButton.__init__(self, *args, **kwargs)
        OptionsWidget.__init__(self, *args, **kwargs)

        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)
        setting.bind(gs.PluginKey.BUTTON_RELIEF, self,
                     'button_relief', Gio.SettingsBindFlags.GET)

        self.connect('notify::button-relief',
                     self.on_notify_button_relief)

        # initialise some variables
        self.image_display = False
        self.initialised = False

        # ensure button appearance rather than standard radio toggle
        self.set_mode(False)

        #label colours
        self._not_active_colour = None
        self._active_colour = None
コード例 #12
0
    def __init__(self, plugin, album_model):
        super(SortPopupController, self).__init__()

        self._album_model = album_model
        self.plugin = plugin
        # sorts dictionary
        cl = CoverLocale()
        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        self.values = OrderedDict([(_('Sort by album name'), 'name'),
            (_('Sort by album artist'), 'artist'),
            (_('Sort by year'), 'year'),
            (_('Sort by rating'), 'rating')])

        self.options = self.values.keys()
        
        # get the current sort key and initialise the superclass
        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        value = source_settings[gs.PluginKey.SORT_BY]

        self._spritesheet = None
        self.update_images(False)
        
        self.current_key = self.values.keys()[
            self.values.values().index(value)]
コード例 #13
0
 def _connect_properties(self):
     gs = GSetting()
     setting = gs.get_setting(gs.Path.PLUGIN)
     setting.bind(
         gs.PluginKey.USE_FAVOURITES,
         self,
         'favourites',
         Gio.SettingsBindFlags.DEFAULT)
コード例 #14
0
    def do_action(self):
        sort = self.values[self.current_key]

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)
        settings[gs.PluginKey.SORT_BY] = sort

        self._album_model.sort(sort)
コード例 #15
0
    def do_action(self):
        sort = self.values[self.current_key]

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)
        settings[gs.PluginKey.SORT_BY] = sort

        self._album_model.sort(sort)
コード例 #16
0
    def __init__(self, *args, **kwargs):
        super(EnhancedButton, self).__init__(*args, **kwargs)

        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)
        setting.bind(gs.PluginKey.BUTTON_RELIEF, self, "button_relief", Gio.SettingsBindFlags.GET)

        self.connect("notify::button-relief", self.on_notify_button_relief)
コード例 #17
0
    def do_action(self):
        sort = self.values[self.current_key]

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)
        settings[gs.PluginKey.SORT_BY_ARTIST] = sort

        self._viewmgr.current_view.get_default_manager().emit('sort', "artist")
コード例 #18
0
    def do_action(self):
        sort = self.values[self.current_key]

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)
        settings[gs.PluginKey.SORT_BY_ARTIST] = sort

        self._viewmgr.current_view.get_default_manager().emit('sort', "artist")
コード例 #19
0
    def __init__(self, *args, **kwargs):
        super(EnhancedButton, self).__init__(*args, **kwargs)

        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)
        setting.bind(gs.PluginKey.BUTTON_RELIEF, self, 'button_relief',
                     Gio.SettingsBindFlags.GET)

        self.connect('notify::button-relief', self.on_notify_button_relief)
コード例 #20
0
    def play_random_album_menu_item_callback(self, favourites=False):
        print('''CoverArtBrowser DEBUG - play_random_album_menu_item_callback''')
        query_model = RB.RhythmDBQueryModel.new_empty(self.shell.props.db)

        num_albums = len(self.album_manager.model.store)

        #random_list = []
        selected_albums = []

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)        
        to_queue = settings[gs.PluginKey.RANDOM]

        if num_albums <= to_queue:
            dialog = Gtk.MessageDialog(None,
                    Gtk.DialogFlags.MODAL,
                    Gtk.MessageType.INFO,
                    Gtk.ButtonsType.OK,
                    _("The number of albums to randomly play is less than that displayed."))

            dialog.run()
            dialog.destroy()
            return
            
        album_col = self.album_manager.model.columns['album']

        chosen = {}

        # now loop through finding unique random albums
        # i.e. ensure we dont queue the same album twice
        
        for loop in range(0, to_queue):
            while True:
                pos = random.randint(0, num_albums - 1)
                if pos not in chosen:
                    chosen[pos] = None
                    selected_albums.append(self.album_manager.model.store[pos][album_col])
                    break

        threshold = self.rating_threshold if favourites else 0

        for album in selected_albums:
            # Retrieve and sort the entries of the album
            tracks = album.get_tracks(threshold)

            # Add the songs to the play queue
            for track in tracks:
                query_model.add_entry(track.entry, -1)

        self.props.query_model = query_model

        # Start the music
        player = self.shell.props.shell_player

        player.play_entry(query_model[0][0], self)

        print("CoverArtBrowser DEBUG - end play_selected_album")
コード例 #21
0
    def sort(self):

        albums = SortedCollection(key=lambda album: getattr(album, 'name'))

        gs = GSetting()
        source_settings = gs.get_setting(gs.Path.PLUGIN)
        key = source_settings[gs.PluginKey.SORT_BY_ARTIST]
        order = source_settings[gs.PluginKey.SORT_ORDER_ARTIST]

        sort_keys = {
            'name_artist': ('album_sort', 'album_sort'),
            'year_artist': ('real_year', 'calc_year_sort'),
            'rating_artist': ('rating', 'album_sort')
        }

        props = sort_keys[key]

        def key_function(album):
            keys = [getattr(album, prop) for prop in props]
            return keys

        # remember the current sort then remove the sort order
        # because sorting will only work in unsorted lists
        sortSettings = self.store.get_sort_column_id()

        self.store.set_sort_column_id(-1, Gtk.SortType.ASCENDING)

        for artist in self._iters:
            albums.clear()
            albums.key = key_function

            if 'album' in self._iters[artist] and len(self._iters[artist]['album']) > 1:
                # we only need to sort an artists albums if there is more than one album

                # sort all the artists albums
                for album_iter in self._iters[artist]['album']:
                    albums.insert(self._tree_store[album_iter][self.columns['artist_album']])

                if not order:
                    albums = reversed(albums)

                # now we iterate through the sorted artist albums.  Look and swap iters
                # according to where they are in the tree store

                artist_iter = self._iters[artist]['iter']
                next_iter = self._tree_store.iter_children(artist_iter)

                for album in albums:
                    if self._tree_store[next_iter][self.columns['artist_album']] != album:
                        self._tree_store.swap(next_iter, self._albumiters[album]['iter'])
                        next_iter = self._albumiters[album]['iter']
                    next_iter = self._tree_store.iter_next(next_iter)

        # now we have finished sorting, reapply the sort
        if sortSettings[0]:
            self.store.set_sort_column_id(*sortSettings)
コード例 #22
0
    def load_complete(self, *args, **kwargs):
        '''
        Called by Rhythmbox when it has completed loading all data
        Used to automatically switch to the browser if the user
        has set in the preferences
        '''
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        if setting[gs.PluginKey.AUTOSTART]:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                self.source)
コード例 #23
0
    def load_complete(self, *args, **kwargs):
        '''
        Called by Rhythmbox when it has completed loading all data
        Used to automatically switch to the browser if the user
        has set in the preferences
        '''
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        if setting[gs.PluginKey.AUTOSTART]:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.source)
コード例 #24
0
    def load_complete(self, *args, **kwargs):
        '''
        Called by Rhythmbox when it has completed loading all data
        Used to automatically switch to the browser if the user
        has set in the preferences
        '''

        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        if setting[gs.PluginKey.AUTOSTART]:
            self._externalmenu.autostart_source()
コード例 #25
0
    def load_complete(self, *args, **kwargs):
        '''
        Called by Rhythmbox when it has completed loading all data
        Used to automatically switch to the browser if the user
        has set in the preferences
        '''
        
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        if setting[gs.PluginKey.AUTOSTART]:
            self._externalmenu.autostart_source()
コード例 #26
0
    def _connect_properties(self):
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
                     Gio.SettingsBindFlags.GET)
コード例 #27
0
    def _connect_properties(self):
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
                     Gio.SettingsBindFlags.GET)
コード例 #28
0
 def view_change_cb(self, action, current):
     '''
     Called when the view state on a page is changed. Sets the new 
     state.
     '''
     action.set_state(current)
     view_name = self._views.get_view_name_for_action(current)
     if view_name != ListView.name:
         gs = GSetting()
         setting = gs.get_setting(gs.Path.PLUGIN)
         setting[gs.PluginKey.VIEW_NAME] = view_name
         GLib.idle_add(self.shell.props.display_page_tree.select,
                 self.source)
コード例 #29
0
 def _connect_properties(self):
     gs = GSetting()
     setting = gs.get_setting(gs.Path.PLUGIN)
     setting.bind(
         gs.PluginKey.USE_FAVOURITES,
         self,
         'favourites',
         Gio.SettingsBindFlags.DEFAULT)
     setting.bind(
         gs.PluginKey.FOLLOWING,
         self,
         'follow',
         Gio.SettingsBindFlags.DEFAULT)
コード例 #30
0
    class _impl(GObject.Object):
        """ Implementation of the singleton interface """
        # properties
        theme = GObject.property(type=str, default="standard")

        # signals
        '''
        changed = signal emitted when a theme has changed
        '''
        __gsignals__ = {
            'theme_changed': (GObject.SIGNAL_RUN_LAST, None, ())
        }
        # below public variables and methods that can be called for Theme
        def __init__(self, plugin):
            '''
            Initializes the singleton interface, assigning all the constants
            used to access the plugin's settings.
            '''
            super(Theme._impl, self).__init__()

            self.plugin = plugin
            popups = rb.find_plugin_file(plugin, 'img/popups.xml')
            root = ET.parse(open(popups)).getroot()

            base = 'theme/theme'
            self.themes = []

            for elem in root.xpath(base):
                self.themes.append(elem.attrib['folder_name'])

            self.gs = GSetting()
            self.setting = self.gs.get_setting(self.gs.Path.PLUGIN)

            # connect properties and signals
            self._connect_properties()
            self._connect_signals()

        @property
        def current(self):
            return self.setting[self.gs.PluginKey.THEME]

        def _connect_properties(self):
            self.setting.bind(self.gs.PluginKey.THEME, self,
                              'theme', Gio.SettingsBindFlags.GET)

        def _connect_signals(self):
            self.connect('notify::theme', self._on_theme_changed,
                         None)

        def _on_theme_changed(self, *args):
            self.emit('theme_changed')
コード例 #31
0
class SortOrderToggleController(OptionsController):

    toolbar_type = "album"

    def __init__(self, plugin, viewmgr):
        super(SortOrderToggleController, self).__init__()

        self._viewmgr = viewmgr
        self.plugin = plugin

        # options
        self.values = OrderedDict([(_('Sort in descending order'), False),
                                   (_('Sort in ascending order'), True)])
        self.options = list(self.values.keys())

        self._images = []

        # set the current key
        self.gs = GSetting()
        self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
        self.key = self.get_key()
        sort_order = self.settings[self.key]
        self.current_key = list(self.values.keys())[list(
            self.values.values()).index(sort_order)]
        self.update_images(False)

    def get_key(self):
        return self.gs.PluginKey.SORT_ORDER

    def update_images(self, *args):
        # initialize images
        if len(self._images) > 0:
            del self._images[:]

        self._images.append(
            self.create_button_image(self.plugin, None, 'arrow_down.png'))
        self._images.append(
            self.create_button_image(self.plugin, None, 'arrow_up.png'))

        if args[-1]:
            self.update_image = True

    def do_action(self):
        sort_order = self.values[self.current_key]
        self.settings[self.key] = sort_order
        self._viewmgr.current_view.get_default_manager().emit(
            'sort', self.toolbar_type)

    def get_current_image(self):
        return self._images[self.get_current_key_index()]
コード例 #32
0
    class _impl(GObject.Object):
        """ Implementation of the singleton interface """
        # properties
        theme = GObject.property(type=str, default="standard")

        # signals
        '''
        changed = signal emitted when a theme has changed
        '''
        __gsignals__ = {'theme_changed': (GObject.SIGNAL_RUN_LAST, None, ())}

        # below public variables and methods that can be called for Theme
        def __init__(self, plugin):
            '''
            Initializes the singleton interface, assigning all the constants
            used to access the plugin's settings.
            '''
            super(Theme._impl, self).__init__()

            self.plugin = plugin
            popups = rb.find_plugin_file(plugin, 'img/popups.xml')
            root = ET.parse(open(popups)).getroot()

            base = 'theme/theme'
            self.themes = []

            for elem in root.xpath(base):
                self.themes.append(elem.attrib['folder_name'])

            self.gs = GSetting()
            self.setting = self.gs.get_setting(self.gs.Path.PLUGIN)

            # connect properties and signals
            self._connect_properties()
            self._connect_signals()

        @property
        def current(self):
            return self.setting[self.gs.PluginKey.THEME]

        def _connect_properties(self):
            self.setting.bind(self.gs.PluginKey.THEME, self, 'theme',
                              Gio.SettingsBindFlags.GET)

        def _connect_signals(self):
            self.connect('notify::theme', self._on_theme_changed, None)

        def _on_theme_changed(self, *args):
            self.emit('theme_changed')
コード例 #33
0
class SortOrderToggleController(OptionsController):

    toolbar_type = "album"
    
    def __init__(self, plugin, viewmgr):
        super(SortOrderToggleController, self).__init__()

        self._viewmgr = viewmgr
        self.plugin = plugin
        
        # options
        self.values = OrderedDict([(_('Sort in descending order'), False),
            (_('Sort in ascending order'), True)])
        self.options = list(self.values.keys())

        self._images = []
        
        # set the current key
        self.gs = GSetting()
        self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
        self.key = self.get_key()
        sort_order = self.settings[self.key]
        self.current_key = list(self.values.keys())[
            list(self.values.values()).index(sort_order)]
        self.update_images(False)
        
    def get_key(self):
        return self.gs.PluginKey.SORT_ORDER
        
    def update_images(self, *args):
        # initialize images
        if len(self._images) > 0:
            del self._images[:]
                        
        self._images.append(self.create_button_image( self.plugin,
            None, 'arrow_down.png'))
        self._images.append(self.create_button_image( self.plugin,
            None, 'arrow_up.png'))

        if args[-1]:
            self.update_image = True
            
    def do_action(self):
        sort_order = self.values[self.current_key]
        self.settings[self.key] = sort_order
        self._viewmgr.current_view.get_default_manager().emit('sort', self.toolbar_type)
        
    def get_current_image(self):
        return self._images[self.get_current_key_index()]
コード例 #34
0
    def _sort_changed(self, menu, sort):
        '''
        called when sort popup menu item chosen
        '''
        if not menu or menu.get_active():
            self.set_popup_value(self.sorts[sort])
            #self.sort_by = sort
            print sort
            gs = GSetting()
            settings = gs.get_setting(gs.Path.PLUGIN)
            settings[gs.PluginKey.SORT_BY] = sort

            self.resize_button_image(self._spritesheet[sort])

            self.callback(sort)
コード例 #35
0
    def album_art_requested(self, store, key, last_time):
        searches = []
        
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)
        
        if setting[gs.PluginKey.EMBEDDED_SEARCH]:
            searches.append(CoverAlbumSearch())
        if setting[gs.PluginKey.DISCOGS_SEARCH]:
            searches.append(DiscogsSearch())

        print "about to search"
        s = CoverSearch(store, key, last_time, searches)
        print "finished about to return"
        return s.next_search()
コード例 #36
0
    def on_notify_view_name(self, *args):
        if self._lastview and self.view_name != self._lastview:
            selected = self._views[self._lastview].get_selected_objects()
            current_album = None
            if len(selected) > 0:
                current_album = self._views[
                    self._lastview].get_selected_objects()[0]

            if self._views[self.view_name].use_plugin_window:
                child = self.window.get_child()

                if child:
                    self.window.remove(child)
                self.window.add(self._views[self.view_name].view)
                self.window.show_all()
                self.click_count = 0

                self._views[
                    self.
                    _lastview].panedposition = self.source.paned.get_expansion_status(
                    )

            self._views[self.view_name].switch_to_view(self.source,
                                                       current_album)
            self._views[self.view_name].emit('update-toolbar')
            self._views[self.view_name].get_default_manager().emit(
                'sort', None)

            if self._views[self.view_name].use_plugin_window:
                self.source.paned.expand(
                    self._views[self.view_name].panedposition)

            self.current_view.set_popup_menu(self.source.popup_menu)
            self.source.album_manager.current_view = self.current_view

            if self._views[self.view_name].use_plugin_window:
                # we only ever save plugin views not external views
                saved_view = self.view_name
            else:
                saved_view = self._lastview

            self._lastview = self.view_name

            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            setting[gs.PluginKey.VIEW_NAME] = saved_view

        self.emit('new-view', self.view_name)
コード例 #37
0
class SortOrderToggleController(OptionsController):

    def __init__(self, plugin, album_model):
        super(SortOrderToggleController, self).__init__()

        self._album_model = album_model
        self.plugin = plugin

        # options
        self.values = OrderedDict([(_('Sort in descending order'), False),
            (_('Sort in ascending order'), True)])
        self.options = self.values.keys()

        self._images = []
        
        # set the current key
        self.gs = GSetting()
        self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
        sort_order = self.settings[self.gs.PluginKey.SORT_ORDER]
        self.current_key = self.values.keys()[
            self.values.values().index(sort_order)]
        self.update_images(False)
        
    def update_images(self, *args):
        # initialize images
        if len(self._images) > 0:
            del self._images[:]
                        
        self._images.append(self.create_button_image( self.plugin,
            None, 'arrow_down.png'))
        self._images.append(self.create_button_image( self.plugin,
            None, 'arrow_up.png'))

        if args[-1]:
            self.update_image = True
            
    def do_action(self):
        sort_order = self.values[self.current_key]

        if not sort_order or\
            sort_order != self.settings[self.gs.PluginKey.SORT_ORDER]:
            self._album_model.sort(reverse=True)

        self.settings[self.gs.PluginKey.SORT_ORDER] = sort_order

    def get_current_image(self):
        return self._images[self.get_current_key_index()]
コード例 #38
0
 def _connect_properties(self):
     gs = GSetting()
     settings = gs.get_setting(gs.Path.PLUGIN)
     settings.bind(gs.PluginKey.FLOW_APPEARANCE, self,
         'flow_appearance', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self,
         'flow_hide', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_SCALE, self,
         'flow_scale', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self,
         'flow_automatic', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_BACKGROUND_COLOUR, self,
         'flow_background', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_WIDTH, self,
         'flow_width', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_MAX, self,
         'flow_max', Gio.SettingsBindFlags.GET)
コード例 #39
0
class SortOrderToggleController(OptionsController):
    def __init__(self, plugin, album_model):
        super(SortOrderToggleController, self).__init__()

        self._album_model = album_model
        self.plugin = plugin

        # options
        self.values = OrderedDict([(_('Sort in descending order'), False),
                                   (_('Sort in ascending order'), True)])
        self.options = self.values.keys()

        self._images = []

        # set the current key
        self.gs = GSetting()
        self.settings = self.gs.get_setting(self.gs.Path.PLUGIN)
        sort_order = self.settings[self.gs.PluginKey.SORT_ORDER]
        self.current_key = self.values.keys()[self.values.values().index(
            sort_order)]
        self.update_images(False)

    def update_images(self, *args):
        # initialize images
        if len(self._images) > 0:
            del self._images[:]

        self._images.append(
            self.create_button_image(self.plugin, None, 'arrow_down.png'))
        self._images.append(
            self.create_button_image(self.plugin, None, 'arrow_up.png'))

        if args[-1]:
            self.update_image = True

    def do_action(self):
        sort_order = self.values[self.current_key]

        if not sort_order or\
            sort_order != self.settings[self.gs.PluginKey.SORT_ORDER]:
            self._album_model.sort(reverse=True)

        self.settings[self.gs.PluginKey.SORT_ORDER] = sort_order

    def get_current_image(self):
        return self._images[self.get_current_key_index()]
コード例 #40
0
 def _connect_properties(self):
     gs = GSetting()
     settings = gs.get_setting(gs.Path.PLUGIN)
     settings.bind(gs.PluginKey.FLOW_APPEARANCE, self,
         'flow_appearance', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_HIDE_CAPTION, self,
         'flow_hide', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_SCALE, self,
         'flow_scale', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_AUTOMATIC, self,
         'flow_automatic', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_BACKGROUND_COLOUR, self,
         'flow_background', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_WIDTH, self,
         'flow_width', Gio.SettingsBindFlags.GET)
     settings.bind(gs.PluginKey.FLOW_MAX, self,
         'flow_max', Gio.SettingsBindFlags.GET)
コード例 #41
0
    def __init__(self, plugin):
        super(ExternalPluginMenu, self).__init__()

        self.plugin = plugin
        self.shell = plugin.shell
        self.source = plugin.source
        self.app_id = None
        self.locations = [
            'library-toolbar', 'queue-toolbar', 'playsource-toolbar'
        ]

        from coverart_browser_source import Views

        self._views = Views(self.shell)

        self._use_standard_control = True
        self.plugin.using_alternative_toolbar = hasattr(
            self.shell, 'alternative_toolbar')
        if self.plugin.using_alternative_toolbar:
            from alttoolbar_type import AltToolbarHeaderBar
            self.plugin.using_headerbar = isinstance(
                self.shell.alternative_toolbar.toolbar_type,
                AltToolbarHeaderBar)

        if self.plugin.using_headerbar:
            self._use_standard_control = False

            # register with headerbar to complete the setup for coverart-browser
            print("registering")
            self.shell.alternative_toolbar.toolbar_type.setup_completed_async(
                self._headerbar_toolbar_completed)

        if self._use_standard_control:
            # ... otherwise just use the standard menubutton approach
            self.source.props.visibility = True  # make the source visible
            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
                         Gio.SettingsBindFlags.GET)

            self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
            self.shell.props.display_page_tree.connect("selected",
                                                       self.on_page_change)

            self._create_menu()
コード例 #42
0
    def _connect_properties(self):
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.ADD_SHADOW, self, 'add-shadow',
                     Gio.SettingsBindFlags.GET)

        setting.bind(gs.PluginKey.TEXT_ALIGNMENT, self, 'text-alignment',
                     Gio.SettingsBindFlags.GET)
コード例 #43
0
 def on_notify_view_name(self, *args):
     if self._lastview and self.view_name != self._lastview:
         selected = self._views[self._lastview].get_selected_objects()
         current_album = None
         if len(selected) > 0:
             current_album = self._views[self._lastview].get_selected_objects()[0]
             
         if self._views[self.view_name].use_plugin_window:
             child = self.window.get_child()
             
             if child:
                 self.window.remove(child)
             self.window.add(self._views[self.view_name].view)
             self.window.show_all()
             self.click_count = 0
         
             self._views[self._lastview].panedposition = self.source.paned.get_expansion_status()
         
         self._views[self.view_name].switch_to_view(self.source, current_album)
         self._views[self.view_name].emit('update-toolbar')
         self._views[self.view_name].get_default_manager().emit('sort', None)
         
         if self._views[self.view_name].use_plugin_window:
             self.source.paned.expand(self._views[self.view_name].panedposition)
         
         self.current_view.set_popup_menu(self.source.popup_menu)
         self.source.album_manager.current_view = self.current_view
         
         if self._views[self.view_name].use_plugin_window:
             # we only ever save plugin views not external views
             saved_view = self.view_name
         else:
             saved_view = self._lastview
         
         self._lastview = self.view_name
             
         gs = GSetting()
         setting = gs.get_setting(gs.Path.PLUGIN)
         setting[gs.PluginKey.VIEW_NAME] = saved_view
         
     self.emit('new-view', self.view_name)
コード例 #44
0
    def __init__(self, plugin):
        super(ExternalPluginMenu, self).__init__()

        self.plugin = plugin
        self.shell = plugin.shell
        self.source = plugin.source
        self.app_id = None
        self.locations = ['library-toolbar', 'queue-toolbar', 'playsource-toolbar']
        
        from coverart_browser_source import Views

        self._views = Views(self.shell)

        self._use_standard_control = True
        self.plugin.using_alternative_toolbar = hasattr(self.shell, 'alternative_toolbar')
        if self.plugin.using_alternative_toolbar:
            from alttoolbar_type import AltToolbarHeaderBar
            self.plugin.using_headerbar = isinstance(self.shell.alternative_toolbar.toolbar_type, AltToolbarHeaderBar)

        if self.plugin.using_headerbar:
            self._use_standard_control = False
    
            # register with headerbar to complete the setup for coverart-browser
            print ("registering")
            self.shell.alternative_toolbar.toolbar_type.setup_completed_async(self._headerbar_toolbar_completed)
                    
        if self._use_standard_control:
            # ... otherwise just use the standard menubutton approach
            self.source.props.visibility = True # make the source visible
            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
                         Gio.SettingsBindFlags.GET)
                         
            self.connect('notify::toolbar-pos', self._on_notify_toolbar_pos)
            self.shell.props.display_page_tree.connect(
                "selected", self.on_page_change
            )
            
            self._create_menu()
コード例 #45
0
    def _select_view(self, view_name):
        '''
          with the view_name decide which view to be displayed
          or if view_name is None then use the last remembered view_name
          
          return view_name
        '''

        if not self.shell.props.display_page_tree:
            return

        print("_select_view")
        print(view_name)
        if view_name != ListView.name and \
                        view_name != QueueView.name and \
                        view_name != PlaySourceView.name:
            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            if view_name:
                setting[gs.PluginKey.VIEW_NAME] = view_name
            else:
                view_name = setting[gs.PluginKey.VIEW_NAME]
            player = self.shell.props.shell_player
            player.set_selected_source(self.source)  #.playlist_source)

            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.source)
        elif view_name == ListView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.shell.props.library_source)
        elif view_name == QueueView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.shell.props.queue_source)
        elif view_name == PlaySourceView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.plugin.playlist_source)

        return view_name
コード例 #46
0
    def _select_view(self, view_name):
        '''
          with the view_name decide which view to be displayed
          or if view_name is None then use the last remembered view_name
          
          return view_name
        '''
        
        if not self.shell.props.display_page_tree:
            return
            
        print ("_select_view")
        print (view_name)
        if view_name != ListView.name and \
                        view_name != QueueView.name and \
                        view_name != PlaySourceView.name:
            gs = GSetting()
            setting = gs.get_setting(gs.Path.PLUGIN)
            if view_name:
                setting[gs.PluginKey.VIEW_NAME] = view_name
            else:
                view_name = setting[gs.PluginKey.VIEW_NAME]
            player = self.shell.props.shell_player
            player.set_selected_source(self.source) #.playlist_source)

            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.source)
        elif view_name == ListView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.shell.props.library_source)
        elif view_name == QueueView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.shell.props.queue_source)
        elif view_name == PlaySourceView.name:
            GLib.idle_add(self.shell.props.display_page_tree.select,
                          self.plugin.playlist_source)

        return view_name
コード例 #47
0
 def _connect_properties(self):
     gs = GSetting()
     setting = gs.get_setting(gs.Path.PLUGIN)
     setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
                  Gio.SettingsBindFlags.GET)
コード例 #48
0
class EntryViewPane(object):
    '''
        encapulates all of the Track Pane objects
    '''
    def __init__(self, shell, plugin, source, entry_view_grid, viewmgr):
        self.gs = GSetting()

        self.entry_view_grid = entry_view_grid
        self.shell = shell
        self.viewmgr = viewmgr
        self.plugin = plugin
        self.source = source

        # setup entry-view objects and widgets
        self.stack = Gtk.Stack()
        self.stack.set_transition_type(
            Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        self.stack.set_transition_duration(750)

        # create entry views. Don't allow to reorder until the load is finished
        self.entry_view_compact = CoverArtCompactEntryView(
            self.shell, self.source)
        self.entry_view_full = CoverArtEntryView(self.shell, self.source)
        self.entry_view = self.entry_view_compact
        self.shell.props.library_source.get_entry_view().set_columns_clickable(
            False)

        self.entry_view_results = ResultsGrid()
        self.entry_view_results.initialise(self.entry_view_grid, source)

        self.stack.add_titled(self.entry_view_results, "notebook_tracks",
                              _("Tracks"))
        self.entry_view_grid.attach(self.stack, 0, 0, 3, 1)

    def setup_source(self):

        colour = self.viewmgr.get_selection_colour()
        self.cover_search_pane = CoverSearchPane(self.plugin, colour)

        self.stack.add_titled(self.cover_search_pane, "notebook_covers",
                              _("Covers"))

        # define entry-view toolbar
        self.stars = ReactiveStar()
        self.stars.set_rating(0)
        self.stars.connect('changed', self.rating_changed_callback)
        self.stars.props.valign = Gtk.Align.CENTER
        self.entry_view_grid.attach(self.stars, 1, 1, 1, 1)
        stack_switcher = Gtk.StackSwitcher()
        stack_switcher.set_stack(self.stack)
        self.entry_view_grid.attach(stack_switcher, 0, 1, 1, 1)
        viewtoggle = PixbufButton()
        viewtoggle.set_image(create_button_image(self.plugin, "entryview.png"))
        self.viewtoggle_id = None

        setting = self.gs.get_setting(self.gs.Path.PLUGIN)
        viewtoggle.set_active(not setting[self.gs.PluginKey.ENTRY_VIEW_MODE])
        self.entry_view_toggled(viewtoggle, True)
        viewtoggle.connect('toggled', self.entry_view_toggled)

        smallwindowbutton = PixbufButton()
        smallwindowbutton.set_image(
            create_button_image(self.plugin, "view-restore.png"))
        smallwindowbutton.connect('toggled', self.smallwindowbutton_callback)

        self.smallwindowext = ExternalPlugin()
        self.smallwindowext.appendattribute('plugin_name', 'smallwindow')
        self.smallwindowext.appendattribute('action_group_name',
                                            'small window actions')
        self.smallwindowext.appendattribute('action_name', 'SmallWindow')
        self.smallwindowext.appendattribute('action_type', 'app')

        whatsplayingtoggle = PixbufButton()
        whatsplayingtoggle.set_image(
            create_button_image(self.plugin, "whatsplaying.png"))
        whatsplayingtoggle.connect('toggled', self.whatsplayingtoggle_callback)

        rightgrid = Gtk.Grid()
        rightgrid.props.halign = Gtk.Align.END

        # rightgrid.attach(whatsplayingtoggle, 0, 0, 1, 1)
        rightgrid.attach(viewtoggle, 1, 0, 1, 1)
        rightgrid.attach(smallwindowbutton, 2, 0, 1, 1)

        self.entry_view_grid.attach_next_to(rightgrid, self.stars,
                                            Gtk.PositionType.RIGHT, 1, 1)
        self.stack.set_visible_child(self.entry_view_results)
        self.stack.connect('notify::visible-child-name',
                           self.notebook_switch_page_callback)

        self.entry_view_grid.show_all()
        smallwindowbutton.set_visible(self.smallwindowext.is_activated())

    def whatsplayingtoggle_callback(self, widget):
        self.entry_view_results.emit('whats-playing', widget.get_active())

    def smallwindowbutton_callback(self, widget):
        if widget.get_active():
            self.smallwindowext.activate(self.shell)
            widget.emit('clicked')

    def entry_view_toggled(self, widget, initialised=False):
        print("DEBUG - entry_view_toggled")
        if widget.get_active():
            next_view = self.entry_view_full
            show_coverart = False
            if self.viewtoggle_id:
                self.shell.props.window.disconnect(self.viewtoggle_id)
                self.viewtoggle_id = None
        else:
            next_view = self.entry_view_compact
            show_coverart = True
            self.viewtoggle_id = self.shell.props.window.connect(
                'check_resize', self.entry_view_results.window_resize)

        setting = self.gs.get_setting(self.gs.Path.PLUGIN)
        setting[self.gs.PluginKey.ENTRY_VIEW_MODE] = not widget.get_active()

        self.entry_view_results.change_view(next_view, show_coverart)
        self.entry_view = next_view
        if not initialised:
            self.source.update_with_selection()

    def notebook_switch_page_callback(self, *args):
        '''
        Callback called when the notebook page gets switched. It initiates
        the cover search when the cover search pane's page is selected.
        '''
        print("CoverArtBrowser DEBUG - notebook_switch_page_callback")

        if self.stack.get_visible_child_name() == 'notebook_covers':
            self.viewmgr.current_view.switch_to_coverpane(
                self.cover_search_pane)
        else:
            entries = self.entry_view.get_selected_entries()
            if entries and len(entries) > 0:
                self.entry_view_results.emit('update-cover', self.source,
                                             entries[0])
            else:
                selected = self.viewmgr.current_view.get_selected_objects()
                tracks = selected[0].get_tracks()
                self.entry_view_results.emit('update-cover', self.source,
                                             tracks[0].entry)

        print("CoverArtBrowser DEBUG - end notebook_switch_page_callback")

    def rating_changed_callback(self, widget):
        '''
        Callback called when the Rating stars is changed
        '''
        print("CoverArtBrowser DEBUG - rating_changed_callback")

        rating = widget.get_rating()

        for album in self.viewmgr.current_view.get_selected_objects():
            album.rating = rating

        print("CoverArtBrowser DEBUG - end rating_changed_callback")

    def get_entry_view(self):
        return self.entry_view

    def update_cover(self, album_artist, manager):
        if not self.stack.get_visible_child_name() == "notebook_covers":
            return

        self.cover_search_pane.clear()
        self.cover_search(album_artist, manager)

    def cover_search(self, album_artist, manager):
        self.cover_search_pane.do_search(album_artist,
                                         manager.cover_man.update_cover)

    def update_selection(self, last_selected_album, click_count):
        '''
        Update the source view when an item gets selected.
        '''
        print("DEBUG - update_with_selection")
        selected = self.viewmgr.current_view.get_selected_objects()

        # clear the entry view
        self.entry_view.clear()

        cover_search_pane_visible = self.stack.get_visible_child_name(
        ) == "notebook_covers"

        if not selected:
            # clean cover tab if selected
            if cover_search_pane_visible:
                self.cover_search_pane.clear()

            self.entry_view_results.emit('update-cover', self.source, None)
            return last_selected_album, click_count
        elif len(selected) == 1:
            self.stars.set_rating(selected[0].rating)

            if selected[0] is not last_selected_album:
                # when the selection changes we've to take into account two
                # things
                if not click_count:
                    # we may be using the arrows, so if there is no mouse
                    # involved, we should change the last selected
                    last_selected_album = selected[0]
                else:
                    # we may've doing a fast change after a valid second click,
                    # so it shouldn't be considered a double click
                    click_count -= 1
        else:
            self.stars.set_rating(0)

        if len(selected) == 1:
            self.source.artist_info.emit('selected', selected[0].artist,
                                         selected[0].name)

        self.entry_view.set_sorting_order('track-number',
                                          Gtk.SortType.ASCENDING)

        for album in selected:
            # add the album to the entry_view
            self.entry_view.add_album(album)

        if len(selected) > 0:

            def cover_update(*args):
                print("emitting")
                self.entry_view_results.emit('update-cover', self.source,
                                             selected[0].get_tracks()[0].entry)

            # add a short delay to give the entry-pane time to expand etc.
            Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
                                    cover_update, None)

        # update the cover search pane with the first selected album
        if cover_search_pane_visible:
            self.cover_search_pane.do_search(
                selected[0], self.source.album_manager.cover_man.update_cover)

        return last_selected_album, click_count
コード例 #49
0
class ArtistInfoPane(GObject.GObject):
    __gsignals__ = {
        'selected': (GObject.SIGNAL_RUN_LAST, None, (GObject.TYPE_STRING,
                                                     GObject.TYPE_STRING))
    }

    artist_info_paned_pos = GObject.property(type=str)

    min_paned_pos = 100

    def __init__(self, button_box, scroll_window, info_paned, source):
        GObject.GObject.__init__(self)
        self.tab = {}
        self.ds = {}
        self.view = {}

        self.buttons = button_box
        self.source = source
        self.plugin = source.plugin
        self.shell = source.shell
        self.info_scrolled_window = scroll_window
        self.info_paned = info_paned
        self.current_artist = None
        self.current_album_title = None

        self.webview = WebKit.WebView()
        self.webview.connect("navigation-requested",
                             self.navigation_request_cb)
        self.webview.connect("notify::title", self.view_title_change)
        self.info_scrolled_window.set_policy(Gtk.PolicyType.NEVER,
                                             Gtk.PolicyType.AUTOMATIC)
        self.info_scrolled_window.add(self.webview)
        self.info_scrolled_window.show_all()

        # cache for artist/album information: valid for a month, can be used indefinitely
        # if offline, discarded if unused for six months
        self.info_cache = rb.URLCache(name='info',
                                      path=os.path.join(
                                          'coverart_browser', 'info'),
                                      refresh=30,
                                      discard=180)
        # cache for rankings (artist top tracks and top albums): valid for a week,
        # can be used for a month if offline
        self.ranking_cache = rb.URLCache(name='ranking',
                                         path=os.path.join(
                                             'coverart_browser', 'ranking'),
                                         refresh=7,
                                         lifetime=30)

        self.info_cache.clean()
        self.ranking_cache.clean()

        self.ds['link'] = LinksDataSource()
        self.ds['artist'] = ArtistDataSource(self.info_cache,
                                             self.ranking_cache)
        self.view['artist'] = ArtistInfoView(self.shell, self.plugin,
                                             self.webview, self.ds['artist'],
                                             self.ds['link'])
        self.tab['artist'] = ArtistInfoTab(self.plugin, self.shell,
                                           self.buttons, self.ds['artist'],
                                           self.view['artist'])
        self.ds['album'] = AlbumDataSource(self.info_cache, self.ranking_cache)
        self.view['album'] = AlbumInfoView(self.shell, self.plugin,
                                           self.webview, self.ds['album'])
        self.tab['album'] = AlbumInfoTab(self.plugin, self.shell, self.buttons,
                                         self.ds['album'], self.view['album'])
        self.ds['echoartist'] = EchoArtistDataSource(self.info_cache,
                                                     self.ranking_cache)
        self.view['echoartist'] = EchoArtistInfoView(self.shell, self.plugin,
                                                     self.webview,
                                                     self.ds['echoartist'],
                                                     self.ds['link'])
        self.tab['echoartist'] = EchoArtistInfoTab(self.plugin, self.shell,
                                                   self.buttons,
                                                   self.ds['echoartist'],
                                                   self.view['echoartist'])

        self.gs = GSetting()
        self.connect_properties()
        self.connect_signals()
        Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50,
                                self._change_paned_pos,
                                self.source.viewmgr.view_name)
        self.current = 'artist'
        self.tab[self.current].activate()

    def connect_properties(self):
        '''
        Connects the source properties to the saved preferences.
        '''
        setting = self.gs.get_setting(self.gs.Path.PLUGIN)

        setting.bind(self.gs.PluginKey.ARTIST_INFO_PANED_POSITION, self,
                     'artist-info-paned-pos', Gio.SettingsBindFlags.DEFAULT)

    def connect_signals(self):
        self.tab_cb_ids = []

        # Listen for switch-tab signal from each tab
        for key, value in self.tab.items():
            self.tab_cb_ids.append(
                (key, self.tab[key].connect('switch-tab', self.change_tab)))

        # Listen for selected signal from the views
        self.connect('selected', self.select_artist)

        # lets remember info paned click
        self.info_paned.connect('button-release-event',
                                self.artist_info_paned_button_release_callback)

        # lets also listen for changes to the view to set the paned position
        self.source.viewmgr.connect('new-view', self.on_view_changed)

    def view_title_change(self, webview, param):
        title = webview.get_title()
        if title:
            args = json.loads(title)
            artist = args['artist']

            if args['toggle']:
                self.source.album_manager.model.replace_filter(
                    'similar_artist', artist)
            else:
                self.source.album_manager.model.remove_filter('similar_artist')
        else:
            self.source.album_manager.model.remove_filter('similar_artist')

    def on_view_changed(self, widget, view_name):
        self._change_paned_pos(view_name)

    def _change_paned_pos(self, view_name):
        paned_positions = eval(self.artist_info_paned_pos)

        found = None
        for viewpos in paned_positions:
            if view_name in viewpos:
                found = viewpos
                break

        if not found:
            return

        child_width = int(found.split(":")[1])

        calc_pos = self.source.page.get_allocated_width() - child_width
        self.info_paned.set_position(calc_pos)
        self.info_paned.set_visible(True)

    def _get_child_width(self):
        child = self.info_paned.get_child2()
        return child.get_allocated_width()

    def artist_info_paned_button_release_callback(self, *args):
        '''
        Callback when the artist paned handle is released from its mouse click.
        '''

        child_width = self._get_child_width()

        paned_positions = eval(self.artist_info_paned_pos)

        found = None
        for viewpos in paned_positions:
            if self.source.viewmgr.view_name in viewpos:
                found = viewpos
                break

        if not found:
            return

        paned_positions.remove(found)
        if child_width <= self.min_paned_pos:
            child_width = 0
            self.info_paned.set_position(
                self.source.page.get_allocated_width())

        paned_positions.append(self.source.viewmgr.view_name + ":" +
                               str(child_width))

        self.artist_info_paned_pos = repr(paned_positions)

    def select_artist(self, widget, artist, album_title):
        if self._get_child_width() > self.min_paned_pos:
            self.tab[self.current].reload(artist, album_title)
        else:
            self.tab[self.current].view.blank_view()

        self.current_album_title = album_title
        self.current_artist = artist

    def change_tab(self, tab, newtab):
        print("swapping tab from %s to %s" % (self.current, newtab))
        if (self.current != newtab):
            self.tab[self.current].deactivate()
            if self._get_child_width() > self.min_paned_pos:
                self.tab[newtab].activate(self.current_artist,
                                          self.current_album_title)
            else:
                self.tab[newtab].view.blank_view()

            self.current = newtab

    def navigation_request_cb(self, view, frame, request):
        # open HTTP URIs externally.  this isn't a web browser.
        if request.get_uri().startswith('http'):
            print("opening uri %s" % request.get_uri())
            Gtk.show_uri(self.shell.props.window.get_screen(),
                         request.get_uri(), Gdk.CURRENT_TIME)

            return 1  # WEBKIT_NAVIGATION_RESPONSE_IGNORE
        else:
            return 0  # WEBKIT_NAVIGATION_RESPONSE_ACCEPT
コード例 #50
0
 def _connect_properties(self):
     gs = GSetting()
     setting = gs.get_setting(gs.Path.PLUGIN)
     setting.bind(gs.PluginKey.TOOLBAR_POS, self, 'toolbar_pos',
                  Gio.SettingsBindFlags.GET)
コード例 #51
0
    def play_random_album_menu_item_callback(self, favourites=False):
        print(
            '''CoverArtBrowser DEBUG - play_random_album_menu_item_callback''')
        query_model = RB.RhythmDBQueryModel.new_empty(self.shell.props.db)

        num_albums = len(self.album_manager.model.store)

        #random_list = []
        selected_albums = []

        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)
        to_queue = settings[gs.PluginKey.RANDOM]

        if num_albums <= to_queue:
            dialog = Gtk.MessageDialog(
                None, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO,
                Gtk.ButtonsType.OK,
                _("The number of albums to randomly play is less than that displayed."
                  ))

            dialog.run()
            dialog.destroy()
            return

        album_col = self.album_manager.model.columns['album']

        chosen = {}

        # now loop through finding unique random albums
        # i.e. ensure we dont queue the same album twice

        for loop in range(0, to_queue):
            while True:
                pos = random.randint(0, num_albums - 1)
                if pos not in chosen:
                    chosen[pos] = None
                    selected_albums.append(
                        self.album_manager.model.store[pos][album_col])
                    break

        threshold = self.rating_threshold if favourites else 0

        total = 0
        for album in selected_albums:
            # Retrieve and sort the entries of the album
            tracks = album.get_tracks(threshold)
            total = total + len(tracks)
            # Add the songs to the play queue
            for track in tracks:
                query_model.add_entry(track.entry, -1)

        if total == 0 and threshold:
            dialog = Gtk.MessageDialog(
                None, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO,
                Gtk.ButtonsType.OK,
                _("No tracks have been added because no tracks meet the favourite rating threshold"
                  ))

            dialog.run()
            dialog.destroy()

        self.props.query_model = query_model

        # Start the music
        player = self.shell.props.shell_player

        player.play_entry(query_model[0][0], self)

        print("CoverArtBrowser DEBUG - end play_selected_album")
コード例 #52
0
    def _connect_properties(self):
        gs = GSetting()
        setting = gs.get_setting(gs.Path.PLUGIN)

        setting.bind(gs.PluginKey.NEW_GENRE_ICON, self, 'new_genre_icon',
                     Gio.SettingsBindFlags.GET)
コード例 #53
0
class ArtistView(Gtk.TreeView, AbstractView):
    __gtype_name__ = "ArtistView"

    name = 'artistview'
    icon_automatic = GObject.property(type=bool, default=True)
    panedposition = PanedCollapsible.Paned.COLLAPSE
    
    __gsignals__ = {
        'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
        }
    

    def __init__(self, *args, **kwargs):
        super(ArtistView, self).__init__(*args, **kwargs)
        
        self._external_plugins = None
        self.gs = GSetting()
        self.show_policy = ArtistShowingPolicy(self)
        self.view = self
        self._has_initialised = False        
        self._last_row_was_artist = False
            
    def initialise(self, source):
        if self._has_initialised:
            return
            
        self._has_initialised = True

        self.view_name = "artist_view"
        super(ArtistView, self).initialise(source)
        self.album_manager = source.album_manager
        self.shell = source.shell
        self.props.has_tooltip = True
        
        self.set_enable_tree_lines(True)
        
        col = Gtk.TreeViewColumn('       ', Gtk.CellRendererText(), text=6)
        self.append_column(col)
        
        pixbuf = Gtk.CellRendererPixbuf()
        col = Gtk.TreeViewColumn(_('Covers'), pixbuf, pixbuf=1)
        
        self.append_column(col)
        
        col = Gtk.TreeViewColumn(_('Artist'), Gtk.CellRendererText(), markup=5)
        self._artist_col = col
        col.set_clickable(True)
        col.set_sort_column_id(0)
        col.set_sort_indicator(True)
        col.connect('clicked', self._artist_sort_clicked)
        self.append_column(col)
        col = Gtk.TreeViewColumn('', Gtk.CellRendererText(), text=4)
        self.append_column(col) # dummy column to expand horizontally
        
        self.artist_manager = self.album_manager.artist_man
        self.artist_manager.model.store.set_sort_column_id(0, Gtk.SortType.ASCENDING)
        self.set_model(self.artist_manager.model.store)
        
        # setup iconview drag&drop support
        # first drag and drop on the coverart view to receive coverart
        self.enable_model_drag_dest([], Gdk.DragAction.COPY)
        self.drag_dest_add_image_targets()
        self.drag_dest_add_text_targets()
        self.connect('drag-drop', self.on_drag_drop)
        self.connect('drag-data-received',
            self.on_drag_data_received)
            
        # lastly support drag-drop from coverart to devices/nautilus etc
        # n.b. enabling of drag-source is controlled by the selection-changed to ensure
        # we dont allow drag from artists
        self.connect('drag-begin', self.on_drag_begin)
        self._targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0) ])
    
        # N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c
        self._targets.add_uri_targets(1)
        self.connect("drag-data-get", self.on_drag_data_get)
        
        # define artist specific popup menu
        self.artist_popup_menu = Menu(self.plugin, self.shell)
        self.artist_popup_menu.load_from_file('ui/coverart_artist_pop_rb2.ui',
            'ui/coverart_artist_pop_rb3.ui')
        signals = \
            { 'play_album_menu_item': self.source.play_album_menu_item_callback,
              'queue_album_menu_item': self.source.queue_album_menu_item_callback,
              'new_playlist': self.source.add_playlist_menu_item_callback,
              'artist_cover_search_menu_item': self.cover_search_menu_item_callback
            }
              
        self.artist_popup_menu.connect_signals(signals)
        self.artist_popup_menu.connect('pre-popup', self.add_external_menu)
            
        # connect properties and signals
        self._connect_properties()
        self._connect_signals()
        
    def _connect_properties(self):
        setting = self.gs.get_setting(self.gs.Path.PLUGIN)
        setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self,
            'icon_automatic', Gio.SettingsBindFlags.GET)
        
    def _connect_signals(self):
        self.connect('row-activated', self._row_activated)
        self.connect('row-expanded', self._row_expanded)
        self.connect('button-press-event', self._row_click)
        self.get_selection().connect('changed', self._selection_changed)
        self.connect('query-tooltip', self._query_tooltip)
    
    def _artist_sort_clicked(self, *args):
        # in the absence of an apparent way to remove the unsorted default_sort_func
        # find out if we are now in an unsorted state - if we are
        # throw another clicked event so that we remain sorted.
        value, order = self.artist_manager.model.store.get_sort_column_id()
        
        if order == None:
            self._artist_col.emit('clicked')
        
    def cover_search_menu_item_callback(self, *args):
        self.artist_manager.cover_man.search_covers(self.get_selected_objects(just_artist=True),
            callback=self.source.update_request_status_bar)
        
    def _query_tooltip( self, widget, x, y, key, tooltip ):
        
        try:
            winx, winy = self.convert_widget_to_bin_window_coords(x, y)
            treepath, treecolumn, cellx, celly = self.get_path_at_pos(winx, winy)
            active_object = self.artist_manager.model.get_from_path(treepath)
            
            #active_object=self.artist_manager.model.store[treepath][self.artist_manager.model.columns['artist_album']]
            
            if isinstance(active_object, Artist) and \
                treecolumn.get_title() == _('Covers') and \
                active_object.cover.original != self.artist_manager.cover_man.unknown_cover.original:
                # we display the tooltip if the row is an artist and the column
                # is actually the artist cover itself
                pixbuf = GdkPixbuf.Pixbuf.new_from_file(active_object.cover.original)
                    
                src_width = pixbuf.get_width()
                src_height = pixbuf.get_height()
                
                factor = min(float(256)  / float(src_width), float(256) / float(src_height))
                new_width  = int(src_width * factor + 0.5)
                new_height = int(src_height * factor + 0.5)
    
                pixbuf = create_pixbuf_from_file_at_size(
                    active_object.cover.original, new_width, new_height)
                
                tooltip.set_icon( pixbuf )
                return True
            else:
                return False

        except:
                pass
            
    def _row_expanded(self, treeview, treeiter, treepath):
        '''
        event called when clicking the expand icon on the treeview
        '''
        self._row_activated(treeview, treepath, _)
        
    def _row_activated(self, treeview, treepath, treeviewcolumn):
        '''
        event called when double clicking on the tree-view or by keyboard ENTER
        '''
        active_object = self.artist_manager.model.get_from_path(treepath)
        if isinstance(active_object, Artist):
            self.artist_manager.model.emit('update-path', treepath)
        else:
            #we need to play this album
            self.source.play_selected_album(self.source.favourites)
            
    def add_external_menu(self, *args):
        '''
          callback when artist popup menu is about to be displayed
        '''
        
        self.source.playlist_menu_item_callback()
            
    def _row_click(self, widget, event):
        '''
        event called when clicking on a row
        '''
        
        try:
            treepath, treecolumn, cellx, celly = self.get_path_at_pos(event.x, event.y)
        except:
            return
            
        active_object = self.artist_manager.model.get_from_path(treepath)
        
        if not isinstance(active_object, Album):
            self.source.artist_info.emit('selected', active_object.name, None)
            if self.icon_automatic:
                # reset counter so that we get correct double click action for albums
                self.source.click_count = 0 
                
            if treecolumn != self.get_expander_column():
                if self.row_expanded(treepath) and event.button == 1 and self._last_row_was_artist:
                    self.collapse_row(treepath)
                else:
                    self.expand_row(treepath, False)
        
                self._last_row_was_artist = True
                
                if event.button ==3:
                    # on right click
                    # display popup
                    
                    self.artist_popup_menu.popup(self.source, 'popup_menu', 3,
                                    Gtk.get_current_event_time())
            return
            
        if event.button == 1:
            # on click
            # to expand the entry view
            ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
            shift = event.state & Gdk.ModifierType.SHIFT_MASK

            if self.icon_automatic and not self._last_row_was_artist:
                self.source.click_count += 1 if not ctrl and not shift else 0

            if self.source.click_count == 1:
                Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
                    self.source.show_hide_pane, active_object)
                    
        elif event.button ==3:
            # on right click
            # display popup
            
            self.popup.popup(self.source, 'popup_menu', 3,
                            Gtk.get_current_event_time())
                            
        self._last_row_was_artist = False
            
    def get_view_icon_name(self):
        return "artistview.png"
        
    def _selection_changed(self, *args):
        selected = self.get_selected_objects(just_artist=True)

        print (selected)
        if len(selected) == 0:
            self.source.entry_view.clear()
            return
            
        if isinstance(selected[0], Artist):
            print ("selected artist")
            self.unset_rows_drag_source() # turn off drag-drop for artists
                
            # clear the entry view
            self.source.entry_view.clear()

            cover_search_pane_visible = self.source.notebook.get_current_page() == \
                self.source.notebook.page_num(self.source.cover_search_pane)
                            
            # update the cover search pane with the first selected artist
            if cover_search_pane_visible:
                print ("update coversearch for artist")
                print (selected[0])
                self.source.cover_search_pane.do_search(selected[0],
                    self.artist_manager.cover_man.update_cover)
            
        else:
            print ("selected album")
            self.source.update_with_selection()
            # now turnon drag-drop for album.
            self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
                [], Gdk.DragAction.COPY)
            self.drag_source_set_target_list(self._targets)
    
    def switch_to_coverpane(self, cover_search_pane):
        '''
        called from the source to update the coverpane when
        it is switched from the track pane
        This overrides the base method
        '''
        
        selected = self.get_selected_objects(just_artist=True)

        if selected:
            manager = self.get_default_manager()
            cover_search_pane.do_search(selected[0],
                manager.cover_man.update_cover)

    def get_selected_objects(self, just_artist=False):
        '''
        finds what has been selected

        returns an array of `Album`
        '''
        selection = self.get_selection()
        model, treeiter = selection.get_selected()
        if treeiter:
            active_object = model.get_value(treeiter,ArtistsModel.columns['artist_album'])
            if isinstance(active_object, Album):
                # have chosen an album then just return that album
                return [active_object]
            else:
                # must have chosen an artist - return all albums for the artist by default
                # or just the artist itself
                if not just_artist:
                    return self.artist_manager.model.get_albums(active_object.name)
                else:
                    return [active_object]
        return []
        
    def switch_to_view(self, source, album):
        self.initialise(source)
        self.show_policy.initialise(source.album_manager)
        
        self.scroll_to_album(album)
                
    def scroll_to_album(self, album):
        if album:
            print ("switch to artist view")
            print (album)
            artist = self.artist_manager.model.get(album.artist)
            path = self.artist_manager.model.get_path(artist)
            print (artist)
            print (path)
            path = self.artist_manager.model.store.convert_child_path_to_path(path)
            print (path)
            if path:
                self.scroll_to_cell(path, self._artist_col)
                self.expand_row(path, False)
                self.set_cursor(path)
        
    def do_update_toolbar(self, *args):
        self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_BY)
        self.source.toolbar_manager.set_enabled(False, ToolbarObject.SORT_ORDER)
        self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_BY_ARTIST)
        self.source.toolbar_manager.set_enabled(True, ToolbarObject.SORT_ORDER_ARTIST)
        
    def on_drag_drop(self, widget, context, x, y, time):
        '''
        Callback called when a drag operation finishes over the view
        of the source. It decides if the dropped item can be processed as
        an image to use as a cover.
        '''

        # stop the propagation of the signal (deactivates superclass callback)
        if rb3compat.is_rb3(self.shell):
            widget.stop_emission_by_name('drag-drop')
        else:
            widget.stop_emission('drag-drop')

        # obtain the path of the icon over which the drag operation finished
        drop_info = self.get_dest_row_at_pos(x, y)
        path = None
        if drop_info:
            path, position = drop_info
            
        result = path is not None

        if result:
            target = self.drag_dest_find_target(context, None)
            widget.drag_get_data(context, target, time)

        return result

    def on_drag_data_received(self, widget, drag_context, x, y, data, info,
        time):
        '''
        Callback called when the drag source has prepared the data (pixbuf)
        for us to use.
        '''

        # stop the propagation of the signal (deactivates superclass callback)
        if rb3compat.is_rb3(self.shell):
            widget.stop_emission_by_name('drag-data-received')
        else:
            widget.stop_emission('drag-data-received')

        # get the artist and the info and ask the loader to update the cover
        path, position = self.get_dest_row_at_pos(x, y)
        artist_album = widget.get_model()[path][2]

        pixbuf = data.get_pixbuf()  

        if isinstance(artist_album, Album):
            manager = self.album_manager
        else:
            manager = self.artist_manager
            
        if pixbuf:
            manager.cover_man.update_cover(artist_album, pixbuf)
        else:
            uri = data.get_text()
            manager.cover_man.update_cover(artist_album, uri=uri)

        # call the context drag_finished to inform the source about it
        drag_context.finish(True, False, time)
        
    def on_drag_data_get(self, widget, drag_context, data, info, time):
        '''
        Callback called when the drag destination (playlist) has
        requested what album (icon) has been dragged
        '''

        uris = []
        for album in widget.get_selected_objects():
            for track in album.get_tracks():
                uris.append(track.location)

        data.set_uris(uris)
        # stop the propagation of the signal (deactivates superclass callback)
        if rb3compat.is_rb3(self.shell):
            widget.stop_emission_by_name('drag-data-get')
        else:
            widget.stop_emission('drag-data-get')

    def on_drag_begin(self, widget, context):
        '''
        Callback called when the drag-drop from coverview has started
        Changes the drag icon as appropriate
        '''
        album_number = len(widget.get_selected_objects())

        if album_number == 1:
            item = Gtk.STOCK_DND
        else:
            item = Gtk.STOCK_DND_MULTIPLE

        widget.drag_source_set_icon_stock(item)
        if rb3compat.is_rb3(self.shell):
            widget.stop_emission_by_name('drag-begin')
        else:
            widget.stop_emission('drag-begin')
    
        
    def get_default_manager(self):
        '''
        the default manager for this view is the artist_manager
        '''
        return self.artist_manager
コード例 #54
0
    def _connect_properties(self):
        gs = GSetting()
        settings = gs.get_setting(gs.Path.PLUGIN)

        settings.bind(gs.PluginKey.CUSTOM_STATUSBAR, self,
            'custom_statusbar_enabled', Gio.SettingsBindFlags.GET)
コード例 #55
0
    def __init__(self, shell, source):
        '''
        Initializes the entryview.
        '''
        self.shell = shell
        self.source = source
        self.plugin = self.source.props.plugin

        super(RB.EntryView, self).__init__(db=shell.props.db,
            shell_player=shell.props.shell_player, is_drag_source=True,
            visible_columns=[])

        cl = CoverLocale()
        cl.switch_locale(cl.Locale.RB)

        self.append_column(RB.EntryViewColumn.TRACK_NUMBER, False)
        self.append_column(RB.EntryViewColumn.TITLE, True)  # always shown
        self.append_column(RB.EntryViewColumn.GENRE, False)
        self.append_column(RB.EntryViewColumn.ARTIST, False)
        self.append_column(RB.EntryViewColumn.ALBUM, False)
        self.append_column(RB.EntryViewColumn.DURATION, False)
        self.append_column(RB.EntryViewColumn.COMMENT, False)
        self.append_column(RB.EntryViewColumn.RATING, False)
        self.append_column(RB.EntryViewColumn.QUALITY, False)
        self.append_column(RB.EntryViewColumn.PLAY_COUNT, False)
        self.append_column(RB.EntryViewColumn.LAST_PLAYED, False)
        self.append_column(RB.EntryViewColumn.YEAR, False)
        self.append_column(RB.EntryViewColumn.FIRST_SEEN, False)
        self.append_column(RB.EntryViewColumn.LOCATION, False)
        self.append_column(RB.EntryViewColumn.BPM, False)

        cl.switch_locale(cl.Locale.LOCALE_DOMAIN)

        # UI elements need to be imported.
        ui = Gtk.Builder()
        ui.set_translation_domain(cl.Locale.LOCALE_DOMAIN)
        ui.add_from_file(rb.find_plugin_file(self.plugin,
            'ui/coverart_entryview.ui'))
        ui.connect_signals(self)

        self.popup_menu = ui.get_object('entryview_popup_menu')

        # connect signals to the shell to know when the playing state changes
        self.shell.props.shell_player.connect('playing-song-changed',
            self.playing_song_changed)
        self.shell.props.shell_player.connect('playing-changed',
            self.playing_changed)

        self.playlist_sub_menu_item = ui.get_object('playlist_sub_menu_item')
        self.actiongroup = Gtk.ActionGroup('coverentryplaylist_submenu')
        uim = self.shell.props.ui_manager
        uim.insert_action_group(self.actiongroup)

        self.external_plugins = \
            CreateExternalPluginMenu("ca_entryview", self.shell)

        # connect the visible-columns global setting to update our entryview
        gs = GSetting()
        rhythm_settings = gs.get_setting(gs.Path.RBSOURCE)
        rhythm_settings.connect('changed::visible-columns',
            self.on_visible_columns_changed)
        self.on_visible_columns_changed(rhythm_settings, 'visible-columns')

        self.qm = RB.RhythmDBQueryModel.new_empty(self.shell.props.db)
        self.set_model(self.qm)

        # connect the sort-order to the library source sort
        library_view = self.shell.props.library_source.get_entry_view()
        library_view.connect('notify::sort-order',
            self._on_library_sorting_changed)
        self._on_library_sorting_changed(library_view,
            library_view.props.sort_order)

         # connect to the sort-order property
        self.connect('notify::sort-order', self._notify_sort_order,
            library_view)
コード例 #56
0
class CoverIconView(EnhancedIconView, AbstractView):
    __gtype_name__ = "CoverIconView"

    icon_spacing = GObject.property(type=int, default=0)
    icon_padding = GObject.property(type=int, default=0)
    icon_automatic = GObject.property(type=bool, default=True)

    display_text_enabled = GObject.property(type=bool, default=False)
    display_text_pos = GObject.property(type=bool, default=False)
    name = 'coverview'
    panedposition = PanedCollapsible.Paned.COLLAPSE
    text_alignment = GObject.property(type=int, default=1)

    __gsignals__ = {
        'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
    }

    def __init__(self, *args, **kwargs):
        super(CoverIconView, self).__init__(cell_area=AlbumArtCellArea(), *args, **kwargs)

        self.gs = GSetting()
        # custom text renderer
        self._text_renderer = None
        self.show_policy = AlbumShowingPolicy(self)
        self.view = self
        self._has_initialised = False
        self._last_path = None
        self._calc_motion_step = 0
        self.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
        self.object_column = AlbumsModel.columns['album']

    def initialise(self, source):
        if self._has_initialised:
            return

        self._has_initialised = True

        self.view_name = "covers_view"
        super(CoverIconView, self).initialise(source)

        self.shell = source.shell
        self.album_manager = source.album_manager

        # setup iconview drag&drop support
        # first drag and drop on the coverart view to receive coverart
        self.enable_model_drag_dest([], Gdk.DragAction.COPY)
        self.drag_dest_add_image_targets()
        self.drag_dest_add_text_targets()
        self.connect('drag-drop', self.on_drag_drop)
        self.connect('drag-data-received',
                     self.on_drag_data_received)
        self.source.paned.connect("expanded", self.bottom_expander_expanded_callback)

        # lastly support drag-drop from coverart to devices/nautilus etc
        self.connect('drag-begin', self.on_drag_begin)
        self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
            [], Gdk.DragAction.COPY)
        # targets = Gtk.TargetList.new([Gtk.TargetEntry.new("application/x-rhythmbox-entry", 0, 0),
        # Gtk.TargetEntry.new("text/uri-list", 0, 1) ])
        targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0)])
        # N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c
        targets.add_uri_targets(1)

        self.drag_source_set_target_list(targets)
        self.connect("drag-data-get", self.on_drag_data_get)

        # set the model to the view
        # self.set_pixbuf_column(AlbumsModel.columns['pixbuf'])
        self.set_model(self.album_manager.model.store)

        # setup view to monitor mouse movements
        self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)

        self.hover_pixbufs = {
            'button_play': None,
            'button_play_hover': None,
            'button_playpause': None,
            'button_playpause_hover': None,
            'button_queue': None,
            'button_queue_hover': None,
        }

        for pixbuf_type in self.hover_pixbufs:
            filename = 'img/' + pixbuf_type + '.png'
            filename = rb.find_plugin_file(self.plugin, filename)
            self.hover_pixbufs[pixbuf_type] = GdkPixbuf.Pixbuf.new_from_file_at_size(filename,
                                                                                     PLAY_SIZE_X,
                                                                                     PLAY_SIZE_Y)

        self._connect_properties()
        self._connect_signals()

        self._activate_markup()
        self.on_notify_icon_padding()
        self.on_notify_icon_spacing()

    def _connect_properties(self):
        setting = self.gs.get_setting(self.gs.Path.PLUGIN)
        setting.bind(
            self.gs.PluginKey.ICON_SPACING,
            self,
            'icon_spacing',
            Gio.SettingsBindFlags.GET)
        setting.bind(
            self.gs.PluginKey.ICON_PADDING,
            self,
            'icon_padding',
            Gio.SettingsBindFlags.GET)

        setting.bind(self.gs.PluginKey.DISPLAY_TEXT, self,
                     'display_text_enabled', Gio.SettingsBindFlags.GET)

        setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self,
                     'icon_automatic', Gio.SettingsBindFlags.GET)

        setting.bind(self.gs.PluginKey.DISPLAY_TEXT_POS, self,
                     'display-text-pos', Gio.SettingsBindFlags.GET)

        setting.bind(self.gs.PluginKey.TEXT_ALIGNMENT, self,
                     'text-alignment', Gio.SettingsBindFlags.GET)

    def _connect_signals(self):
        self.connect("item-clicked", self.item_clicked_callback)
        self.connect("selection-changed", self.selectionchanged_callback)
        self.connect("item-activated", self.item_activated_callback)
        self.connect('notify::icon-spacing',
                     self.on_notify_icon_spacing)
        self.connect('notify::icon-padding',
                     self.on_notify_icon_padding)
        self.connect('notify::display-text-enabled',
                     self._activate_markup)
        self.connect('notify::display-text-pos',
                     self._activate_markup)
        self.connect('notify::text-alignment',
                     self._create_and_configure_renderer)
        self.connect("motion-notify-event", self.on_pointer_motion)

    def get_view_icon_name(self):
        return "iconview.png"

    def resize_icon(self, cover_size):
        '''
        Callback called when to resize the icon
        [common to all views]
        '''
        self.set_item_width(cover_size)

    def on_drag_drop(self, widget, context, x, y, time):
        '''
        Callback called when a drag operation finishes over the cover view
        of the source. It decides if the dropped item can be processed as
        an image to use as a cover.
        '''

        # stop the propagation of the signal (deactivates superclass callback)
        widget.stop_emission_by_name('drag-drop')

        # obtain the path of the icon over which the drag operation finished
        path, pos = widget.get_dest_item_at_pos(x, y)
        result = path is not None

        if result:
            target = self.drag_dest_find_target(context, None)
            widget.drag_get_data(context, target, time)

        return result

    def on_drag_data_received(self, widget, drag_context, x, y, data, info,
                              time):
        '''
        Callback called when the drag source has prepared the data (pixbuf)
        for us to use.
        '''

        # stop the propagation of the signal (deactivates superclass callback)
        widget.stop_emission_by_name('drag-data-received')

        # get the album and the info and ask the loader to update the cover
        path, pos = widget.get_dest_item_at_pos(x, y)
        album = widget.get_model()[path][2]

        pixbuf = data.get_pixbuf()

        if pixbuf:
            self.album_manager.cover_man.update_cover(album, pixbuf)
        else:
            uri = data.get_text()
            self.album_manager.cover_man.update_cover(album, uri=uri)

        # call the context drag_finished to inform the source about it
        drag_context.finish(True, False, time)


    def on_drag_data_get(self, widget, drag_context, data, info, time):
        '''
        Callback called when the drag destination (playlist) has
        requested what album (icon) has been dragged
        '''

        uris = []
        for album in widget.get_selected_objects():
            for track in album.get_tracks():
                uris.append(track.location)

        sel = data.set_uris(uris)
        # stop the propagation of the signal (deactivates superclass callback)
        widget.stop_emission_by_name('drag-data-get')

    def on_drag_begin(self, widget, context):
        '''
        Callback called when the drag-drop from coverview has started
        Changes the drag icon as appropriate
        '''
        album_number = len(widget.get_selected_objects())

        if album_number == 1:
            item = Gtk.STOCK_DND
        else:
            item = Gtk.STOCK_DND_MULTIPLE

        widget.drag_source_set_icon_stock(item)
        widget.stop_emission_by_name('drag-begin')

    def _cover_play_hotspot(self, path, in_vacinity=False):
        if path:
            valid, rect = self.get_cell_rect(path, None)  # rect of widget coords

            cursor_x, cursor_y = self.get_pointer()  # returns widget coords
            c_x = cursor_x - rect.x - (self.icon_padding / 2) - (self.icon_spacing / 2)
            c_y = cursor_y - rect.y - (self.icon_padding / 2) - (self.icon_spacing / 2)

            sizing = (rect.width / 3) if in_vacinity else 0

            full, x_offset, y_offset = self.props.cell_area.calc_play_icon_offset(0, 0)
            if full and c_y > y_offset:
                return False

            y_offset = y_offset - PLAY_SIZE_Y

            if (y_offset - PLAY_SIZE_Y) < 0:
                return False

            if c_x < (PLAY_SIZE_X + sizing + x_offset) and \
                            c_y < (PLAY_SIZE_Y + sizing + y_offset) and \
                            c_x > x_offset and \
                            c_y > (y_offset - sizing):
                return True

                # c_y 0 value at top - largest at bottom of the cover
        return False

    def on_pointer_motion(self, widget, event):
        self._current_mouse_x = event.x
        self._current_mouse_y = event.y

        if self._calc_motion_step == 0:
            self._calc_motion_step = 1
            Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
                                    self._calculate_hotspot)
        else:
            path = self.get_path_at_pos(self._current_mouse_x,
                                        self._current_mouse_y)

            if not self._last_path or self._last_path != path:
                self._display_icon(None, self._last_path)

    def _display_icon(self, icon, path):
        self.props.cell_area.hover_pixbuf = icon
        if path and self.props.window:
            valid, rect = self.get_cell_rect(path, None)
            self.props.window.invalidate_rect(rect, True)

        self.queue_draw()

    def _calculate_hotspot(self, *args):

        path = self.get_path_at_pos(self._current_mouse_x,
                                    self._current_mouse_y)

        # if the current path was not the same as the last path then
        # reset the counter
        if not self._last_path or self._last_path != path:
            self._display_icon(None, self._last_path)
            self._last_path = path
            self._calc_motion_step = 0
            return False

        self._calc_motion_step = self._calc_motion_step + 1

        # if havent yet reached the requisite number of steps then
        # let the thread roll to the next increment
        if self._calc_motion_step < 8:
            return True

        if not self._cover_play_hotspot(path, in_vacinity=True):
            # we are not near the hot-spot so decrement the counter
            # hoping next time around we are near
            self._calc_motion_step = self._calc_motion_step - 1
            self._display_icon(None, self._last_path)
            return True

        # from  here on in, we are going to display a hotspot icon
        # so lets decide which one

        (_, playing) = self.shell.props.shell_player.get_playing()

        calc_path = -1
        if playing:
            entry = self.shell.props.shell_player.get_playing_entry()
            album = self.album_manager.model.get_from_dbentry(entry)
            calc_path = self.album_manager.model.get_path(album)

        if playing and calc_path == path:
            icon = 'button_playpause'
        elif playing:
            icon = 'button_queue'
        else:
            icon = 'button_play'

        # now we've got the icon - lets double check that we are
        # actually hovering exactly on the hotspot because the icon will visually change

        exact_hotspot = self._cover_play_hotspot(path)
        if exact_hotspot:
            icon = icon + '_hover'

        hover = self.hover_pixbufs[icon]

        self._display_icon(hover, path)
        self._calc_motion_step = self._calc_motion_step - 1

        return True

    def item_clicked_callback(self, iconview, event, path):
        '''
        Callback called when the user clicks somewhere on the cover_view.
        Along with source "show_hide_pane", takes care of showing/hiding the bottom
        pane after a second click on a selected album.
        '''

        # first test if we've clicked on the cover-play icon
        if self._cover_play_hotspot(path):
            (_, playing) = self.shell.props.shell_player.get_playing()

            # first see if anything is playing...
            if playing:
                entry = self.shell.props.shell_player.get_playing_entry()
                album = self.album_manager.model.get_from_dbentry(entry)

                # if the current playing entry corresponds to the album
                # we are hovering over then we are requesting to pause
                if self.album_manager.model.get_from_path(path) == album:
                    self._last_path = path
                    self.shell.props.shell_player.pause()
                    self.on_pointer_motion(self, event)
                    return

            # this must be a new album so we are asking just
            # to play this new album ... just need a short interval
            # for the selection event to kick in first
            def delay(*args):
                if playing:  # if we are playing then queue up the next album
                    self.source.queue_selected_album(None, self.source.favourites)
                    album = self.get_selected_objects()[0]
                    cl = CoverLocale()
                    cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
                    message = gettext.gettext('Album has added to list of playing albums')
                    self.display_notification(album.name,
                                              message,
                                              album.cover.original)
                else:  # otherwise just play it
                    self._last_path = path
                    self.source.play_selected_album(self.source.favourites)

                icon = 'button_play_hover'
                self.props.cell_area.hover_pixbuf = \
                    self.hover_pixbufs[icon]

            Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
                                    delay, None)

            return

        # to expand the entry view
        ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
        shift = event.state & Gdk.ModifierType.SHIFT_MASK

        if self.icon_automatic:
            self.source.click_count += 1 if not ctrl and not shift else 0

        if self.source.click_count == 1:
            album = self.album_manager.model.get_from_path(path) \
                if path else None
            Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
                                    self.source.show_hide_pane, album)

    def item_activated_callback(self, iconview, path):
        '''
        Callback called when the cover view is double clicked or space-bar
        is pressed. It plays the selected album
        '''
        self.source.play_selected_album(self.source.favourites)

        return True

    def on_notify_icon_padding(self, *args):
        '''
        Callback called when the icon-padding gsetting value is changed
        '''
        self.set_item_padding(self.icon_padding)

    def on_notify_icon_spacing(self, *args):
        '''
        Callback called when the icon-spacing gsetting value is changed
        '''
        self.set_row_spacing(self.icon_spacing)
        self.set_column_spacing(self.icon_spacing)

    def _create_and_configure_renderer(self, *args):
        if not self._text_renderer:
            # Add own cellrenderer
            self._text_renderer = Gtk.CellRendererText()

        self._text_renderer.props.alignment = self.text_alignment
        self._text_renderer.props.wrap_mode = Pango.WrapMode.WORD
        if self.text_alignment == 1:
            self._text_renderer.props.xalign = 0.5
        elif self.text_alignment == 0:
            self._text_renderer.props.xalign = 0
        else:
            self._text_renderer.props.xalign = 1

        self._text_renderer.props.yalign = 0
        self._text_renderer.props.width = \
            self.album_manager.cover_man.cover_size
        self._text_renderer.props.wrap_width = \
            self.album_manager.cover_man.cover_size

    def _activate_markup(self, *args):
        '''
        Utility method to activate/deactivate the markup text on the
        cover view.
        '''
        if self.display_text_enabled and self.display_text_pos:
            if not self._text_renderer:
                # create and configure the custom cell renderer
                self._create_and_configure_renderer()

            # set the renderer
            self.pack_end(self._text_renderer, False)
            self.add_attribute(self._text_renderer,
                               'markup', AlbumsModel.columns['markup'])
        elif self._text_renderer:
            # remove the cell renderer
            self.props.cell_area.remove(self._text_renderer)

        if self.display_text_enabled:
            self.set_tooltip_column(-1)  # turnoff tooltips
        else:
            self.set_tooltip_column(AlbumsModel.columns['tooltip'])

    def bottom_expander_expanded_callback(self, paned, expand):
        '''
        Callback connected to expanded signal of the paned GtkExpander
        '''
        if expand:
            # accommodate the viewport if there's an album selected
            if self.source.last_selected_album:
                def scroll_to_album(*args):
                    # accommodate the viewport if there's an album selected
                    path = self.album_manager.model.get_path(
                        self.source.last_selected_album)

                    self.scroll_to_path(path, False, 0, 0)

                    return False

                Gdk.threads_add_idle(GObject.PRIORITY_DEFAULT_IDLE,
                                     scroll_to_album, None)


    def switch_to_view(self, source, album):
        self.initialise(source)
        self.show_policy.initialise(source.album_manager)

        self.scroll_to_album(album)

    def grab_focus(self):
        super(EnhancedIconView, self).grab_focus()
コード例 #57
0
class ArtistInfoPane(GObject.GObject):
    __gsignals__ = {
        'selected': (GObject.SIGNAL_RUN_LAST, None, (GObject.TYPE_STRING,
                                                     GObject.TYPE_STRING))
    }

    paned_pos = GObject.property(type=str)

    min_paned_pos = 100

    def __init__(self, button_box, stack, info_paned, source):
        GObject.GObject.__init__(self)

        self.ds = {}
        self.view = {}

        # self.buttons = button_box
        self.source = source
        self.plugin = source.plugin
        self.shell = source.shell
        self.info_paned = info_paned
        self.current_artist = None
        self.current_album_title = None
        self.current = 'artist'
        self._from_paned_handle = 0

        self.stack = stack
        self.stack.set_transition_type(
            Gtk.StackTransitionType.SLIDE_LEFT_RIGHT)
        stack_switcher = Gtk.StackSwitcher()
        stack_switcher.set_stack(self.stack)
        self.stack.connect('notify::visible-child-name', self.change_stack)
        button_box.pack_start(stack_switcher, False, False, 0)
        button_box.show_all()

        # cache for artist/album information: valid for a month, can be used indefinitely
        # if offline, discarded if unused for six months
        self.info_cache = rb.URLCache(name='info',
                                      path=os.path.join(
                                          'coverart_browser', 'info'),
                                      refresh=30,
                                      discard=180)
        # cache for rankings (artist top tracks and top albums): valid for a week,
        # can be used for a month if offline
        self.ranking_cache = rb.URLCache(name='ranking',
                                         path=os.path.join(
                                             'coverart_browser', 'ranking'),
                                         refresh=7,
                                         lifetime=30)

        self.info_cache.clean()
        self.ranking_cache.clean()

        self.ds['link'] = LinksDataSource()
        self.ds['artist'] = ArtistDataSource(self.info_cache,
                                             self.ranking_cache)

        self.view['artist'] = ArtistInfoView()
        self.view['artist'].initialise(self.source, self.shell, self.plugin,
                                       self.stack, self.ds['artist'],
                                       self.ds['link'])

        self.ds['album'] = AlbumDataSource(self.info_cache, self.ranking_cache)
        self.view['album'] = AlbumInfoView()
        self.view['album'].initialise(self.source, self.shell, self.plugin,
                                      self.stack, self.ds['album'])

        self.ds['echoartist'] = EchoArtistDataSource(self.info_cache,
                                                     self.ranking_cache)
        self.view['echoartist'] = EchoArtistInfoView()
        self.view['echoartist'].initialise(self.source, self.shell,
                                           self.plugin, self.stack,
                                           self.ds['echoartist'],
                                           self.ds['link'])

        self.gs = GSetting()
        self.connect_properties()
        self.connect_signals()
        Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 50,
                                self._change_paned_pos,
                                self.source.viewmgr.view_name)
        self.view[self.current].activate()

    def connect_properties(self):
        '''
        Connects the source properties to the saved preferences.
        '''
        setting = self.gs.get_setting(self.gs.Path.PLUGIN)

        setting.bind(self.gs.PluginKey.ARTIST_INFO_PANED_POSITION, self,
                     'paned-pos', Gio.SettingsBindFlags.DEFAULT)

    def connect_signals(self):
        self.tab_cb_ids = []

        # Listen for switch-tab signal from each tab
        '''
        for key, value in self.tab.items():
            self.tab_cb_ids.append(( key, 
                                    self.tab[key].connect ('switch-tab', 
                                                            self.change_tab)
                                    ))
        '''

        # Listen for selected signal from the views
        self.connect('selected', self.select_artist)

        # lets remember info paned click
        self.info_paned.connect('button_press_event',
                                self.paned_button_press_callback)
        self.info_paned.connect('button-release-event',
                                self.paned_button_release_callback)

        # lets also listen for changes to the view to set the paned position
        self.source.viewmgr.connect('new-view', self.on_view_changed)

    def on_view_changed(self, widget, view_name):
        self._change_paned_pos(view_name)

    def _change_paned_pos(self, view_name):
        print(self.paned_pos)
        paned_positions = eval(self.paned_pos)

        found = None
        for viewpos in paned_positions:
            if view_name in viewpos:
                found = viewpos
                break

        if not found:
            return

        values = found.split(":")
        child_width = int(values[1])

        open_type = "closed"
        if len(values) > 2:
            open_type = values[2]
        elif child_width > 0:
            open_type = "opened"

        if open_type == "closed":
            child_width = 0

        calc_pos = self.source.page.get_allocated_width() - child_width
        self.info_paned.set_position(calc_pos)
        self.info_paned.set_visible(True)

    def _get_child_width(self):
        child = self.info_paned.get_child2()
        return child.get_allocated_width()

    def paned_button_press_callback(self, widget, event):
        print('paned_button_press_callback')
        self._from_paned_handle = 1

        if event.type == Gdk.EventType._2BUTTON_PRESS:
            self._from_paned_handle = 2

    def paned_button_release_callback(self, *args):
        '''
        Callback when the artist paned handle is released from its mouse click.
        '''
        if self._from_paned_handle == 0:
            return False

        print("paned_button_release_callback")

        paned_positions = eval(self.paned_pos)

        found = None
        for viewpos in paned_positions:
            if self.source.viewmgr.view_name in viewpos:
                found = viewpos
                break

        if not found:
            print("cannot find")
            return True

        values = found.split(':')

        child_width = self.source.page.get_allocated_width(
        ) - self.info_paned.get_position()
        print(child_width)
        open_type = "closed"
        print(values)
        if len(values) > 2:
            open_type = values[2]

        if child_width <= self.min_paned_pos and \
                        self._from_paned_handle == 1 and \
                        open_type == "closed":
            # we are dealing with a situation where the pane is already closed
            # or almost closed - just shut the door
            print("we are closed")
            calc_pos = self.source.page.get_allocated_width()
            self.info_paned.set_position(calc_pos)
            return False

        open_type = "closed"
        paned_positions.remove(found)

        if self._from_paned_handle == 2:
            # we are dealing with a double click situation
            new_width = child_width
            if new_width <= self.min_paned_pos:
                if int(values[1]) == 0:
                    new_width = self.min_paned_pos + 1
                else:
                    new_width = int(values[1])

                open_type = "opened"
                child_width = new_width
            else:
                new_width = 0

            calc_pos = self.source.page.get_allocated_width() - new_width

            self.info_paned.set_position(calc_pos)

        if child_width <= self.min_paned_pos and self._from_paned_handle == 1:
            if int(values[1]) == 0:
                child_width = self.min_paned_pos + 1
                open_type = "opened"
            else:
                child_width = 0

            calc_pos = self.source.page.get_allocated_width() - child_width
            self.info_paned.set_position(calc_pos)

        if self._from_paned_handle == 1 and child_width != 0:
            open_type = "opened"

        paned_positions.append(self.source.viewmgr.view_name + \
                               ":" + \
                               str(child_width) + \
                               ":" + \
                               open_type)

        self.paned_pos = repr(paned_positions)

        self._from_paned_handle = 0
        print("End artist_info_paned_button_release_callback")

    def select_artist(self, widget, artist, album_title):
        print("artist %s title %s" % (artist, album_title))
        if self._get_child_width() > self.min_paned_pos:
            self.view[self.current].reload(artist, album_title)
        else:
            self.view[self.current].blank_view()

        self.current_album_title = album_title
        self.current_artist = artist

    def change_stack(self, widget, value):
        child_name = self.stack.get_visible_child_name()
        if child_name and self.current != child_name:
            self.view[self.current].deactivate()
            if self._get_child_width() > self.min_paned_pos:
                self.view[child_name].activate(self.current_artist,
                                               self.current_album_title)
            else:
                self.view[child_name].blank_view()

            self.current = child_name