/* This file is part of Cinaest. * * Copyright (C) 2009 Philipp Zabel * * Cinaest is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Cinaest is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Cinaest. If not, see . */ using Gtk; using Hildon; public class GoogleMovie : Movie { public string cinema_name; public string cinema_phone; public int runtime; public string showtimes; } class GooglePlugin : Plugin { List sources; SList locations; string last_location; GConf.Client gconf; public override void hello (Gtk.Window window, Osso.Context context) { stdout.printf ("Google Plugin Loaded.\n"); var source = new GoogleSource (); sources = new List (); sources.append (source); locations = null; gconf = GConf.Client.get_default (); try { source.location = last_location = gconf.get_string ("/apps/cinaest/location"); locations = gconf.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING); } catch (Error e) { stdout.printf ("Error getting GConf option: %s\n", e.message); } // FIXME - this forces the inclusion of config.h (void) Config.GETTEXT_PACKAGE; } public override unowned List get_sources () { return sources; } public override List get_actions (Movie _movie, Gtk.Window window) { List list = null; var movie = _movie as GoogleMovie; if (movie != null) { list.append (new MovieAction (_("Add to calendar"), on_add_calendar_event, movie, window)); if (movie.cinema_phone != null) list.append (new MovieAction (_("Call cinema"), on_call_cinema, movie, window)); } return list; } private void on_add_calendar_event (Movie _movie, Gtk.Window window) { var movie = (GoogleMovie) _movie; var dialog = new PickerDialog (window); dialog.set_title (_("Add showtime to calendar")); var selector = new TouchSelector.text (); var showtimes = movie.showtimes.split (", "); foreach (string s in showtimes) { selector.append_text (s); } dialog.set_selector (selector); var res = dialog.run (); if (res == ResponseType.OK) { string s = selector.get_current_text (); int hour = s.to_int (); int min = s.str (":").offset (1).to_int (); var showtime = time_t (); var timeinfo = Time.local (showtime); timeinfo.second = 0; timeinfo.minute = min; timeinfo.hour = hour; showtime = timeinfo.mktime (); int runtime = movie.runtime; if (runtime == 0) { // Default to 120min if we failed to parse the runtime runtime = 7200; } res = Calendar.add_event (movie.title, _("Movie"), movie.cinema_name, showtime, showtime + runtime); var banner = (Banner) Banner.show_information_with_markup (window, null, (res == 0) ? _("Added calendar event at %d:%02d").printf (hour, min) : _("Failed to add calendar event")); banner.set_timeout (1500); } dialog.destroy (); } private void on_call_cinema (Movie _movie, Gtk.Window window) { var movie = (GoogleMovie) _movie; var url = "tel://" + movie.cinema_phone; try { var action = Hildon.URIAction.get_default_action_by_uri (url); if (action != null) { action.open (url); } else { var banner = (Banner) Banner.show_information_with_markup (window, null, "Failed to get tel:// URI action"); banner.set_timeout (1500); } } catch (Error e) { if (e is Hildon.URIError) { stdout.printf ("Error: %s\n", e.message); } } } public override void settings_dialog (Gtk.Window window) { GoogleSource source = (GoogleSource) sources.data; var dialog = new Gtk.Dialog (); dialog.set_transient_for (window); dialog.set_title (_("Google plugin settings")); try { source.location = gconf.get_string ("/apps/cinaest/location"); locations = gconf.get_list ("/apps/cinaest/locations", GConf.ValueType.STRING); } catch (Error e) { stdout.printf ("Error getting GConf option: %s\n", e.message); } var selector = new TouchSelectorEntry.text (); insert_location_sorted (source.location); foreach (string l in locations) selector.append_text (l); var button = new PickerButton (SizeType.FINGER_HEIGHT, ButtonArrangement.HORIZONTAL); button.set_title (_("Location")); button.set_selector (selector); button.set_value (source.location); var content = (VBox) dialog.get_content_area (); content.pack_start (button, true, true, 0); dialog.add_button (_("Done"), ResponseType.ACCEPT); dialog.show_all (); int res = dialog.run (); if (res == ResponseType.ACCEPT) { source.location = button.get_value (); try { if (insert_location_sorted (source.location)) gconf.set_list ("/apps/cinaest/locations", GConf.ValueType.STRING, locations); if (source.location != last_location) gconf.set_string ("/apps/cinaest/location", source.location); } catch (Error e) { stdout.printf ("Error setting GConf option: %s\n", e.message); } } dialog.destroy (); } private bool insert_location_sorted (string? location) { if (location == null) return false; if (locations != null) { for (unowned SList l = locations; l != null; l = l.next) { if (l.data == location) { return false; } if (l.data > location) { l.insert (location, 0); return true; } } } locations.append (location); return true; } public override unowned string get_name () { return "Google"; } } class GoogleSource : MovieSource { public string location; public string description; public MovieSource.ReceiveMovieFunction callback; dynamic DBus.Object search; public override bool active { get; set construct; } public GoogleSource () { GLib.Object (active: true); } SourceFunc get_movies_callback; public override async int get_movies (MovieFilter filter, MovieSource.ReceiveMovieFunction _callback, int limit, Cancellable? cancellable) { try { string search_path; dynamic DBus.Object server; var conn = DBus.Bus.get (DBus.BusType.SESSION); server = conn.get_object ("org.maemo.cinaest.GoogleShowtimes", "/org/maemo/cinaest/googleshowtimes", "org.maemo.cinaest.MovieService"); server.NewSearch (out search_path); search = conn.get_object ("org.maemo.cinaest.GoogleShowtimes", search_path, "org.maemo.cinaest.MovieSearch"); callback = _callback; search.MoviesFound.connect (on_movies_found); search.start (filter.title); } catch (Error e1) { Banner.show_information (null, null, e1.message); return 0; } get_movies_callback = get_movies.callback; if (cancellable != null) cancellable.cancelled.connect (() => { search.abort (); Idle.add (get_movies_callback); }); yield; var gc = GConf.Client.get_default (); try { location = gc.get_string ("/apps/cinaest/location"); } catch (Error e) { stdout.printf ("Error getting GConf option: %s\n", e.message); } return 1 /*n*/; } private void on_movies_found (DBus.Object sender, string[] movies, bool finished) { print ("found %d movies\n", movies.length); var parser = new Json.Parser (); for (int i = 0; i < movies.length; i++) { var movie = new GoogleMovie (); try { parser.load_from_data (movies[i], -1); } catch (Error e) { stderr.printf ("Error: %s\n%s\n", e.message, movies[i]); } var object = parser.get_root ().get_object (); movie.title = object.get_string_member ("title"); movie.rating = (int) object.get_double_member ("rating"); movie.cinema_name = object.get_string_member ("cinema_name"); movie.cinema_phone = object.get_string_member ("cinema_phone"); movie.runtime = (int) object.get_int_member ("runtime"); movie.showtimes = object.get_string_member ("showtimes"); if (movie.runtime > 0) movie.secondary = "%d min - %s - %s".printf (movie.runtime / 60, movie.cinema_name, movie.showtimes); else movie.secondary = movie.cinema_name + " - " + movie.showtimes; callback (movie); } if (finished) { search = null; Idle.add (get_movies_callback); } } public override void add_movie (Movie movie) { } public override void delete_movie (Movie movie) { } public override unowned string get_name () { return _("Google"); } public override unowned string get_description () { if (location != null && location != "") { description = _("Movie Showtimes near %s").printf (location); } else { description = _("Movie Showtimes"); } return description; } public override bool get_editable () { return false; } } [ModuleInit] public Type register_plugin (TypeModule module) { // types are registered automatically return typeof (GooglePlugin); }