~ubuntu-core-dev/update-manager/main

2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
1
# Dialogs.py
2511.1.8 by Michael Terry
more pep8 fixes
2
# -*- Mode: Python; indent-tabs-mode: nil; tab-width: 4; coding: utf-8 -*-
3
#
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
4
#  Copyright (c) 2012 Canonical
2511.1.8 by Michael Terry
more pep8 fixes
5
#
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
6
#  Author: Michael Terry <michael.terry@canonical.com>
2511.1.8 by Michael Terry
more pep8 fixes
7
#
8
#  This program is free software; you can redistribute it and/or
9
#  modify it under the terms of the GNU General Public License as
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
10
#  published by the Free Software Foundation; either version 2 of the
11
#  License, or (at your option) any later version.
2511.1.8 by Michael Terry
more pep8 fixes
12
#
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
13
#  This program is distributed in the hope that it will be useful,
14
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
#  GNU General Public License for more details.
2511.1.8 by Michael Terry
more pep8 fixes
17
#
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
18
#  You should have received a copy of the GNU General Public License
19
#  along with this program; if not, write to the Free Software
20
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
#  USA
22
2741.1.1 by Jeremy Bicha
Add gi.require_version in a few more places to reduce the annoying warnings
23
import gi
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
24
2741.1.1 by Jeremy Bicha
Add gi.require_version in a few more places to reduce the annoying warnings
25
gi.require_version("Gtk", "3.0")
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
26
from gi.repository import Gtk
2523.1.2 by Michael Terry
don't allow closing the restart-needed dialog
27
from gi.repository import Gdk
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
28
from gi.repository import Gio
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
29
import warnings
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
30
2511.1.8 by Michael Terry
more pep8 fixes
31
warnings.filterwarnings(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
32
    "ignore", "Accessed deprecated property", DeprecationWarning
33
)
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
34
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
35
import logging
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
36
import datetime
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
37
import dbus
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
38
import distro_info
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
39
import os
40
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
41
import HweSupportStatus.consts
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
42
from .Core.LivePatchSocket import LivePatchSocket
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
43
from .Core.utils import get_dist
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
44
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
45
from gettext import gettext as _
2762.1.10 by Andrea Azzarone
Use ngettext to correctly handle the pluarl form.
46
from gettext import ngettext
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
47
2511.1.8 by Michael Terry
more pep8 fixes
48
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
49
class Dialog(object):
50
    def __init__(self, window_main):
51
        self.window_main = window_main
52
53
    def start(self):
54
        pass
55
56
    def close(self):
57
        return self.stop()
58
59
    def stop(self):
60
        pass
61
62
    def run(self, parent=None):
63
        pass
64
65
66
class BuilderDialog(Dialog, Gtk.Alignment):
67
    def __init__(self, window_main, ui_path, root_widget):
68
        Dialog.__init__(self, window_main)
69
        Gtk.Alignment.__init__(self)
70
71
        builder = self._load_ui(ui_path, root_widget)
72
        self.add(builder.get_object(root_widget))
73
        self.show()
74
75
    def _load_ui(self, path, root_widget, domain="update-manager"):
76
        builder = Gtk.Builder()
77
        builder.set_translation_domain(domain)
78
        builder.add_objects_from_file(path, [root_widget])
79
        builder.connect_signals(self)
80
81
        for o in builder.get_objects():
82
            if issubclass(type(o), Gtk.Buildable):
83
                name = Gtk.Buildable.get_name(o)
84
                setattr(self, name, o)
85
            else:
86
                logging.debug("WARNING: can not get name for '%s'" % o)
87
88
        return builder
89
90
    def run(self, parent=None):
91
        # FIXME: THIS WILL CRASH!
92
        if parent:
93
            self.window_dialog.set_transient_for(parent)
94
            self.window_dialog.set_modal(True)
95
        self.window_dialog.run()
96
97
98
class InternalDialog(BuilderDialog):
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
99
    def __init__(self, window_main, content_widget=None):
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
100
        ui_path = os.path.join(window_main.datadir, "gtkbuilder/Dialog.ui")
