diff options
| author | Michael Vogt <michael.vogt@ubuntu.com> | 2009-01-13 17:22:27 +0100 |
|---|---|---|
| committer | Michael Vogt <michael.vogt@ubuntu.com> | 2009-01-13 17:22:27 +0100 |
| commit | 38d602dc83006c51dfe4ed594d691ea9b0679498 (patch) | |
| tree | b7aedfba82c44cad6c3012f879b5d6d7e8ad1425 /apt/gtk/widgets.py | |
| parent | 12cf58d12b969010f3d98b2974d72bbb950b775f (diff) | |
| parent | 614897f798d9f16591fbd29ebe2a6c5674102d2d (diff) | |
| download | python-apt-38d602dc83006c51dfe4ed594d691ea9b0679498.tar.gz | |
* apt/*.py:
- Almost complete cleanup of the code
- Remove inconsistent use of tabs and spaces (Closes: #505443)
- Improved documentation
* apt/debfile.py:
- Drop get*() methods, as they are deprecated and were
never in a stable release
- Make DscSrcPackage working
* apt/gtk/widgets.py:
- Fix the code and document the signals
* Introduce new documentation build with Sphinx
- Contains style Guide (Closes: #481562)
- debian/rules: Build the documentation here
- setup.py: Remove pydoc building and add new docs.
- debian/examples: Include examples from documentation
- debian/python-apt.docs:
+ Change html/ to build/doc/html.
+ Add build/doc/text for the text-only documentation
* setup.py:
- Only create build/data when building, not all the time
- Remove build/mo and build/data on clean -a
* debian/control:
- Remove the Conflicts on python2.3-apt, python2.4-apt, as
they are only needed for oldstable (sarge)
- Build-Depend on python-sphinx (>= 0.5)
* aptsources/distinfo.py:
- Allow @ in mirror urls (Closes: #478171) (LP: #223097)
* Merge Ben Finney's whitespace changes (Closes: #481563)
* Merge Ben Finney's do not use has_key() (Closes: #481878)
* Do not use deprecated form of raise statement (Closes: #494259)
* Add support for PkgRecords.SHA256Hash (Closes: #456113)
Diffstat (limited to 'apt/gtk/widgets.py')
| -rw-r--r-- | apt/gtk/widgets.py | 306 |
1 files changed, 176 insertions, 130 deletions
diff --git a/apt/gtk/widgets.py b/apt/gtk/widgets.py index 3a15258f..34cc2759 100644 --- a/apt/gtk/widgets.py +++ b/apt/gtk/widgets.py @@ -1,28 +1,26 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -widgets - GTK widgets to show the progress and status of apt - -Copyright (c) 2004,2005 Canonical Ltd. - -Authors: Michael Vogt <mvo@ubuntu.com> - Sebastian Heinlein <glatzor@ubuntu.com> - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License as -published by the Free Software Foundation; either version 2 of the -License, or (at your option) any later version. - -his program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -USA -""" +# +# Copyright (c) 2004-2005 Canonical +# +# Authors: Michael Vogt <michael.vogt@ubuntu.com> +# Sebastian Heinlein <glatzor@ubuntu.com> +# Julian Andres Klode <jak@debian.org> +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. +# +# his program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA +"""GObject-powered progress classes and a GTK+ status widget.""" from gettext import gettext as _ import os @@ -39,15 +37,32 @@ import vte import apt import apt_pkg + +def mksig(params=(), run=gobject.SIGNAL_RUN_FIRST, rettype=gobject.TYPE_NONE): + """Simplified Create a gobject signal. + + This allows us to write signals easier, because we just need to define the + type of the parameters (in most cases). + + ``params`` is a tuple which defines the types of the arguments. + """ + return (run, rettype, params) + + class GOpProgress(gobject.GObject, apt.progress.OpProgress): + """Operation progress with GObject signals. + + Signals: - __gsignals__ = {"status-changed":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING, gobject.TYPE_INT)), - "status-started":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-finished":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ())} + * status-changed(str: operation, int: percent) + * status-started() - Not Implemented yet + * status-finished() + + """ + + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-finished": mksig()} def __init__(self): apt.progress.OpProgress.__init__(self) @@ -55,31 +70,38 @@ class GOpProgress(gobject.GObject, apt.progress.OpProgress): self._context = glib.main_context_default() def update(self, percent): + """Called to update the percentage done""" self.emit("status-changed", self.op, percent) while self._context.pending(): self._context.iteration() def done(self): + """Called when all operation have finished.""" self.emit("status-finished") + class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): + """Installation progress with GObject signals. + + Signals: + + * status-changed(str: status, int: percent) + * status-started() + * status-finished() + * status-timeout() + * status-error() + * status-conffile() + """ # Seconds until a maintainer script will be regarded as hanging INSTALL_TIMEOUT = 5 * 60 - __gsignals__ = {"status-changed":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING, gobject.TYPE_INT)), - "status-started":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-timeout":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-error":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-conffile":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-finished":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ())} + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-timeout": mksig(), + "status-error": mksig(), + "status-conffile": mksig(), + "status-finished": mksig()} def __init__(self, term): apt.progress.InstallProgress.__init__(self) @@ -89,32 +111,57 @@ class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): self.term = term reaper = vte.reaper_get() reaper.connect("child-exited", self.childExited) - self.env = ["VTE_PTY_KEEP_FD=%s"% self.writefd, + self.env = ["VTE_PTY_KEEP_FD=%s" % self.writefd, "DEBIAN_FRONTEND=gnome", "APT_LISTCHANGES_FRONTEND=gtk"] self._context = glib.main_context_default() def childExited(self, term, pid, status): + """Called when a child process exits""" self.apt_status = os.WEXITSTATUS(status) self.finished = True def error(self, pkg, errormsg): + """Called when an error happens. + + Emits: status-error() + """ self.emit("status-error") def conffile(self, current, new): + """Called during conffile. + + Emits: status-conffile() + """ self.emit("status-conffile") def startUpdate(self): + """Called when the update starts. + + Emits: status-started() + """ self.emit("status-started") def finishUpdate(self): + """Called when the update finished. + + Emits: status-finished() + """ self.emit("status-finished") def statusChange(self, pkg, percent, status): + """Called when the status changed. + + Emits: status-changed(status, percent) + """ self.time_last_update = time.time() self.emit("status-changed", status, percent) def updateInterface(self): + """Called periodically to update the interface. + + Emits: status-timeout() [When a timeout happens] + """ apt.progress.InstallProgress.updateInterface(self) while self._context.pending(): self._context.iteration() @@ -122,34 +169,55 @@ class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): self.emit("status-timeout") def fork(self): + """Fork the process.""" return self.term.forkpty(envv=self.env) def waitChild(self): + """Wait for the child process to exit.""" while not self.finished: self.updateInterface() return self.apt_status -class GDpkgInstallProgress(apt.progress.DpkgInstallProgress,GInstallProgress): +class GDpkgInstallProgress(apt.progress.DpkgInstallProgress, GInstallProgress): + """An InstallProgress for local installations. + + Signals: + + * status-changed(str: status, int: percent) + * status-started() - Not Implemented yet + * status-finished() + * status-timeout() - When the maintainer script hangs + * status-error() - When an error happens + * status-conffile() - On Conffile + """ def run(self, debfile): + """Install the given package.""" apt.progress.DpkgInstallProgress.run(self, debfile) def updateInterface(self): + """Called periodically to update the interface. + + Emits: status-timeout() [When a timeout happens]""" apt.progress.DpkgInstallProgress.updateInterface(self) if self.time_last_update + self.INSTALL_TIMEOUT < time.time(): self.emit("status-timeout") class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): + """A Fetch Progress with GObject signals. - __gsignals__ = {"status-changed":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, - (gobject.TYPE_STRING, gobject.TYPE_INT)), - "status-started":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ()), - "status-finished":(gobject.SIGNAL_RUN_FIRST, - gobject.TYPE_NONE, ())} + Signals: + + * status-changed(str: description, int: percent) + * status-started() + * status-finished() + """ + + __gsignals__ = {"status-changed": mksig((str, int)), + "status-started": mksig(), + "status-finished": mksig()} def __init__(self): apt.progress.FetchProgress.__init__(self) @@ -170,17 +238,17 @@ class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): apt.progress.FetchProgress.pulse(self) currentItem = self.currentItems + 1 if currentItem > self.totalItems: - currentItem = self.totalItems + currentItem = self.totalItems if self.currentCPS > 0: text = (_("Downloading file %(current)li of %(total)li with " "%(speed)s/s") % \ - {"current" : currentItem, - "total" : self.totalItems, - "speed" : humanize_size(self.currentCPS)}) + {"current": currentItem, + "total": self.totalItems, + "speed": apt_pkg.SizeToStr(self.currentCPS)}) else: text = (_("Downloading file %(current)li of %(total)li") % \ - {"current" : currentItem, - "total" : self.totalItems }) + {"current": currentItem, + "total": self.totalItems}) self.emit("status-changed", text, self.percent) while self._context.pending(): self._context.iteration() @@ -188,33 +256,12 @@ class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): class GtkAptProgress(gtk.VBox): - """ + """Graphical progress for installation/fetch/operations. + This widget provides a progress bar, a terminal and a status bar for showing the progress of package manipulation tasks. - - A simple example code snippet to install/remove a package: - - import pygtk - pygtk.require('2.0') - import gtk - - import apt.widgets - - win = gtk.Window() - progress = apt.widgets.GtkAptProgress() - win.set_title("GtkAptProgress Demo") - win.add(progress) - progress.show() - win.show() - - cache = apt.cache.Cache(progress.open)) - cache["xterm"].markDelete() - progress.show_terminal(expanded=True) - cache.commit(progress.fetch), - progress.install) - - gtk.main() """ + def __init__(self): gtk.VBox.__init__(self) self.set_spacing(6) @@ -226,7 +273,7 @@ class GtkAptProgress(gtk.VBox): self._progressbar = gtk.ProgressBar() # Setup the always italic status label self._label = gtk.Label() - attr_list = pango.AttrList() + attr_list = pango.AttrList() attr_list.insert(pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)) self._label.set_attributes(attr_list) self._label.set_ellipsize(pango.ELLIPSIZE_END) @@ -239,86 +286,80 @@ class GtkAptProgress(gtk.VBox): self._progress_open = GOpProgress() self._progress_open.connect("status-changed", self._on_status_changed) self._progress_open.connect("status-started", self._on_status_started) - self._progress_open.connect("status-finished", self._on_status_finished) + self._progress_open.connect("status-finished", + self._on_status_finished) self._progress_fetch = GFetchProgress() self._progress_fetch.connect("status-changed", self._on_status_changed) self._progress_fetch.connect("status-started", self._on_status_started) - self._progress_fetch.connect("status-finished", + self._progress_fetch.connect("status-finished", self._on_status_finished) self._progress_install = GInstallProgress(self._terminal) self._progress_install.connect("status-changed", self._on_status_changed) - self._progress_install.connect("status-started", + self._progress_install.connect("status-started", self._on_status_started) - self._progress_install.connect("status-finished", + self._progress_install.connect("status-finished", self._on_status_finished) - self._progress_install.connect("status-timeout", + self._progress_install.connect("status-timeout", self._on_status_timeout) - self._progress_install.connect("status-error", + self._progress_install.connect("status-error", self._on_status_timeout) - self._progress_install.connect("status-conffile", + self._progress_install.connect("status-conffile", self._on_status_timeout) self._progress_dpkg_install = GDpkgInstallProgress(self._terminal) self._progress_dpkg_install.connect("status-changed", self._on_status_changed) - self._progress_dpkg_install.connect("status-started", + self._progress_dpkg_install.connect("status-started", self._on_status_started) - self._progress_dpkg_install.connect("status-finished", + self._progress_dpkg_install.connect("status-finished", self._on_status_finished) - self._progress_dpkg_install.connect("status-timeout", + self._progress_dpkg_install.connect("status-timeout", self._on_status_timeout) - self._progress_dpkg_install.connect("status-error", + self._progress_dpkg_install.connect("status-error", self._on_status_timeout) - self._progress_dpkg_install.connect("status-conffile", + self._progress_dpkg_install.connect("status-conffile", self._on_status_timeout) def clear(self): - """ - Reset all status information - """ + """Reset all status information.""" self._label.set_label("") - self._progress.set_fraction(0) + self._progressbar.set_fraction(0) self._expander.set_expanded(False) @property def open(self): - """ - Return the cache opening progress handler. - """ + """Return the cache opening progress handler.""" return self._progress_open @property def install(self): - """ - Return the install progress handler - """ + """Return the install progress handler.""" return self._progress_install @property def dpkg_install(self): - """ - Return the install progress handler for dpkg - """ + """Return the install progress handler for dpkg.""" return self._dpkg_progress_install - + @property def fetch(self): - """ - Return the fetch progress handler - """ + """Return the fetch progress handler.""" return self._progress_fetch def _on_status_started(self, progress): + """Called when something starts.""" self._on_status_changed(progress, _("Starting..."), 0) while gtk.events_pending(): gtk.main_iteration() def _on_status_finished(self, progress): + """Called when something finished.""" self._on_status_changed(progress, _("Complete"), 100) while gtk.events_pending(): gtk.main_iteration() def _on_status_changed(self, progress, status, percent): + """Called when the status changed.""" self._label.set_text(status) if percent is None: self._progressbar.pulse() @@ -328,18 +369,18 @@ class GtkAptProgress(gtk.VBox): gtk.main_iteration() def _on_status_timeout(self, progress): - selt._expander.set_expanded(True) + """Called when timeout happens.""" + self._expander.set_expanded(True) while gtk.events_pending(): gtk.main_iteration() def cancel_download(self): - """ - Cancel a currently running download - """ + """Cancel a currently running download.""" self._progress_fetch.cancel() def show_terminal(self, expanded=False): - """ + """Show the expander for the terminal. + Show an expander with a terminal widget which provides a way to interact with dpkg """ @@ -350,31 +391,33 @@ class GtkAptProgress(gtk.VBox): gtk.main_iteration() def hide_terminal(self): - """ - Hide the expander with the terminal widget - """ + """Hide the expander with the terminal widget.""" self._expander.hide() while gtk.events_pending(): gtk.main_iteration() def show(self): + """Show the Box""" gtk.HBox.show(self) self._label.show() self._progressbar.show() while gtk.events_pending(): gtk.main_iteration() -if __name__ == "__main__": + +def _test(): + """Test function""" import sys - import debfile + + from apt.debfile import DebPackage win = gtk.Window() - apt_progress = GAptProgress() + apt_progress = GtkAptProgress() win.set_title("GtkAptProgress Demo") win.add(apt_progress) apt_progress.show() win.show() - cache = apt.cache.Cache(apt_progress.get_open_progress()) + cache = apt.cache.Cache(apt_progress.open) pkg = cache["xterm"] if pkg.isInstalled: pkg.markDelete() @@ -382,13 +425,16 @@ if __name__ == "__main__": pkg.markInstall() apt_progress.show_terminal(True) try: - cache.commit(apt_progress.get_fetch_progress(), - apt_progress.get_install_progress()) - except: - pass + cache.commit(apt_progress.fetch, apt_progress.install) + except Exception, exc: + print >> sys.stderr, "Exception happened:", exc if len(sys.argv) > 1: deb = DebPackage(sys.argv[1], cache) - deb.install(apt_progress.get_dpkg_install_progress()) + deb.install(apt_progress.dpkg_install) gtk.main() + +if __name__ == "__main__": + _test() + # vim: ts=4 et sts=4 |
