diff options
| author | Sebastian Heinlein <sebi@glatzor.de> | 2008-08-26 20:01:59 +0200 |
|---|---|---|
| committer | Sebastian Heinlein <sebi@glatzor.de> | 2008-08-26 20:01:59 +0200 |
| commit | 423a25e57a4c07c2803ef39e2d0d7a2b73d5ab7c (patch) | |
| tree | e3a6d8fcd8b6b860002292ad0d1e49d6ed0b74b0 /apt | |
| parent | 59fe10665676e2e6142cada2580064c5fa881b6e (diff) | |
| download | python-apt-423a25e57a4c07c2803ef39e2d0d7a2b73d5ab7c.tar.gz | |
Rename gtk to widgets. Replace the GDebi progresses by gobject based ones and add GtkAptProgress as a general progress providing widget.
Diffstat (limited to 'apt')
| -rw-r--r-- | apt/gtk.py | 125 | ||||
| -rw-r--r-- | apt/widgets.py | 372 |
2 files changed, 372 insertions, 125 deletions
diff --git a/apt/gtk.py b/apt/gtk.py deleted file mode 100644 index cb635e87..00000000 --- a/apt/gtk.py +++ /dev/null @@ -1,125 +0,0 @@ -# GtkProgress.py -# -# Copyright (c) 2004,2005 Canonical -# -# Author: Michael Vogt <michael.vogt@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. -# -# This 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 - -import pygtk -pygtk.require('2.0') -import gtk -import apt -import apt_pkg -from gettext import gettext as _ -from Common.utils import * - -# intervals of the start up progress -# 3x caching and menu creation -STEPS_UPDATE_CACHE = [33, 66, 100] - -class GtkOpProgress(apt.OpProgress): - def __init__(self, host_window, progressbar, status, parent, - steps=STEPS_UPDATE_CACHE): - # used for the "one run progressbar" - self.steps = steps[:] - self.base = 0 - self.old = 0 - self.next = int(self.steps.pop(0)) - - self._parent = parent - self._window = host_window - self._status = status - self._progressbar = progressbar - # Do not show the close button - self._window.realize() - host_window.window.set_functions(gtk.gdk.FUNC_MOVE) - self._window.set_transient_for(parent) - - def update(self, percent): - #print percent - #print self.Op - #print self.SubOp - self._window.show() - self._parent.set_sensitive(False) - # if the old percent was higher, a new progress was started - if self.old > percent: - # set the borders to the next interval - self.base = self.next - try: - self.next = int(self.steps.pop(0)) - except: - pass - progress = self.base + percent/100 * (self.next - self.base) - self.old = percent - self._status.set_markup("<i>%s</i>" % self.op) - self._progressbar.set_fraction(progress/100.0) - while gtk.events_pending(): - gtk.main_iteration() - - def done(self): - self._parent.set_sensitive(True) - def hide(self): - self._window.hide() - -class GtkFetchProgress(apt.progress.FetchProgress): - def __init__(self, parent, summary="", descr=""): - # if this is set to false the download will cancel - self._continue = True - # init vars here - # FIXME: find a more elegant way, this sucks - self.summary = parent.label_fetch_summary - self.status = parent.label_fetch_status - self.progress = parent.progressbar_fetch - self.window_fetch = parent.window_fetch - self.window_fetch.set_transient_for(parent.window_main) - self.window_fetch.realize() - self.window_fetch.window.set_functions(gtk.gdk.FUNC_MOVE) - # set summary - if self.summary != "": - self.summary.set_markup("<big><b>%s</b></big> \n\n%s" % - (summary, descr)) - def start(self): - self.progress.set_fraction(0) - self.window_fetch.show() - def stop(self): - self.window_fetch.hide() - def on_button_fetch_cancel_clicked(self, widget): - self._continue = False - def pulse(self): - apt.progress.FetchProgress.pulse(self) - currentItem = self.currentItems + 1 - if currentItem > self.totalItems: - currentItem = self.totalItems - if self.currentCPS > 0: - statusText = (_("Downloading file %(current)li of %(total)li with " - "%(speed)s/s") % {"current" : currentItem, - "total" : self.totalItems, - "speed" : humanize_size(self.currentCPS)}) - else: - statusText = (_("Downloading file %(current)li of %(total)li") % \ - {"current" : currentItem, - "total" : self.totalItems }) - self.progress.set_fraction(self.percent/100.0) - self.status.set_markup("<i>%s</i>" % statusText) - # TRANSLATORS: show the remaining time in a progress bar: - #self.progress.set_text(_("About %s left" % (apt_pkg.TimeToStr(self.eta)))) - # FIXME: show remaining time - self.progress.set_text("") - - while gtk.events_pending(): - gtk.main_iteration() - return self._continue diff --git a/apt/widgets.py b/apt/widgets.py new file mode 100644 index 00000000..09236d21 --- /dev/null +++ b/apt/widgets.py @@ -0,0 +1,372 @@ +#!/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 +""" + +from gettext import gettext as _ +import os +import time + +import pygtk +pygtk.require('2.0') +import gtk +import gobject +import pango +import vte + +import apt +import apt_pkg + +# Seconds until a maintainer script will be regarded as hanging +INSTALL_TIMEOUT = 4 * 60 + +class GOpProgress(gobject.GObject, apt.progress.OpProgress): + + __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, ())} + + def __init__(self): + apt.progress.OpProgress.__init__(self) + gobject.GObject.__init__(self) + + def update(self, percent): + self.emit("status-changed", self.op, percent) + while gtk.events_pending(): + gtk.main_iteration() + + def done(self): + self.emit("status-finished") + +class GInstallProgress(gobject.GObject, apt.progress.InstallProgress): + + __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, ())} + + def __init__(self, term): + apt.progress.InstallProgress.__init__(self) + gobject.GObject.__init__(self) + self.finished = False + self.time_last_update = time.time() + self.term = term + reaper = vte.reaper_get() + reaper.connect("child-exited", self.childExited) + self.env = ["VTE_PTY_KEEP_FD=%s"% self.writefd, + "DEBIAN_FRONTEND=gnome", + "APT_LISTCHANGES_FRONTEND=gtk"] + + def childExited(self, term, pid, status): + self.apt_status = os.WEXITSTATUS(status) + self.finished = True + + def error(self, pkg, errormsg): + self.emit("status-error") + + def conffile(self, current, new): + self.emit("status-conffile") + + def startUpdate(self): + self.emit("status-started") + + def finishUpdate(self): + self.emit("status-finished") + + def statusChange(self, pkg, percent, status): + self.time_last_update = time.time() + self.emit("status-changed", status, percent) + + def updateInterface(self): + apt.progress.InstallProgress.updateInterface(self) + while gtk.events_pending(): + gtk.main_iteration() + if self.time_last_update + INSTALL_TIMEOUT < time.time(): + self.emit("status-timeout") + + def fork(self): + return self.term.forkpty(envv=self.env) + + def waitChild(self): + while not self.finished: + self.updateInterface() + return self.apt_status + + +class GDpkgInstallProgress(apt.progress.DpkgInstallProgress,GInstallProgress): + + def run(self, debfile): + apt.progress.DpkgInstallProgress.run(self, debfile) + + def updateInterface(self): + apt.progress.DpkgInstallProgress.updateInterface(self) + while gtk.events_pending(): + gtk.main_iteration() + if self.time_last_update + INSTALL_TIMEOUT < time.time(): + self.emit("status-timeout") + + +class GFetchProgress(gobject.GObject, apt.progress.FetchProgress): + + __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, ())} + + def __init__(self): + apt.progress.FetchProgress.__init__(self) + gobject.GObject.__init__(self) + self._continue = True + + def start(self): + self.emit("status-started") + + def stop(self): + self.emit("status-finished") + + def cancel(self): + self._continue = False + + def pulse(self): + apt.progress.FetchProgress.pulse(self) + currentItem = self.currentItems + 1 + if 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)}) + else: + text = (_("Downloading file %(current)li of %(total)li") % \ + {"current" : currentItem, + "total" : self.totalItems }) + self.emit("status-changed", text, self.percent) + while gtk.events_pending(): + gtk.main_iteration() + return self._continue + + +class GtkAptProgress(gtk.VBox): + """ + 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.get_open_progress()) + cache["xterm"].markDelete() + progress.show_terminal(expanded=True) + cache.commit(progress.get_fetch_progress(), + progress.get_install_progress()) + + gtk.main() + """ + def __init__(self): + gtk.VBox.__init__(self) + self.set_spacing(6) + # Setup some child widgets + self._expander = gtk.Expander(_("Details")) + self._terminal = vte.Terminal() + #self._terminal.set_font_from_string("monospace 10") + self._expander.add(self._terminal) + self._progressbar = gtk.ProgressBar() + # Setup the always italic status label + self._label = gtk.Label() + 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) + self._label.set_alignment(0, 0) + # add child widgets + self.pack_start(self._progressbar, False) + self.pack_start(self._label, False) + self.pack_start(self._expander, False) + # Setup the internal progress handlers + 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_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._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._on_status_started) + self._progress_install.connect("status-finished", + self._on_status_finished) + self._progress_install.connect("status-timeout", + self._on_status_timeout) + self._progress_install.connect("status-error", + self._on_status_timeout) + 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._on_status_started) + self._progress_dpkg_install.connect("status-finished", + self._on_status_finished) + self._progress_dpkg_install.connect("status-timeout", + self._on_status_timeout) + self._progress_dpkg_install.connect("status-error", + self._on_status_timeout) + self._progress_dpkg_install.connect("status-conffile", + self._on_status_timeout) + + def clear(self): + """ + Reset all status information + """ + self._label.set_label("") + self._progress.set_fraction(0) + self._expander.set_expanded(False) + + def get_open_progress(self): + """ + Return the cache opening progress handler. + """ + return self._progress_open + + def get_install_progress(self): + """ + Return the install progress handler + """ + return self._progress_install + + def get_dpkg_install_progress(self): + """ + Return the install progress handler for dpkg + """ + return self._dpkg_progress_install + + def get_fetch_progress(self): + """ + Return the fetch progress handler + """ + return self._progress_fetch + + def _on_status_started(self, progress): + self._on_status_changed(progress, _("Starting..."), 0) + + def _on_status_finished(self, progress): + self._on_status_changed(progress, _("Complete"), 100) + + def _on_status_changed(self, progress, status, percent): + self._label.set_text(status) + self._progressbar.pulse() + self._progressbar.set_fraction(percent/100.0) + + def _on_status_timeout(self, progress): + selt._expander.set_expanded(True) + + def cancel_download(self): + """ + Cancel a currently running download + """ + self._progress_fetch.cancel() + + def show_terminal(self, expanded=False): + """ + Show an expander with a terminal widget which provides a way + to interact with dpkg + """ + self._expander.show() + self._terminal.show() + self._expander.set_expanded(True) + + def hide_terminal(self): + """ + Hide the expander with the terminal widget + """ + self._expander.hide() + + def show(self): + gtk.HBox.show(self) + self._label.show() + self._progressbar.show() + +if __name__ == "__main__": + import sys + import debfile + + win = gtk.Window() + 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()) + pkg = cache["xterm"] + if pkg.isInstalled: + pkg.markDelete() + else: + pkg.markInstall() + apt_progress.show_terminal(True) + try: + cache.commit(apt_progress.get_fetch_progress(), + apt_progress.get_install_progress()) + except: + pass + if len(sys.argv) > 1: + deb = DebPackage(sys.argv[1], cache) + deb.install(apt_progress.get_dpkg_install_progress()) + gtk.main() + +# vim: ts=4 et sts=4 |