101
        BuilderDialog.__init__(self, window_main, ui_path, "pane_dialog")
102
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
103
        self.settings = Gio.Settings.new("com.ubuntu.update-manager")
104
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
105
        self.focus_button = None
106
        self.set_content_widget(content_widget)
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
107
        self.connect("realize", self._on_realize)
108
109
    def _on_realize(self, user_data):
110
        if self.focus_button:
111
            self.focus_button.set_can_default(True)
112
            self.focus_button.set_can_focus(True)
113
            self.focus_button.grab_default()
114
            self.focus_button.grab_focus()
2511.1.8 by Michael Terry
more pep8 fixes
115
116
    def add_button(self, label, callback, secondary=False):
117
        # from_stock tries stock first and falls back to mnemonic
118
        button = Gtk.Button.new_from_stock(label)
119
        button.connect("clicked", lambda x: callback())
120
        button.show()
121
        self.buttonbox.add(button)
122
        self.buttonbox.set_child_secondary(button, secondary)
123
        return button
124
125
    def add_settings_button(self):
126
        if os.path.exists("/usr/bin/software-properties-gtk"):
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
127
            return self.add_button(
128
                _("Settings…"), self.on_settings_button_clicked, secondary=True
129
            )
2511.1.8 by Michael Terry
more pep8 fixes
130
        else:
131
            return None
132
133
    def on_settings_button_clicked(self):
2622.1.1 by Dylan McCall
Defensive coding around package objects in UpdateList and UpdatesAvailable.
134
        self.window_main.show_settings()
2511.1.8 by Michael Terry
more pep8 fixes
135
136
    def set_header(self, label):
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
137
        if label:
2622.1.3 by Dylan McCall
Clean up header and description label for dialogs. Now reallocates height for width, fixing empty space in some dialogs.
138
            self.label_header.set_markup(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
139
                "<span size='larger' weight='bold'>%s</span>" % label
140
            )
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
141
        self.label_header.set_visible(bool(label))
2511.1.8 by Michael Terry
more pep8 fixes
142
143
    def set_desc(self, label):
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
144
        if label:
2622.1.4 by Dylan McCall
Fixed typo in Dialog.set_desc that wrongly wrote description to header label.
145
            self.label_desc.set_markup(label)
2511.1.8 by Michael Terry
more pep8 fixes
146
        self.label_desc.set_visible(bool(label))
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
147
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
148
    def set_content_widget(self, content_widget):
149
        if content_widget:
2622.1.5 by Dylan McCall
Fixed error in restart_icon_renderer_data_func caused by updates list being set at the incorrect time.
150
            self.main_container.add(content_widget)
2622.1.2 by Dylan McCall
UpdatesAvailable is now a Dialog subclass.
151
        self.main_container.set_visible(bool(content_widget))
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
152
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
153
    def _is_livepatch_supported(self):
154
        di = distro_info.UbuntuDistroInfo()
155
        codename = get_dist()
156
        return di.is_lts(codename)
157
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
158
    def on_livepatch_status_ready(self, active, cs, ps, fixes):
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
159
        self.set_desc(None)
160
161
        if not active:
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
162
            if (
163
                self._is_livepatch_supported()
164
                and self.settings_button
165
                and self.settings.get_int("launch-count") >= 4
166
            ):
167
                self.set_desc(
168
                    _(
169
                        "<b>Tip:</b> You can use Livepatch with "
170
                        "Ubuntu Pro to keep your computer more "
171
                        "secure between restarts."
172
                    )
173
                )
2955 by Sebastien Bacher
Updated Livepatch wording follow the Ubuntu Pro changes
174
                self.settings_button.set_label(_("Settings & Pro…"))
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
175
            return
176
177
        needs_reschedule = False
178
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
179
        if cs == "needs-check":
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
180
            needs_reschedule = True
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
181
        elif cs == "check-failed":
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
182
            pass
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
183
        elif cs == "checked":
