/* 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 ();
var result = new SList ();
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;
result.append (movie);
}
callback (result);
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 SourceFlags get_flags () {
return SourceFlags.ONLINE;
}
}
[ModuleInit]
public Type register_plugin (TypeModule module) {
// types are registered automatically
return typeof (GooglePlugin);
}