Merge lp:~donadigo/appcenter/drivers-2 into lp:~elementary-apps/appcenter/appcenter
- drivers-2
- Merge into appcenter
Status: | Needs review | ||||
---|---|---|---|---|---|
Proposed branch: | lp:~donadigo/appcenter/drivers-2 | ||||
Merge into: | lp:~elementary-apps/appcenter/appcenter | ||||
Diff against target: |
734 lines (+294/-221) 10 files modified
src/AbstractAppContainer.vala (+6/-0) src/CMakeLists.txt (+1/-0) src/Core/Client.vala (+60/-1) src/Core/Package.vala (+24/-11) src/Views/AppListView.vala (+74/-68) src/Views/InstalledView.vala (+6/-0) src/Widgets/AppListRow.vala (+1/-0) src/Widgets/DriversHeaderRow.vala (+31/-0) src/Widgets/PackageRow.vala (+4/-0) src/Widgets/UpdateHeaderRow.vala (+87/-141) |
||||
To merge this branch: | bzr merge lp:~donadigo/appcenter/drivers-2 | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Neal Gompa (community) | code and portability | Needs Fixing | |
elementary Apps team | Pending | ||
Review via email: mp+317400@code.launchpad.net |
Commit message
* Add ability to install drivers from the installed page
Description of the change
This branch fixes bug #1469733: "A sane place for Additional Drivers".
This is a follow-up drivers-new branch which was abandoned due to the changes that appcenter had back then. Unfortunately, I had to change more code than expected because of some conflicts:
* get_can_launch uses Component.
* assigning headers to rows is now a header function, unlike previously, sorting them manually; furthermore the UpdatesHeaderRow class is now gone since it was no longer based on an AppListRow, the headers are created on demand and are no longer updated every 20 miliseconds
Neal Gompa (ngompa13) wrote : | # |
Is this code supposed to be Ubuntu specific? If so, it needs to be guarded so it can be disabled.
Jeremy Wootten (jeremywootten) wrote : | # |
Is it possible to use an async function rather than an explicit thread? Does it need to be cancellable?
Adam Bieńkowski (donadigo) wrote : | # |
jeremywootten: I disscussed the change with Neal in the Slack channel. The functionality of getting drivers is already implemented in AppStream (using ComponentKind.
Rico Tzschichholz (ricotz) wrote : | # |
When using threads then better make it thread-safe.
RabbitBot (rabbitbot-a) wrote : | # |
Attempt to merge into lp:appcenter failed due to conflicts:
text conflict in src/CMakeLists.txt
text conflict in src/Views/
text conflict in src/Widgets/
Unmerged revisions
- 406. By Adam Bieńkowski
-
Remove unneded action button visible assignment; decrease task cout when parsing driver output actually ended
- 405. By Adam Bieńkowski
-
Fix codestyle: added space
- 404. By Adam Bieńkowski
-
Drivers -> Device Drivers
- 403. By Adam Bieńkowski
-
Remove unneded errordomain
- 402. By Adam Bieńkowski
-
Remove unneded UpdatesHeaderGrid class
- 401. By Adam Bieńkowski
-
Removed unneded code
- 400. By Adam Bieńkowski
-
Show drivers in the installed page
Preview Diff
1 | === modified file 'src/AbstractAppContainer.vala' |
2 | --- src/AbstractAppContainer.vala 2017-02-04 17:18:30 +0000 |
3 | +++ src/AbstractAppContainer.vala 2017-02-16 12:35:38 +0000 |
4 | @@ -23,6 +23,12 @@ |
5 | } |
6 | } |
7 | |
8 | + public bool is_os_driver { |
9 | + get { |
10 | + return package.is_os_driver; |
11 | + } |
12 | + } |
13 | + |
14 | public bool update_available { |
15 | get { |
16 | return package.update_available || package.is_updating; |
17 | |
18 | === modified file 'src/CMakeLists.txt' |
19 | --- src/CMakeLists.txt 2017-02-10 20:15:32 +0000 |
20 | +++ src/CMakeLists.txt 2017-02-16 12:35:38 +0000 |
21 | @@ -23,6 +23,7 @@ |
22 | Widgets/AppListRow.vala |
23 | Widgets/AppActionButton.vala |
24 | Widgets/UpdateHeaderRow.vala |
25 | + Widgets/DriversHeaderRow.vala |
26 | ${CMAKE_CURRENT_BINARY_DIR}/config.vala |
27 | PACKAGES |
28 | appstream |
29 | |
30 | === modified file 'src/Core/Client.vala' |
31 | --- src/Core/Client.vala 2017-02-04 17:18:30 +0000 |
32 | +++ src/Core/Client.vala 2017-02-16 12:35:38 +0000 |
33 | @@ -16,12 +16,14 @@ |
34 | |
35 | public class AppCenterCore.Client : Object { |
36 | public signal void updates_available (); |
37 | + public signal void drivers_detected (); |
38 | |
39 | public bool connected { public get; private set; } |
40 | public bool updating_cache { public get; private set; } |
41 | public uint task_count { public get; private set; default = 0; } |
42 | |
43 | - public AppCenterCore.Package os_updates { public get; private set; } |
44 | + public AppCenterCore.Package os_updates { get; construct; } |
45 | + public Gee.ArrayList<AppCenterCore.Package> driver_list { get; construct; } |
46 | |
47 | private Gee.HashMap<string, AppCenterCore.Package> package_list; |
48 | private AppStream.Pool appstream_pool; |
49 | @@ -41,6 +43,7 @@ |
50 | |
51 | construct { |
52 | package_list = new Gee.HashMap<string, AppCenterCore.Package> (null, null); |
53 | + driver_list = new Gee.ArrayList<AppCenterCore.Package> (); |
54 | cancellable = new GLib.Cancellable (); |
55 | |
56 | client = new Task (); |
57 | @@ -236,6 +239,62 @@ |
58 | updates_available (); |
59 | } |
60 | |
61 | + public void get_drivers () { |
62 | + task_count++; |
63 | + if (driver_list.size > 0) { |
64 | + drivers_detected (); |
65 | + task_count--; |
66 | + return; |
67 | + } |
68 | + |
69 | + var command = new Granite.Services.SimpleCommand ("/usr/bin", "ubuntu-drivers list"); |
70 | + command.done.connect ((command, status) => parse_drivers_output (command.standard_output_str, status)); |
71 | + command.run (); |
72 | + } |
73 | + |
74 | + private void parse_drivers_output (string output, int status) { |
75 | + if (status != 0) { |
76 | + task_count--; |
77 | + return; |
78 | + } |
79 | + |
80 | + new Thread<void*> ("parse-drivers-output", () => { |
81 | + string[] tokens = output.split ("\n"); |
82 | + for (int i = 0; i < tokens.length; i++) { |
83 | + string package_name = tokens[i]; |
84 | + if (package_name.strip () == "") { |
85 | + continue; |
86 | + } |
87 | + |
88 | + var driver_component = new AppStream.Component (); |
89 | + driver_component.set_pkgnames ({ package_name }); |
90 | + driver_component.id = "%s-%i".printf (Package.OS_DRIVERS_ID, i); |
91 | + |
92 | + var icon = new AppStream.Icon (); |
93 | + icon.set_name ("application-x-firmware"); |
94 | + icon.set_kind (AppStream.IconKind.STOCK); |
95 | + driver_component.add_icon (icon); |
96 | + |
97 | + var package = new Package (driver_component); |
98 | + var pk_package = package.find_package (); |
99 | + if (pk_package != null && pk_package.get_info () == Pk.Info.INSTALLED) { |
100 | + package.installed_packages.add (pk_package); |
101 | + package.update_state (); |
102 | + } |
103 | + |
104 | + driver_list.add (package); |
105 | + } |
106 | + |
107 | + Idle.add (() => { |
108 | + drivers_detected (); |
109 | + return false; |
110 | + }); |
111 | + |
112 | + task_count--; |
113 | + return null; |
114 | + }); |
115 | + } |
116 | + |
117 | public async Gee.Collection<AppCenterCore.Package> get_installed_applications () { |
118 | var packages = new Gee.TreeSet<AppCenterCore.Package> (); |
119 | var installed = yield get_installed_packages (); |
120 | |
121 | === modified file 'src/Core/Package.vala' |
122 | --- src/Core/Package.vala 2017-02-04 17:18:30 +0000 |
123 | +++ src/Core/Package.vala 2017-02-16 12:35:38 +0000 |
124 | @@ -19,7 +19,6 @@ |
125 | */ |
126 | |
127 | public errordomain PackageLaunchError { |
128 | - DESKTOP_ID_NOT_FOUND, |
129 | APP_INFO_NOT_FOUND |
130 | } |
131 | |
132 | @@ -37,6 +36,7 @@ |
133 | } |
134 | |
135 | public const string OS_UPDATES_ID = "xxx-os-updates"; |
136 | + public const string OS_DRIVERS_ID = "xxx-os-drivers"; |
137 | |
138 | public AppStream.Component component { get; construct; } |
139 | public ChangeInformation change_information { public get; private set; } |
140 | @@ -76,7 +76,13 @@ |
141 | |
142 | public bool is_os_updates { |
143 | get { |
144 | - return component.id == "xxx-os-updates"; |
145 | + return component.id == OS_UPDATES_ID; |
146 | + } |
147 | + } |
148 | + |
149 | + public bool is_os_driver { |
150 | + get { |
151 | + return component.id.has_prefix (OS_DRIVERS_ID); |
152 | } |
153 | } |
154 | |
155 | @@ -87,7 +93,10 @@ |
156 | private get { return _latest_version; } |
157 | internal set { _latest_version = convert_version (value); } |
158 | } |
159 | + |
160 | private Pk.Package? pk_package = null; |
161 | + private AppInfo? app_info; |
162 | + private bool app_info_retrieved = false; |
163 | |
164 | construct { |
165 | installed_packages = new Gee.TreeSet<Pk.Package> (); |
166 | @@ -154,14 +163,8 @@ |
167 | } |
168 | |
169 | public void launch () throws Error { |
170 | - string desktop_id = component.get_desktop_id (); |
171 | - if (desktop_id == null) { |
172 | - throw new PackageLaunchError.DESKTOP_ID_NOT_FOUND ("desktop ID not found"); |
173 | - } |
174 | - |
175 | - var app_info = new DesktopAppInfo (desktop_id); |
176 | if (app_info == null) { |
177 | - throw new PackageLaunchError.APP_INFO_NOT_FOUND ("AppInfo not found for %s ID".printf (desktop_id)); |
178 | + throw new PackageLaunchError.APP_INFO_NOT_FOUND ("AppInfo not found for package: %s".printf (get_name ())); |
179 | } |
180 | |
181 | try { |
182 | @@ -332,10 +335,20 @@ |
183 | } |
184 | |
185 | public bool get_can_launch () { |
186 | - return component.get_desktop_id () != null; |
187 | + if (app_info_retrieved) { |
188 | + return app_info != null; |
189 | + } |
190 | + |
191 | + string? desktop_id = component.get_desktop_id (); |
192 | + if (desktop_id != null) { |
193 | + app_info = new DesktopAppInfo (desktop_id); |
194 | + } |
195 | + |
196 | + app_info_retrieved = true; |
197 | + return app_info != null; |
198 | } |
199 | |
200 | - private Pk.Package? find_package () { |
201 | + public Pk.Package? find_package () { |
202 | if (component.id == OS_UPDATES_ID) { |
203 | return null; |
204 | } |
205 | |
206 | === modified file 'src/Views/AppListView.vala' |
207 | --- src/Views/AppListView.vala 2017-02-15 18:02:21 +0000 |
208 | +++ src/Views/AppListView.vala 2017-02-16 12:35:38 +0000 |
209 | @@ -86,9 +86,7 @@ |
210 | * Does not show Uninstall Button **/ |
211 | public class AppListUpdateView : AbstractAppList { |
212 | private bool updates_on_top; |
213 | - private Widgets.UpdateHeaderRow updates_header; |
214 | - private Widgets.UpdateHeaderRow updated_header; |
215 | - private Widgets.AppActionButton update_all_button; |
216 | + private Widgets.AppActionButton? update_all_button; |
217 | private bool updating_all_apps = false; |
218 | private bool apps_remaining_started = false; |
219 | private GLib.Mutex update_mutex; |
220 | @@ -105,7 +103,7 @@ |
221 | set { |
222 | if (_updating_cache != value) { |
223 | _updating_cache = value; |
224 | - update_headers (); |
225 | + list_box.invalidate_headers (); |
226 | } |
227 | } |
228 | } |
229 | @@ -113,19 +111,7 @@ |
230 | construct { |
231 | updates_on_top = true; |
232 | |
233 | - update_all_button = new Widgets.AppActionButton (_("Update All")); |
234 | - update_all_button.set_suggested_action_header (); |
235 | - update_all_button.clicked.connect (on_update_all); |
236 | - update_all_button.no_show_all = true; |
237 | - action_button_group.add_widget (update_all_button); |
238 | - |
239 | - updates_header = new Widgets.UpdateHeaderRow.updates (); |
240 | - updates_header.add_widget (update_all_button); |
241 | - |
242 | - updated_header = new Widgets.UpdateHeaderRow.updated (); |
243 | - |
244 | - list_box.add (updates_header); |
245 | - list_box.add (updated_header); |
246 | + list_box.set_header_func ((Gtk.ListBoxUpdateHeaderFunc) row_update_header); |
247 | |
248 | update_mutex = GLib.Mutex (); |
249 | apps_to_update = new Gee.LinkedList<AppCenterCore.Package> (); |
250 | @@ -137,7 +123,7 @@ |
251 | _updating_cache = true; |
252 | } |
253 | |
254 | - protected override void after_add_remove_change_row () {update_headers ();} |
255 | + protected override void after_add_remove_change_row () { list_box.invalidate_headers (); } |
256 | |
257 | protected override Widgets.AppListRow make_row (AppCenterCore.Package package) { |
258 | return (Widgets.AppListRow)(new Widgets.PackageRow.installed (package, action_button_group, false)); |
259 | @@ -145,34 +131,91 @@ |
260 | |
261 | protected override void on_package_changing (AppCenterCore.Package package, bool is_changing) { |
262 | base.on_package_changing (package, is_changing); |
263 | - update_all_button.sensitive = packages_changing == 0; |
264 | + |
265 | + if (update_all_button != null) { |
266 | + update_all_button.sensitive = packages_changing == 0; |
267 | + } |
268 | } |
269 | |
270 | [CCode (instance_pos = -1)] |
271 | protected override int package_row_compare (Widgets.AppListRow row1, Widgets.AppListRow row2) { |
272 | - bool a_is_header = !row1.has_package (); |
273 | - bool b_is_header = !row2.has_package (); |
274 | - bool a_has_updates = row1.get_update_available (); |
275 | - bool b_has_updates = row2.get_update_available (); |
276 | - |
277 | - if (a_is_header) { |
278 | - return (a_has_updates || !b_has_updates) ? -1 : 1; |
279 | - } else if (b_is_header) { |
280 | - return (b_has_updates || !a_has_updates) ? 1 : -1; |
281 | - } |
282 | - |
283 | bool a_is_os = row1.get_is_os_updates (); |
284 | bool b_is_os = row2.get_is_os_updates (); |
285 | |
286 | if (a_is_os || b_is_os) { /* OS update row sorts ahead of other update rows */ |
287 | return a_is_os ? -1 : 1; |
288 | - } else if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */ |
289 | + } |
290 | + |
291 | + bool a_has_updates = row1.get_update_available (); |
292 | + bool b_has_updates = row2.get_update_available (); |
293 | + |
294 | + if ((a_has_updates && !b_has_updates) || (!a_has_updates && b_has_updates)) { /* Updates rows sort ahead of updated rows */ |
295 | return a_has_updates ? -1 : 1; |
296 | } |
297 | |
298 | + bool a_is_driver = row1.get_is_os_driver (); |
299 | + bool b_is_driver = row2.get_is_os_driver (); |
300 | + |
301 | + if ((a_is_driver && !b_is_driver) || (!a_is_driver && b_is_driver)) { |
302 | + return a_is_driver ? -1 : 1; |
303 | + } |
304 | + |
305 | return row1.get_name_label ().collate (row2.get_name_label ()); /* Else sort in name order */ |
306 | } |
307 | |
308 | + [CCode (instance_pos = -1)] |
309 | + private void row_update_header (Widgets.AppListRow row, Widgets.AppListRow? before) { |
310 | + bool update_available = row.get_update_available (); |
311 | + bool is_driver = row.get_is_os_driver (); |
312 | + bool different = before != null && (update_available != before.get_update_available () || is_driver != before.get_is_os_driver ()); |
313 | + |
314 | + if (update_available) { |
315 | + if (before == null || different) { |
316 | + var header = new Widgets.UpdatesGrid (); |
317 | + |
318 | + uint update_numbers = 0U; |
319 | + uint64 update_real_size = 0ULL; |
320 | + foreach (var package in get_packages ()) { |
321 | + if (package.update_available) { |
322 | + update_numbers++; |
323 | + update_real_size += package.change_information.get_size (); |
324 | + } |
325 | + } |
326 | + |
327 | + header.update (update_numbers, update_real_size, updating_cache); |
328 | + |
329 | + if (!updating_cache && update_numbers > 0) { |
330 | + update_all_button = new Widgets.AppActionButton (_("Update All")); |
331 | + update_all_button.set_suggested_action_header (); |
332 | + update_all_button.clicked.connect (on_update_all); |
333 | + action_button_group.add_widget (update_all_button); |
334 | + |
335 | + header.add_widget (update_all_button); |
336 | + } |
337 | + |
338 | + header.show_all (); |
339 | + row.set_header (header); |
340 | + } else { |
341 | + row.set_header (null); |
342 | + } |
343 | + } else if (is_driver) { |
344 | + if (before == null || different) { |
345 | + var header = new Widgets.DriversHeaderRow (); |
346 | + header.show_all (); |
347 | + row.set_header (header); |
348 | + } else { |
349 | + row.set_header (null); |
350 | + } |
351 | + } else if ((before == null && !update_available) || different) { |
352 | + var header = new Widgets.UpdatedGrid (); |
353 | + header.update (0, 0, updating_cache); |
354 | + header.show_all (); |
355 | + row.set_header (header); |
356 | + } else { |
357 | + row.set_header (null); |
358 | + } |
359 | + } |
360 | + |
361 | private void on_update_all () { |
362 | perform_all_updates.begin (); |
363 | } |
364 | @@ -278,42 +321,5 @@ |
365 | return GLib.Source.REMOVE; |
366 | }); |
367 | } |
368 | - |
369 | - private void update_headers () { |
370 | - /* Do not repeatedly update headers while rapidly adding packages to list */ |
371 | - schedule_header_update (); |
372 | - } |
373 | - |
374 | - uint grid_timeout_id = 0; |
375 | - private void schedule_header_update () { |
376 | - if (grid_timeout_id > 0) { |
377 | - return; |
378 | - } |
379 | - |
380 | - grid_timeout_id = GLib.Timeout.add (20, () => { |
381 | - update_updates_grid (); |
382 | - update_updated_grid (); |
383 | - grid_timeout_id = 0; |
384 | - return false; |
385 | - }); |
386 | - } |
387 | - |
388 | - private void update_updates_grid () { |
389 | - uint update_numbers = 0U; |
390 | - uint64 update_real_size = 0ULL; |
391 | - foreach (var package in get_packages ()) { |
392 | - if (package.update_available) { |
393 | - update_numbers++; |
394 | - update_real_size += package.change_information.get_size (); |
395 | - } |
396 | - } |
397 | - |
398 | - updates_header.update (update_numbers, update_real_size, updating_cache); |
399 | - update_all_button.visible = !updating_cache && update_numbers > 0; |
400 | - } |
401 | - |
402 | - private void update_updated_grid () { |
403 | - updated_header.update (0, 0, updating_cache); |
404 | - } |
405 | } |
406 | } |
407 | |
408 | === modified file 'src/Views/InstalledView.vala' |
409 | --- src/Views/InstalledView.vala 2017-02-15 18:02:21 +0000 |
410 | +++ src/Views/InstalledView.vala 2017-02-16 12:35:38 +0000 |
411 | @@ -53,10 +53,16 @@ |
412 | |
413 | public async void get_apps () { |
414 | unowned Client client = Client.get_default (); |
415 | + client.drivers_detected.connect (() => { |
416 | + foreach (var driver in client.driver_list) { |
417 | + app_list_view.add_package (driver); |
418 | + } |
419 | + }); |
420 | |
421 | var installed_apps = yield client.get_installed_applications (); |
422 | app_list_view.add_packages (installed_apps); |
423 | |
424 | + client.get_drivers (); |
425 | yield client.get_updates (); |
426 | } |
427 | |
428 | |
429 | === modified file 'src/Widgets/AppListRow.vala' |
430 | --- src/Widgets/AppListRow.vala 2016-09-17 19:28:03 +0000 |
431 | +++ src/Widgets/AppListRow.vala 2017-02-16 12:35:38 +0000 |
432 | @@ -24,6 +24,7 @@ |
433 | public interface AppListRow : Gtk.ListBoxRow { |
434 | public abstract bool get_update_available (); |
435 | public abstract bool get_is_os_updates (); |
436 | + public abstract bool get_is_os_driver (); |
437 | public abstract string get_name_label (); |
438 | public abstract bool has_package (); |
439 | public abstract AppCenterCore.Package? get_package (); |
440 | |
441 | === added file 'src/Widgets/DriversHeaderRow.vala' |
442 | --- src/Widgets/DriversHeaderRow.vala 1970-01-01 00:00:00 +0000 |
443 | +++ src/Widgets/DriversHeaderRow.vala 2017-02-16 12:35:38 +0000 |
444 | @@ -0,0 +1,31 @@ |
445 | +// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*- |
446 | +/*- |
447 | + * Copyright (c) 2017 elementary LLC. (https://elementary.io) |
448 | + * |
449 | + * This program is free software: you can redistribute it and/or modify |
450 | + * it under the terms of the GNU General Public License as published by |
451 | + * the Free Software Foundation, either version 3 of the License, or |
452 | + * (at your option) any later version. |
453 | + * |
454 | + * This program is distributed in the hope that it will be useful, |
455 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
456 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
457 | + * GNU General Public License for more details. |
458 | + * |
459 | + * You should have received a copy of the GNU General Public License |
460 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
461 | + * |
462 | + * Authored by: Adam Bieńkowski <donadigos159@gmail.com> |
463 | + */ |
464 | + |
465 | +namespace AppCenter.Widgets { |
466 | + public class DriversHeaderRow : Gtk.Grid { |
467 | + construct { |
468 | + var label = new Gtk.Label (_("Device Drivers")); |
469 | + label.margin = 12; |
470 | + label.halign = Gtk.Align.START; |
471 | + label.get_style_context ().add_class ("h4"); |
472 | + add (label); |
473 | + } |
474 | + } |
475 | +} |
476 | |
477 | === modified file 'src/Widgets/PackageRow.vala' |
478 | --- src/Widgets/PackageRow.vala 2017-02-05 15:48:49 +0000 |
479 | +++ src/Widgets/PackageRow.vala 2017-02-16 12:35:38 +0000 |
480 | @@ -50,6 +50,10 @@ |
481 | return grid.is_os_updates; |
482 | } |
483 | |
484 | + public bool get_is_os_driver () { |
485 | + return grid.is_os_driver; |
486 | + } |
487 | + |
488 | public string get_name_label () { |
489 | return grid.name_label; |
490 | } |
491 | |
492 | === modified file 'src/Widgets/UpdateHeaderRow.vala' |
493 | --- src/Widgets/UpdateHeaderRow.vala 2016-09-17 19:28:03 +0000 |
494 | +++ src/Widgets/UpdateHeaderRow.vala 2017-02-16 12:35:38 +0000 |
495 | @@ -19,152 +19,98 @@ |
496 | */ |
497 | |
498 | namespace AppCenter.Widgets { |
499 | - public class UpdateHeaderRow : Gtk.ListBoxRow, AppListRow { |
500 | - AbstractHeaderGrid grid; |
501 | - public bool is_updates_header {get; private set;} |
502 | + /** Base class for Grids in Header Rows **/ |
503 | + public abstract class AbstractHeaderGrid : Gtk.Grid { |
504 | + public uint update_numbers {get; protected set; default = 0;} |
505 | + public uint64 update_real_size {get; protected set; default = 0;} |
506 | + public bool is_updating {get; protected set; default = false;} |
507 | |
508 | construct { |
509 | - set_activatable (false); |
510 | - set_selectable (false); |
511 | - } |
512 | - |
513 | - public UpdateHeaderRow.updates () { |
514 | - grid = new UpdatesGrid (); |
515 | - add (grid); |
516 | - is_updates_header = true; |
517 | - } |
518 | - |
519 | - public UpdateHeaderRow.updated () { |
520 | - grid = new UpdatedGrid (); |
521 | - add (grid); |
522 | - is_updates_header = false; |
523 | - } |
524 | - |
525 | - /** AppListRow Interface methods **/ |
526 | - |
527 | - /** Updates header row reports it has updates in order to sort first in list **/ |
528 | - /** Updated header reports it has updates when updating in order to sort first in list **/ |
529 | - public bool get_update_available () { |
530 | - return is_updates_header || grid.is_updating; |
531 | - } |
532 | - |
533 | - public bool get_is_os_updates () { |
534 | - critical ("Must not attempt to get is_os_update from header row"); |
535 | - assert_not_reached (); |
536 | - } |
537 | - |
538 | - /* This indicates it is a header row, not a package row */ |
539 | - public bool has_package () {return false;} |
540 | - |
541 | - public AppCenterCore.Package? get_package () { |
542 | - critical ("Must not attempt to get package from header row"); |
543 | - assert_not_reached (); |
544 | - } |
545 | - |
546 | - public string get_name_label () { |
547 | - critical ("Must not attempt to get package name from header row"); |
548 | - assert_not_reached (); |
549 | + margin = 12; |
550 | + column_spacing = 12; |
551 | + } |
552 | + |
553 | + protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
554 | + update_numbers = _update_numbers; |
555 | + update_real_size = _update_real_size; |
556 | + is_updating = _is_updating; |
557 | } |
558 | |
559 | public void add_widget (Gtk.Widget widget) { |
560 | - grid.add (widget); |
561 | - } |
562 | - |
563 | - public void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
564 | - grid.update (_update_numbers, _update_real_size, _is_updating); |
565 | - changed (); /* Triggers resort */ |
566 | - } |
567 | - /** ---------------- **/ |
568 | - |
569 | - /** Base class for Grids in Header Rows **/ |
570 | - private abstract class AbstractHeaderGrid : Gtk.Grid { |
571 | - public uint update_numbers {get; protected set; default = 0;} |
572 | - public uint64 update_real_size {get; protected set; default = 0;} |
573 | - public bool is_updating {get; protected set; default = false;} |
574 | - |
575 | - construct { |
576 | - margin = 12; |
577 | - column_spacing = 12; |
578 | - } |
579 | - |
580 | - protected void store_data (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
581 | - update_numbers = _update_numbers; |
582 | - update_real_size = _update_real_size; |
583 | - is_updating = _is_updating; |
584 | - } |
585 | - |
586 | - public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating); |
587 | - } |
588 | - |
589 | - /** Header to show at top of list if there are updates available **/ |
590 | - private class UpdatesGrid : AbstractHeaderGrid { |
591 | - private Gtk.Label update_size_label; |
592 | - private Gtk.Label updates_label; |
593 | - |
594 | - construct { |
595 | - margin_top = 18; |
596 | - updates_label = new Gtk.Label (null); |
597 | - ((Gtk.Misc) updates_label).xalign = 0; |
598 | - updates_label.get_style_context ().add_class ("h4"); |
599 | - updates_label.hexpand = true; |
600 | - |
601 | - update_size_label = new Gtk.Label (null); |
602 | - |
603 | - add (updates_label); |
604 | - add (update_size_label); |
605 | - } |
606 | - |
607 | - public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
608 | - store_data (_update_numbers, _update_real_size, _is_updating); |
609 | - |
610 | - if (!is_updating) { |
611 | - updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers); |
612 | - update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size)); |
613 | - if (update_numbers > 0) { |
614 | - show_all (); |
615 | - } else { |
616 | - hide (); |
617 | - } |
618 | - } else { |
619 | - hide (); /* Updated header shows updating spinner and message */ |
620 | - } |
621 | - } |
622 | - } |
623 | - |
624 | - /** Header to show above first package that is up to date, or if the cache is updating **/ |
625 | - private class UpdatedGrid : AbstractHeaderGrid { |
626 | - private Gtk.Label label; |
627 | - private Gtk.Spinner spinner; |
628 | - |
629 | - construct { |
630 | - label = new Gtk.Label (""); /* Should not be displayed before being updated */ |
631 | - label.hexpand = true; |
632 | - ((Gtk.Misc)label).xalign = 0; |
633 | - |
634 | - spinner = new Gtk.Spinner (); |
635 | - |
636 | - add (label); |
637 | - add (spinner); |
638 | - } |
639 | - |
640 | - public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
641 | - store_data (_update_numbers, _update_real_size, _is_updating); |
642 | - |
643 | - if (is_updating) { |
644 | - halign = Gtk.Align.CENTER; |
645 | - spinner.start (); |
646 | - spinner.no_show_all = false; |
647 | - spinner.show (); |
648 | - label.label = _("Searching for updates…"); |
649 | - label.get_style_context ().remove_class ("h4"); |
650 | - } else { |
651 | - halign = Gtk.Align.START; |
652 | - spinner.stop (); |
653 | - spinner.no_show_all = true; |
654 | - spinner.hide (); |
655 | - label.label = _("Up to Date"); |
656 | - label.get_style_context ().add_class ("h4"); |
657 | - } |
658 | + add (widget); |
659 | + } |
660 | + |
661 | + public abstract void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating); |
662 | + } |
663 | + |
664 | + /** Header to show at top of list if there are updates available **/ |
665 | + public class UpdatesGrid : AbstractHeaderGrid { |
666 | + private Gtk.Label update_size_label; |
667 | + private Gtk.Label updates_label; |
668 | + |
669 | + construct { |
670 | + margin_top = 18; |
671 | + updates_label = new Gtk.Label (null); |
672 | + ((Gtk.Misc) updates_label).xalign = 0; |
673 | + updates_label.get_style_context ().add_class ("h4"); |
674 | + updates_label.hexpand = true; |
675 | + |
676 | + update_size_label = new Gtk.Label (null); |
677 | + |
678 | + add (updates_label); |
679 | + add (update_size_label); |
680 | + } |
681 | + |
682 | + public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
683 | + store_data (_update_numbers, _update_real_size, _is_updating); |
684 | + |
685 | + if (!is_updating) { |
686 | + updates_label.label = ngettext ("%u Update Available", "%u Updates Available", update_numbers).printf (update_numbers); |
687 | + update_size_label.label = _("Size: %s").printf (GLib.format_size (update_real_size)); |
688 | + if (update_numbers > 0) { |
689 | + show_all (); |
690 | + } else { |
691 | + hide (); |
692 | + } |
693 | + } else { |
694 | + hide (); /* Updated header shows updating spinner and message */ |
695 | + } |
696 | + } |
697 | + } |
698 | + |
699 | + /** Header to show above first package that is up to date, or if the cache is updating **/ |
700 | + public class UpdatedGrid : AbstractHeaderGrid { |
701 | + private Gtk.Label label; |
702 | + private Gtk.Spinner spinner; |
703 | + |
704 | + construct { |
705 | + label = new Gtk.Label (""); /* Should not be displayed before being updated */ |
706 | + label.hexpand = true; |
707 | + ((Gtk.Misc)label).xalign = 0; |
708 | + |
709 | + spinner = new Gtk.Spinner (); |
710 | + |
711 | + add (label); |
712 | + add (spinner); |
713 | + } |
714 | + |
715 | + public override void update (uint _update_numbers, uint64 _update_real_size, bool _is_updating) { |
716 | + store_data (_update_numbers, _update_real_size, _is_updating); |
717 | + |
718 | + if (is_updating) { |
719 | + halign = Gtk.Align.CENTER; |
720 | + spinner.start (); |
721 | + spinner.no_show_all = false; |
722 | + spinner.show (); |
723 | + label.label = _("Searching for updates…"); |
724 | + label.get_style_context ().remove_class ("h4"); |
725 | + } else { |
726 | + halign = Gtk.Align.START; |
727 | + spinner.stop (); |
728 | + spinner.no_show_all = true; |
729 | + spinner.hide (); |
730 | + label.label = _("Up to Date"); |
731 | + label.get_style_context ().add_class ("h4"); |
732 | } |
733 | } |
734 | } |
You're the man! I can confirm that drivers show here :)