diff options
-rw-r--r-- | MANIFEST | 2 | ||||
-rw-r--r-- | ep_modifier_rectangulartile.py | 4 | ||||
-rw-r--r-- | ep_page_ancestors.py | 152 | ||||
-rw-r--r-- | ep_page_status.py | 3 | ||||
-rw-r--r-- | ka_controller.py | 20 | ||||
-rw-r--r-- | ka_debug.py | 2 | ||||
-rw-r--r-- | ka_history.py | 218 | ||||
-rw-r--r-- | ka_status.py | 52 | ||||
-rw-r--r-- | ka_widget.py | 1 | ||||
-rw-r--r-- | kandid.glade | 125 | ||||
-rw-r--r-- | model_population.py | 13 | ||||
-rw-r--r-- | po/Kandid.pot | 66 | ||||
-rw-r--r-- | test_history.py | 111 | ||||
-rw-r--r-- | test_suite.py | 26 |
14 files changed, 752 insertions, 43 deletions
@@ -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): |