-###--------------------------------------------------------------------------
-### Miscellaneous utilities.
-
-def fetch_url(url):
- """Fetch the resource named by URL, returning its content as a string."""
- out = StringIO()
- with U.urlopen(url) as u:
- while True:
- stuff = u.read(16384)
- if not stuff: break
- out.write(stuff)
- return out.getvalue()
-
-def fix_background(w):
- """Hack the style of the window W so that it shows white-on-black."""
- style = w.get_style().copy()
- style.base[GTK.STATE_NORMAL] = BLACK
- style.bg[GTK.STATE_NORMAL] = BLACK
- style.text[GTK.STATE_NORMAL] = WHITE
- w.set_style(style)
-
-###--------------------------------------------------------------------------
-### The windows.
-
-class BaseCoverViewer (GTK.ScrolledWindow):
- """
- I represent a viewer for a collection of cover images, shown as thumbnails.
-
- The image objects should have the following attributes.
-
- img The actual image, as a CacheableImage.
-
- text Some text to associate with the image, as a Python
- string.
-
- I will store an `iterator' in the image object's `it' attribute, which will
- let others identify it later to the underlying Gtk machinery.
-
- Subclasses should implement two methods:
-
- activate(COVER) The COVER has been activated by the user (e.g.,
- double-clicked).
-
- select(COVER) The COVER has been selected by the user (e.g.,
- clicked) in a temporary manner; if COVER is None,
- then a previously selected cover has become
- unselected.
- """
-
- ## Useful attributes:
- ## iv = an IconView widget used to show the thumbnails
- ## list = a ListStore object used to keep track of the cover images; each
- ## item is a list of the form [PIXBUF, TEXT, COVER], where the PIXBUF
- ## and TEXT are extracted from the cover object in the obvious way
-
- def __init__(me):
- """Initialize a BaseCoverViewer."""
-
- ## Initialize myself, as a scrollable thingy.
- GTK.ScrolledWindow.__init__(me)
- me.set_policy(GTK.POLICY_AUTOMATIC, GTK.POLICY_AUTOMATIC)
-
- ## Set up an IconView to actually show the cover thumbnails.
- me.iv = GTK.IconView()
- me.iv.connect('item-activated',
- lambda iv, p: me.activate(me._frompath(p)))
- me.iv.connect('selection-changed', me._select)
- me.iv.set_pixbuf_column(0)
- me.iv.set_text_column(1)
- me.iv.set_orientation(GTK.ORIENTATION_VERTICAL)
- me.iv.set_item_width(THUMBSZ + 32)
- fix_background(me.iv)
- me.add(me.iv)
-
- ## Clear the list ready for cover images to be added.
- me.reset()
-
- def reset(me):
- """
- Clear the viewer of cover images.
-
- This does /not/ clear the `it' attribute of previously attached cover
- object.
- """
- me.list = GTK.ListStore(GDK.Pixbuf, G.TYPE_STRING, G.TYPE_PYOBJECT)
- me.iv.set_model(me.list)
- me.iv.unselect_all()
-
- def addcover(me, cov):
- """
- Add the cover image COV to the viewer.
-
- `COV.it' is filled in with the object's iterator.
- """
- cov.it = me.list.append([cov.img.thumbnail.pixbuf, cov.text, cov])
-
- def _frompath(me, path):
- """Convert a PATH to a cover image, and return it."""
- return me.list[path][2]
-
- def _select(me, iv):
- """Handle a selection event, calling the subclass `select' method."""
- sel = me.iv.get_selected_items()
- if len(sel) != 1: me.select(None)
- else: me.select(me._frompath(sel[0]))
-
-class SearchCover (object):
- """
- A base class for images in the SearchViewer window.
- """
- def __init__(me, img, width = None, height = None, marker = ''):
- """
- Initialize a SearchCover object.
-
- The IMG is a CacheableImage of some kind. If the WIDTH and HEIGHT are
- omitted, the image data will be acquired and both dimensions calculated
- (since, after all, if we have to go to the bother of fetching the image,
- we may as well get an accurate size).
- """
- me.img = img
- if width is None or height is None:
- pix = img.pixbuf
- width = pix.get_width()
- height = pix.get_height()
- me.text = '%d×%d%s' % (width, height, marker)
-
-class SearchViewer (BaseCoverViewer):
- """
- I'm a BaseCoverViewer subclass for showing search results.
-
- I'll be found within a CoverChooser window, showing the thumbnails
- resulting from a search. I need to keep track of my parent CoverChooser,
- so that I can tell it to show a large version of a selected image.
- """
-
- ## Useful attributes:
- ## _chooser = the containing CoverChooser object
-
- def __init__(me, chooser):
- """
- Initialize the SearchViewer, associating it with its parent CoverChooser.
- """
- BaseCoverViewer.__init__(me)
- me._chooser = chooser
-
- def switch(me, current):
- """
- Switch to a different album chosen in the CoverChooser.
-
- CURRENT is either None, in which case the viewer is simply cleared, or
- the current cover image (some CacheableImage object) for the newly chosen
- album, which should be shown as the initial selection.
- """
- me.reset()
- if current:
- cov = SearchCover(current, marker = '*')
- me.addcover(cov)
- me.iv.select_path(me.list.get_path(cov.it))
-
- def activate(me, cov):
- """Inform the CoverChooser that the user activated COV."""
- me._chooser.activated(cov)
-
- def select(me, cov):
- """Inform the CoverChooser that the user selected COV."""
- me._chooser.selected(cov)
-