diff options
-rw-r--r-- | canvas.py | 8 | ||||
-rw-r--r-- | model.py | 204 | ||||
-rw-r--r-- | treeview.py | 16 | ||||
-rw-r--r-- | view.py | 84 |
4 files changed, 88 insertions, 224 deletions
@@ -56,6 +56,8 @@ class Canvas(gtk.DrawingArea): rect.x = 0 rect.y = 0 + logging.debug('__expose_event_cb1 %r %r %r %r' % (event.area.x, event.area.y, + event.area.width, event.area.height)) context.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) context.clip() @@ -65,6 +67,7 @@ class Canvas(gtk.DrawingArea): for element in self._elements: rect = element.get_rect() + logging.debug('__expose_event_cb %r %r %r %r' % (rect.x, rect.y, rect.width, rect.height)) if rect.intersect(event.area): context.save() @@ -107,6 +110,9 @@ class Canvas(gtk.DrawingArea): self._elements = [] + def get_elements(self): + return self._elements + def __element_invalidated_cb(self, **kwargs): element = kwargs['sender'] @@ -180,7 +186,7 @@ class Canvas(gtk.DrawingArea): class CanvasElement(object): def __init__(self): self.invalidated = dispatch.Signal() - self.previous_rect = (0, 0, 0, 0) + self.previous_rect = gtk.gdk.Rectangle(0, 0, 0, 0) def draw(self, context): self.previous_rect = self.get_rect() @@ -22,50 +22,29 @@ import cjson from sugar import dispatch -class MindMapModel(gtk.GenericTreeModel): - - _COLUMN_TYPES = (str, str, long, long, str) +class MindMapModel(gtk.TreeStore): def __init__(self): - gobject.GObject.__init__(self) + gtk.TreeStore.__init__(self, int, str, long, long, str) self._next_thought_id = 0 self._thoughts_by_id = {} self._thoughts = [] def create_new_thought(self): - thought = Thought(self._next_thought_id) - self._add_thought(thought) - - def _add_thought(self, thought): - thought.changed.connect(self.__thought_changed_cb) - self._thoughts.append(thought) - self._thoughts_by_id[thought.id] = thought + self.append(None, (self._next_thought_id, '', 0, 0, '')) self._next_thought_id += 1 - path = (thought.id,) - self.row_inserted(path, self.get_iter(path)) - - def get_thought(self, thought_id): - return self._thoughts_by_id[int(thought_id)] - - def __thought_changed_cb(self, **kwargs): - thought = kwargs['sender'] - path = (thought.id,) - self.row_changed(path, self.get_iter(path)) - - def get_thoughts(self): - return self._thoughts - def serialize(self): thoughts = [] - for thought in self._thoughts: + for row in self: + logging.debug('serialize %r' % row[0]) thought_dict = {} - thought_dict['id'] = thought.id - thought_dict['name'] = thought.name - thought_dict['x'] = thought.x - thought_dict['y'] = thought.y - thought_dict['color'] = thought.color + thought_dict['id'] = row[0] + thought_dict['name'] = row[1] + thought_dict['x'] = row[2] + thought_dict['y'] = row[3] + thought_dict['color'] = row[4] thoughts.append(thought_dict) return cjson.encode({'thoughts': thoughts}) @@ -73,152 +52,19 @@ class MindMapModel(gtk.GenericTreeModel): def unserialize(self, data): thoughts = cjson.decode(data)['thoughts'] for thought_dict in thoughts: - thought = Thought(thought_dict['id']) - thought.name = thought_dict.get('name', None) - thought.x = thought_dict.get('x', None) - thought.y = thought_dict.get('y', None) - thought.color = thought_dict.get('color', None) - self._add_thought(thought) - - # gtk.GenericTreeModel methods - # paths and rowrefs are the thought ids - def on_get_flags(self): - return gtk.TREE_MODEL_ITERS_PERSIST - - def on_get_n_columns(self): - return len(self._COLUMN_TYPES) - - def on_get_column_type(self, n): - return self._COLUMN_TYPES[n] - - def on_get_iter(self, path): - logging.debug('on_get_iter %r %r' % (type(path), path)) - if path[0] in self._thoughts_by_id: - return path[0] - else: - return None - - def on_get_path(self, rowref): - logging.debug('on_get_path %r' % rowref) - return (rowref,) - - def on_get_value(self, rowref, column): - #logging.debug('on_get_value %r %r' % (rowref, column)) - if rowref >= len(self._thoughts): - return None - thought = self._thoughts[rowref] - value_tuple = thought.get_tuple() - return value_tuple[column] - - def on_iter_next(self, rowref): - #logging.debug('on_iter_next %r' % rowref) - if rowref not in self._thoughts_by_id: - return None - thought = self._thoughts_by_id[rowref] - - index = self._thoughts.index(thought) - if index + 1 >= len(self._thoughts): - return None - next_thought = self._thoughts[index + 1] - #logging.debug('on_iter_next returning %r' % next_thought.id) - return next_thought.id - - def on_iter_children(self, rowref): - logging.debug('on_iter_children %r' % rowref) - if rowref: - return None - if self._thoughts: - return self._thoughts[0].id - else: - return None - - def on_iter_has_child(self, rowref): - return False - - def on_iter_n_children(self, rowref): - logging.debug('on_iter_n_children %r' % rowref) - if rowref: - return 0 - return len(self._thoughts) - - def on_iter_nth_child(self, rowref, n): - logging.debug('on_iter_nth_child %r %r' % (rowref, n)) - if rowref is not None: - return None - if n < len(self._thoughts): - return self._thoughts[n].id - - def on_iter_parent(child): - return None - -class Thought(object): - - def __init__(self, thought_id, name=None, x=0, y=0, color=None): - if thought_id is None: - raise ValueError('thought_id cannot be None') - self._id = thought_id - self._name = name - self._x = x - self._y = y - self._color = color - - self.changed = dispatch.Signal() - - def get_tuple(self): - return (self.id, self.name, self.x, self.y, self.color) - - def set_id(self, new_id): - if self._id == new_id: - return - self._id = new_id - self.changed.send(self) - - def get_id(self): - return self._id - - id = property(get_id, set_id) - - def set_name(self, new_name): - if self._name == new_name: - return - self._name = new_name - self.changed.send(self) - - def get_name(self): - return self._name - - name = property(get_name, set_name) - - def set_x(self, new_x): - if self._x == new_x: - return - self._x = new_x - self.changed.send(self) - - def get_x(self): - return self._x - - x = property(get_x, set_x) - - def set_y(self, new_y): - if self._y == new_y: - return - self._y = new_y - self.changed.send(self) - - def get_y(self): - return self._y - - y = property(get_y, set_y) - - def set_color(self, new_color): - if self._color == new_color: - return - self._color = new_color - self.changed.send(self) - - def get_color(self): - return self._color - - color = property(get_color, set_color) + self._next_thought_id = max(self._next_thought_id + 1, + thought_dict['id'] + 1) + self.append(None, (thought_dict['id'], + thought_dict.get('name', None), + thought_dict.get('x', None), + thought_dict.get('y', None), + thought_dict.get('color', None))) + + def find_by_id(self, thought_id, rows=None): + if rows is None: + rows = self + for row in rows: + if row[0] == thought_id: + return row + self.find_by_id(thought_id, row.iterchildren()) diff --git a/treeview.py b/treeview.py index cec8562..e255fa8 100644 --- a/treeview.py +++ b/treeview.py @@ -69,18 +69,18 @@ class TreeView(gtk.ScrolledWindow): self.set_size_request(200, -1) def __name_edited_cb(self, cell_renderer, path, new_text): - thought = self._tree_view.props.model.get_thought(path[0]) - thought.name = new_text + model = self._tree_view.props.model + model.set(model.get_iter(path), 1, new_text) def __x_edited_cb(self, cell_renderer, path, new_text): - thought = self._tree_view.props.model.get_thought(path[0]) - thought.x = int(new_text) + model = self._tree_view.props.model + model.set(model.get_iter(path), 2, float(new_text)) def __y_edited_cb(self, cell_renderer, path, new_text): - thought = self._tree_view.props.model.get_thought(path[0]) - thought.y = int(new_text) + model = self._tree_view.props.model + model.set(model.get_iter(path), 3, float(new_text)) def __color_edited_cb(self, cell_renderer, path, new_text): - thought = self._tree_view.props.model.get_thought(path[0]) - thought.color = new_text + model = self._tree_view.props.model + model.set(model.get_iter(path), 4, new_text) @@ -31,8 +31,8 @@ class MindMapView(Canvas): def __init__(self, model=None): self._model = None + self._row_changed_sid = None self._row_deleted_sid = None - self._row_inserted_sid = None self._selected_thought = None Canvas.__init__(self) @@ -63,8 +63,8 @@ class MindMapView(Canvas): thought_rect = thought.get_rect() if (x >= 0 and x + thought_rect.width <= rect.width) and \ (y >= 0 and y + thought_rect.height <= rect.height): - thought.model.x = x - thought.model.y = y + row = self.model.find_by_id(thought.id) + self.model.set(row.iter, 2, x, 3, y) def __button_release_event_cb(self, widget, event): logging.debug('button_release_event_cb') @@ -86,43 +86,55 @@ class MindMapView(Canvas): return if self._model is not None: + self._model.disconnect(self._row_changed_sid) self._model.disconnect(self._row_deleted_sid) - self._model.disconnect(self._row_inserted_sid) self._model = new_model if self._model is not None: + self._row_changed_sid = \ + self._model.connect('row-changed', self.__row_changed_cb) self._row_deleted_sid = \ self._model.connect('row-deleted', self.__row_deleted_cb) - self._row_inserted_sid = \ - self._model.connect('row-inserted', self.__row_inserted_cb) self.remove_all_elements() - for thought_model in self._model.get_thoughts(): - though_view = ThoughtView(thought_model) - self.add_element(though_view) + self._populate_from_model(self._model) + + def _populate_from_model(self, rows): + for row in rows: + thought_view = ThoughtView(row[0], row[1], row[2], row[3], row[4]) + self._populate_from_model(row.iterchildren()) + self.add_element(thought_view) def get_model(self): return self._model model = property(get_model, set_model) - def __row_inserted_cb(self, model, path, iter): - logging.debug('__row_inserted_cb %r' % path) + def __row_changed_cb(self, model, path, iter): + logging.debug('__row_changed_cb %r' % path) - thought_model = model.get_thought(path[0]) - though_view = ThoughtView(thought_model) - self.add_element(though_view) + row = model[iter] + thought_view = self._get_thought_by_id(row[0]) + if thought_view is None: + thought_view = ThoughtView(row[0], row[1], row[2], row[3], row[4]) + self.add_element(thought_view) + else: + thought_view.name = row[1] + thought_view.x = row[2] + thought_view.y = row[3] + thought_view.color = row[4] + thought_view.invalidate() def __row_deleted_cb(self, model, path): logging.debug('__row_deleted_cb %r' % path) - though_view = self._get_though_by_id(path[0]) - self.remove_element(though_view) + thought_view = self._get_thought_by_id(path[0]) + self.remove_element(thought_view) - def _get_though_by_id(self, thought_id): + def _get_thought_by_id(self, thought_id): for thought_view in self.get_elements(): - if thought_view.model.id == path[0]: + if thought_view.id == thought_id: return thought_view return None @@ -131,17 +143,22 @@ class ThoughtView(CanvasElement): _PADDING = style.zoom(15) _LINE_WIDTH = style.zoom(2) - def __init__(self, model): + def __init__(self, thought_id, name, x, y, color): CanvasElement.__init__(self) - self.model = model + logging.debug('ThoughtView %r %r' % (thought_id, name)) + + self.id = thought_id + self.name = name + self.x = x + self.y = y + self.color = color + self._last_width = -1 self._last_height = -1 self._dragging = False self._selected = False - self.model.changed.connect(self.__model_changed_cb) - def set_dragging(self, dragging): if self._dragging != dragging: self._dragging = dragging @@ -165,10 +182,10 @@ class ThoughtView(CanvasElement): pixmap = gtk.gdk.Pixmap(None, 1, 1, visual.depth) context = pixmap.cairo_create() - if self.model.name is None or not self.model.name: + if self.name is None or not self.name: name = _('Unnamed') else: - name = self.model.name + name = self.name layout = context.create_layout() layout.set_text(name) @@ -186,10 +203,10 @@ class ThoughtView(CanvasElement): CanvasElement.draw(self, context) def _draw_background(self, context): - if self.model.color is None or not self.model.color: + if self.color is None or not self.color: color = style.Color('#FFFFFF') else: - color = style.Color(self.model.color) + color = style.Color(self.color) r, g, b, a = color.get_rgba() context.save() @@ -208,8 +225,8 @@ class ThoughtView(CanvasElement): width += self._PADDING * 2 height += self._PADDING * 2 - x = self.model.x + self._PADDING - y = self.model.y + self._PADDING + x = self.x + self._PADDING + y = self.y + self._PADDING context.translate(x, y) context.show_layout(layout) context.restore() @@ -226,8 +243,8 @@ class ThoughtView(CanvasElement): context.set_source_rgb(0, 0, 0) context.set_line_width(self._LINE_WIDTH) - x = self.model.x + self._LINE_WIDTH / 2 - y = self.model.y + self._LINE_WIDTH / 2 + x = self.x + self._LINE_WIDTH / 2 + y = self.y + self._LINE_WIDTH / 2 rect_width = width - self._LINE_WIDTH rect_height = height - self._LINE_WIDTH @@ -235,11 +252,6 @@ class ThoughtView(CanvasElement): context.stroke() context.restore() - def __model_changed_cb(self, **kwargs): - self.x = self.model.x - self.y = self.model.y - self.invalidate() - def get_rect(self): if -1 in (self._last_width, self._last_height): layout = self._get_name_layout() @@ -247,6 +259,6 @@ class ThoughtView(CanvasElement): self._last_width = width + self._PADDING * 2 self._last_height = height + self._PADDING * 2 - return gtk.gdk.Rectangle(self.model.x, self.model.y, + return gtk.gdk.Rectangle(self.x, self.y, self._last_width, self._last_height) |