Debian packaging: 0.0.4-1
[beifahrer] / src / lift-detail-window.vala
1 /* This file is part of Beifahrer.
2  *
3  * Copyright (C) 2010 Philipp Zabel
4  *
5  * Beifahrer is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Beifahrer is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with Beifahrer. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 using Gtk;
20 using Hildon;
21
22 public class LiftDetailWindow : StackableWindow {
23         private const string CALENDAR_SERVICE = "com.nokia.calendar";
24         private const string CALENDAR_PATH = "/com/nokia/calendar";
25         private const string CALENDAR_IF = "com.nokia.calendar";
26
27         AdacMitfahrclub adac;
28         Lift lift;
29         Alignment alignment;
30         PannableArea pannable;
31         VBox vbox;
32         OssoABook.Button button_route;
33         OssoABook.Button button_calendar;
34         Label label_driver;
35         OssoABook.Button button_phone;
36         OssoABook.Button button_sms;
37         OssoABook.Button button_email;
38         Image image_smoke;
39         Label label;
40         Label label_changed;
41         Table table;
42         string ics_filename = null;
43
44         public LiftDetailWindow (AdacMitfahrclub _adac, Lift _lift) {
45                 adac = _adac;
46                 lift = _lift;
47
48                 update_lift_details ();
49
50                 if (lift.description == null)
51                         get_lift_details.begin ();
52         }
53
54         construct {
55                 set_title ("Beifahrer");
56
57                 var menu = new AppMenu ();
58                 var add_contact = new Gtk.Button.with_label (_("New contact"));
59                 add_contact.show ();
60                 menu.append (add_contact);
61                 var goto_website = new Gtk.Button.with_label (_("Show website"));
62                 goto_website.show ();
63                 menu.append (goto_website);
64                 set_main_menu (menu);
65
66                 alignment = new Alignment (0.0f, 0.0f, 1.0f, 1.0f);
67                 alignment.top_padding = MARGIN_HALF;
68                 alignment.left_padding = MARGIN_DOUBLE;
69                 alignment.right_padding = MARGIN_DOUBLE;
70
71                 pannable = new PannableArea ();
72                 pannable.hscrollbar_policy = PolicyType.NEVER;
73
74                 vbox = new VBox (false, 0);
75
76                 var hbox = new HBox (false, 0);
77
78                 button_route = new OssoABook.Button (SizeType.FINGER_HEIGHT);
79                 button_route.style = OssoABook.ButtonStyle.LABEL;
80
81                 var image_eventbox = new EventBox ();
82                 image_smoke = new Image ();
83                 image_eventbox.add (image_smoke);
84
85                 hbox.pack_start (button_route, true, true, 0);
86                 hbox.pack_start (image_eventbox, false, false, MARGIN_DEFAULT);
87
88                 table = new Table (7, 2, false);
89
90                 button_calendar = new OssoABook.Button (SizeType.FINGER_HEIGHT);
91                 button_calendar.set_icon_name ("general_calendar");
92                 button_calendar.set_icon_visible (true);
93                 button_calendar.title = _("Departure time");
94
95                 label_driver = new Label (_("Driver:"));
96                 label_driver.set_alignment (0.0f, 0.5f);
97                 Hildon.gtk_widget_set_theme_size (label_driver, SizeType.FINGER_HEIGHT);
98
99                 button_phone = new OssoABook.Button (SizeType.FINGER_HEIGHT);
100                 button_phone.set_icon_name ("general_call");
101                 button_phone.set_icon_visible (true);
102                 button_phone.title = _("Phone");
103
104                 button_sms = new OssoABook.Button (SizeType.FINGER_HEIGHT);
105                 button_sms.set_icon_name ("general_sms");
106                 button_sms.set_icon_visible (true);
107                 button_sms.title = _("SMS");
108
109                 button_email = new OssoABook.Button (SizeType.FINGER_HEIGHT);
110                 button_email.set_icon_name ("general_email");
111                 button_email.set_icon_visible (true);
112                 button_email.title = _("E-mail");
113
114                 label = new Label ("");
115                 label.set_alignment (0.0f, 0.5f);
116                 label.set_line_wrap (true);
117
118                 label_changed = new Label ("");
119                 label_changed.set_alignment (1.0f, 0.0f);
120                 Hildon.helper_set_logical_color (label_changed, RcFlags.FG, StateType.NORMAL, "SecondaryTextColor");
121                 Hildon.helper_set_logical_font (label_changed, "SmallSystemFont");
122
123                 if (BeifahrerProgram.orientation.portrait) {
124                         table.attach (button_calendar, 0, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
125                         table.attach (label_driver, 0, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
126                         table.attach (button_phone, 0, 2, 2, 3, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
127                         table.attach (button_sms, 0, 2, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
128                         table.attach (button_email, 0, 2, 4, 5, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
129                 } else {
130                         table.attach (button_calendar, 1, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
131                         table.attach (label_driver, 0, 1, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
132                         table.attach (button_phone, 1, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
133                         table.attach (button_sms, 1, 2, 2, 3, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
134                         table.attach (button_email, 1, 2, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
135                 }
136                 table.attach (label, 0, 2, 5, 6, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
137                 table.attach (label_changed, 0, 2, 6, 7, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
138
139                 vbox.pack_start (hbox, true, true, 0);
140                 vbox.pack_start (table, true, true, 0);
141
142                 pannable.add_with_viewport (vbox);
143                 alignment.add (pannable);
144
145                 alignment.show_all ();
146                 button_email.hide ();
147                 add (alignment);
148
149                 Gdk.Screen.get_default ().size_changed.connect (on_orientation_changed);
150                 add_contact.clicked.connect (on_add_contact_clicked);
151                 goto_website.clicked.connect (on_goto_website_clicked);
152                 image_eventbox.button_press_event.connect (on_image_eventbox_button_pressed);
153                 button_calendar.clicked.connect (on_button_calendar_clicked);
154                 button_phone.clicked.connect (on_button_phone_clicked);
155                 button_sms.clicked.connect (on_button_sms_clicked);
156                 button_email.clicked.connect (on_button_email_clicked);
157                 destroy.connect (on_destroy);
158                 map_event.connect (on_map_event);
159         }
160
161         private async void get_lift_details () {
162                 Hildon.gtk_window_set_progress_indicator (this, 1);
163                 yield adac.update_lift_details (lift);
164                 Hildon.gtk_window_set_progress_indicator (this, 0);
165
166                 update_lift_details ();
167         }
168
169         private void update_lift_details () {
170                 button_route.title = _("From %s to %s").printf (lift.city_from, lift.city_to);
171                 if (lift.city_via.length () > 0) {
172                         string route = _("via ");
173                         foreach (string via in lift.city_via)
174                                 route += via + " ";
175                         button_route.value = route;
176                 } else {
177                         button_route.value = "";
178                 }
179
180                 button_calendar.value = "%02d.%02d.%04d, %d:%02d".printf (lift.time.day, lift.time.month, lift.time.year, lift.time.hour, lift.time.minute);
181
182                 label_driver.set_text (_("Driver: ") + lift.name);
183                 if (lift.cell != null) {
184                         button_phone.title = _("Cell");
185                         string cell_number = E.normalize_phone_number (lift.cell);
186                         button_phone.value = cell_number;
187                         button_sms.value = cell_number;
188                 } else if (lift.phone != null) {
189                         button_phone.title = _("Phone");
190                         string phone_number = E.normalize_phone_number (lift.phone);
191                         button_phone.value = phone_number;
192                         button_sms.value = phone_number;
193                 } else if (lift.phone2 != null) {
194                         button_phone.title = _("Phone");
195                         string phone_number = E.normalize_phone_number (lift.phone2);
196                         button_phone.value = phone_number;
197                         button_sms.value = phone_number;
198                 }
199
200                 if (lift.email_image_uri != null) {
201                         button_email.value = _("Click to view E-mail image");
202                         button_email.show ();
203                 }
204
205                 string lift_text = _("Free places: %d\n").printf (lift.places);
206                 lift_text += (lift.price != null) ? _("Price: %s\n").printf (lift.price) : _("(no price given)\n");
207                 if (LiftFlags.SMOKER in lift.flags) try {
208                         var pixbuf = IconTheme.get_default ().load_icon ("beifahrer_smoker", 32, IconLookupFlags.NO_SVG);
209                         image_smoke.pixbuf = pixbuf;
210                 } catch (Error e) {
211                 } else if (LiftFlags.NON_SMOKER in lift.flags) try {
212                         var pixbuf = IconTheme.get_default ().load_icon ("beifahrer_non_smoker", 32, IconLookupFlags.NO_SVG);
213                         image_smoke.pixbuf = pixbuf;
214                 } catch (Error e) {
215                 }
216                 if (LiftFlags.ADAC_MEMBER in lift.flags)
217                         lift_text += _("ADAC member ");
218                 if (LiftFlags.WOMEN_ONLY in lift.flags)
219                         lift_text += _("only women ");
220                 lift_text += "\n\n" + lift.description;
221
222                 label.set_text (lift_text);
223
224                 if (lift.modified != null)
225                         label_changed.set_text (_("\nLast changed: ") + lift.modified);
226
227                 // Reduce right margin for scrollbar, if update_lift_details is called after mapping the window
228                 if (vbox.allocation.height > pannable.allocation.height)
229                         alignment.right_padding = MARGIN_DEFAULT;
230         }
231
232         void on_button_calendar_clicked () {
233                 var ical = new StringBuilder ("BEGIN:VCALENDAR\nVERSION:2.0\nMETHOD:PUBLISH\nBEGIN:VEVENT\nUID:");
234                 ical.append ("beifahrer" + lift.href); // UID
235                 ical.append ("\nCLASS:PUBLIC\nSUMMARY:");
236                 ical.append_printf (_("From %s to %s with %s"), lift.city_from, lift.city_to, lift.name);
237                 ical.append ("\nDTSTART;TZID=Europe/Berlin:");
238                 ical.append_printf ("%04d%02d%02dT%02d%02d00", lift.time.year + 2000, lift.time.month, lift.time.day, lift.time.hour, lift.time.minute);
239                 ical.append ("\nDTEND;TZID=Europe/Berlin:");
240                 ical.append_printf ("%04d%02d%02dT%02d%02d00", lift.time.year + 2000, lift.time.month, lift.time.day, lift.time.hour, lift.time.minute);
241                 ical.append ("\nDESCRIPTION:");
242                 ical.append (lift.description.replace ("\n", "\\n"));
243                 ical.append ("\nEND:VEVENT\nEND:VCALENDAR\n");
244
245                 ics_filename = Path.build_path ("/", Environment.get_tmp_dir (),
246                                                 "beifahrer.ics");
247                 try {
248                         FileUtils.set_contents (ics_filename, ical.str);
249                 } catch (FileError e) {
250                         stderr.printf ("Failed to write %s: %s\n", ics_filename, e.message);
251                         return;
252                 }
253
254                 var error = DBus.RawError ();
255                 var bus = DBus.RawBus.get (DBus.BusType.SESSION, ref error);
256                 var res = HildonMime.open_file (bus, "file://" + ics_filename);
257         }
258
259         void on_destroy () {
260                 if (ics_filename != null)
261                         FileUtils.remove (ics_filename);
262         }
263
264         bool on_map_event (Gdk.Event event) {
265                 // Reduce right margin for scrollbar, for preloaded lift
266                 if (vbox.allocation.height > pannable.allocation.height)
267                         alignment.right_padding = MARGIN_DEFAULT;
268                 return true;
269         }
270
271         void on_button_phone_clicked () {
272                 var uri = "tel://";
273                 if (lift.cell != null)
274                         uri += E.normalize_phone_number (lift.cell);
275                 else if (lift.phone != null)
276                         uri += E.normalize_phone_number (lift.phone);
277                 try {
278                         var action = URIAction.get_default_action_by_uri (uri);
279                         if (action != null) {
280                                 action.open (uri);
281                         } else {
282                                 
283                                 Banner.show_information (this, null, _("Couldn't call %s URI").printf (uri));
284                         }
285                 } catch (Error e) {
286                         if (e is URIError) {
287                                 Banner.show_information (this, null, _("Error: %s").printf (e.message));
288                         }
289                 }
290         }
291
292         void on_button_sms_clicked () {
293                 var uri = "sms://";
294                 if (lift.cell != null)
295                         uri += E.normalize_phone_number (lift.cell);
296                 else if (lift.phone != null)
297                         uri += E.normalize_phone_number (lift.phone);
298                 try {
299                         var action = URIAction.get_default_action_by_uri (uri);
300                         if (action != null) {
301                                 action.open (uri);
302                         } else {
303                                 
304                                 Banner.show_information (this, null, _("Couldn't open %s URI").printf (uri));
305                         }
306                 } catch (Error e) {
307                         if (e is URIError) {
308                                 Banner.show_information (this, null, _("Error: %s").printf (e.message));
309                         }
310                 }
311         }
312
313         void on_button_email_clicked () {
314                 var uri = "http://mitfahrclub.adac.de";
315                 uri += lift.email_image_uri;
316                 try {
317                         var action = URIAction.get_default_action_by_uri (uri);
318                         if (action != null) {
319                                 action.open (uri);
320                         } else {
321
322                                 Banner.show_information (this, null, _("Couldn't open %s URI").printf (uri));
323                         }
324                 } catch (Error e) {
325                         if (e is URIError) {
326                                 Banner.show_information (this, null, _("Error: %s").printf (e.message));
327                         }
328                 }
329         }
330
331         void on_add_contact_clicked () {
332                 var contact = new OssoABook.Contact ();
333                 var attr_fn = new E.VCardAttribute (null, E.EVC_FN);
334                 contact.add_attribute_with_value ((owned) attr_fn, lift.name);
335                 if (lift.cell != null) {
336                         var attr_cell = new E.VCardAttribute (null, E.EVC_TEL);
337                         var param = new E.VCardAttributeParam (E.EVC_TYPE);
338                         attr_cell.add_param_with_value ((owned) param, "CELL");
339                         contact.add_attribute_with_value ((owned) attr_cell, E.normalize_phone_number (lift.cell));
340                 }
341                 if (lift.phone != null) {
342                         var attr_phone = new E.VCardAttribute (null, E.EVC_TEL);
343                         var param = new E.VCardAttributeParam (E.EVC_TYPE);
344                         attr_phone.add_param_with_value ((owned) param, "VOICE");
345                         contact.add_attribute_with_value ((owned) attr_phone, E.normalize_phone_number (lift.phone));
346                 }
347                 var dialog = new OssoABook.TemporaryContactDialog.with_contact (this, contact);
348                 dialog.show ();
349         }
350
351         void on_goto_website_clicked () {
352                 BeifahrerProgram.open_browser (this, adac.get_lift_details_url (lift));
353         }
354
355         bool on_image_eventbox_button_pressed (Gdk.EventButton event) {
356                 if (event.button != 1)
357                         return true;
358                 if (LiftFlags.SMOKER in lift.flags)
359                         Banner.show_information (this, null, _("Smoker"));
360                 if (LiftFlags.NON_SMOKER in lift.flags)
361                         Banner.show_information (this, null, _("Non-smoker"));
362                 return false;
363         }
364
365         void on_orientation_changed (Gdk.Screen screen) {
366                 // Maybe this will be fixed directly in Maemo-GTK, see
367                 // http://lists.maemo.org/pipermail/maemo-developers/2010-May/026332.html
368                 vbox.queue_resize ();
369
370                 table.remove (button_calendar);
371                 table.remove (label_driver);
372                 table.remove (button_phone);
373                 table.remove (button_sms);
374                 table.remove (button_email);
375                 if (BeifahrerProgram.orientation.portrait) {
376                         table.attach (button_calendar, 0, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
377                         table.attach (label_driver, 0, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
378                         table.attach (button_phone, 0, 2, 2, 3, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
379                         table.attach (button_sms, 0, 2, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
380                         table.attach (button_email, 0, 2, 4, 5, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
381                 } else {
382                         table.attach (button_calendar, 1, 2, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
383                         table.attach (label_driver, 0, 1, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, MARGIN_DEFAULT, 0);
384                         table.attach (button_phone, 1, 2, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
385                         table.attach (button_sms, 1, 2, 2, 3, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
386                         table.attach (button_email, 1, 2, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
387                 }
388         }
389 }