9b6300dea1cbf01ac153f29783066e4ef70b26a1
[jamaendo] / jamaui / ui.py
1 #!/usr/bin/env python
2 #
3 # This file is part of Jamaendo.
4 # Copyright (c) 2010 Kristoffer Gronlund
5 #
6 # Jamaendo is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
10 #
11 # Jamaendo is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Jamaendo.  If not, see <http://www.gnu.org/licenses/>.
18 #
19 # Player code heavily based on http://thpinfo.com/2008/panucci/:
20 #  A resuming media player for Podcasts and Audiobooks
21 #  Copyright (c) 2008-05-26 Thomas Perl <thpinfo.com>
22 #  (based on http://pygstdocs.berlios.de/pygst-tutorial/seeking.html)
23 #
24 # Jamaendo jamendo.com API wrapper licensed under the New BSD License;
25 # see module for details.
26 #
27
28 import os, sys
29 import gtk
30 import gobject
31 import util
32 import logging
33 from settings import settings
34
35 import ossohelper
36
37 gobject.threads_init()
38
39 log = logging.getLogger(__name__)
40
41 VERSION = '0.1'
42
43 try:
44     import hildon
45 except:
46     if util.platform == 'maemo':
47         log.critical('Using GTK widgets, install "python2.5-hildon" '
48             'for this to work properly.')
49     else:
50         log.critical('This ui only works in maemo')
51         sys.exit(1)
52
53 from dbus.mainloop.glib import DBusGMainLoop
54
55 DBusGMainLoop(set_as_default=True)
56
57 import jamaendo
58
59 from postoffice import postoffice
60 from playerwindow import open_playerwindow
61 from search import SearchWindow
62 from featured import FeaturedWindow
63 from radios import RadiosWindow
64 from favorites import FavoritesWindow
65
66 class PlaylistsWindow(hildon.StackableWindow):
67     def __init__(self):
68         hildon.StackableWindow.__init__(self)
69         self.set_title("Playlists")
70
71         label = gtk.Label("Playlists")
72         vbox = gtk.VBox(False, 0)
73         vbox.pack_start(label, True, True, 0)
74         self.add(vbox)
75
76 class Jamaui(object):
77     def __init__(self):
78         self.app = None
79         self.menu = None
80         self.window = None
81
82     def create_window(self):
83         log.debug("Creating main window...")
84         self.app = hildon.Program()
85         self.window = hildon.StackableWindow()
86         self.app.add_window(self.window)
87
88         self.window.set_title("jamaendo")
89
90         self.window.connect("destroy", self.destroy)
91
92         self.CONFDIR = os.path.expanduser('~/MyDocs/.jamaendo')
93         jamaendo.set_cache_dir(self.CONFDIR)
94         settings.set_filename(os.path.join(self.CONFDIR, 'ui_settings'))
95         settings.load()
96
97         postoffice.connect('request-album-cover', self, self.on_request_cover)
98         log.debug("Created main window.")
99
100     def save_settings(self):
101         settings.save()
102
103     def create_menu(self):
104         self.menu = hildon.AppMenu()
105
106         #search = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
107         #search.set_label("Search")
108         #search.connect("clicked", self.on_search)
109         #self.menu.append(search)
110
111         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
112         player.set_label("Open player")
113         player.connect("clicked", self.on_player)
114         self.menu.append(player)
115
116         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
117         player.set_label("Favorites")
118         player.connect("clicked", self.on_favorites)
119         self.menu.append(player)
120
121         #player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
122         #player.set_label("Playlists")
123         #player.connect("clicked", self.on_playlists)
124         #self.menu.append(player)
125
126         player = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
127         player.set_label("Settings")
128         player.connect("clicked", self.on_settings)
129         self.menu.append(player)
130
131
132         # Don't use localdb ATM
133         #refresh = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
134         #refresh.set_label("Refresh")
135         #refresh.connect("clicked", self.on_refresh)
136         #self.menu.append(refresh)
137
138         menu_about = hildon.GtkButton(gtk.HILDON_SIZE_AUTO)
139         menu_about.set_label("About")
140         menu_about.connect("clicked", self.show_about, self.window)
141         self.menu.append(menu_about)
142         gtk.about_dialog_set_url_hook(self.open_link, None)
143
144         self.menu.show_all()
145         self.window.set_app_menu(self.menu)
146
147
148     def setup_widgets(self):
149         bgimg = util.find_resource('bg.png')
150         if bgimg:
151             background, mask = gtk.gdk.pixbuf_new_from_file(bgimg).render_pixmap_and_mask()
152             self.window.realize()
153             self.window.window.set_back_pixmap(background, False)
154
155         bbox = gtk.HButtonBox()
156         alignment = gtk.Alignment(xalign=0.2, yalign=0.925, xscale=1.0)
157         alignment.add(bbox)
158         bbox.set_property('layout-style', gtk.BUTTONBOX_SPREAD)
159         self.bbox = bbox
160         self.window.add(alignment)
161
162         self.add_mainscreen_button("Featured", "Most listened to", self.on_featured)
163         self.add_mainscreen_button("Radios", "The best in free music", self.on_radios)
164         self.add_mainscreen_button("Search", "Search for artists/albums", self.on_search)
165
166         self.window.show_all()
167
168     def add_mainscreen_button(self, title, subtitle, callback):
169         btn = hildon.Button(gtk.HILDON_SIZE_THUMB_HEIGHT,
170                             hildon.BUTTON_ARRANGEMENT_VERTICAL)
171         btn.set_text(title, subtitle)
172         btn.set_property('width-request', 225)
173         btn.connect('clicked', callback)
174         self.bbox.add(btn)
175
176     def on_request_cover(self, albumid, size):
177         jamaendo.get_album_cover_async(self.got_album_cover, int(albumid), size)
178
179     def got_album_cover(self, albumid, size, cover):
180         postoffice.notify('album-cover', albumid, size, cover)
181
182     #def add_featured_button(self):
183     #    self.featured_sel = hildon.TouchSelector(text=True)
184     #    self.featured_sel.append_text("Albums of the week")
185     #    self.featured_sel.append_text("Tracks of the week")
186     #    self.featured_sel.append_text("New releases")
187     #    btn = hildon.PickerButton(gtk.HILDON_SIZE_THUMB_HEIGHT,
188     #                              hildon.BUTTON_ARRANGEMENT_VERTICAL)
189     #    btn.set_text("Featured", "Most listened to")
190     #    btn.set_property('width-request', 225)
191     #    btn.set_selector(self.featured_sel)
192     #    self.featured_btn = btn
193     #    self.bbox.add(btn)
194
195     def destroy(self, widget):
196         postoffice.disconnect('request-album-cover', self)
197         self.save_settings()
198         from player import the_player
199         if the_player:
200             the_player.stop()
201         gtk.main_quit()
202
203     def show_about(self, w, win):
204         dialog = gtk.AboutDialog()
205         dialog.set_program_name("jamaendo")
206         dialog.set_website("http://jamaendo.garage.maemo.org/")
207         dialog.set_website_label("http://jamaendo.garage.maemo.org/")
208         dialog.set_version(VERSION)
209         dialog.set_license("""Copyright (c) 2010, Kristoffer Gronlund
210 All rights reserved.
211
212 Redistribution and use in source and binary forms, with or without
213 modification, are permitted provided that the following conditions are met:
214      * Redistributions of source code must retain the above copyright
215        notice, this list of conditions and the following disclaimer.
216      * Redistributions in binary form must reproduce the above copyright
217        notice, this list of conditions and the following disclaimer in the
218        documentation and/or other materials provided with the distribution.
219      * Neither the name of Jamaendo nor the
220        names of its contributors may be used to endorse or promote products
221        derived from this software without specific prior written permission.
222
223 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
224 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
225 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
226 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
227 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
228 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
229 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
230 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
232 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
233 """)
234         dialog.set_authors(("Kristoffer Gronlund <kristoffer.gronlund@purplescout.se>",
235                             "Based on Panucci, written by Thomas Perl <thpinfo.com>"))
236         dialog.set_comments("""Jamaendo plays music from the music catalog of JAMENDO.
237
238 JAMENDO is an online platform that distributes musical works under Creative Commons licenses.""")
239         gtk.about_dialog_set_email_hook(self.open_link, dialog)
240         gtk.about_dialog_set_url_hook(self.open_link, dialog)
241         dialog.connect( 'response', lambda dlg, response: dlg.destroy())
242         for parent in dialog.vbox.get_children():
243             for child in parent.get_children():
244                 if isinstance(child, gtk.Label):
245                     child.set_selectable(False)
246                     child.set_alignment(0.0, 0.5)
247         dialog.run()
248         dialog.destroy()
249
250     def open_link(self, d, url, data):
251         #print "url: %s" % (url)
252         import webbrowser
253         webbrowser.open_new(url)
254
255
256     #def on_refresh(self, button):
257     #    dialog = RefreshDialog()
258     #    dialog.show_all()
259     #    dialog.run()
260     #    dialog.hide()
261
262     def on_featured(self, button):
263         dialog = hildon.PickerDialog(self.window)
264         sel = hildon.TouchSelector(text=True)
265         for feature, _ in FeaturedWindow.features:
266             sel.append_text(feature)
267         dialog.set_selector(sel)
268         dialog.set_title("Featured")
269         if dialog.run() == gtk.RESPONSE_OK:
270             txt = sel.get_current_text()
271             self.featuredwnd = FeaturedWindow(txt)
272             self.featuredwnd.show_all()
273         dialog.destroy()
274
275     def on_radios(self, button):
276         self.radioswnd = RadiosWindow()
277         self.radioswnd.show_all()
278
279     def on_search(self, button):
280         self.searchwnd = SearchWindow()
281         self.searchwnd.show_all()
282
283     def on_playlists(self, button):
284         self.playlistswnd = PlaylistsWindow()
285         self.playlistswnd.show_all()
286
287     def on_settings(self, button):
288         dialog = gtk.Dialog()
289         dialog.set_title("Settings")
290         dialog.add_button( gtk.STOCK_OK, gtk.RESPONSE_OK )
291         vbox = dialog.vbox
292         tbl = gtk.Table(1, 2)
293         tbl.attach(gtk.Label("Username:"), 0, 1, 0, 1)
294         entry = hildon.Entry(gtk.HILDON_SIZE_FINGER_HEIGHT)
295         entry.set_placeholder("jamendo.com username")
296         if settings.user:
297             entry.set_text(settings.user)
298         tbl.attach(entry, 1, 2, 0, 1)
299         vbox.pack_start(tbl, True, True, 2)
300         dialog.show_all()
301         result = dialog.run()
302         val = entry.get_text()
303         dialog.destroy()
304         #print val, result
305         if val and result == gtk.RESPONSE_OK:
306             #print "new user name:", val
307             settings.user = val
308             self.save_settings()
309
310
311     def on_favorites(self, button):
312         self.favoriteswnd = FavoritesWindow()
313         self.favoriteswnd.show_all()
314
315     def on_player(self, button):
316         open_playerwindow()
317
318     '''
319     def on_search(self, button):
320         if self.searchbar:
321             self.searchbar.show()
322         else:
323             self.searchstore = gtk.ListStore(gobject.TYPE_STRING)
324             iter = self.searchstore.append()
325             self.searchstore.set(iter, 0, "Test1")
326             iter = self.searchstore.append()
327             self.searchstore.set(iter, 0, "Test2")
328             self.searchbar = hildon.FindToolbar("Search", self.searchstore, 0)
329             self.searchbar.set_active(0)
330             self.window.add_toolbar(self.searchbar)
331             self.searchbar.show()
332     '''
333
334     def run(self):
335         ossohelper.application_init('org.jamaendo', '0.1')
336         self.create_window()
337         self.create_menu()
338         self.setup_widgets()
339         self.window.show_all()
340         gtk.main()
341         ossohelper.application_exit()
342
343 if __name__=="__main__":
344     ui = Jamaui()
345     ui.run()
346