summaryrefslogtreecommitdiffstats
path: root/frontend/frontend_gtk.py
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/frontend_gtk.py')
-rw-r--r--frontend/frontend_gtk.py606
1 files changed, 606 insertions, 0 deletions
diff --git a/frontend/frontend_gtk.py b/frontend/frontend_gtk.py
new file mode 100644
index 0000000..2a2e7f4
--- /dev/null
+++ b/frontend/frontend_gtk.py
@@ -0,0 +1,606 @@
+# File name: main.py
+# Date: 2008/04/21
+# Author: Martin Sivak <msivak at redhat dot com>
+#
+# Copyright (C) Red Hat 2008
+#
+# 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
+# in a file called COPYING along with this program; if not, write to
+# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+# 02139, USA.
+
+import gtk
+import gtk.glade
+import gobject #we need gobject.idle_add
+import copy
+import logging
+from pyfirstaidkit import reporting
+import pprint
+import os.path
+import thread
+
+class CallbacksMainWindow(object):
+ def __init__(self, dialog, cfg, tasker, glade, data):
+ self._dialog = dialog
+ self._tasker = tasker
+ self._glade = glade
+ self._cfg = cfg
+ self._data = data
+ self._running_lock = thread.allocate_lock()
+
+ def execute(self):
+ if not self._running_lock.acquire(0):
+ return
+
+ def _o(pages, stopbutton):
+ """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)
+ return False
+
+ def worker(*args):
+ self._cfg.lock()
+ self._tasker.run()
+ self._cfg.unlock()
+ gobject.idle_add(_o, *args)
+ self._running_lock.release()
+
+ self._data.pages.set_current_page(-1)
+ for i in range(self._data.pages.get_n_pages())[:-1]:
+ self._data.pages.get_nth_page(i).set_sensitive(False)
+ 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))
+
+ #menu callbacks
+ def on_mainmenu_open_activate(self, widget, *args):
+ print "on_mainmenu_open_activate"
+ 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))
+ print d.run()
+ d.destroy()
+ return True
+
+ def on_mainmenu_save_activate(self, widget, *args):
+ print "on_mainmenu_save_activate"
+ d = gtk.FileChooserDialog(title="Save the configuration file", parent=self._dialog, action=gtk.FILE_CHOOSER_ACTION_SAVE,
+ buttons = (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT, gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
+ ret=d.run()
+
+ if ret==gtk.RESPONSE_ACCEPT:
+ try:
+ filename = d.get_filename()
+ fd = open(filename, "w")
+ self._cfg.write(fd)
+ except IOError, e:
+ pass
+
+ d.destroy()
+ return True
+
+ def on_quit_activate(self, widget, *args):
+ print "on_quit_activate"
+ if True: #XXX destroy right now, but warn, in final code we have to wait until plugin finishes
+ print "!!! You should wait until the running plugin finishes!!"
+ self._dialog.destroy()
+ return True
+
+ def on_destroy(self, widget, *args):
+ print "on_destroy"
+ self._tasker.end()
+ del self._tasker
+ del self._cfg
+ del self._data.result_list_iter
+ gtk.main_quit()
+
+ def on_mainmenu_about_activate(self, widget, *args):
+ print "on_mainmenu_about_activate"
+ return True
+
+ #simple mode callbacks
+ def on_b_StartSimple_activate(self, widget, *args):
+ print "on_b_StartSimple_activate"
+
+ flags = set(self._cfg.operation._list("flags"))
+
+ #check fix
+ if self._glade.get_widget("check_Simple_Fix").get_active():
+ self._cfg.operation.mode = "auto-flow"
+ self._cfg.operation.flow = "fix"
+ else:
+ self._cfg.operation.mode = "auto-flow"
+ self._cfg.operation.flow = "diagnose"
+
+ #check interactive
+ if self._glade.get_widget("check_Simple_Interactive").get_active():
+ self._cfg.operation.interactive = "True"
+ else:
+ self._cfg.operation.interactive = "False"
+
+ #check verbose
+ if self._glade.get_widget("check_Simple_Verbose").get_active():
+ self._cfg.operation.verbose = "True"
+ else:
+ self._cfg.operation.verbose = "False"
+
+ #check experimental
+ if self._glade.get_widget("check_Simple_Experimental").get_active():
+ flags.add("experimental")
+ else:
+ try:
+ flags.remove("experimental")
+ except KeyError, e:
+ pass
+
+ self._cfg.operation.flags = " ".join(map(lambda x: x.encode("string-escape"), flags))
+ self.execute()
+ return True
+
+ #advanced mode callbacks
+ def on_b_StartAdvanced_activate(self, widget, *args):
+ print "on_b_StartAdvanced_activate"
+
+ flags = set(self._cfg.operation._list("flags"))
+
+ #set the auto-flow
+ self._cfg.operation.mode = "auto-flow"
+
+ idx = self._data.flow_list.get_active_iter()
+ if idx is None:
+ return True
+ self._cfg.operation.flow = self._data.flow_list_store.get_value(idx,0)
+
+ #check verbose
+ if self._glade.get_widget("check_Advanced_Verbose").get_active():
+ self._cfg.operation.verbose = "True"
+ else:
+ self._cfg.operation.verbose = "False"
+
+ #check experimental
+ if self._glade.get_widget("check_Advanced_Experimental").get_active():
+ flags.add("experimental")
+ else:
+ try:
+ flags.remove("experimental")
+ except KeyError, e:
+ pass
+
+ #check interactive
+ if self._glade.get_widget("check_Advanced_Interactive").get_active():
+ self._cfg.operation.interactive = "True"
+ else:
+ self._cfg.operation.interactive = "False"
+
+ #check dependency
+ if self._glade.get_widget("check_Advanced_Dependency").get_active():
+ self._cfg.operation.dependencies = "True"
+ else:
+ self._cfg.operation.dependencies = "False"
+
+ self._cfg.operation.flags = " ".join(map(lambda x: x.encode("string-escape"), flags))
+
+ self.execute()
+ return True
+
+ #expert mode callbacks
+ def on_b_FlagsExpert_activate(self, widget, *args):
+ print "on_b_FlagsExpert_activate"
+ FlagList(self._cfg, self._tasker.flags(), dir = os.path.dirname(self._glade.relative_file(".")))
+ return True
+
+ def on_b_InfoExpert_activate(self, widget, *args):
+ print "on_b_InfoExpert_activate"
+
+ path,focus = self._data.plugin_list.get_cursor()
+ if path is None:
+ return True
+
+ iter = self._data.plugin_list_store.get_iter(path)
+ pluginname = self._data.plugin_list_store.get_value(iter, 4)
+ print "Selected: ", pluginname
+
+ PluginInfo(self._tasker.pluginsystem().getplugin(pluginname), dir = os.path.dirname(self._glade.relative_file(".")))
+
+ return True
+
+ def on_b_StartExpert_activate(self, widget, *args):
+ print "on_b_StartExpert_activate"
+
+ #check verbose
+ if self._glade.get_widget("check_Expert_Verbose").get_active():
+ self._cfg.operation.verbose = "True"
+ else:
+ self._cfg.operation.verbose = "False"
+
+ #check interactive
+ if self._glade.get_widget("check_Expert_Interactive").get_active():
+ self._cfg.operation.interactive = "True"
+ else:
+ self._cfg.operation.interactive = "False"
+
+ #check dependency
+ if self._glade.get_widget("check_Expert_Dependency").get_active():
+ self._cfg.operation.dependencies = "True"
+ else:
+ self._cfg.operation.dependencies = "False"
+
+ #get the plugin & flow list
+ plugins = []
+ flows = []
+
+ for pname,iter in self._data.plugin_iter.iteritems():
+ childiter = self._data.plugin_list_store.iter_children(iter)
+ while childiter is not None:
+ if self._data.plugin_list_store.get_value(childiter, 0): #checkbox is checked
+ plugins.append(pname)
+ flows.append(self._data.plugin_list_store.get_value(childiter, 1))
+ childiter = self._data.plugin_list_store.iter_next(childiter)
+
+ plugins = map(lambda x: x.encode("string-escape"), plugins)
+ flows = map(lambda x: x.encode("string-escape"), flows)
+
+ #set the flow mode
+ self._cfg.operation.mode = "flow"
+ self._cfg.operation.flow = " ".join(flows)
+ self._cfg.operation.plugin = " ".join(plugins)
+
+ self.execute()
+ return True
+
+ #results callbacks
+ def on_b_ResetResults_activate(self, widget, *args):
+ print "on_b_ResetResults_activate"
+ self._data.result_list_store.clear()
+ del self._data.result_list_iter
+ self._data.result_list_iter = dict()
+ return True
+
+ def on_b_StopResults_activate(self, widget, *args):
+ print "on_b_StopResults_activate"
+ self._tasker.interrupt()
+ return True
+
+class CallbacksFlagList(object):
+ def __init__(self, dialog, cfg, flags):
+ self._dialog = dialog
+ self._flags = flags
+ self._cfg = cfg
+
+ def on_b_OK_activate(self, widget, *args):
+ print "on_b_OK_activate"
+
+ f = set()
+ for k,w in self._flags.iteritems():
+ if w.get_active():
+ f.add(k)
+
+ if len(f)==0:
+ self._cfg.operation.flags = ""
+ else:
+ self._cfg.operation.flags = " ".join(map(lambda x: x.encode("string-escape"), f))
+
+ self._dialog.destroy()
+ return True
+
+ def on_b_Cancel_activate(self, widget, *args):
+ print "on_b_Cancel_activate"
+ self._dialog.destroy()
+ return True
+
+class MainWindow(object):
+ def __init__(self, cfg, 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)
+ self._glade.signal_autoconnect(self._cb)
+ self._window.connect("destroy", self._cb.on_destroy)
+
+ self.pages = self._glade.get_widget("pages")
+ self.status_text = self._glade.get_widget("status_text")
+ self.status_progress = self._glade.get_widget("status_progress")
+
+ self.plugin_list_store = gtk.TreeStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.plugin_list = self._glade.get_widget("tree_Expert")
+ self.plugin_list.set_model(self.plugin_list_store)
+
+ self.plugin_rend_text = gtk.CellRendererText()
+ self.plugin_rend_toggle = gtk.CellRendererToggle()
+ self.plugin_rend_toggle.set_radio(False)
+ self.plugin_rend_toggle.set_property("activatable", False)
+
+ def plugin_rend_text_func(column, cell_renderer, tree_model, iter, user_data):
+ if tree_model.iter_depth(iter)==0:
+ cell_renderer.set_property("cell-background-set", True)
+ cell_renderer.set_property("cell-background-gdk", gtk.gdk.Color(red=50000, green=50000, blue=50000))
+ cell_renderer.set_property("markup", "<b>" + tree_model.get_value(iter, user_data) + "</b>")
+ else:
+ cell_renderer.set_property("cell-background-set", False)
+ cell_renderer.set_property("text", tree_model.get_value(iter, user_data))
+ return
+
+ def plugin_rend_toggle_func(column, cell_renderer, tree_model, iter, user_data = None):
+ if tree_model.iter_depth(iter)==0:
+ cell_renderer.set_property("activatable", False)
+ cell_renderer.set_property("active", False)
+ cell_renderer.set_property("visible", False)
+ cell_renderer.set_property("cell-background-set", True)
+ cell_renderer.set_property("cell-background-gdk", gtk.gdk.Color(red=40000, green=40000, blue=40000))
+ else:
+ cell_renderer.set_property("activatable", True)
+ cell_renderer.set_property("active", tree_model.get_value(iter,0))
+ cell_renderer.set_property("visible", True)
+ cell_renderer.set_property("cell-background-set", False)
+ return
+
+ def plugin_rend_toggle_cb(cell, path, data):
+ model, col = data
+ model[path][0] = not model[path][col]
+ return
+
+ self.plugin_list_col_0 = gtk.TreeViewColumn('Use')
+ self.plugin_list_col_0.pack_start(self.plugin_rend_toggle, False)
+ self.plugin_list_col_0.set_cell_data_func(self.plugin_rend_toggle, plugin_rend_toggle_func)
+ self.plugin_rend_toggle.connect("toggled", plugin_rend_toggle_cb, (self.plugin_list_store, 0))
+
+ self.plugin_list_col_1 = gtk.TreeViewColumn('Name')
+ self.plugin_list_col_1.pack_start(self.plugin_rend_text, True)
+ self.plugin_list_col_1.set_cell_data_func(self.plugin_rend_text, plugin_rend_text_func, 1)
+
+ self.plugin_list_col_2 = gtk.TreeViewColumn('Description')
+ self.plugin_list_col_2.pack_start(self.plugin_rend_text, True)
+ self.plugin_list_col_2.set_cell_data_func(self.plugin_rend_text, plugin_rend_text_func, 2)
+
+ self.plugin_list_col_3 = gtk.TreeViewColumn('Parameters')
+ self.plugin_list_col_3.pack_start(self.plugin_rend_text, True)
+ self.plugin_list_col_3.set_cell_data_func(self.plugin_rend_text, plugin_rend_text_func, 3)
+
+ self.plugin_list.append_column(self.plugin_list_col_0)
+ self.plugin_list.append_column(self.plugin_list_col_1)
+ self.plugin_list.append_column(self.plugin_list_col_2)
+ self.plugin_list.append_column(self.plugin_list_col_3)
+ self.plugin_list.set_search_column(1)
+
+ pluginsystem = tasker.pluginsystem()
+ self.plugin_iter = {}
+ self.flow_list_data = set()
+
+ #flow combobox
+ for plname in pluginsystem.list():
+ p = pluginsystem.getplugin(plname)
+ piter = self.plugin_list_store.append(None, [False, "%s (%s)" % (p.name, p.version), p.description, "", plname])
+ self.plugin_iter[plname] = piter
+ for n,d in [ (f, p.getFlow(f).description) for f in p.getFlows() ]:
+ self.plugin_list_store.append(piter, [False, n, d, "", plname])
+ self.flow_list_data.add(n)
+
+ self.flow_list_rend_text = gtk.CellRendererText()
+ self.flow_list_store = gtk.ListStore(gobject.TYPE_STRING)
+ self.flow_list_store_diagnose = -1
+ for idx,n in enumerate(sorted(self.flow_list_data)):
+ self.flow_list_store.append([n])
+ if n=="diagnose":
+ self.flow_list_store_diagnose = idx
+ self.flow_list = self._glade.get_widget("combo_Advanced_Flows")
+ self.flow_list.set_model(self.flow_list_store)
+ self.flow_list.pack_start(self.flow_list_rend_text, True)
+ self.flow_list.add_attribute(self.flow_list_rend_text, 'text', 0)
+ self.flow_list.set_active(self.flow_list_store_diagnose)
+
+ # results
+ self.result_list_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_INT)
+ self.result_list = self._glade.get_widget("tree_Results")
+ self.result_list.set_model(self.result_list_store)
+ self.result_list_iter = {}
+
+ def result_rend_text_func(column, cell_renderer, tree_model, iter, user_data):
+ colors = [
+ gtk.gdk.Color(red=50000, green=50000, blue=50000),
+ gtk.gdk.Color(red=10000, green=50000, blue=10000),
+ gtk.gdk.Color(red=50000, green=10000, blue=10000),
+ gtk.gdk.Color(red=10000, green=10000, blue=50000)
+ ]
+ state = tree_model.get_value(iter, 3)
+
+ cell_renderer.set_property("cell-background-set", True)
+ cell_renderer.set_property("cell-background-gdk", colors[state])
+
+ if user_data==2 and state!=2:
+ cell_renderer.set_property("foreground-set", True)
+ cell_renderer.set_property("foreground-gdk", gtk.gdk.Color(red=40000, green=40000, blue=40000))
+ else:
+ cell_renderer.set_property("foreground-set", False)
+
+ cell_renderer.set_property("text", tree_model.get_value(iter, user_data))
+ return
+
+ self.result_rend_text = gtk.CellRendererText()
+
+ self.result_list_col_0 = gtk.TreeViewColumn('Name')
+ self.result_list_col_0.pack_start(self.result_rend_text, True)
+ self.result_list_col_0.set_cell_data_func(self.result_rend_text, result_rend_text_func, 0)
+
+ self.result_list_col_1 = gtk.TreeViewColumn('Status')
+ self.result_list_col_1.pack_start(self.result_rend_text, True)
+ self.result_list_col_1.set_cell_data_func(self.result_rend_text, result_rend_text_func, 1)
+
+ self.result_list_col_2 = gtk.TreeViewColumn('Description')
+ self.result_list_col_2.pack_start(self.result_rend_text, True)
+ self.result_list_col_2.set_cell_data_func(self.result_rend_text, result_rend_text_func, 2)
+
+ self.result_list_col_3 = gtk.TreeViewColumn('Status ID')
+ self.result_list_col_3.pack_start(self.result_rend_text, True)
+ self.result_list_col_3.add_attribute(self.result_rend_text, 'text', 3)
+ self.result_list_col_3.set_property("visible", False)
+
+ self.result_list.append_column(self.result_list_col_0)
+ self.result_list.append_column(self.result_list_col_1)
+ self.result_list.append_column(self.result_list_col_2)
+ self.result_list.append_column(self.result_list_col_3)
+ self.result_list.set_search_column(0)
+
+ def update(self, message):
+ def _o(func, *args, **kwargs):
+ """Always return False -> remove from the idle queue after first execution"""
+ func(*args, **kwargs)
+ return False
+
+ def issue_state(self):
+ if self._fixed:
+ return ("Fixed", 3)
+ elif self._happened and self._detected:
+ return ("Detected", 2)
+ elif self._detected:
+ return ("No problem", 1)
+ else:
+ return ("Waiting for check", 0)
+
+
+ if self._cfg.operation.verbose == "True":
+ self._importance = logging.DEBUG
+ else:
+ self._importance = logging.INFO
+
+ """Read the reporting system message and schedule a call to update stuff in the gui using gobject.idle_add(_o, func, params...)"""
+ if message["action"]==reporting.END:
+ gobject.idle_add(_o, self._window.destroy)
+ elif message["action"]==reporting.QUESTION:
+ print "FIXME: Questions not implemented yet"
+ elif message["action"]==reporting.START:
+ if self._importance<=message["importance"]:
+ ctx = self.status_text.get_context_id(message["origin"].name)
+ gobject.idle_add(_o, self.status_text.push, ctx, "START: %s (%s)" % (message["origin"].name, message["message"]))
+ elif message["action"]==reporting.STOP:
+ if self._importance<=message["importance"]:
+ ctx = self.status_text.get_context_id(message["origin"].name)
+ gobject.idle_add(_o, self.status_text.push, ctx, "STOP: %s (%s)" % (message["origin"].name, message["message"]))
+ elif message["action"]==reporting.PROGRESS:
+ if self._importance<=message["importance"]:
+ if message["message"] is None:
+ gobject.idle_add(self.status_progress.hide)
+ else:
+ gobject.idle_add(_o, self.status_progress.set_text, "%d/%d - %s" % (message["message"][0], message["message"][1], message["origin"].name))
+ gobject.idle_add(_o, self.status_progress.set_fraction, float(message["message"][0])/message["message"][1])
+ gobject.idle_add(_o, self.status_progress.show)
+ elif message["action"]==reporting.INFO:
+ if self._importance<=message["importance"]:
+ ctx = self.status_text.get_context_id(message["origin"].name)
+ gobject.idle_add(_o, self.status_text.push, ctx, "INFO: %s (%s)" % (message["message"], message["origin"].name))
+ elif message["action"]==reporting.ALERT:
+ if self._importance<=message["importance"]:
+ ctx = self.status_text.get_context_id(message["origin"].name)
+ gobject.idle_add(_o, self.status_text.push, ctx, "ALERT: %s (%s)" % (message["message"], message["origin"].name))
+ elif message["action"]==reporting.EXCEPTION:
+ ctx = self.status_text.get_context_id(message["origin"].name)
+ gobject.idle_add(_o, self.status_text.push, ctx, "EXCEPTION: %s (%s)" % (message["message"], message["origin"].name))
+ elif message["action"]==reporting.TABLE:
+ if self._importance<=message["importance"]:
+ print "TABLE %s FROM %s" % (message["title"], message["origin"].name,)
+ pprint.pprint(message["message"])
+ elif message["action"]==reporting.TREE:
+ if self._importance<=message["importance"]:
+ print "TREE %s FROM %s" % (message["title"], message["origin"].name,)
+ pprint.pprint(message["message"])
+ elif message["action"]==reporting.ISSUE:
+ i = message["message"]
+ t,ids = issue_state(i)
+ if not self.result_list_iter.has_key(i):
+ self.result_list_iter[i] = self.result_list_store.append([i.name, t, i.description, ids])
+ else:
+ for idx,val in enumerate([i.name, t, i.description, ids]):
+ gobject.idle_add(_o, self.result_list_store.set, self.result_list_iter[i], idx, val)
+ else:
+ print "FIXME: Unknown message action %d!!" % (message["action"],)
+ print message
+
+ def run(self):
+ gtk.gdk.threads_init()
+ gtk.main()
+
+class FlagList(object):
+ def __init__(self, cfg, flags, dir=""):
+ self._glade = gtk.glade.XML(os.path.join(dir, "firstaidkit.glade"), "FlagList")
+ self._window = self._glade.get_widget("FlagList")
+ self._window.set_modal(True)
+ self.flags = {}
+ self._cb = CallbacksFlagList(self._window, cfg, self.flags)
+ self._glade.signal_autoconnect(self._cb)
+ fl_gui = self._glade.get_widget("box_flags")
+ flags_set = cfg.operation._list("flags")
+ for f in sorted(flags.known()):
+ b = gtk.CheckButton(label=f)
+ self.flags[f] = b
+ b.set_active(f in flags_set)
+ b.show()
+ fl_gui.pack_start(b, expand=False, fill=True)
+ l = gtk.Label("")
+ l.show()
+
+ fl_gui.pack_end(l, expand=True, fill=True)
+
+class PluginInfo(object):
+ def close(self, widget):
+ self._window.destroy()
+
+ def __init__(self, plugin, dir=""):
+ self._glade = gtk.glade.XML(os.path.join(dir, "firstaidkit.glade"), "PluginInfo")
+ self._window = self._glade.get_widget("PluginInfo")
+ self._window.set_modal(True)
+ self._window.set_title(self._window.get_title()+plugin.name)
+
+ self._close = self._glade.get_widget("CloseButton")
+ self._close.connect("clicked", self.close)
+
+ self._name = self._glade.get_widget("Info_name")
+ self._name.set_label(plugin.name)
+
+ self._version = self._glade.get_widget("Info_version")
+ self._version.set_label(plugin.version)
+
+ self._author = self._glade.get_widget("Info_author")
+ self._author.set_label(plugin.author)
+
+ self._description = self._glade.get_widget("Info_description")
+ self._description.set_label(plugin.description)
+
+ self._table = self._glade.get_widget("Table")
+
+ for n,d in [ (f, plugin.getFlow(f).description) for f in plugin.getFlows() ]:
+ if n==plugin.default_flow:
+ lname = gtk.Label("<b>"+n+"</b>")
+ lname.set_property("use-markup", True)
+ else:
+ lname = gtk.Label(n)
+ lname.show()
+ ldesc = gtk.Label(d)
+ ldesc.show()
+ ldesc.set_line_wrap(True)
+
+ sy = self._table.get_property("n-rows")
+ sx = self._table.get_property("n-columns")
+ sy += 1
+ self._table.resize(sy, sx)
+ self._table.attach(lname, 0, 1, sy-1, sy, yoptions = gtk.FILL, xoptions = gtk.FILL)
+ lname.set_alignment(0, 0)
+ self._table.attach(ldesc, 1, 2, sy-1, sy, yoptions = gtk.FILL, xoptions = gtk.FILL)
+ ldesc.set_alignment(0, 0)
+
+
+if __name__=="__main__":
+ w = MainWindow(None, None, None)
+ w.run()
+