Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/jarabe/journal/browse/tableview.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/jarabe/journal/browse/tableview.py')
-rw-r--r--src/jarabe/journal/browse/tableview.py264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/jarabe/journal/browse/tableview.py b/src/jarabe/journal/browse/tableview.py
new file mode 100644
index 0000000..34fe42b
--- /dev/null
+++ b/src/jarabe/journal/browse/tableview.py
@@ -0,0 +1,264 @@
+# Copyright (C) 2009, Aleksey Lim
+#
+# 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 gtk
+import hippo
+import math
+import gobject
+import logging
+
+from sugar.graphics import style
+from sugar.graphics.roundbox import CanvasRoundBox
+
+COLOR_BACKGROUND = style.COLOR_WHITE
+COLOR_SELECTED = style.COLOR_TEXT_FIELD_GREY
+
+class TableCell:
+ def __init__(self):
+ self.row = None
+
+ def fillin(self):
+ pass
+
+ def on_release(self, widget, event):
+ pass
+
+class TableView(gtk.Viewport):
+ def __init__(self, cell_class, rows, cols):
+ gobject.GObject.__init__(self)
+
+ self._cell_class = cell_class
+ self._rows = rows
+ self._cols = cols
+ self._cells = []
+ self._model = None
+ self._hover_selection = True
+ self._full_adjustment = None
+ self._full_height = 0
+ self._selected_cell = None
+
+ self._table = gtk.Table()
+ self._table.show()
+
+ for y in range(self._rows + 1):
+ self._cells.append(self._cols * [None])
+ for x in range(self._cols):
+ canvas = hippo.Canvas()
+ canvas.show()
+ canvas.modify_bg(gtk.STATE_NORMAL,
+ COLOR_BACKGROUND.get_gdk_color())
+
+ sel_box = CanvasRoundBox()
+ sel_box.props.border_color = COLOR_BACKGROUND.get_int()
+ canvas.set_root(sel_box)
+ canvas.root = sel_box
+
+ cell = self._cell_class()
+ sel_box.append(cell, hippo.PACK_EXPAND)
+
+ if self._hover_selection:
+ canvas.connect('enter-notify-event',
+ self.__enter_notify_event_cb, cell)
+ canvas.connect('leave-notify-event',
+ self.__leave_notify_event_cb)
+ canvas.connect('button-release-event',
+ self.__button_release_event_cb, cell)
+
+ self._table.attach(canvas, x, x + 1, y, y + 1,
+ gtk.EXPAND | gtk.FILL, gtk.EXPAND | gtk.FILL, 0, 0)
+ self._cells[y][x] = (canvas, cell)
+
+ smooth_box = gtk.ScrolledWindow()
+ smooth_box.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
+ smooth_box.show()
+ smooth_box.add_with_viewport(self._table)
+ self.add(smooth_box)
+
+ self.connect('key-press-event', self.__key_press_event_cb)
+
+ def do_set_scroll_adjustments(self, hadj, vadj):
+ if vadj is None:
+ return
+ if self._full_adjustment is not None:
+ self._full_adjustment.disconnect_by_func(
+ self.__adjustment_value_changed)
+ self._full_adjustment = vadj
+ self._full_adjustment.connect('value-changed',
+ self.__adjustment_value_changed)
+ self._setup_adjustment()
+
+ def get_size(self):
+ return (self._cols, self._rows)
+
+ def get_cursor(self):
+ frame = self._get_frame()
+ return (frame[0],)
+
+ def set_cursor(self, cursor):
+ if self._full_adjustment is None:
+ return
+ #self._full_adjustment.props.value = cursor
+
+ def get_model(self):
+ return self._model
+
+ def set_model(self, model):
+ if self._model == model:
+ return
+ if self._model:
+ self._model.disconnect_by_func(self.__row_changed_cb)
+ self._model.disconnect_by_func(self.__table_resized_cb)
+ self._model = model
+ if model:
+ self._model.connect('row-changed', self.__row_changed_cb)
+ self._model.connect('row-inserted', self.__table_resized_cb)
+ self._model.connect('row-deleted', self.__table_resized_cb)
+ self._setup_adjustment()
+
+ model = gobject.property(type=object,
+ getter=get_model, setter=set_model)
+
+ def get_hover_selection(self):
+ return self._hover_selection
+
+ def set_hover_selection(self, value):
+ self._hover_selection = value
+
+ hover_selection = gobject.property(type=object,
+ getter=get_hover_selection, setter=set_hover_selection)
+
+ def get_visible_range(self):
+ frame = self._get_frame()
+ return ((frame[0],), (frame[1],))
+
+ def do_size_allocate(self, alloc):
+ gtk.Viewport.do_size_allocate(self, alloc)
+ self._full_height = alloc.height + 100
+ self._table.set_size_request(-1, self._full_height)
+ self._setup_adjustment()
+
+ def _fillin_cell(self, canvas, cell):
+ if cell.row is None:
+ cell.set_visible(False)
+ else:
+ cell.fillin()
+ cell.set_visible(True)
+
+ bg_color = COLOR_BACKGROUND
+ if self._selected_cell == cell:
+ if cell.get_visible():
+ bg_color = COLOR_SELECTED
+ canvas.root.props.background_color = bg_color.get_int()
+
+ def _setup_adjustment(self):
+ if self._full_adjustment is None or self._full_height == 0:
+ return
+
+ adj = self._full_adjustment.props
+
+ if self._model is None:
+ adj.upper = 0
+ adj.value = 0
+ return
+
+ if self._cols == 0:
+ adj.upper = 0
+ else:
+ count = self._model.iter_n_children(None)
+ adj.upper = int(math.ceil(float(count) / self._cols))
+
+ adj.value = min(adj.value, adj.upper - self._rows)
+ adj.page_size = self._rows
+ adj.page_increment = self._rows
+ self._full_adjustment.changed()
+
+ self.__adjustment_value_changed(self._full_adjustment)
+
+ def _get_frame(self):
+ return (int(self._full_adjustment.props.value) * self._cols,
+ (int(self._full_adjustment.props.value) + self._rows) * self._cols - 1)
+
+ def __row_changed_cb(self, model, path, iter):
+ range = self._get_frame()
+ if path[0] < range[0] or path[0] > range[1]:
+ return
+
+ y = (path[0] - range[0]) / self._cols
+ x = (path[0] - range[0]) % self._cols
+
+ canvas, cell = self._cells[y][x]
+ cell.row = self._model.get_row(path)
+ self._fillin_cell(canvas, cell)
+
+ def __table_resized_cb(self, model=None, path=None, iter=None):
+ self._setup_adjustment()
+
+ def __key_press_event_cb(self, widget, event):
+ if self._full_adjustment is None or self._full_height == 0:
+ return
+
+ adj = self._full_adjustment.props
+ uplimit = adj.upper - self._rows
+
+ if event.keyval == gtk.keysyms.Up:
+ adj.value -= 1
+ elif event.keyval == gtk.keysyms.Down:
+ if adj.value + 1 <= uplimit:
+ adj.value += 1
+ elif event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.KP_Page_Up):
+ adj.value -= self._rows
+ elif event.keyval in (gtk.keysyms.Page_Down, gtk.keysyms.KP_Page_Down):
+ if adj.value + self._rows <= uplimit:
+ adj.value += self._rows
+ elif event.keyval in (gtk.keysyms.Home, gtk.keysyms.KP_Home):
+ adj.value = 0
+ elif event.keyval in (gtk.keysyms.End, gtk.keysyms.KP_End):
+ adj.value = uplimit
+ else:
+ return False
+
+ return True
+
+ def __button_release_event_cb(self, widget, event, cell):
+ cell.on_release(widget, event)
+
+ def __enter_notify_event_cb(self, canvas, event, cell):
+ if cell.get_visible():
+ canvas.root.props.background_color = COLOR_SELECTED.get_int()
+ self._selected_cell = cell
+
+ def __leave_notify_event_cb(self, canvas, event):
+ canvas.root.props.background_color = COLOR_BACKGROUND.get_int()
+ self._selected_cell = None
+
+ def __adjustment_value_changed(self, adjustment):
+ if self._model:
+ count = self._model.iter_n_children(None)
+ else:
+ count = 0
+ cell_num = int(adjustment.props.value) * self._cols
+
+ for y in range(self._rows):
+ for x in range(self._cols):
+ canvas, cell = self._cells[y][x]
+
+ cell.row = None
+ if cell_num < count:
+ cell.row = self._model.get_row((cell_num,),
+ self._get_frame())
+
+ self._fillin_cell(canvas, cell)
+ cell_num += 1