CoverArt Browser  v2.0
Browse your cover-art albums in Rhythmbox
/home/foss/Downloads/coverart-browser/coverart_covericonview.py
00001 # -*- Mode: python; coding: utf-8; tab-width: 4; indent-tabs-mode: nil; -*-
00002 #
00003 # Copyright (C) 2012 - fossfreedom
00004 # Copyright (C) 2012 - Agustin Carrasco
00005 #
00006 # This program is free software; you can redistribute it and/or modify
00007 # it under the terms of the GNU General Public License as published by
00008 # the Free Software Foundation; either version 2, or (at your option)
00009 # any later version.
00010 #
00011 # This program is distributed in the hope that it will be useful,
00012 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 # GNU General Public License for more details.
00015 #
00016 # You should have received a copy of the GNU General Public License
00017 # along with this program; if not, write to the Free Software
00018 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
00019 
00020 from gi.repository import Gdk
00021 from gi.repository import Gtk
00022 from gi.repository import GLib
00023 from gi.repository import GObject
00024 from gi.repository import Gio
00025 from gi.repository import Pango
00026 from gi.repository import PangoCairo
00027 from gi.repository import GdkPixbuf
00028 
00029 from coverart_widgets import EnhancedIconView
00030 from coverart_browser_prefs import GSetting
00031 from coverart_browser_prefs import CoverLocale
00032 from coverart_album import AlbumsModel
00033 from coverart_widgets import AbstractView
00034 from coverart_widgets import PanedCollapsible
00035 import coverart_rb3compat as rb3compat
00036 import rb
00037 import gettext
00038 
00039 PLAY_SIZE_X = 30
00040 PLAY_SIZE_Y = 30
00041 
00042 
00043 class CellRendererThumb(Gtk.CellRendererPixbuf):
00044     markup = GObject.property(type=str, default="")
00045 
00046     def __init__(self, font_description, cell_area_source):
00047         super(CellRendererThumb, self).__init__()
00048         self.font_description = font_description
00049         self.cell_area_source = cell_area_source
00050         ypad = 0
00051 
00052     def do_render(self, cr, widget,
00053                   background_area,
00054                   cell_area,
00055                   flags):
00056 
00057 
00058         x_offset = cell_area.x + 1
00059         y_offset = cell_area.y + 1
00060         wi = 0
00061         he = 0
00062         #IMAGE
00063         pixbuf = self.props.pixbuf.scale_simple(cell_area.width - 2, cell_area.height - 2,
00064                                                 GdkPixbuf.InterpType.NEAREST)
00065         Gdk.cairo_set_source_pixbuf(cr, pixbuf, x_offset, y_offset)
00066         cr.paint()
00067 
00068         alpha = 0.40
00069 
00070         if ((flags & Gtk.CellRendererState.PRELIT) == Gtk.CellRendererState.PRELIT):
00071             alpha -= 0.15
00072 
00073             if hasattr(Gtk.IconView, "get_cell_rect") and self.cell_area_source.hover_pixbuf:
00074                 # this only works on Gtk+3.6 and later
00075                 Gdk.cairo_set_source_pixbuf(cr,
00076                                             self.cell_area_source.hover_pixbuf, x_offset, y_offset)
00077                 cr.paint()
00078 
00079         #if((flags & Gtk.CellRendererState.SELECTED) == Gtk.CellRendererState.SELECTED or \
00080         #   (flags & Gtk.CellRendererState.FOCUSED) == Gtk.CellRendererState.FOCUSED):
00081         #    alpha -= 0.15
00082 
00083 
00084         if not (self.cell_area_source.display_text and self.cell_area_source.display_text_pos == False):
00085             return
00086 
00087         #PANGO LAYOUT
00088         layout_width = cell_area.width - 2
00089         pango_layout = PangoCairo.create_layout(cr)
00090         pango_layout.set_markup(self.markup, -1)
00091         pango_layout.set_alignment(Pango.Alignment.CENTER)
00092         pango_layout.set_font_description(self.font_description)
00093         pango_layout.set_width(int(layout_width * Pango.SCALE))
00094         pango_layout.set_wrap(Pango.WrapMode.WORD_CHAR)
00095         wi, he = pango_layout.get_pixel_size()
00096 
00097         rect_offset = y_offset + (int((2.0 * self.cell_area_source.cover_size) / 3.0))
00098         rect_height = int(self.cell_area_source.cover_size / 3.0)
00099         was_to_large = False;
00100         if (he > rect_height):
00101             was_to_large = True
00102             pango_layout.set_ellipsize(Pango.EllipsizeMode.END)
00103             pango_layout.set_height(int((self.cell_area_source.cover_size / 3.0) * Pango.SCALE))
00104             wi, he = pango_layout.get_pixel_size()
00105 
00106         #RECTANGLE
00107         cr.set_source_rgba(0.0, 0.0, 0.0, alpha)
00108         cr.set_line_width(0)
00109         cr.rectangle(x_offset,
00110                      rect_offset,
00111                      cell_area.width - 1,
00112                      rect_height - 1)
00113         cr.fill()
00114 
00115         #DRAW FONT
00116         cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
00117         cr.move_to(x_offset,
00118                    y_offset
00119                    + 2.0 * self.cell_area_source.cover_size / 3.0
00120                    + (((self.cell_area_source.cover_size / 3.0) - he) / 2.0)
00121         )
00122         PangoCairo.show_layout(cr, pango_layout)
00123 
00124 
00125 class AlbumArtCellArea(Gtk.CellAreaBox):
00126     font_family = GObject.property(type=str, default="Sans")
00127     font_size = GObject.property(type=int, default=10)
00128     cover_size = GObject.property(type=int, default=0)
00129     display_text_pos = GObject.property(type=bool, default=False)
00130     display_text = GObject.property(type=bool, default=False)
00131     hover_pixbuf = GObject.property(type=object, default=None)
00132 
00133     def __init__(self, ):
00134         super(AlbumArtCellArea, self).__init__()
00135 
00136         self.font_description = Pango.FontDescription.new()
00137         self.font_description.set_family(self.font_family)
00138         self.font_description.set_size(int(self.font_size * Pango.SCALE))
00139 
00140         self._connect_properties()
00141 
00142         #Add own cellrenderer
00143         renderer_thumb = CellRendererThumb(self.font_description, self)
00144 
00145         self.pack_start(renderer_thumb, False, False, False)
00146         self.attribute_connect(renderer_thumb, "pixbuf", AlbumsModel.columns['pixbuf'])
00147         self.attribute_connect(renderer_thumb, "markup", AlbumsModel.columns['markup'])
00148         self.props.spacing = 2
00149 
00150     def _connect_properties(self):
00151         gs = GSetting()
00152         setting = gs.get_setting(gs.Path.PLUGIN)
00153 
00154         setting.bind(gs.PluginKey.COVER_SIZE, self, 'cover-size',
00155                      Gio.SettingsBindFlags.GET)
00156 
00157         setting.bind(gs.PluginKey.DISPLAY_TEXT_POS, self, 'display-text-pos',
00158                      Gio.SettingsBindFlags.GET)
00159 
00160         setting.bind(gs.PluginKey.DISPLAY_TEXT, self, 'display-text',
00161                      Gio.SettingsBindFlags.GET)
00162 
00163 
00164 class AlbumShowingPolicy(GObject.Object):
00165     '''
00166     Policy that mostly takes care of how and when things should be showed on
00167     the view that makes use of the `AlbumsModel`.
00168     '''
00169 
00170     def __init__(self, cover_view):
00171         super(AlbumShowingPolicy, self).__init__()
00172 
00173         self._cover_view = cover_view  # this will need to be reworked for all views
00174         self._visible_paths = None
00175         self._has_initialised = False
00176 
00177     def initialise(self, album_manager):
00178         if self._has_initialised:
00179             return
00180 
00181         self._album_manager = album_manager
00182         self._model = album_manager.model
00183         self._connect_signals()
00184         self._has_initialised = True
00185 
00186     def _connect_signals(self):
00187         self._cover_view.props.vadjustment.connect('value-changed',
00188                                                    self._viewport_changed)
00189         self._model.connect('album-updated', self._album_updated)
00190         self._model.connect('visual-updated', self._album_updated)
00191 
00192     def _viewport_changed(self, *args):
00193         visible_range = self._cover_view.get_visible_range()
00194 
00195         if visible_range:
00196             init, end = visible_range
00197 
00198             # i have to use the tree iter instead of the path to iterate since
00199             # for some reason path.next doesn't work with the filtermodel
00200             tree_iter = self._model.store.get_iter(init)
00201 
00202             self._visible_paths = []
00203 
00204             while init and init != end:
00205                 self._visible_paths.append(init)
00206 
00207                 tree_iter = self._model.store.iter_next(tree_iter)
00208                 init = self._model.store.get_path(tree_iter)
00209 
00210             self._visible_paths.append(end)
00211 
00212     def _album_updated(self, model, album_path, album_iter):
00213         # get the currently showing paths
00214         if not self._visible_paths:
00215             self._viewport_changed()
00216 
00217         if (album_path and self._visible_paths) and album_path in self._visible_paths:
00218             # if our path is on the viewport, emit the signal to update it
00219             self._cover_view.queue_draw()
00220 
00221 
00222 class CoverIconView(EnhancedIconView, AbstractView):
00223     __gtype_name__ = "CoverIconView"
00224 
00225     icon_spacing = GObject.property(type=int, default=0)
00226     icon_padding = GObject.property(type=int, default=0)
00227     icon_automatic = GObject.property(type=bool, default=True)
00228 
00229     display_text_enabled = GObject.property(type=bool, default=False)
00230     display_text_pos = GObject.property(type=bool, default=False)
00231     name = 'coverview'
00232     panedposition = PanedCollapsible.Paned.COLLAPSE
00233 
00234     __gsignals__ = {
00235         'update-toolbar': (GObject.SIGNAL_RUN_LAST, None, ())
00236     }
00237 
00238 
00239     def __init__(self, *args, **kwargs):
00240         if not rb3compat.compare_pygobject_version("3.9"):
00241             super(CoverIconView, self).__init__(cell_area=AlbumArtCellArea(), *args, **kwargs)
00242         else:
00243             # this works in trusty but not in earlier versions - define in the super above
00244             super(CoverIconView, self).__init__(*args, **kwargs)
00245             self.props.cell_area = AlbumArtCellArea()
00246 
00247         self.gs = GSetting()
00248         # custom text renderer
00249         self._text_renderer = None
00250         self.show_policy = AlbumShowingPolicy(self)
00251         self.view = self
00252         self._has_initialised = False
00253         self._last_path = None
00254         self._calc_motion_step = 0
00255 
00256     def initialise(self, source):
00257         if self._has_initialised:
00258             return
00259 
00260         self._has_initialised = True
00261 
00262         self.view_name = "covers_view"
00263         super(CoverIconView, self).initialise(source)
00264 
00265         self.shell = source.shell
00266         self.album_manager = source.album_manager
00267 
00268         # setup iconview drag&drop support
00269         # first drag and drop on the coverart view to receive coverart
00270         self.enable_model_drag_dest([], Gdk.DragAction.COPY)
00271         self.drag_dest_add_image_targets()
00272         self.drag_dest_add_text_targets()
00273         self.connect('drag-drop', self.on_drag_drop)
00274         self.connect('drag-data-received',
00275                      self.on_drag_data_received)
00276         self.source.paned.connect("expanded", self.bottom_expander_expanded_callback)
00277 
00278         # lastly support drag-drop from coverart to devices/nautilus etc
00279         self.connect('drag-begin', self.on_drag_begin)
00280         self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK,
00281             [], Gdk.DragAction.COPY)
00282         #targets = Gtk.TargetList.new([Gtk.TargetEntry.new("application/x-rhythmbox-entry", 0, 0),
00283         #    Gtk.TargetEntry.new("text/uri-list", 0, 1) ])
00284         targets = Gtk.TargetList.new([Gtk.TargetEntry.new("text/uri-list", 0, 0)])
00285         # N.B. values taken from rhythmbox v2.97 widgets/rb_entry_view.c
00286         targets.add_uri_targets(1)
00287 
00288         self.drag_source_set_target_list(targets)
00289         self.connect("drag-data-get", self.on_drag_data_get)
00290 
00291         # set the model to the view
00292         #self.set_pixbuf_column(AlbumsModel.columns['pixbuf'])
00293         self.set_model(self.album_manager.model.store)
00294 
00295         # setup view to monitor mouse movements
00296         self.add_events(Gdk.EventMask.POINTER_MOTION_MASK)
00297 
00298         self.hover_pixbufs = {
00299             'button_play': None,
00300             'button_play_hover': None,
00301             'button_playpause': None,
00302             'button_playpause_hover': None,
00303             'button_queue': None,
00304             'button_queue_hover': None,
00305             }
00306 
00307         for pixbuf_type in self.hover_pixbufs:
00308             filename = 'img/' + pixbuf_type + '.png'
00309             filename = rb.find_plugin_file(self.plugin, filename)
00310             self.hover_pixbufs[pixbuf_type] = GdkPixbuf.Pixbuf.new_from_file_at_size(filename,
00311                                                                                      PLAY_SIZE_X, PLAY_SIZE_Y)
00312 
00313         self._connect_properties()
00314         self._connect_signals()
00315 
00316         self._activate_markup()
00317         self.on_notify_icon_padding()
00318         self.on_notify_icon_spacing()
00319 
00320     def _connect_properties(self):
00321         setting = self.gs.get_setting(self.gs.Path.PLUGIN)
00322         setting.bind(
00323             self.gs.PluginKey.ICON_SPACING,
00324             self,
00325             'icon_spacing',
00326             Gio.SettingsBindFlags.GET)
00327         setting.bind(
00328             self.gs.PluginKey.ICON_PADDING,
00329             self,
00330             'icon_padding',
00331             Gio.SettingsBindFlags.GET)
00332 
00333         setting.bind(self.gs.PluginKey.DISPLAY_TEXT, self,
00334                      'display_text_enabled', Gio.SettingsBindFlags.GET)
00335 
00336         setting.bind(self.gs.PluginKey.ICON_AUTOMATIC, self,
00337                      'icon_automatic', Gio.SettingsBindFlags.GET)
00338 
00339         setting.bind(self.gs.PluginKey.DISPLAY_TEXT_POS, self,
00340                      'display-text-pos', Gio.SettingsBindFlags.GET)
00341 
00342     def _connect_signals(self):
00343         self.connect("item-clicked", self.item_clicked_callback)
00344         self.connect("selection-changed", self.selectionchanged_callback)
00345         self.connect("item-activated", self.item_activated_callback)
00346         self.connect('notify::icon-spacing',
00347                      self.on_notify_icon_spacing)
00348         self.connect('notify::icon-padding',
00349                      self.on_notify_icon_padding)
00350         self.connect('notify::display-text-enabled',
00351                      self._activate_markup)
00352         self.connect('notify::display-text-pos',
00353                      self._activate_markup)
00354         self.connect("motion-notify-event", self.on_pointer_motion)
00355 
00356     def get_view_icon_name(self):
00357         return "iconview.png"
00358 
00359     def resize_icon(self, cover_size):
00360         '''
00361         Callback called when to resize the icon
00362         [common to all views]
00363         '''
00364         self.set_item_width(cover_size)
00365 
00366     def on_drag_drop(self, widget, context, x, y, time):
00367         '''
00368         Callback called when a drag operation finishes over the cover view
00369         of the source. It decides if the dropped item can be processed as
00370         an image to use as a cover.
00371         '''
00372 
00373         # stop the propagation of the signal (deactivates superclass callback)
00374         widget.stop_emission_by_name('drag-drop')
00375 
00376         # obtain the path of the icon over which the drag operation finished
00377         path, pos = widget.get_dest_item_at_pos(x, y)
00378         result = path is not None
00379 
00380         if result:
00381             target = self.drag_dest_find_target(context, None)
00382             widget.drag_get_data(context, target, time)
00383 
00384         return result
00385 
00386     def on_drag_data_received(self, widget, drag_context, x, y, data, info,
00387                               time):
00388         '''
00389         Callback called when the drag source has prepared the data (pixbuf)
00390         for us to use.
00391         '''
00392 
00393         # stop the propagation of the signal (deactivates superclass callback)
00394         widget.stop_emission_by_name('drag-data-received')
00395 
00396         # get the album and the info and ask the loader to update the cover
00397         path, pos = widget.get_dest_item_at_pos(x, y)
00398         album = widget.get_model()[path][2]
00399 
00400         pixbuf = data.get_pixbuf()
00401 
00402         if pixbuf:
00403             self.album_manager.cover_man.update_cover(album, pixbuf)
00404         else:
00405             uri = data.get_text()
00406             self.album_manager.cover_man.update_cover(album, uri=uri)
00407 
00408         # call the context drag_finished to inform the source about it
00409         drag_context.finish(True, False, time)
00410 
00411 
00412     def on_drag_data_get(self, widget, drag_context, data, info, time):
00413         '''
00414         Callback called when the drag destination (playlist) has
00415         requested what album (icon) has been dragged
00416         '''
00417 
00418         uris = []
00419         for album in widget.get_selected_objects():
00420             for track in album.get_tracks():
00421                 uris.append(track.location)
00422 
00423         sel = data.set_uris(uris)
00424         # stop the propagation of the signal (deactivates superclass callback)
00425         widget.stop_emission_by_name('drag-data-get')
00426 
00427     def on_drag_begin(self, widget, context):
00428         '''
00429         Callback called when the drag-drop from coverview has started
00430         Changes the drag icon as appropriate
00431         '''
00432         album_number = len(widget.get_selected_objects())
00433 
00434         if album_number == 1:
00435             item = Gtk.STOCK_DND
00436         else:
00437             item = Gtk.STOCK_DND_MULTIPLE
00438 
00439         widget.drag_source_set_icon_stock(item)
00440         widget.stop_emission_by_name('drag-begin')
00441 
00442     def _cover_play_hotspot(self, path, in_vacinity=False):
00443         if path:
00444             valid, rect = self.get_cell_rect(path, None)  # rect of widget coords
00445 
00446             cursor_x, cursor_y = self.get_pointer()  # returns widget coords
00447             c_x = cursor_x - rect.x - (self.icon_padding / 2) - (self.icon_spacing / 2)
00448             c_y = cursor_y - rect.y - (self.icon_padding / 2) - (self.icon_spacing / 2)
00449 
00450             sizing = (rect.width / 2) if in_vacinity else 0
00451 
00452             if c_x < (PLAY_SIZE_X + sizing) and \
00453                             c_y < (PLAY_SIZE_Y + sizing) and \
00454                             c_x > 0 and \
00455                             c_y > 0:
00456                 return True
00457 
00458         return False
00459 
00460     def on_pointer_motion(self, widget, event):
00461         self._current_mouse_x = event.x
00462         self._current_mouse_y = event.y
00463 
00464         if self._calc_motion_step == 0:
00465             self._calc_motion_step = 1
00466             Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 100,
00467                                     self._calculate_hotspot)
00468         else:
00469             path = self.get_path_at_pos(self._current_mouse_x,
00470                                     self._current_mouse_y)
00471 
00472             if not self._last_path or self._last_path != path:
00473                 self._display_icon(None, self._last_path)
00474 
00475     def _display_icon(self, icon, path):
00476         self.props.cell_area.hover_pixbuf = icon
00477         if path:
00478             valid, rect = self.get_cell_rect(path, None)
00479             self.props.window.invalidate_rect(rect, True)
00480 
00481         self.queue_draw()
00482 
00483     def _calculate_hotspot(self, *args):
00484 
00485         path = self.get_path_at_pos(self._current_mouse_x,
00486                                     self._current_mouse_y)
00487 
00488         # if the current path was not the same as the last path then
00489         # reset the counter
00490         if not self._last_path or self._last_path != path:
00491             self._display_icon(None, self._last_path)
00492             self._last_path = path
00493             self._calc_motion_step = 0
00494             return False
00495 
00496         self._calc_motion_step = self._calc_motion_step + 1
00497 
00498         # if havent yet reached the requisite number of steps then
00499         # let the thread roll to the next increment
00500         if self._calc_motion_step < 8:
00501             return True
00502 
00503         if not self._cover_play_hotspot(path, in_vacinity = True):
00504             # we are not near the hot-spot so decrement the counter
00505             # hoping next time around we are near
00506             self._calc_motion_step = self._calc_motion_step - 1
00507             self._display_icon(None, self._last_path)
00508             return True
00509 
00510         # from  here on in, we are going to display a hotspot icon
00511         # so lets decide which one
00512 
00513         (_, playing) = self.shell.props.shell_player.get_playing()
00514 
00515         calc_path = -1
00516         if playing:
00517             entry = self.shell.props.shell_player.get_playing_entry()
00518             album = self.album_manager.model.get_from_dbentry(entry)
00519             calc_path = self.album_manager.model.get_path(album)
00520 
00521         if playing and calc_path == path:
00522             icon = 'button_playpause'
00523         elif playing:
00524             icon = 'button_queue'
00525         else:
00526             icon = 'button_play'
00527 
00528         # now we've got the icon - lets double check that we are
00529         # actually hovering exactly on the hotspot because the icon will visually change
00530 
00531         exact_hotspot = self._cover_play_hotspot(path)
00532         if exact_hotspot:
00533             icon = icon + '_hover'
00534 
00535         hover = self.hover_pixbufs[icon]
00536 
00537         self._display_icon(hover, path)
00538         self._calc_motion_step = self._calc_motion_step - 1
00539 
00540         return True
00541 
00542     def item_clicked_callback(self, iconview, event, path):
00543         '''
00544         Callback called when the user clicks somewhere on the cover_view.
00545         Along with source "show_hide_pane", takes care of showing/hiding the bottom
00546         pane after a second click on a selected album.
00547         '''
00548 
00549         # first test if we've clicked on the cover-play icon
00550         if self._cover_play_hotspot(path):
00551             (_, playing) = self.shell.props.shell_player.get_playing()
00552 
00553             # first see if anything is playing...
00554             if playing:
00555                 entry = self.shell.props.shell_player.get_playing_entry()
00556                 album = self.album_manager.model.get_from_dbentry(entry)
00557 
00558                 # if the current playing entry corresponds to the album
00559                 # we are hovering over then we are requesting to pause
00560                 if self.album_manager.model.get_from_path(path) == album:
00561                     self._last_path = path
00562                     self.shell.props.shell_player.pause()
00563                     self.on_pointer_motion(self, event)
00564                     return
00565 
00566             # this must be a new album so we are asking just
00567             # to play this new album ... just need a short interval
00568             # for the selection event to kick in first
00569             def delay(*args):
00570                 if playing:  # if we are playing then queue up the next album
00571                     self.source.queue_selected_album(None, self.source.favourites)
00572                     album = self.get_selected_objects()[0]
00573                     cl = CoverLocale()
00574                     cl.switch_locale(cl.Locale.LOCALE_DOMAIN)
00575                     message  = gettext.gettext('Album has added to list of playing albums')
00576                     self.display_notification(album.name,
00577                                             message,
00578                                             album.cover.original)
00579                 else:  # otherwise just play it
00580                     self._last_path = path
00581                     self.source.play_selected_album(self.source.favourites)
00582 
00583                 icon = 'button_play_hover'
00584                 self.props.cell_area.hover_pixbuf = \
00585                     self.hover_pixbufs[icon]
00586 
00587             Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
00588                                     delay, None)
00589 
00590             return
00591 
00592         # to expand the entry view
00593         ctrl = event.state & Gdk.ModifierType.CONTROL_MASK
00594         shift = event.state & Gdk.ModifierType.SHIFT_MASK
00595 
00596         if self.icon_automatic:
00597             self.source.click_count += 1 if not ctrl and not shift else 0
00598 
00599         if self.source.click_count == 1:
00600             album = self.album_manager.model.get_from_path(path) \
00601                 if path else None
00602             Gdk.threads_add_timeout(GLib.PRIORITY_DEFAULT_IDLE, 250,
00603                                     self.source.show_hide_pane, album)
00604 
00605     def item_activated_callback(self, iconview, path):
00606         '''
00607         Callback called when the cover view is double clicked or space-bar
00608         is pressed. It plays the selected album
00609         '''
00610         self.source.play_selected_album(self.source.favourites)
00611 
00612         return True
00613 
00614     def on_notify_icon_padding(self, *args):
00615         '''
00616         Callback called when the icon-padding gsetting value is changed
00617         '''
00618         self.set_item_padding(self.icon_padding)
00619 
00620     def on_notify_icon_spacing(self, *args):
00621         '''
00622         Callback called when the icon-spacing gsetting value is changed
00623         '''
00624         self.set_row_spacing(self.icon_spacing)
00625         self.set_column_spacing(self.icon_spacing)
00626 
00627     def _create_and_configure_renderer(self):
00628         #Add own cellrenderer
00629         self._text_renderer = Gtk.CellRendererText()
00630 
00631         self._text_renderer.props.alignment = Pango.Alignment.CENTER
00632         self._text_renderer.props.wrap_mode = Pango.WrapMode.WORD
00633         self._text_renderer.props.xalign = 0.5
00634         self._text_renderer.props.yalign = 0
00635         self._text_renderer.props.width = \
00636             self.album_manager.cover_man.cover_size
00637         self._text_renderer.props.wrap_width = \
00638             self.album_manager.cover_man.cover_size
00639 
00640     def _activate_markup(self, *args):
00641         '''
00642         Utility method to activate/deactivate the markup text on the
00643         cover view.
00644         '''
00645         if self.display_text_enabled and self.display_text_pos:
00646             if not self._text_renderer:
00647                 # create and configure the custom cell renderer
00648                 self._create_and_configure_renderer()
00649 
00650             # set the renderer
00651             self.pack_end(self._text_renderer, False)
00652             self.add_attribute(self._text_renderer,
00653                                'markup', AlbumsModel.columns['markup'])
00654         elif self._text_renderer:
00655             # remove the cell renderer
00656             self.props.cell_area.remove(self._text_renderer)
00657 
00658         if self.display_text_enabled:
00659             self.set_tooltip_column(-1)  # turnoff tooltips
00660         else:
00661             self.set_tooltip_column(AlbumsModel.columns['tooltip'])
00662 
00663     def bottom_expander_expanded_callback(self, paned, expand):
00664         '''
00665         Callback connected to expanded signal of the paned GtkExpander
00666         '''
00667         if expand:
00668             # accommodate the viewport if there's an album selected
00669             if self.source.last_selected_album:
00670                 def scroll_to_album(*args):
00671                     # accommodate the viewport if there's an album selected
00672                     path = self.album_manager.model.get_path(
00673                         self.source.last_selected_album)
00674 
00675                     self.scroll_to_path(path, False, 0, 0)
00676 
00677                     return False
00678 
00679                 Gdk.threads_add_idle(GObject.PRIORITY_DEFAULT_IDLE,
00680                                      scroll_to_album, None)
00681 
00682 
00683     def switch_to_view(self, source, album):
00684         self.initialise(source)
00685         self.show_policy.initialise(source.album_manager)
00686 
00687         self.scroll_to_album(album)
00688 
00689     def grab_focus(self):
00690         super(EnhancedIconView, self).grab_focus()
 All Classes Functions