Debian packaging: 0.0.4-1
[beifahrer] / src / lift-list-window.vala
index 118a81a..2e5d6ef 100644 (file)
@@ -22,13 +22,28 @@ 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;
@@ -37,10 +52,31 @@ public class LiftListWindow : StackableWindow {
        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 (6, typeof (string), typeof (string), typeof (string), typeof (string), typeof (string), typeof (Lift));
+               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, store);
+               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);
@@ -50,36 +86,69 @@ public class LiftListWindow : StackableWindow {
                var selection = tree.get_selection ();
                selection.set_mode (SelectionMode.SINGLE);
 
-               // Source and destination column
-               route_column = new TreeViewColumn.with_attributes ("Route", new CellRendererText (), "text", 0);
+               // 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", 1);
+               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", 2);
+               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", 3);
+               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", 4);
+               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);
@@ -98,14 +167,80 @@ public class LiftListWindow : StackableWindow {
                vbox.pack_start (pannable, true, true, 0);
                vbox.pack_start (no_lifts, false, false, 0);
 
-               add (vbox);
+               alignment.add (vbox);
+               add (alignment);
 
-               vbox.show_all ();
+               alignment.show_all ();
                no_lifts.hide ();
                route_column.set_visible (!BeifahrerProgram.orientation.portrait);
 
                tree.row_activated.connect (this.on_row_activated);
-               BeifahrerProgram.orientation.changed.connect (this.on_orientation_changed);
+               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) {
@@ -113,6 +248,10 @@ public class LiftListWindow : StackableWindow {
                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;
@@ -123,14 +262,17 @@ public class LiftListWindow : StackableWindow {
                        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, 0, lift.city_from + " - " + lift.city_to,
-                                                               1, datetime,
-                                                               2, _("%d pl.").printf (lift.places),
-                                                               3, lift.price,
-                                                               4, icon_name,
-                                                               5, lift);
+                       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 ();
 
@@ -142,31 +284,37 @@ public class LiftListWindow : StackableWindow {
                if (preload) {
                        if (store.get_iter_first (out iter)) do {
                                Lift lift2;
-                               store.@get (iter, 5, out lift2);
+                               store.@get (iter, Columns.LIFT, out lift2);
                                if (lift2 == null)
                                        continue;
-                               if (lift2.description == null)
+                               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, 5, out lift);
+                       model.get (iter, Columns.LIFT, out lift);
 
                        var window = new LiftDetailWindow (adac, lift);
-                       window.show_all ();
+                       window.show ();
                }
        }
 
-       private void on_orientation_changed () {
+       private void on_orientation_changed (Gdk.Screen screen) {
                route_column.set_visible (!BeifahrerProgram.orientation.portrait);
        }
 }