Merge lp:~donadigo/appcenter/drivers-2 into lp:~elementary-apps/appcenter/appcenter

Proposed by Adam Bieńkowski
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
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.get_desktop_id which apparently returns a desktop id *even if it's not valid*, this had to be reworked in order to not show "Open" button in a driver page

* 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

To post a comment you must log in.
Revision history for this message
Danielle Foré (danrabbit) wrote :

You're the man! I can confirm that drivers show here :)

Revision history for this message
Neal Gompa (ngompa13) wrote :

Is this code supposed to be Ubuntu specific? If so, it needs to be guarded so it can be disabled.

review: Needs Fixing (code and portability)
Revision history for this message
Jeremy Wootten (jeremywootten) wrote :

Is it possible to use an async function rather than an explicit thread? Does it need to be cancellable?

Revision history for this message
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.DRIVER) and hence why I put the merge to WIP, thoguh I need some data to test that and make sure it works.

Revision history for this message
Rico Tzschichholz (ricotz) wrote :

When using threads then better make it thread-safe.

Revision history for this message
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/AppListView.vala
text conflict in src/Widgets/UpdateHeaderRow.vala

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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 }

Subscribers

People subscribed via source and target branches