184
            if ps == "unapplied" or ps == "applying":
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
185
                needs_reschedule = True
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
186
            elif ps == "applied":
187
                fixes = [fix for fix in fixes if fix.patched]
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
188
                d = ngettext(
189
                    "%d Livepatch update applied since the last restart.",
190
                    "%d Livepatch updates applied since the last restart.",
191
                    len(fixes),
192
                ) % len(fixes)
2762.1.10 by Andrea Azzarone
Use ngettext to correctly handle the pluarl form.
193
                self.set_desc(d)
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
194
            elif ps == "applied-with-bug" or ps == "apply-failed":
195
                fixes = [fix for fix in fixes if fix.patched]
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
196
                d = ngettext(
197
                    "%d Livepatch update failed to apply since the "
198
                    "last restart.",
199
                    "%d Livepatch updates failed to apply since the "
200
                    "last restart.",
201
                    len(fixes),
202
                ) % len(fixes)
2762.1.10 by Andrea Azzarone
Use ngettext to correctly handle the pluarl form.
203
                self.set_desc(d)
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
204
            elif ps == "nothing-to-apply":
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
205
                pass
2762.1.7 by Andrea Azzarone
Fix all remaining pep8 and pyflask issues.
206
            elif ps == "unknown":
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
207
                pass
208
209
        if needs_reschedule:
210
            self.lp_socket.get_status(self.on_livepatch_status_ready)
211
212
    def check_livepatch_status(self):
213
        self.lp_socket = LivePatchSocket()
214
        self.lp_socket.get_status(self.on_livepatch_status_ready)
215
2634 by Martin Pitt
Fix PEP-8 errors.
216
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
217
class StoppedUpdatesDialog(InternalDialog):
2534.1.1 by Michael Terry
add you-stopped-update dialog
218
    def __init__(self, window_main):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
219
        InternalDialog.__init__(self, window_main)
2534.1.1 by Michael Terry
add you-stopped-update dialog
220
        self.set_header(_("You stopped the check for updates."))
221
        self.add_settings_button()
222
        self.add_button(_("_Check Again"), self.check)
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
223
        self.focus_button = self.add_button(
224
            Gtk.STOCK_OK, self.window_main.close
225
        )
2534.1.1 by Michael Terry
add you-stopped-update dialog
226
227
    def check(self):
228
        self.window_main.start_update()
229
230
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
231
class NoUpdatesDialog(InternalDialog):
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
232
    def __init__(self, window_main, error_occurred=False):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
233
        InternalDialog.__init__(self, window_main)
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
234
        if error_occurred:
235
            self.set_header(_("No software updates are available."))
236
        else:
237
            self.set_header(_("The software on this computer is up to date."))
2826.2.1 by Andrea Azzarone
Add a reminder to install Livepatch if it is not installed and it is supported by the current release. The reminder is displayed after a few upgrades.
238
        self.settings_button = self.add_settings_button()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
239
        self.focus_button = self.add_button(
240
            Gtk.STOCK_OK, self.window_main.close
241
        )
2762.1.1 by Andrea Azzarone
Add Canonical LivePatch status to update-manager.
242
        self.check_livepatch_status()
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
243
244
245
class DistUpgradeDialog(InternalDialog):
2511.1.8 by Michael Terry
more pep8 fixes
246
    def __init__(self, window_main, meta_release):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
247
        InternalDialog.__init__(self, window_main)
2511.1.8 by Michael Terry
more pep8 fixes
248
        self.meta_release = meta_release
249
        self.set_header(_("The software on this computer is up to date."))
250
        # Translators: these are Ubuntu version names like "Ubuntu 12.04"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
251
        self.set_desc(
252
            _("However, %s %s is now available (you have %s).")
253
            % (
254
                meta_release.flavor_name,
255
                meta_release.upgradable_to.version,
256
                meta_release.current_dist_version,
257
            )
258
        )
2511.1.8 by Michael Terry
more pep8 fixes
259
        self.add_settings_button()
