summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xfirstaidkit10
-rw-r--r--frontend/firstaidkit.glade234
-rw-r--r--frontend/frontend_gtk.py62
-rw-r--r--pyfirstaidkit/__init__.py2
-rw-r--r--pyfirstaidkit/configuration.py22
-rw-r--r--pyfirstaidkit/plugins.py2
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)