/* This file is part of Beifahrer. * * Copyright (C) 2010 Philipp Zabel * * Beifahrer 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. * * Beifahrer 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 Beifahrer. If not, see . */ using Gtk; using Hildon; public class LiftListWindow : StackableWindow { public const string GCONF_KEY_PRELOAD = "/apps/beifahrer/preload"; enum Columns { ROUTE, SECONDARY, DATETIME, PLACES, PRICE, SMOKER, LIFT } AdacMitfahrclub adac; ListStore store; TreeSortable sortable; Alignment alignment; TreeView tree; TreeViewColumn route_column; Label no_lifts; GConf.Client gconf; bool preload = false; string url; Gtk.Button goto_website; public LiftListWindow (AdacMitfahrclub _adac) { adac = _adac; } construct { set_title ("Beifahrer"); var menu = new AppMenu (); var sort_by_time = new RadioButton.with_label (null, _("Time")); sort_by_time.set_mode (false); sort_by_time.show (); var sort_by_price = new RadioButton.with_label_from_widget (sort_by_time, _("Price")); sort_by_price.set_mode (false); sort_by_price.show (); menu.add_filter (sort_by_time); menu.add_filter (sort_by_price); goto_website = new Gtk.Button.with_label (_("Show website")); menu.append (goto_website); set_main_menu (menu); gconf = GConf.Client.get_default (); store = new ListStore (7, typeof (string), typeof (string), typeof (string), typeof (string), typeof (string), typeof (string), typeof (Lift)); sortable = new TreeModelSort.with_model (store); sortable.set_sort_func (Columns.DATETIME, datetime_sort_func); sortable.set_sort_func (Columns.PRICE, price_sort_func); alignment = new Alignment (0.0f, 0.0f, 1.0f, 1.0f); alignment.top_padding = MARGIN_HALF; alignment.left_padding = MARGIN_DOUBLE; alignment.right_padding = MARGIN_DOUBLE; tree = (TreeView) Hildon.gtk_tree_view_new_with_model (UIMode.NORMAL, sortable); Hildon.gtk_widget_set_theme_size (tree, SizeType.FINGER_HEIGHT); tree.set_headers_visible (false); tree.set_rules_hint (true); // Tree selection object var selection = tree.get_selection (); selection.set_mode (SelectionMode.SINGLE); // Source - destination / driver column var route_column = new TreeViewColumn (); route_column.set_title (_("Route")); route_column.set_reorderable (false); route_column.set_sizing (TreeViewColumnSizing.AUTOSIZE); route_column.set_expand (true); tree.append_column (route_column); var vbox_renderer = new CellRendererVBox (); var renderer = new CellRendererText (); renderer.yalign = 1.0f; renderer.set_fixed_size (-1, 32); vbox_renderer.append (renderer, true); vbox_renderer.set_data ("route-renderer", renderer); // Add secondary text to column (driver name, route details) renderer = new CellRendererText (); renderer.yalign = 0; renderer.set_fixed_size (-1, 32); renderer.ellipsize = Pango.EllipsizeMode.END; Pango.AttrList attr_list = new Pango.AttrList (); var style = Gtk.rc_get_style_by_paths (Gtk.Settings.get_default (), "SmallSystemFont", null, typeof (void)); if (style != null) { var attr_font_desc = new Pango.AttrFontDesc (style.font_desc.copy ()); attr_list.insert ((owned) attr_font_desc); } Gdk.Color color; this.ensure_style (); if (this.style.lookup_color ("SecondaryTextColor", out color)) { Pango.Attribute attr_color = Pango.attr_foreground_new (color.red, color.green, color.blue); attr_list.insert ((owned) attr_color); } renderer.attributes = attr_list; vbox_renderer.append (renderer, true); vbox_renderer.set_data ("secondary-renderer", renderer); route_column.pack_start (vbox_renderer, true); route_column.set_cell_data_func (vbox_renderer, vbox_data_func); // Date and time column var datetime_column = new TreeViewColumn.with_attributes ("DateTime", new CellRendererText (), "text", Columns.DATETIME); datetime_column.set_reorderable (false); datetime_column.set_sizing (TreeViewColumnSizing.AUTOSIZE); datetime_column.set_expand (true); tree.append_column (datetime_column); // Free places column var places_column = new TreeViewColumn.with_attributes ("Places", new CellRendererText (), "text", Columns.PLACES); places_column.set_reorderable (false); places_column.set_sizing (TreeViewColumnSizing.AUTOSIZE); places_column.set_expand (true); tree.append_column (places_column); // Price column var price_column = new TreeViewColumn.with_attributes ("Price", new CellRendererText (), "text", Columns.PRICE); price_column.set_reorderable (false); price_column.set_sizing (TreeViewColumnSizing.AUTOSIZE); price_column.set_expand (true); tree.append_column (price_column); // Smoker/Non-smoker column var smoke_column = new TreeViewColumn.with_attributes ("Smoker", new CellRendererPixbuf (), "icon-name", Columns.SMOKER); smoke_column.set_reorderable (false); smoke_column.set_sizing (TreeViewColumnSizing.AUTOSIZE); smoke_column.set_expand (false); tree.append_column (smoke_column); var pannable = new PannableArea (); pannable.add (tree); no_lifts = new Label (_("No lifts")); Hildon.helper_set_logical_font (no_lifts, "LargeSystemFont"); Hildon.helper_set_logical_color (no_lifts, RcFlags.FG, StateType.NORMAL, "SecondaryTextColor"); no_lifts.set_size_request (-1, 6 * 70); no_lifts.set_alignment ((float) 0.5, (float) 0.42); var vbox = new VBox (false, 0); vbox.pack_start (pannable, true, true, 0); vbox.pack_start (no_lifts, false, false, 0); alignment.add (vbox); add (alignment); alignment.show_all (); no_lifts.hide (); route_column.set_visible (!BeifahrerProgram.orientation.portrait); tree.row_activated.connect (this.on_row_activated); Gdk.Screen.get_default ().size_changed.connect (this.on_orientation_changed); goto_website.clicked.connect (on_goto_website_clicked); sort_by_time.toggled.connect (button => { if (button.get_active ()) sortable.set_sort_column_id (Columns.DATETIME, Gtk.SortType.ASCENDING); }); sort_by_price.toggled.connect (button => { if (button.get_active ()) sortable.set_sort_column_id (Columns.PRICE, Gtk.SortType.ASCENDING); }); } private int datetime_sort_func (TreeModel model, TreeIter a, TreeIter b) { Lift la; Lift lb; model.get (a, Columns.LIFT, out la); model.get (b, Columns.LIFT, out lb); int year = la.time.year - lb.time.year; if (year != 0) return year; int month = la.time.month - lb.time.month; if (month != 0) return month; int day = la.time.day - lb.time.day; if (day != 0) return day; int hour = la.time.hour - lb.time.hour; // Negative hour means no exact time available // - sort those entries last if (la.time.hour < 0) { hour += 24; return hour; } if (lb.time.hour < 0) { hour -= 24; return hour; } if (hour != 0) return hour; int minute = la.time.minute - lb.time.minute; return minute; } private int price_sort_func (TreeModel model, TreeIter a, TreeIter b) { string pa; string pb; model.get (a, Columns.PRICE, out pa); model.get (b, Columns.PRICE, out pb); if (pa == null && pb != null) return 1; if (pa != null && pb == null) return -1; return strcmp (pa, pb); } private void vbox_data_func (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter) { unowned string text; CellRendererText renderer; model.get (iter, Columns.ROUTE, out text); renderer = cell.get_data ("route-renderer"); renderer.text = text; model.get (iter, Columns.SECONDARY, out text); renderer = cell.get_data ("secondary-renderer"); renderer.text = text; } public async void find_lifts (string city_from, int radius_from, string city_to, int radius_to, Date date, int tolerance = 0) { TreeIter iter; set_title ("%s - %s".printf (city_from, city_to)); Hildon.gtk_window_set_progress_indicator (this, 1); url = adac.get_lift_list_url (city_from, radius_from, city_to, radius_to, date, tolerance); if (url == null) return; goto_website.show (); var lift_list = yield adac.get_lift_list (city_from, radius_from, city_to, radius_to, date, tolerance); foreach (Lift lift in lift_list) { string icon_name = null; if (LiftFlags.SMOKER in lift.flags) icon_name = "beifahrer_smoker"; else if (LiftFlags.NON_SMOKER in lift.flags) icon_name = "beifahrer_non_smoker"; string datetime = "%02d.%02d.%04d".printf (lift.time.day, lift.time.month, lift.time.year); if (lift.time.hour >= 0) datetime += ", %d:%02d".printf (lift.time.hour, lift.time.minute); store.insert_with_values (out iter, -1, Columns.ROUTE, lift.city_from + " - " + lift.city_to, Columns.SECONDARY, "", Columns.DATETIME, datetime, Columns.PLACES, _("%d pl.").printf (lift.places), Columns.PRICE, lift.price, Columns.SMOKER, icon_name, Columns.LIFT, lift); // (LiftFlags.WOMEN_ONLY,ADAC_MEMBER in lift.flags) } if (lift_list.length () > 6) alignment.right_padding = MARGIN_DEFAULT; if (lift_list.length () == 0) no_lifts.show (); bool preload = false; try { preload = gconf.get_bool (GCONF_KEY_PRELOAD); } catch (Error e) { } if (preload) { if (store.get_iter_first (out iter)) do { Lift lift2; store.@get (iter, Columns.LIFT, out lift2); if (lift2 == null) continue; if (lift2.description == null) { yield adac.update_lift_details (lift2); store.@set (iter, Columns.SECONDARY, lift2.name); } } while (store.iter_next (ref iter)); } Hildon.gtk_window_set_progress_indicator (this, 0); } void on_goto_website_clicked () { BeifahrerProgram.open_browser (this, url); } private void on_row_activated (TreeView tree, TreePath /*_*/path, TreeViewColumn column) { TreeModel model = tree.model; TreeIter iter; Lift lift; if (model.get_iter (out iter, path)) { model.get (iter, Columns.LIFT, out lift); var window = new LiftDetailWindow (adac, lift); window.show (); } } private void on_orientation_changed (Gdk.Screen screen) { route_column.set_visible (!BeifahrerProgram.orientation.portrait); } }