Lift detail window layout updates
[beifahrer] / src / query-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 QueryWindow : StackableWindow {
23         public const string GCONF_KEY_ARRIVAL = "/apps/beifahrer/arrival";
24         public const string GCONF_KEY_DEPARTURE = "/apps/beifahrer/departure";
25         public const string GCONF_KEY_USE_LOCATION = "/apps/beifahrer/use_location";
26
27         AdacMitfahrclub adac;
28         TouchSelector city_from_selector;
29         TouchSelector city_to_selector;
30         TouchSelector umkreis_from_selector;
31         TouchSelector umkreis_to_selector;
32         DateButton date;
33         TouchSelector tolerance_selector;
34         Location.GPSDControl control;
35         Location.GPSDevice device;
36         GConf.Client gconf;
37         bool use_location = true;
38         bool want_location;
39
40         construct {
41                 set_title ("Beifahrer");
42
43                 var menu = new AppMenu ();
44                 var settings = new Gtk.Button.with_label (_("Settings"));
45                 settings.show ();
46                 menu.append (settings);
47                 set_main_menu (menu);
48
49                 adac = new AdacMitfahrclub ();
50                 gconf = GConf.Client.get_default ();
51
52                 city_from_selector = new TouchSelectorEntry.text ();
53                 city_to_selector = new TouchSelectorEntry.text ();
54                 foreach (unowned City city in adac.get_city_list ()) {
55                         city_from_selector.append_text (city.name);
56                         city_to_selector.append_text (city.name);
57                 }
58
59                 umkreis_from_selector = new TouchSelector.text ();
60                 umkreis_to_selector = new TouchSelector.text ();
61                 for (int km = 0; km <= 50; km += 10) {
62                         umkreis_from_selector.append_text ("%d km".printf (km));
63                         umkreis_to_selector.append_text ("%d km".printf (km));
64                 }
65
66                 tolerance_selector = new TouchSelector.text ();
67                 for (int days = 0; days <= 4; days += 1)
68                         tolerance_selector.append_text (_("+/- %d days").printf (days));
69
70                 var alignment = new Alignment (0.0f, 0.0f, 1.0f, 1.0f);
71                 alignment.top_padding = MARGIN_HALF;
72                 alignment.left_padding = MARGIN_DOUBLE;
73                 alignment.right_padding = MARGIN_DOUBLE;
74                 var table = new Table (5, 2, false);
75
76                 var button = new PickerButton (SizeType.FINGER_HEIGHT,
77                                                ButtonArrangement.VERTICAL);
78                 button.set_selector (city_from_selector);
79                 button.set_title (_("Departure"));
80                 button.set_value (_("Please select"));
81                 button.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
82                 table.attach (button, 0, 1, 0, 1, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
83
84                 try {
85                         button.set_active (gconf.get_int ("/apps/beifahrer/departure"));
86                 } catch (Error e) {
87                 }
88
89                 button = new PickerButton (SizeType.FINGER_HEIGHT,
90                                            ButtonArrangement.VERTICAL);
91                 button.set_selector (umkreis_from_selector);
92                 button.set_title (_("Vicinity"));
93                 button.set_value ("0 km");
94                 button.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
95                 table.attach (button, 1, 2, 0, 1, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
96
97                 button = new PickerButton (SizeType.FINGER_HEIGHT,
98                                            ButtonArrangement.VERTICAL);
99                 button.set_selector (city_to_selector);
100                 button.set_title (_("Arrival"));
101                 button.set_value (_("Please select"));
102                 button.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
103                 table.attach (button, 0, 1, 1, 2, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
104
105                 try {
106                         button.set_active (gconf.get_int ("/apps/beifahrer/arrival"));
107                 } catch (Error e) {
108                 }
109
110                 button = new PickerButton (SizeType.FINGER_HEIGHT,
111                                            ButtonArrangement.VERTICAL);
112                 button.set_selector (umkreis_to_selector);
113                 button.set_title (_("Vicinity"));
114                 button.set_value ("0 km");
115                 button.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
116                 table.attach (button, 1, 2, 1, 2, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
117
118                 var switch_button = new Gtk.Button.with_label (_("Switch departure and arrival"));
119                 Hildon.gtk_widget_set_theme_size (switch_button, SizeType.FINGER_HEIGHT);
120                 switch_button.set_alignment (0.0f, 0.5f);
121                 table.attach (switch_button, 0, 1, 2, 3, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
122
123                 date = new DateButton (SizeType.FINGER_HEIGHT,
124                                        ButtonArrangement.VERTICAL);
125                 date.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
126                 table.attach (date, 0, 1, 3, 4, AttachOptions.FILL | AttachOptions.EXPAND, AttachOptions.FILL, 0, 0);
127
128                 button = new PickerButton (SizeType.FINGER_HEIGHT,
129                                            ButtonArrangement.VERTICAL);
130                 button.set_selector (tolerance_selector);
131                 button.set_title (_("Tolerance"));
132                 button.set_value (_("+/- 0 days"));
133                 button.set_alignment (0.0f, 0.0f, 0.5f, 0.5f);
134                 table.attach (button, 1, 2, 3, 4, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
135
136                 var search_button = new Gtk.Button.with_label (_("Search"));
137                 Hildon.gtk_widget_set_theme_size (search_button, SizeType.FINGER_HEIGHT);
138                 table.attach (search_button, 0, 2, 4, 5, AttachOptions.FILL, AttachOptions.FILL, 0, 0);
139
140                 alignment.add (table);
141                 add (alignment);
142
143                 switch_button.clicked.connect (on_switch_button_clicked);
144                 search_button.clicked.connect (on_search_button_clicked);
145                 settings.clicked.connect (on_settings_clicked);
146
147                 show_all ();
148
149                 control = Location.GPSDControl.get_default ();
150                 control.preferred_method = Location.METHOD_ACWP;
151                 control.preferred_interval = Location.GPSDControlInterval.@1S;
152                 control.error.connect (() => { print ("control error\n"); });
153                 control.error_verbose.connect ((e) => {
154                         switch (e) {
155                         case Location.GPSDControlError.USER_REJECTED_DIALOG:
156                                 print ("\tuser rejected dialog\n");
157                                 break;
158                         case Location.GPSDControlError.USER_REJECTED_SETTINGS:
159                                 print ("\tuser rejected settings\n");
160                                 break;
161                         case Location.GPSDControlError.BT_GPS_NOT_AVAILABLE:
162                                 print ("\tbt gps not available\n");
163                                 break;
164                         case Location.GPSDControlError.METHOD_NOT_ALLOWED_IN_OFFLINE_MODE:
165                                 print ("\tmethod not allowed in offline mode\n");
166                                 break;
167                         case Location.GPSDControlError.SYSTEM:
168                                 Banner.show_information (this, null, _("No GPS available!"));
169                                 break;
170                         }
171                 });
172                 control.gpsd_running.connect (() => { print ("control running\n"); });
173                 control.gpsd_stopped.connect (() => { print ("control stopped\n"); });
174
175                 try {
176                         use_location = gconf.get_bool (GCONF_KEY_USE_LOCATION);
177                 } catch (Error e) {
178                 }
179                 want_location = use_location;
180                 if (want_location)
181                         control.start ();
182
183                 device = (Location.GPSDevice) GLib.Object.@new (typeof (Location.GPSDevice), null);
184                 device.changed.connect (on_location_changed);
185                 device.connected.connect (() => { print ("device connected\n"); });
186                 device.disconnected.connect (() => { print ("device disconnected\n"); });
187
188                 // In case the device already has a fix:
189                 on_location_changed ();
190         }
191
192         void on_location_changed () requires (device.fix != null) {
193                 if (!want_location || device.status == Location.GPSDeviceStatus.NO_FIX)
194                         return;
195
196                 if (Location.GPS_DEVICE_LATLONG_SET in (int) device.fix.fields) {
197                         print ("fix: lat=%f, lon=%f\n", device.fix.latitude, device.fix.longitude);
198
199                         unowned City city = adac.find_nearest_city (device.fix.latitude, device.fix.longitude);
200                         if (city != null) {
201                                 int n = adac.get_city_list ().index (city);
202                                 int n_from = city_from_selector.get_active (0);
203                                 int n_to = city_to_selector.get_active (0);
204
205                                 print ("city(%d): %s (%d)\n", n, city.name, city.number);
206
207                                 if (n != n_from) {
208                                         city_from_selector.set_active (0, n);
209
210                                         // If we are at the previous point of arrival, prepare for return trip
211                                         if (n == n_to)
212                                                 city_to_selector.set_active (0, n_from);
213                                 }
214                         }
215
216                         control.stop ();
217                         want_location = false;
218                 }
219         }
220
221         void on_search_button_clicked (Gtk.Button button) {
222                 int n;
223
224                 n = city_from_selector.get_active (0);
225                 if (n == -1)
226                         return;
227                 string city_from = adac.get_city_list ().nth_data (n).name;
228                 try {
229                         if (gconf.get_int (GCONF_KEY_DEPARTURE) != n)
230                                 gconf.set_int (GCONF_KEY_DEPARTURE, n);
231                 } catch (Error e) {
232                 }
233
234                 n = city_to_selector.get_active (0);
235                 if (n == -1)
236                         return;
237                 string city_to = adac.get_city_list ().nth_data (n).name;
238                 try {
239                         if (gconf.get_int (GCONF_KEY_ARRIVAL) != n)
240                                 gconf.set_int (GCONF_KEY_ARRIVAL, n);
241                 } catch (Error e) {
242                 }
243
244                 uint year, month, day;
245                 date.get_date (out year, out month, out day);
246                 var date = Date ();
247                 date.set_day ((DateDay) day);
248                 date.set_month ((DateMonth) (month + DateMonth.JANUARY));
249                 date.set_year ((DateYear) year);
250
251                 int tolerance = tolerance_selector.get_active (0);
252
253                 var window = new LiftListWindow (adac);
254                 window.show ();
255                 window.find_lifts.begin (city_from, city_to, date, tolerance);
256         }
257
258         // Switch departure and arrival
259         void on_switch_button_clicked () {
260                 int n = city_from_selector.get_active (0);
261                 city_from_selector.set_active (0, city_to_selector.get_active (0));
262                 city_to_selector.set_active (0, n);
263                 n = umkreis_from_selector.get_active (0);
264                 umkreis_from_selector.set_active (0, umkreis_to_selector.get_active (0));
265                 umkreis_to_selector.set_active (0, n);
266         }
267
268         void on_settings_clicked () {
269                 var dialog = new SettingsDialog (this);
270                 dialog.response.connect (on_settings_response);
271                 dialog.show ();
272         }
273
274         void on_settings_response (int response_id) {
275                 bool old_use_location = use_location;
276                 use_location = gconf.get_bool (GCONF_KEY_USE_LOCATION);
277                 if (!old_use_location && use_location) {
278                         want_location = true;
279                         control.start ();
280                 }
281         }
282 }