# Copyright (C) 2009, Tomeu Vizoso # # 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 # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA import logging from gettext import gettext as _ import gobject import gtk from gaphas import GtkView, Canvas, state, Line from gaphas.tool import HandleTool, DefaultTool, ConnectHandleTool # We'd rather not depend on sugar in this class from sugar.graphics import style from thoughtview import ThoughtView class MindMapView(GtkView): __gtype_name__ = 'MindMapView' def __init__(self, model=None): self._model = None self._row_changed_sid = None self._row_deleted_sid = None GtkView.__init__(self) self.canvas = Canvas() tool = DefaultTool() tool.prepend(NewThoughtTool()) self.tool = tool if model is not None: self.model = model state.observers.add(self.__state_changed_cb) def __state_changed_cb(self, event): func, args, dict_ = event if len(args) > 1 and isinstance(args[1], ThoughtView): thought_view = args[1] x, y = thought_view.get_position() row = self.model.find_by_id(thought_view.id) if row[2] != x or row[3] != y: self.model.set(row.iter, 2, x, 3, y) def set_model(self, new_model): logging.debug('set_model %r' % new_model) if self._model == new_model: return if self._model is not None: self._model.disconnect(self._row_changed_sid) self._model.disconnect(self._row_deleted_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) for item in self.canvas.get_all_items(): self.canvas.remove(item) 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_changed_cb(self, model, path, iter): row = model[iter] #logging.debug('__row_changed_cb %r' % ((row[0], row[1], row[2], row[3], row[4],),)) 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.canvas.add(thought_view) else: thought_view.name = row[1] thought_view.set_position(row[2], row[3]) thought_view.x = row[2] thought_view.y = row[3] thought_view.color = row[4] self.canvas.request_update(thought_view) def __row_deleted_cb(self, model, path): logging.debug('__row_deleted_cb %r' % path) raise NotImplementedError() thought_view = self._get_thought_by_id(path[0]) self.remove_element(thought_view) def _get_thought_by_id(self, thought_id): for item in self.canvas.get_all_items(): if isinstance(item, ThoughtView) and item.id == thought_id: return item return None class NewThoughtTool(HandleTool): def __init__(self): HandleTool.__init__(self) self._new_connection = None self._parent_thought = None def grab_handle(self, item, handle): logging.debug('NewThoughtTool.grab_handle %r %r' % (item, handle)) HandleTool.grab_handle(self, item, handle) def ungrab_handle(self): logging.debug('NewThoughtTool.ungrab_handle') HandleTool.ungrab_handle(self) def on_button_release(self, context, event): logging.debug('NewThoughtTool.ungrab_handle') if self._new_connection is not None: context.view.canvas.remove(self._new_connection) self._new_connection = None context.view.model.create_new_thought(x=event.x, y=event.y, parent_id=self._parent_thought.id) HandleTool.on_button_release(self, context, event) def move(self, view, item, handle, pos): #logging.debug('NewThoughtTool.move') if isinstance(item, ThoughtView) and handle == item.new_thought_handle: matrix = view.canvas.get_matrix_i2c(item) offset = matrix[4], matrix[5] if self._new_connection is None: self._new_connection = Line() view.canvas.add(self._new_connection) start_handle = self._new_connection.handles()[0] start_handle.x = item.handles()[4].pos[0] + offset[0] start_handle.y = item.handles()[4].pos[1] + offset[1] #logging.debug('created line starting at %r %r' % item.handles()[4].pos) self._parent_thought = item end_handle = self._new_connection.handles()[1] end_handle.x = pos[0] end_handle.y = pos[1] view.canvas.request_update(self._new_connection) #logging.debug('moved line end to %r %r' % (end_handle.x, end_handle.y)) else: HandleTool.move(self, view, item, handle, pos) def glue(self, view, item, handle, vpos): #logging.debug('NewThoughtTool.glue') HandleTool.glue(self, view, item, handle, vpos) def connect(self, view, item, handle, vpos): logging.debug('NewThoughtTool.connect') HandleTool.connect(self, view, item, handle, vpos) def disconnect(self, view, item, handle): logging.debug('NewThoughtTool.disconnect') HandleTool.disconnect(self, view, item, handle)