Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MANIFEST2
-rw-r--r--ep_modifier_rectangulartile.py4
-rw-r--r--ep_page_ancestors.py152
-rw-r--r--ep_page_status.py3
-rw-r--r--ka_controller.py20
-rw-r--r--ka_debug.py2
-rw-r--r--ka_history.py218
-rw-r--r--ka_status.py52
-rw-r--r--ka_widget.py1
-rw-r--r--kandid.glade125
-rw-r--r--model_population.py13
-rw-r--r--po/Kandid.pot66
-rw-r--r--test_history.py111
-rw-r--r--test_suite.py26
14 files changed, 752 insertions, 43 deletions
diff --git a/MANIFEST b/MANIFEST
index 5f9352c..18e38a3 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -129,6 +129,7 @@ ep_modifier_border.py
ep_modifier_flip.py
ep_modifier_mask.py
ep_modifier_rectangulartile.py
+ep_page_ancestors.py
ep_page_details.py
ep_page_gettingstarted.py
ep_page_intro.py
@@ -151,6 +152,7 @@ ka_controller.py
ka_debug.py
ka_extensionpoint.py
ka_factory.py
+ka_history.py
ka_html_page.py
ka_importer.py
ka_incoming.py
diff --git a/ep_modifier_rectangulartile.py b/ep_modifier_rectangulartile.py
index 8f1b6a3..d290594 100644
--- a/ep_modifier_rectangulartile.py
+++ b/ep_modifier_rectangulartile.py
@@ -42,8 +42,8 @@ class RectangularTileModifier(model_allele.Allele):
def randomize(self):
"""Randomize the layers components."""
- self.x_tiles = random.randint(2, 4)
- self.y_tiles = random.randint(2, 4)
+ self.x_tiles = random.randint(1, 3)
+ self.y_tiles = random.randint(1, 3)
def mutate(self):
"""Make small random changes to the layers components."""
diff --git a/ep_page_ancestors.py b/ep_page_ancestors.py
new file mode 100644
index 0000000..6283cc8
--- /dev/null
+++ b/ep_page_ancestors.py
@@ -0,0 +1,152 @@
+# coding: UTF-8
+# Copyright 2009, 2010 Thomas Jourdan
+#
+# 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 3 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import ka_debug
+import ka_history
+import cairo
+import math
+
+_ANCESTORS_PAGE_NUMBER = 5
+_SCALE = math.sqrt(2.0)
+
+class AncestorsController(object):
+ """
+ inv: self._drawing_page is not None
+ """
+
+ def __init__(self, controller, widget_tree):
+ """
+ pre: controller is not None
+ pre: widget_tree is not None
+ """
+ self._widget_tree = widget_tree
+ self._drawing_page = self._widget_tree.get_widget('kandidNotebook'). \
+ get_nth_page(_ANCESTORS_PAGE_NUMBER)
+ self._historyview = self._widget_tree.get_widget('ancestors_drawingarea')
+ self._history = ka_history.KandidHistory.instance()
+ self._protozoon_id = ''
+
+ def close(self):
+ """Only a dummy."""
+ pass
+
+ def autoconnect_events(self):
+ """Auto connect ancestros view."""
+ events = {
+ 'on_ancestrosarea_expose' : self.on_ancestrosarea_expose,
+ }
+ self._widget_tree.signal_autoconnect(events)
+
+ def localize(self):
+ """A dummy"""
+ pass
+
+ def show(self):
+ """A dummy"""
+
+ def on_notebook_switch_page(self):
+ """Only a dummy."""
+
+ def start_calculation(self, protozoon):
+ """Start explaining of a protozoon.
+ pre: protozoon is not None
+ """
+ ka_debug.info('AncestorsController.start_calculation %s' %
+ (protozoon.get_unique_id()))
+ self._protozoon_id = protozoon.get_unique_id()
+ self._drawing_page.show()
+ self._widget_tree.get_widget('kandidNotebook'). \
+ set_current_page(_ANCESTORS_PAGE_NUMBER)
+
+ def on_ancestrosarea_expose(self, widget, event):
+ """ Repaint image of a single protozoon inside ancestros view.
+ pre: widget is not None
+ """
+ # draw precalculated protozoon stored in the surface cache.
+ ka_debug.info('on_ancestrosarea_expose: ' + widget.name + ' '
+ + str(widget.allocation.width)
+ + 'x' + str(widget.allocation.height))
+ ctx = widget.window.cairo_create()
+ # Restrict Cairo to the exposed area; avoid extra work
+ ctx.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+ ctx.clip()
+ ctx.set_operator(cairo.OPERATOR_SOURCE)
+
+ # Fill the background with white
+ ctx.set_source_rgb(1.0, 1.0, 1.0)
+ ctx.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+ ctx.fill()
+
+ self._paint_next(ctx, event.area.width/2, 3, self._protozoon_id)
+
+ def _paint_connector(self, ctx, mx, my, x0, y0, my_parent):
+ if my_parent is not None:
+ ctx.set_line_width(2)
+ ctx.set_source_rgb(0.2, 0.2, 0.2)
+ ctx.move_to(mx, my)
+ ctx.line_to(x0, y0)
+ ctx.stroke()
+
+ def _collision(self, my_id):
+ if my_id is not None and self._history.contains(my_id):
+ p01, p10 = None, None
+ my_parents = self._history.get_parents(my_id)
+ if my_parents[0] is not None and self._history.contains(my_parents[0]):
+ p0 = self._history.get_parents(my_parents[0])
+ if p0[1] is not None and self._history.contains(p0[1]):
+ p01 = self._history.get_parents(p0[1])
+ if my_parents[1] is not None and self._history.contains(my_parents[1]):
+ p1 = self._history.get_parents(my_parents[1])
+ if p1[0] is not None and self._history.contains(p1[0]):
+ p10 = self._history.get_parents(p1[0])
+ distance = 1.0 if p01 is None or p10 is None else _SCALE
+ return 0.5 * distance * \
+ (self._collision(my_parents[0]) + self._collision(my_parents[1]))
+ else:
+ return 0.5
+
+ def _paint_next(self, ctx, xpos, ypos, my_id):
+ if my_id is not None:
+ ka_debug.info('my_id: ' + my_id)
+ surface = self._history.get_surface(my_id)
+ width = surface.get_width() if surface is not None else 200
+ height = surface.get_height() if surface is not None else 200
+
+ if self._history.contains(my_id):
+ mx, my = xpos, ypos+height
+ x0, y0 = xpos-(self._collision(my_id)*width+23), ypos+height+23
+ x1, y1 = xpos+(self._collision(my_id)*width+23), ypos+height+23
+ my_parents = self._history.get_parents(my_id)
+ self._paint_connector(ctx, mx, my, x0, y0, my_parents[0])
+ self._paint_connector(ctx, mx, my, x1, y1, my_parents[1])
+
+ ctx.save()
+ ctx.scale(1.0/_SCALE, 1.0/_SCALE)
+ self._paint_next(ctx, _SCALE*x0, _SCALE*y0, my_parents[0])
+ self._paint_next(ctx, _SCALE*x1, _SCALE*y1, my_parents[1])
+ ctx.restore()
+
+ if surface is not None:
+ ka_debug.info('(xpos, ypos): %d, %d' % (xpos, ypos))
+ ctx.set_operator(cairo.OPERATOR_SOURCE)
+ ctx.rectangle(xpos-width/2, ypos, width, height)
+ ctx.clip()
+ ctx.set_source_surface(surface, xpos-width/2, ypos)
+ ctx.paint()
+ ctx.reset_clip()
diff --git a/ep_page_status.py b/ep_page_status.py
index b66ae39..3d374d1 100644
--- a/ep_page_status.py
+++ b/ep_page_status.py
@@ -21,7 +21,7 @@ import gobject
import ka_status
import ka_debug
-_STATUS_PAGE_NUMBER = 5
+_STATUS_PAGE_NUMBER = 6
class StatusController(object):
"""
@@ -65,6 +65,7 @@ class StatusController(object):
def refresh(self):
"""Replace status text completely."""
+ self._status.scan_os_status()
buf = self._statusview.get_buffer()
buf.delete(buf.get_start_iter(), buf.get_end_iter())
buf.insert(buf.get_end_iter(), self._status.recall())
diff --git a/ka_controller.py b/ka_controller.py
index 5603936..93ebab6 100644
--- a/ka_controller.py
+++ b/ka_controller.py
@@ -26,6 +26,7 @@ import ka_incoming
import ka_task
import ka_extensionpoint
import kandidtube
+import ka_history
POPULATION_CAPACITY = 12
INCOMMING_CAPACITY = 3
@@ -56,6 +57,7 @@ class KandidController(object):
self._pages = []
self._zoom_controller = None
self._details_controller = None
+ self._ancestors_controller = None
# add optional pages to kandid notebook
pages = ka_extensionpoint.list_extensions('page')
@@ -70,6 +72,8 @@ class KandidController(object):
self._zoom_controller = page_controller
if str(type(page_controller)) == "<class 'ep_page_details.DetailsController'>":
self._details_controller = page_controller
+ if str(type(page_controller)) == "<class 'ep_page_ancestors.AncestorsController'>":
+ self._ancestors_controller = page_controller
self._update_population_gui()
@@ -100,6 +104,8 @@ class KandidController(object):
self.on_exportpng_activate
events['on_explain_activate_' + strix] = \
self.on_explain_activate
+ events['on_ancestors_activate_' + strix] = \
+ self.on_ancestors_activate
events['on_favorite_activate_' + strix] = self.on_favorite_activate
events['on_awfull_activate_' + strix] = self.on_awfull_activate
for cell_index in range(3):
@@ -129,6 +135,9 @@ class KandidController(object):
set_value(self.model.flurry_rate)
# update buttons
dummy, moderate, poor = self.model.classify()
+#TODO 'breed' und 'random' deaktivieren solange Tasks laufen
+# is_sensitive = ka_task.GeneratorTask.is_completed() \
+# and len(poor) > 0 and len(moderate) > 0
is_sensitive = len(poor) > 0 and len(moderate) > 0
self._widget_tree.get_widget('breedGenerationButton'). \
set_sensitive(is_sensitive)
@@ -270,6 +279,8 @@ class KandidController(object):
ctx = cairo.Context(surface)
protozoon.render(task, ctx, width, height)
self.surface_cache[cell_index] = surface
+ history = ka_history.KandidHistory.instance()
+ history.link_surface(protozoon.get_unique_id(), surface)
# ka_debug.info('task_render exit: ' + str(cell_index))
return cell_index
@@ -335,6 +346,15 @@ class KandidController(object):
if self._details_controller is not None:
self._details_controller.start_calculation(protozoon)
+ def on_ancestors_activate(self, *args):
+ """Publish single protozoon to all other buddies.
+ pre: len(args) >= 1
+ """
+ ka_debug.info('on_ancestors_activate [%s]' % args[0].get_name())
+ protozoon = self.model.protozoans[name_to_index(args[0].get_name())]
+ if self._ancestors_controller is not None:
+ self._ancestors_controller.start_calculation(protozoon)
+
def on_favorite_activate(self, *args):
"""Set best ranking for this protozoon.
pre: len(args) >= 1
diff --git a/ka_debug.py b/ka_debug.py
index af89244..9bfcc8c 100644
--- a/ka_debug.py
+++ b/ka_debug.py
@@ -25,7 +25,7 @@ import time
DEBUG_ACTIVITY_PATH = '/home/strom/minimal/activities/Kandid.activity'
DEBUG_PROFILE_PATH = '/home/strom/.sugar/1/'
DBC_BLACK_LIST = ['activity', 'ka_debug', 'kandidtube', 'setup',
- 'test_suite', 'test_enumerator']
+ 'test_suite', 'test_history', 'test_enumerator']
_logger = None
_start_time = time.time()
_last_clock = 0.0
diff --git a/ka_history.py b/ka_history.py
new file mode 100644
index 0000000..228c07c
--- /dev/null
+++ b/ka_history.py
@@ -0,0 +1,218 @@
+# coding: UTF-8
+# Copyright 2009, 2010 Thomas Jourdan
+#
+# 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 3 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import gtk
+from gettext import gettext as _
+
+class KandidHistory(object):
+ """
+ """
+ _history = None
+ _icon_width = 48
+ _newest = 1
+
+ class Item(object):
+ def __init__(self, init_parent1_id, init_parent2_id):
+ self.ref_count = 0
+ self.surface = None
+ self.parent1_id = init_parent1_id
+ self.parent2_id = init_parent2_id
+ self.old = 0
+
+ def __str__(self):
+ return '(' + self.ref_count + ', ' + self.parent1_id + ', ' + self.parent2_id + ')'
+
+ def __init__(self):
+ """
+ inv: self.parents is not None
+ """
+ self.parents = {}
+ self.assumed_icon_width = KandidHistory._icon_width
+ self.surfaces_referenced = 0
+
+ @staticmethod
+ def instance():
+ if KandidHistory._history is None:
+ KandidHistory._history = KandidHistory()
+ return KandidHistory._history
+
+ def clear(self):
+ self.parents = {}
+ self.surfaces_referenced = 0
+
+ def rember_parents(self, my_id, parent1_id, parent2_id):
+ """Remember the ids of my parents.
+ pre: my_id is not None and my_id.startswith('_')
+ pre: parent1_id is not None and parent1_id.startswith('_')
+ pre: parent2_id is not None and parent2_id.startswith('_')
+ pre: not my_id == parent1_id
+ pre: not my_id == parent2_id
+ """
+ if my_id not in self.parents:
+ self.parents[my_id] = KandidHistory.Item(parent1_id, parent2_id)
+ else:
+ self.parents[my_id].parent1_id = parent1_id
+ self.parents[my_id].parent2_id = parent2_id
+ if parent1_id in self.parents:
+ self.parents[parent1_id].ref_count += 1
+ if parent2_id in self.parents:
+ self.parents[parent2_id].ref_count += 1
+
+ def link_surface(self, my_id, my_surface):
+ """Link an id with an surface
+ pre: my_id is not None and my_id.startswith('_')
+ pre: my_surface is not None
+ """
+ if my_id not in self.parents:
+ self.parents[my_id] = KandidHistory.Item(None, None)
+ self.parents[my_id].ref_count += -1
+ if self.parents[my_id].surface is None:
+ self.surfaces_referenced += 1
+ self.parents[my_id].surface = my_surface
+ self.parents[my_id].old = KandidHistory._newest
+ KandidHistory._newest += 1
+ self._limit_memory_usage()
+
+ def _limit_memory_usage(self):
+ """
+ limit memory usage, forget old surfaces
+ """
+ while self.surfaces_referenced > 25:
+ min_id, min_old = None, 2**31
+ for key, parent in self.parents.iteritems():
+ if parent.old < min_old:
+ min_id, min_old = key, parent.old
+ if min_id is not None:
+ self.parents.surface = None
+ self.surfaces_referenced -= 1
+
+
+ def unlink(self, my_id):
+ """Forget an id and free the linked surface.
+ pre: my_id is not None and my_id.startswith('_')
+ """
+ if my_id in self.parents:
+ self.parents[my_id].ref_count -= 1
+ if self.parents[my_id].ref_count < 0:
+ my_parents = self.get_parents(my_id)
+ parent1_id, parent2_id = my_parents[0], my_parents[1]
+ if parent1_id in self.parents:
+ self.unlink(parent1_id)
+ if parent2_id in self.parents:
+ self.unlink(parent2_id)
+ if self.parents[my_id].surface is not None:
+ self.surfaces_referenced -= 1
+ del self.parents[my_id]
+
+ def contains(self, my_id):
+ """Returns True if my_id can be found.
+ pre: my_id is not None and my_id.startswith('_')
+ """
+ return my_id in self.parents
+
+ def get_parents(self, my_id):
+ """Return ids of both parents
+ pre: my_id is not None and my_id.startswith('_')
+ pre: self.parents.has_key(my_id)
+ post: len(__return__) == 2
+ """
+ my_parents = self.parents[my_id]
+ return ( my_parents.parent1_id, my_parents.parent2_id )
+
+ def get_surface(self, my_id):
+ """
+ pre: my_id is not None and my_id.startswith('_')
+ """
+ return self.parents[my_id].surface if my_id in self.parents else None
+
+# def get_pixbuf(self, my_id):
+# """
+# pre: my_id is not None and my_id.startswith('_')
+# """
+# pixbuf, surface = None, self.get_surface(my_id)
+# if surface is not None:
+# width, height = surface.get_width(), surface.get_height()
+# pixmap = gtk.gdk.Pixmap (None, width, height, 24)
+# cr = pixmap.cairo_create()
+# cr.set_source_surface(surface, 0, 0)
+# cr.paint()
+# pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height)
+# pixbuf = pixbuf.get_from_drawable(pixmap, gtk.gdk.colormap_get_system(), 0, 0, 0, 0, width, height)
+# return pixbuf
+
+# def get_pixbuf(self, my_id):
+# """
+# pre: my_id is not None and my_id.startswith('_')
+# """
+# pixbuf, surface = None, self.get_surface(my_id)
+# if surface is not None:
+# filename = '/dev/shm/' + my_id + '.png'
+# surface.write_to_png(filename)
+# pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
+# return pixbuf
+
+# def get_treestore(self, my_id):
+# """
+# pre: my_id is not None and my_id.startswith('_')
+# """
+# treestore = gtk.TreeStore(gtk.gdk.Pixbuf, str)
+# self.assumed_icon_width, icon = self._draw_icon(my_id)
+# it = treestore.append(None, [icon, my_id])
+# self._get_treestore0(my_id, treestore, it)
+# return treestore
+#
+# def _get_treestore0(self, my_id, treestore, it):
+# """
+# pre: my_id is not None and my_id.startswith('_')
+# pre: treestore is not None
+# pre: it is not None
+# """
+# if my_id is not None and self.contains(my_id):
+# my_parents = self.get_parents(my_id)
+# parent1_id, parent2_id = my_parents[0], my_parents[1]
+# self._append_node(my_id, parent1_id, treestore, it)
+# self._append_node(my_id, parent2_id, treestore, it)
+#
+# def _append_node(self, my_id, parent_id, treestore, it):
+# if parent_id is not None:
+# title = parent_id if self.parents[my_id].surface is not None \
+# else parent_id + _('Sorry, can not remember the image')
+# child_it = treestore.append(it, [self._draw_icon(parent_id)[1],
+# title])
+# self._get_treestore0(parent_id, treestore, child_it)
+#
+# def _draw_icon(self, my_id):
+# """
+# post: len(__return__) == 2
+# post: __return__[0] >= 0
+# """
+# pixbuf = None
+# width = KandidHistory._icon_width
+# if my_id in self.parents:
+# surface = self.parents[my_id].surface
+# if surface is not None:
+# width, h = surface.get_width(), surface.get_height()
+# pixmap = gtk.gdk.Pixmap (None, width, h, 24)
+# cr = pixmap.cairo_create()
+# cr.set_source_surface(surface, 0, 0)
+# cr.paint()
+# pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, h)
+# pixbuf = pixbuf.get_from_drawable(pixmap, gtk.gdk.colormap_get_system(), 0, 0, 0, 0, width, h)
+# if pixbuf is None:
+# theme = gtk.icon_theme_get_default()
+# pixbuf = theme.load_icon(gtk.STOCK_DELETE, KandidHistory._icon_width, 0)
+# return width, pixbuf
diff --git a/ka_status.py b/ka_status.py
index bac84aa..9ddb089 100644
--- a/ka_status.py
+++ b/ka_status.py
@@ -15,10 +15,14 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+import os
from gettext import gettext as _
import ka_debug
import ka_extensionpoint
+import sys
+import traceback
+_proc_status = '/proc/%d/status' % os.getpid()
TOPIC_COLLABORATION = 1000
SUB_ID = 1
@@ -32,6 +36,11 @@ SUB_BUDDIES_FOUND = 8
TOPIC_TASK = 2000
SUB_UNFINISHED = 1
+SUB_THREADS = 2
+SUB_VM_SIZE = 3
+SUB_VM_PEAK = 4
+SUB_VM_RSS = 5
+SUB_PID = 6
TOPIC_ACTIVTY = 9000
SUB_REVISION = 1
@@ -48,6 +57,11 @@ TOPIC = {TOPIC_COLLABORATION: _('Collaboration'),
TOPIC_TASK: _('Tasks'),
TOPIC_TASK+SUB_UNFINISHED: _('Unfinished tasks'),
+ TOPIC_TASK+SUB_THREADS: _('Threads'),
+ TOPIC_TASK+SUB_VM_SIZE: _('Virtual memory size'),
+ TOPIC_TASK+SUB_VM_PEAK: _('Virtual memory peak size'),
+ TOPIC_TASK+SUB_VM_RSS: _('Resident set size'),
+ TOPIC_TASK+SUB_PID: _('Process ID'),
TOPIC_ACTIVTY: _('Activity'),
TOPIC_ACTIVTY+SUB_REVISION: _('Running'),
@@ -67,8 +81,9 @@ class Status(object):
self._status_dict = {}
value = 'Kandid, release v' + str(ka_extensionpoint.revision_number)
value = value + ', DoB activated' if ka_debug.is_DbC_activated \
- else value
+ else value
self.set(TOPIC_ACTIVTY, SUB_REVISION, value)
+ self.set(TOPIC_TASK, SUB_PID, str(os.getpid()))
@staticmethod
def instance():
@@ -108,3 +123,38 @@ class Status(object):
topic_head = key / 1000
text += ' ' + TOPIC[key] + ': ' + self._status_dict[key] + '\n'
return text
+
+
+ def _set_process_status(self, os_status, key, sub):
+ pos = os_status.index(key)
+ num_tokens = 3 if key.startswith('Vm') else 2
+ tri = os_status[pos:].split(None, num_tokens) # whitespace
+ pos, pretty = 0, ''
+ for digit in tri[1][::-1]:
+ if pos > 0 and pos % 3 == 0:
+ pretty = '.' + pretty
+ pretty = digit + pretty
+ pos += 1
+ if num_tokens > 2:
+ self.set(TOPIC_TASK, sub, pretty + ' ' + tri[2])
+ else:
+ self.set(TOPIC_TASK, sub, pretty)
+ return pos
+
+ def scan_os_status(self):
+ """see
+ http://linuxdevcenter.com/pub/a/linux/2006/11/30/linux-out-of-memory.html
+ """
+ try:
+ t = open(_proc_status)
+ os_status = t.read()
+ self._set_process_status(os_status, 'Threads:', SUB_THREADS)
+ self._set_process_status(os_status, 'VmSize:', SUB_VM_SIZE)
+ self._set_process_status(os_status, 'VmPeak:', SUB_VM_PEAK)
+ self._set_process_status(os_status, 'VmRSS:', SUB_VM_RSS)
+ t.close()
+ except:
+ # non Linux?
+ ka_debug.err('scan_os_status [%s] [%s]' % \
+ (sys.exc_info()[0], sys.exc_info()[1]))
+ traceback.print_exc(file=sys.__stderr__)
diff --git a/ka_widget.py b/ka_widget.py
index 6752823..b88c148 100644
--- a/ka_widget.py
+++ b/ka_widget.py
@@ -63,6 +63,7 @@ class KandidWidget(object):
'zoomLabel' : _('Zoom'),
'introLabel' : _('Introduction'),
'statusLabel' : _('Status'),
+ 'ancestorsLabel' : _('Ancestors'),
}
for key, label in local.iteritems():
self._widget_tree.get_widget(key).set_label(label)
diff --git a/kandid.glade b/kandid.glade
index 51732ea..d16910b 100644
--- a/kandid.glade
+++ b/kandid.glade
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
-<!--Generated with glade3 3.4.5 on Sun Feb 7 20:45:51 2010 -->
+<!--Generated with glade3 3.4.5 on Sun Mar 21 10:08:36 2010 -->
<glade-interface>
<widget class="GtkWindow" id="kandidWindow">
<child>
@@ -1339,6 +1339,31 @@
</packing>
</child>
<child>
+ <widget class="GtkEventBox" id="ancestorsPage">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkDrawingArea" id="ancestors_drawingarea">
+ <property name="visible">True</property>
+ <signal name="expose_event" handler="on_ancestrosarea_expose"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="ancestorsLabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Ancestors</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ <property name="position">5</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+ <child>
<widget class="GtkEventBox" id="statusPage">
<property name="visible">True</property>
<child>
@@ -1368,7 +1393,7 @@
</widget>
<packing>
<property name="type">tab</property>
- <property name="position">5</property>
+ <property name="position">6</property>
<property name="tab_fill">False</property>
</packing>
</child>
@@ -1433,6 +1458,14 @@
<signal name="activate" handler="on_explain_activate_0"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_0">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_0"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1496,6 +1529,14 @@
<signal name="activate" handler="on_explain_activate_1"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_1"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1559,6 +1600,14 @@
<signal name="activate" handler="on_explain_activate_2"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_2"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1622,6 +1671,14 @@
<signal name="activate" handler="on_explain_activate_3"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_3"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1685,6 +1742,14 @@
<signal name="activate" handler="on_explain_activate_4"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_4"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1748,6 +1813,14 @@
<signal name="activate" handler="on_explain_activate_5"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_5"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1811,6 +1884,14 @@
<signal name="activate" handler="on_explain_activate_6"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_6"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1874,6 +1955,14 @@
<signal name="activate" handler="on_explain_activate_7"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_7"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -1937,6 +2026,14 @@
<signal name="activate" handler="on_explain_activate_8"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_8"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -2000,6 +2097,14 @@
<signal name="activate" handler="on_explain_activate_9"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_9"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -2063,6 +2168,14 @@
<signal name="activate" handler="on_explain_activate_10"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_10">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_10"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
@@ -2126,6 +2239,14 @@
<signal name="activate" handler="on_explain_activate_11"/>
</widget>
</child>
+ <child>
+ <widget class="GtkMenuItem" id="ancestors_menuitem_11">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Show ancestors</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="on_ancestors_activate_11"/>
+ </widget>
+ </child>
</widget>
</child>
</widget>
diff --git a/model_population.py b/model_population.py
index b29fb49..0f2e4e4 100644
--- a/model_population.py
+++ b/model_population.py
@@ -26,6 +26,7 @@ import random
import ka_debug
import model_random
import model_protozoon
+import ka_history
STATE_INIT = 'I'
STATE_RANDOMIZED = 'R'
@@ -190,11 +191,17 @@ class KandidModel(object):
new_one = good[0].crossingover(partner)
new_one.swap_places()
new_one.mutate()
-# ka_debug.info(good[0].get_unique_id() + ' and '
-# + partner.get_unique_id() + ' replaced '
-# + self.protozoans[new_at].get_unique_id())
+ history = ka_history.KandidHistory.instance()
+ history.unlink(self.protozoans[new_at].get_unique_id())
+ ka_debug.info('new offspring ' + new_one.get_unique_id()
+ + ' breeded by ' + good[0].get_unique_id() + ' and '
+ + partner.get_unique_id() + ' replaced '
+ + self.protozoans[new_at].get_unique_id())
self.protozoans[new_at] = new_one
self.fitness[new_at] = 4.0
+ history.rember_parents(new_one.get_unique_id(),
+ good[0].get_unique_id(),
+ partner.get_unique_id())
def find_partner(self, candidates):
"""Find a partner from the candidate list by chance.
diff --git a/po/Kandid.pot b/po/Kandid.pot
index 2d065af..d3d345c 100644
--- a/po/Kandid.pot
+++ b/po/Kandid.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-02-22 21:50+0100\n"
+"POT-Creation-Date: 2010-03-25 20:33+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -193,55 +193,75 @@ msgstr ""
msgid "background color:"
msgstr ""
-#: ka_status.py:39
+#: ka_status.py:48
msgid "Collaboration"
msgstr ""
-#: ka_status.py:40
+#: ka_status.py:49
msgid "My ID"
msgstr ""
-#: ka_status.py:41
+#: ka_status.py:50
msgid "Share"
msgstr ""
-#: ka_status.py:42
+#: ka_status.py:51
msgid "My tubes"
msgstr ""
-#: ka_status.py:43
+#: ka_status.py:52
msgid "Buddies participating"
msgstr ""
-#: ka_status.py:44
+#: ka_status.py:53
msgid "Buddies joined"
msgstr ""
-#: ka_status.py:45
+#: ka_status.py:54
msgid "Buddies left"
msgstr ""
-#: ka_status.py:46
+#: ka_status.py:55
msgid "Received latest"
msgstr ""
-#: ka_status.py:47
+#: ka_status.py:56
msgid "Buddies found during startup"
msgstr ""
-#: ka_status.py:49
+#: ka_status.py:58
msgid "Tasks"
msgstr ""
-#: ka_status.py:50
+#: ka_status.py:59
msgid "Unfinished tasks"
msgstr ""
-#: ka_status.py:52
+#: ka_status.py:60
+msgid "Threads"
+msgstr ""
+
+#: ka_status.py:61
+msgid "Virtual memory size"
+msgstr ""
+
+#: ka_status.py:62
+msgid "Virtual memory peak size"
+msgstr ""
+
+#: ka_status.py:63
+msgid "Resident set size"
+msgstr ""
+
+#: ka_status.py:64
+msgid "Process ID"
+msgstr ""
+
+#: ka_status.py:66
msgid "Activity"
msgstr ""
-#: ka_status.py:53
+#: ka_status.py:67
msgid "Running"
msgstr ""
@@ -371,7 +391,7 @@ msgstr ""
msgid "Population"
msgstr ""
-#: ka_widget.py:63 ka_widget.py:75
+#: ka_widget.py:63 ka_widget.py:76
msgid "Zoom"
msgstr ""
@@ -383,27 +403,31 @@ msgstr ""
msgid "Status"
msgstr ""
-#: ka_widget.py:72
-msgid "My favorite"
+#: ka_widget.py:66
+msgid "Ancestors"
msgstr ""
#: ka_widget.py:73
-msgid "Awful bore, replace it"
+msgid "My favorite"
msgstr ""
#: ka_widget.py:74
+msgid "Awful bore, replace it"
+msgstr ""
+
+#: ka_widget.py:75
msgid "Publish to my friends"
msgstr ""
-#: ka_widget.py:76
+#: ka_widget.py:77
msgid "Send image to journal"
msgstr ""
-#: ka_widget.py:81
+#: ka_widget.py:82
msgid "Accept protozoon"
msgstr ""
-#: ka_widget.py:82
+#: ka_widget.py:83
msgid "Decline protozoon"
msgstr ""
diff --git a/test_history.py b/test_history.py
new file mode 100644
index 0000000..1943540
--- /dev/null
+++ b/test_history.py
@@ -0,0 +1,111 @@
+# coding: UTF-8
+# Copyright 2009, 2010 Thomas Jourdan
+#
+# 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 3 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+import unittest
+import gtk
+
+import ka_debug
+import ka_history
+import cairo
+
+class TestKandidHistory(unittest.TestCase):
+
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_history(self):
+ history = ka_history.KandidHistory.instance()
+ history.clear()
+ self.assertFalse(history.contains('_missing'))
+ self.assertEqual(None, history.get_surface('_missing'))
+
+ history.rember_parents('_ab', '_a', '_b')
+ self.assertTrue(history.contains('_ab'))
+# self.assertTrue(history.contains('_a'))
+# self.assertTrue(history.contains('_c'))
+ p_ab = history.get_parents('_ab')
+ self.assertEqual('_a', p_ab[0],)
+ self.assertEqual('_b', p_ab[1])
+
+ history.rember_parents('_abc', '_ab', '_c')
+ self.assertEqual('_c', history.get_parents('_abc')[1])
+ self.assertEqual('_a', history.get_parents(
+ history.get_parents('_abc')[0])[0])
+
+ s_abc = cairo.ImageSurface(cairo.FORMAT_ARGB32, 2, 2)
+ history.link_surface('_abc', s_abc)
+ self.assertEqual(id(s_abc), id(history.get_surface('_abc')))
+
+ history.rember_parents('_abcd', '_abc', '_d')
+ self.assertEqual('_d', history.get_parents('_abcd')[1])
+ self.assertEqual('_a', history.get_parents(history.get_parents(
+ history.get_parents('_abcd')[0])[0])[0])
+
+ history.unlink('_abc')
+ self.assertTrue(history.contains('_abc'))
+ history.unlink('_abcd')
+ print history.parents
+ self.assertFalse(history.contains('_abcd'))
+ self.assertFalse(history.contains('_abc'))
+
+ def test_treestore(self):
+ history = ka_history.KandidHistory.instance()
+ history.clear()
+ history.rember_parents('_ab', '_a', '_b')
+ history.rember_parents('_abc', '_ab', '_c')
+ history.rember_parents('_abcd', '_abc', '_d')
+# treestore = history.get_treestore('_abcd')
+# PyApp(treestore, '_abcd')
+ gtk.main()
+
+class PyApp(gtk.Window):
+ def __init__(self, treestore, my_id):
+ super(PyApp, self).__init__()
+ self.set_size_request(400, 400)
+ self.set_position(gtk.WIN_POS_CENTER)
+ self.connect('destroy', gtk.main_quit)
+ self.set_title('History Tree')
+ treeview = gtk.TreeView()
+ treeview.set_direction(gtk.TEXT_DIR_RTL)
+ treeview.set_property('enable-tree-lines', True)
+ treeview.set_property('level-indentation', 50)
+
+ ancestors = gtk.TreeViewColumn()
+ ancestors.set_title('Ancestors for ' + my_id)
+ text_cell = gtk.CellRendererText()
+ img_cell = gtk.CellRendererPixbuf()
+ ancestors.pack_start(img_cell, False)
+ ancestors.pack_start(text_cell,True)
+ ancestors.add_attribute(img_cell, 'pixbuf', 0)
+ ancestors.add_attribute(text_cell, 'text', 1)
+ treeview.append_column(ancestors)
+
+ treeview.set_model(treestore)
+ treeview.expand_all()
+
+ self.add(treeview)
+ self.show_all()
+
+ka_debug.info('starting TestSuite')
+ka_debug.err('testing error message channel.')
+alltests = unittest.TestSuite((\
+ unittest.makeSuite(TestKandidHistory), \
+ ))
+unittest.TextTestRunner(verbosity=2).run(alltests)
diff --git a/test_suite.py b/test_suite.py
index 9da3682..21963ea 100644
--- a/test_suite.py
+++ b/test_suite.py
@@ -47,6 +47,7 @@ import ep_page_intro
import test_enumerator
import kandid
+import ka_history
EPSILON = 0.00001
_test_task_completed_count = 0
@@ -158,7 +159,7 @@ class TestKandidModel(unittest.TestCase):
print mm1, mm2, mm3
self.assertTrue(diff)
- def test_0sampler(self):
+ def test_sampler(self):
key = 'sampler'
model_random.set_flurry(9)
for flavor in ka_extensionpoint.list_extensions(key):
@@ -700,17 +701,18 @@ class TestKandidModel(unittest.TestCase):
self.assertTrue(status.isDirty())
status.set(ka_status.TOPIC_COLLABORATION,
ka_status.SUB_BUDDIES_JOINED, '2')
- expected = '''
-Collaboration
- Buddies joined: 2
-
-Tasks
- Unfinished tasks: 5
-
-Activity
- Running: Kandid, release v5, DoB activated
-'''
- self.assertEqual(expected, status.recall())
+# expected = '''
+#Collaboration
+# Buddies joined: 2
+#
+#Tasks
+# Unfinished tasks: 5
+#
+#Activity
+# Running: Kandid, release v5, DoB activated
+#'''
+# self.assertEqual(expected, status.recall())
+ self.assertTrue(status.recall().find('Running: Kandid, release v5, DoB activated') >= 0)
self.assertFalse(status.isDirty())
def _create_context(self, width, height):