diff options
-rwxr-xr-x | firstaidkit | 10 | ||||
-rw-r--r-- | frontend/firstaidkit.glade | 234 | ||||
-rw-r--r-- | frontend/frontend_gtk.py | 62 | ||||
-rw-r--r-- | pyfirstaidkit/__init__.py | 2 | ||||
-rw-r--r-- | pyfirstaidkit/configuration.py | 22 | ||||
-rw-r--r-- | pyfirstaidkit/plugins.py | 2 |
6 files changed, 306 insertions, 26 deletions
diff --git a/firstaidkit b/firstaidkit index 7228db5..2ad6a93 100755 --- a/firstaidkit +++ b/firstaidkit @@ -19,7 +19,7 @@ import sys, getopt, getpass, os, pprint, logging, re, readline, hashlib from threading import Thread from pyfirstaidkit import Tasker -from pyfirstaidkit import Config +from pyfirstaidkit import Config, Info from pyfirstaidkit import reporting from pyfirstaidkit import initLogger from pyfirstaidkit.errors import InvalidPluginNameException @@ -158,10 +158,10 @@ class Output(Thread): raise AssertionError("Unsupported question type %s" % message["action"]) class GuiOutput(Thread): - def __init__(self, cfg, tasker, dir, importance = logging.INFO, + def __init__(self, cfg, info, tasker, dir, importance = logging.INFO, *args, **kwargs): Thread.__init__(self, *args, **kwargs) - self.w = MainWindow(cfg, tasker, importance = importance, dir=dir) + self.w = MainWindow(cfg, info, tasker, importance = importance, dir=dir) def run(self): self.w.run() @@ -369,13 +369,13 @@ if __name__=="__main__": outputThread = Output(singlerun.reporting(), interactive = Config.operation.gui!="gtk") if Config.operation.gui=="gtk": - outputThreadGui = GuiOutput(Config, singlerun, + outputThreadGui = GuiOutput(Config, Info, singlerun, dir = os.path.dirname(frontend_gtk.__file__)) else: outputThread = Output(singlerun.reporting(), importance = 0, interactive = Config.operation.gui!="gtk") if Config.operation.gui=="gtk": - outputThreadGui = GuiOutput(Config, singlerun, importance = 0, + outputThreadGui = GuiOutput(Config, Info, singlerun, importance = 0, dir = os.path.dirname(frontend_gtk.__file__)) if Config.operation.gui=="gtk": diff --git a/frontend/firstaidkit.glade b/frontend/firstaidkit.glade index 869eba8..9bfec2e 100644 --- a/frontend/firstaidkit.glade +++ b/frontend/firstaidkit.glade @@ -61,6 +61,27 @@ </child> <child> + <widget class="GtkImageMenuItem" id="save_results_menu"> + <property name="visible">True</property> + <property name="label" translatable="yes">S_ave results</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_mainmenu_save_results_activate" last_modification_time="Tue, 07 Sep 2010 12:08:05 GMT"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image5"> + <property name="visible">True</property> + <property name="stock">gtk-save-as</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> <widget class="GtkSeparatorMenuItem" id="separatormenuitem1"> <property name="visible">True</property> </widget> @@ -74,7 +95,7 @@ <signal name="activate" handler="on_mainmenu_expert_activate" last_modification_time="Tue, 24 Aug 2010 13:57:18 GMT"/> <child internal-child="image"> - <widget class="GtkImage" id="image1"> + <widget class="GtkImage" id="image6"> <property name="visible">True</property> <property name="stock">gtk-properties</property> <property name="icon_size">1</property> @@ -577,14 +598,155 @@ <property name="spacing">0</property> <child> + <widget class="GtkButton" id="save_results_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="on_mainmenu_save_results_activate" last_modification_time="Tue, 07 Sep 2010 12:09:12 GMT"/> + + <child> + <widget class="GtkAlignment" id="alignment6"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox4"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image2"> + <property name="visible">True</property> + <property name="stock">gtk-save-as</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label19"> + <property name="visible">True</property> + <property name="label" translatable="yes">Save results</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> <widget class="GtkButton" id="b_ResetResults"> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="label" translatable="yes">Reset</property> - <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> <signal name="clicked" handler="on_b_ResetResults_activate"/> + + <child> + <widget class="GtkAlignment" id="alignment7"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox5"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image3"> + <property name="visible">True</property> + <property name="stock">gtk-new</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label20"> + <property name="visible">True</property> + <property name="label" translatable="yes">Reset</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> </widget> <packing> <property name="padding">0</property> @@ -598,11 +760,73 @@ <property name="visible">True</property> <property name="sensitive">False</property> <property name="can_focus">True</property> - <property name="label" translatable="yes">Stop</property> - <property name="use_underline">True</property> <property name="relief">GTK_RELIEF_NORMAL</property> <property name="focus_on_click">True</property> <signal name="clicked" handler="on_b_StopResults_activate"/> + + <child> + <widget class="GtkAlignment" id="alignment8"> + <property name="visible">True</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xscale">0</property> + <property name="yscale">0</property> + <property name="top_padding">0</property> + <property name="bottom_padding">0</property> + <property name="left_padding">0</property> + <property name="right_padding">0</property> + + <child> + <widget class="GtkHBox" id="hbox6"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">2</property> + + <child> + <widget class="GtkImage" id="image4"> + <property name="visible">True</property> + <property name="stock">gtk-media-stop</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="label21"> + <property name="visible">True</property> + <property name="label" translatable="yes">Stop</property> + <property name="use_underline">True</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> + </widget> + </child> </widget> <packing> <property name="padding">0</property> diff --git a/frontend/frontend_gtk.py b/frontend/frontend_gtk.py index c66ed8a..3cb7665 100644 --- a/frontend/frontend_gtk.py +++ b/frontend/frontend_gtk.py @@ -40,11 +40,12 @@ def _o(func, *args, **kwargs): class CallbacksMainWindow(object): - def __init__(self, dialog, cfg, tasker, glade, data): + def __init__(self, dialog, cfg, info, tasker, glade, data): self._dialog = dialog self._tasker = tasker self._glade = glade self._cfg = cfg + self._info = info self._data = data self._running_lock = thread.allocate_lock() @@ -52,21 +53,23 @@ class CallbacksMainWindow(object): if not self._running_lock.acquire(0): return - def _o2(pages, stopbutton): + def _o2(pages, pagesstate, enablebuttons, disablebuttons): """Always return False -> remove from the idle queue after first execution""" - for i in range(pages.get_n_pages()): - pages.get_nth_page(i).set_sensitive(True) - stopbutton.set_sensitive(False) + for i in range(pages.get_n_pages())[:-1]: + pages.get_nth_page(i).set_sensitive(pagesstate) + map(lambda b: b.set_sensitive(False), disablebuttons) + map(lambda b: b.set_sensitive(True), enablebuttons) return False - def worker(*args): + def worker(pages, runningbuttons, stoppedbuttons): + gobject.idle_add(_o2, pages, False, runningbuttons, stoppedbuttons) self._cfg.lock() self._tasker.run() self._cfg.unlock() - gobject.idle_add(_o2, *args) + gobject.idle_add(_o2, pages, True, stoppedbuttons, runningbuttons) self._running_lock.release() self._data.pages.set_current_page(-1) @@ -75,8 +78,10 @@ class CallbacksMainWindow(object): self.on_b_ResetResults_activate(None) stopbutton = self._glade.get_widget("b_StopResults") - stopbutton.set_sensitive(True) - thread.start_new_thread(worker, (self._data.pages, stopbutton)) + saveresmenu = self._glade.get_widget("save_results_menu") + saveresbutton = self._glade.get_widget("save_results_button") + resetresbutton = self._glade.get_widget("b_ResetResults") + thread.start_new_thread(worker, (self._data.pages, [stopbutton], [resetresbutton, saveresmenu, saveresbutton])) #menu callbacks def on_mainmenu_open_activate(self, widget, *args): @@ -84,6 +89,11 @@ class CallbacksMainWindow(object): d = gtk.FileChooserDialog(title="Load the configuration file", parent=self._dialog, action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + fil = gtk.FileFilter() + fil.set_name("FirstAidKit ini files (*.ini)") + fil.add_pattern("*.ini") + d.add_filter(fil) + print(d.run()) d.destroy() return True @@ -94,6 +104,12 @@ class CallbacksMainWindow(object): parent=self._dialog, action=gtk.FILE_CHOOSER_ACTION_SAVE, buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT)) + d.set_filename("firstaidkit.ini") + fil = gtk.FileFilter() + fil.add_pattern("*.ini") + fil.set_name("FirstAidKit ini files (*.ini)") + d.add_filter(fil) + ret=d.run() if ret==gtk.RESPONSE_ACCEPT: @@ -102,7 +118,29 @@ class CallbacksMainWindow(object): fd = open(filename, "w") self._cfg.write(fd) except IOError, e: - pass + print e + + d.destroy() + return True + + def on_mainmenu_save_results_activate(self, widget, *args): + d = gtk.FileChooserDialog(title="Save the results file", + parent=self._dialog, action=gtk.FILE_CHOOSER_ACTION_SAVE, + buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, + gtk.RESPONSE_ACCEPT)) + d.set_filename("results.zip") + fil = gtk.FileFilter() + fil.add_pattern("*.zip") + fil.set_name("FirstAidKit result archives (*.zip)") + d.add_filter(fil) + ret=d.run() + + if ret==gtk.RESPONSE_ACCEPT: + try: + filename = d.get_filename() + self._info.dump(filename) + except IOError, e: + print e d.destroy() return True @@ -468,13 +506,13 @@ class MainWindow(object): _cancel_answer = object() _no_answer = object() - def __init__(self, cfg, tasker, importance = logging.INFO, dir=""): + def __init__(self, cfg, info, tasker, importance = logging.INFO, dir=""): self._importance = importance self._cfg = cfg self._glade = gtk.glade.XML(os.path.join(dir, "firstaidkit.glade"), "MainWindow") self._window = self._glade.get_widget("MainWindow") - self._cb = CallbacksMainWindow(self._window, cfg, tasker, self._glade, + self._cb = CallbacksMainWindow(self._window, cfg, info, tasker, self._glade, self) self._glade.signal_autoconnect(self._cb) self._window.connect("destroy", self._cb.on_destroy) diff --git a/pyfirstaidkit/__init__.py b/pyfirstaidkit/__init__.py index 874f57c..6bfe5ad 100644 --- a/pyfirstaidkit/__init__.py +++ b/pyfirstaidkit/__init__.py @@ -16,7 +16,7 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. from interpret import Tasker -from configuration import Config +from configuration import Config, Info import logging import sys diff --git a/pyfirstaidkit/configuration.py b/pyfirstaidkit/configuration.py index a4cedf1..fc534fb 100644 --- a/pyfirstaidkit/configuration.py +++ b/pyfirstaidkit/configuration.py @@ -20,6 +20,7 @@ import os import sys from cStringIO import StringIO from shlex import shlex +import zipfile if os.environ.has_key("FIRST_AID_KIT_CONF"): cfgfile = os.environ["FIRST_AID_KIT_CONF"].split(":") @@ -95,6 +96,9 @@ class FAKConfigSection(object): def unlock(self): self.__dict__["__use_lock"] = False + def attach(self, file): + self.__dict__["__configuration"].attach(file) + def __getattr__(self, key): if not self.__dict__["__configuration"]. \ has_section(self.__dict__["__section_name"]) and \ @@ -179,13 +183,27 @@ def getConfigBits(name, cfg = Config): return c class FAKInfo(ConfigParser.SafeConfigParser, FAKConfigMixIn): + def __init__(self, *args, **kwargs): + ConfigParser.SafeConfigParser.__init__(self, *args, **kwargs) + FAKConfigMixIn.__init__(self) + self._attachments = [] + def write(self, fd=sys.stdout): fd.write("--- Info section ---\n") ConfigParser.SafeConfigParser.write(self, fd) fd.write("--------------------\n") - pass + def dump(self, filename): + fd = zipfile.ZipFile(filename, "w", zipfile.ZIP_DEFLATED) + temp = StringIO() + ConfigParser.SafeConfigParser.write(self, temp) + fd.writestr("results.ini", temp.getvalue()) + for f in self._attachments: + fd.write(f) + fd.close() + + def attach(self, file): + self._attachments.append(file) Info = FAKInfo() Info.lock() - diff --git a/pyfirstaidkit/plugins.py b/pyfirstaidkit/plugins.py index 5b95dfa..b104953 100644 --- a/pyfirstaidkit/plugins.py +++ b/pyfirstaidkit/plugins.py @@ -283,7 +283,7 @@ class Plugin(object): message = func+" raised "+str(e)) self._reporting.stop(level = TASK, origin = self, message = func) - if self._interpret._config.system.debug: + if Config.system.debug: raise return (self._state, self._result) |