260
        self.add_button(_("Upgrade…"), self.upgrade)
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
261
        self.focus_button = self.add_button(
262
            Gtk.STOCK_OK, self.window_main.close
263
        )
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
264
2511.1.8 by Michael Terry
more pep8 fixes
265
    def upgrade(self):
2571.1.1 by Michael Terry
Pass update-manager arguments on to do-release-upgrade (LP: #1097907)
266
        # Pass on several arguments
267
        extra_args = ""
268
        if self.window_main and self.window_main.options:
269
            if self.window_main.options.devel_release:
270
                extra_args = extra_args + " -d"
271
            if self.window_main.options.use_proposed:
272
                extra_args = extra_args + " -p"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
273
        os.execl(
274
            "/bin/sh",
275
            "/bin/sh",
276
            "-c",
277
            "/usr/bin/do-release-upgrade "
278
            "--frontend=DistUpgradeViewGtk3%s" % extra_args,
279
        )
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
280
281
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
282
class HWEUpgradeDialog(InternalDialog):
283
    def __init__(self, window_main):
284
        InternalDialog.__init__(self, window_main)
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
285
        self.set_header(
286
            _("New important security and hardware support update.")
287
        )
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
288
        if datetime.date.today() < HweSupportStatus.consts.HWE_EOL_DATE:
289
            self.set_desc(_(HweSupportStatus.consts.Messages.HWE_SUPPORT_ENDS))
290
        else:
2775 by Brian Murray
Fix a bunch of pep8 related errors.
291
            self.set_desc(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
292
                _(HweSupportStatus.consts.Messages.HWE_SUPPORT_HAS_ENDED)
293
            )
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
294
        self.add_settings_button()
295
        self.add_button(_("_Install…"), self.install)
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
296
        self.focus_button = self.add_button(
297
            Gtk.STOCK_OK, self.window_main.close
298
        )
2727.1.1 by Brian Murray
Include HWE support tools and information. (LP: #1498059)
299
300
    def install(self):
301
        self.window_main.start_install(hwe_upgrade=True)
302
2776 by Brian Murray
Further pep8 fixes.
303
2428.4.5 by Michael Terry
move meta release checking into main UpdateManager class; use dialog panes for those interactions rather than popup dialogs
304
class UnsupportedDialog(DistUpgradeDialog):
2511.1.8 by Michael Terry
more pep8 fixes
305
    def __init__(self, window_main, meta_release):
306
        DistUpgradeDialog.__init__(self, window_main, meta_release)
307
        # Translators: this is an Ubuntu version name like "Ubuntu 12.04"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
308
        self.set_header(
309
            _("Software updates are no longer provided for %s %s.")
310
            % (meta_release.flavor_name, meta_release.current_dist_version)
311
        )
2511.1.8 by Michael Terry
more pep8 fixes
312
        # Translators: this is an Ubuntu version name like "Ubuntu 12.04"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
313
        self.set_desc(
314
            _("To stay secure, you should upgrade to %s %s.")
315
            % (meta_release.flavor_name, meta_release.upgradable_to.version)
316
        )
2428.4.12 by Michael Terry
further test fixes
317
2511.1.8 by Michael Terry
more pep8 fixes
318
    def run(self, parent):
319
        # This field is used in tests/test_end_of_life.py
320
        self.window_main.no_longer_supported_nag = self.window_dialog
321
        DistUpgradeDialog.run(self, parent)
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
322
323
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
324
class NoUpgradeForYouDialog(InternalDialog):
325
    def __init__(self, window_main, meta_release, arch):
326
        InternalDialog.__init__(self, window_main)
327
        self.set_header(_("Sorry, there are no more upgrades for this system"))
328
        # Translators: this is an Ubuntu version name like "Ubuntu 12.04"
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
329
        self.set_desc(
330
            _(
331
                "\nThere will not be any further Ubuntu releases "
332
                "for this system's '%s' architecture.\n\n"
333
                "Updates for Ubuntu %s will continue until 2023-04-26.\n\n"
334
                "If you reinstall Ubuntu from ubuntu.com/download, "
335
                "future upgrades will be available."
336
            )
337
            % (arch, meta_release.current_dist_version)
338
        )
339
        self.focus_button = self.add_button(
340
            Gtk.STOCK_OK, self.window_main.close
341
        )
2864.1.1 by Brian Murray
UpdateManager/UpdateManager.py: Do not offer to upgrade systems running on
342
343
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
344
class PartialUpgradeDialog(InternalDialog):
2511.1.8 by Michael Terry
more pep8 fixes
345
    def __init__(self, window_main):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
346
        InternalDialog.__init__(self, window_main)
2511.1.8 by Michael Terry
more pep8 fixes
347
        self.set_header(_("Not all updates can be installed"))
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
348
        self.set_desc(
349
            _(
350
                """\
351
Run a partial upgrade, to install as many updates as possible.
2511.1.8 by Michael Terry
more pep8 fixes
352
353
    This can be caused by:
354
     * A previous upgrade which didn't complete
355
     * Problems with some of the installed software
356
     * Unofficial software packages not provided by Ubuntu
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
357
     * Normal changes of a pre-release version of Ubuntu"""
358
            )
359
        )
2511.1.8 by Michael Terry
more pep8 fixes
360
        self.add_settings_button()
361
        self.add_button(_("_Partial Upgrade"), self.upgrade)
362
        self.focus_button = self.add_button(_("_Continue"), Gtk.main_quit)
363
364
    def upgrade(self):
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
365
        os.execl(
366
            "/bin/sh",
367
            "/bin/sh",
368
            "-c",
369
            "/usr/lib/ubuntu-release-upgrader/do-partial-upgrade "
370
            "--frontend=DistUpgradeViewGtk3",
371
        )
2511.1.8 by Michael Terry
more pep8 fixes
372
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
373
    def start(self):
374
        Dialog.start(self)
2511.1.8 by Michael Terry
more pep8 fixes
375
        # Block progress until user has answered this question
376
        Gtk.main()
2428.4.7 by Michael Terry
move partial upgrade dialog into UpdateManager from UpdatesAvailable and enable it again in the bad-cache case
377
378
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
379
class ErrorDialog(InternalDialog):
2511.1.8 by Michael Terry
more pep8 fixes
380
    def __init__(self, window_main, header, desc=None):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
381
        InternalDialog.__init__(self, window_main)
2511.1.8 by Michael Terry
more pep8 fixes
382
        self.set_header(header)
383
        if desc:
384
            self.set_desc(desc)
385
            self.label_desc.set_selectable(True)
386
        self.add_settings_button()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
387
        self.focus_button = self.add_button(
388
            Gtk.STOCK_OK, self.window_main.close
389
        )
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
390
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
391
    def start(self):
392
        Dialog.start(self)
2511.1.8 by Michael Terry
more pep8 fixes
393
        # The label likes to start selecting everything (b/c it got focus
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
394
        # before we switched to our default button).
2511.1.8 by Michael Terry
more pep8 fixes
395
        self.label_desc.select_region(0, 0)
2565.1.1 by Michael Terry
Allow user to continue if an update error occurs
396
397
398
class UpdateErrorDialog(ErrorDialog):
399
    def __init__(self, window_main, header, desc=None):
400
        ErrorDialog.__init__(self, window_main, header, desc)
401
        # Get rid of normal error dialog button before adding our own
402
        self.focus_button.destroy()
403
        self.add_button(_("_Try Again"), self.update)
404
        self.focus_button = self.add_button(Gtk.STOCK_OK, self.available)
405
406
    def update(self):
407
        self.window_main.start_update()
408
409
    def available(self):
410
        self.window_main.start_available(error_occurred=True)
2428.4.4 by Michael Terry
move cache from UpdatesAvailable to UpdateManager; use generic ErrorDialog class in a few places
411
2428.4.1 by Michael Terry
add basic support for no-updates-needed and restart-needed dialogs
412
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
413
class NeedRestartDialog(InternalDialog):
2511.1.8 by Michael Terry
more pep8 fixes
414
    def __init__(self, window_main):
2622.1.8 by Dylan McCall
Fixed broken close buttons and certain dialogs failing to initialize.
415
        InternalDialog.__init__(self, window_main)
2511.1.8 by Michael Terry
more pep8 fixes
416
        self.set_header(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
417
            _("The computer needs to restart to finish installing updates.")
418
        )
2664 by Marc Deslauriers
* Allow user to close the restart required dialog (LP: #1033226)
419
        self.add_settings_button()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
420
        self.focus_button = self.add_button(
421
            _("Restart _Later"), self.window_main.close
422
        )
2756.1.1 by Adolfo Jayme Barrientos
Remove misleading ellipsis in “Restart Now” action button
423
        self.add_button(_("_Restart Now"), self.restart)
2511.1.8 by Michael Terry
more pep8 fixes
424
2622.1.7 by Dylan McCall
Every GUI component is now a Dialog subclass, inserted as a widget into the main window, by the main window.
425
    def start(self):
426
        Dialog.start(self)
2523.1.2 by Michael Terry
don't allow closing the restart-needed dialog
427
        # Turn off close button
2649 by Steve Langasek
Fix a bug introduced in the dialog refactor from version 1:0.189 that
428
        self.window_main.realize()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
429
        self.window_main.get_window().set_functions(
430
            Gdk.WMFunction.MOVE | Gdk.WMFunction.MINIMIZE
431
        )
2523.1.2 by Michael Terry
don't allow closing the restart-needed dialog
432
2511.1.8 by Michael Terry
more pep8 fixes
433
    def restart(self, *args, **kwargs):
434
        self._request_reboot_via_session_manager()
2671 by Marc Deslauriers
[ Marc Deslauriers ]
435
        self.window_main.close()
2511.1.8 by Michael Terry
more pep8 fixes
436
437
    def _request_reboot_via_session_manager(self):
438
        try:
439
            bus = dbus.SessionBus()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
440
            proxy_obj = bus.get_object(
441
                "org.gnome.SessionManager", "/org/gnome/SessionManager"
442
            )
2511.1.8 by Michael Terry
more pep8 fixes
443
            iface = dbus.Interface(proxy_obj, "org.gnome.SessionManager")
444
            iface.RequestReboot()
445
        except dbus.DBusException:
446
            self._request_reboot_via_consolekit()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
447
        except Exception:
2511.1.8 by Michael Terry
more pep8 fixes
448
            pass
449
450
    def _request_reboot_via_consolekit(self):
451
        try:
452
            bus = dbus.SystemBus()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
453
            proxy_obj = bus.get_object(
454
                "org.freedesktop.ConsoleKit",
455
                "/org/freedesktop/ConsoleKit/Manager",
456
            )
2511.1.8 by Michael Terry
more pep8 fixes
457
            iface = dbus.Interface(
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
458
                proxy_obj, "org.freedesktop.ConsoleKit.Manager"
459
            )
2511.1.8 by Michael Terry
more pep8 fixes
460
            iface.Restart()
461
        except dbus.DBusException:
2651 by Brian Murray
Add support for logind to the restart dialog. Thanks to Thaddäus
462
            self._request_reboot_via_logind()
2853 by Brian Murray
debian/tests/control: really use pyflakes3 instead of pyflakes,
463
        except Exception:
2651 by Brian Murray
Add support for logind to the restart dialog. Thanks to Thaddäus
464
            pass
465
466
    def _request_reboot_via_logind(self):
467
        try:
468
            bus = dbus.SystemBus()
2972 by Benjamin Drung
Fix pycodestyle complains by formatting Python code with black
469
            proxy_obj = bus.get_object(
470
                "org.freedesktop.login1", "/org/freedesktop/login1"
471
            )
472
            iface = dbus.Interface(proxy_obj, "org.freedesktop.login1.Manager")
2651 by Brian Murray
Add support for logind to the restart dialog. Thanks to Thaddäus
473
            iface.Reboot(True)
474
        except dbus.DBusException:
2511.1.8 by Michael Terry
more pep8 fixes
475
            pass