diff options
author | Aleksey Lim <alsroot@member.fsf.org> | 2009-03-02 06:03:47 (GMT) |
---|---|---|
committer | Walter Bender <walter@walter-laptop.(none)> | 2009-03-02 14:45:14 (GMT) |
commit | 0b218d3045918e3c32985ced34eb70aa2764e387 (patch) | |
tree | 4462b4356a28ea7f5367a45225d379228f0ed16d /bookview.py | |
parent | edb525a310c2c165de2ee26c1885cb676f867287 (diff) |
Move sugar-free components to infoslicer/ core-library directory
Diffstat (limited to 'bookview.py')
-rw-r--r-- | bookview.py | 269 |
1 files changed, 269 insertions, 0 deletions
diff --git a/bookview.py b/bookview.py new file mode 100644 index 0000000..fc9af86 --- /dev/null +++ b/bookview.py @@ -0,0 +1,269 @@ +# 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 os +import gtk +import logging +import gobject +from gettext import gettext as _ + +from sugar.graphics.toolbutton import ToolButton +from sugar.activity.activity import get_bundle_path, get_activity_root +from sugar.graphics.style import * + +from toolbar import WidgetItem, ButtonItem + +logger = logging.getLogger('infoslicer') + +PUBLISH = 0 +TITLE = 1 + +class BookView(gtk.VBox): + def sync(self): + if not self._changing: + return + gobject.source_remove(self._changing) + index, column = self.tree.get_cursor() + self._cursor_changed(index) + + def __init__(self, book, name, tooltip, custom): + gtk.VBox.__init__(self) + self.book = book + self._changing = None + self._check = None + + title = gtk.Toolbar() + + # title checkbox + + if custom: + self._check = gtk.CheckButton() + self._check.props.can_focus = False + self._check.props.tooltip_text = \ + _('Articles are ready to be published') + self._check.connect('toggled', self._check_toggled_cb) + check_box = gtk.HBox() + check_box.set_size_request(50, -1) + check_box.pack_start(self._check, True, False) + title.insert(WidgetItem(check_box), -1) + else: + title.insert(WidgetItem(gtk.Label(' ')), -1) + + # title caption + + caption_label = gtk.Label(name) + caption_label.props.tooltip_text = tooltip + caption_label.modify_fg(gtk.STATE_NORMAL, COLOR_WHITE.get_gdk_color()) + caption_box = gtk.HBox() + caption_box.pack_start(caption_label, False) + caption = gtk.EventBox() + caption.add(caption_box) + caption.modify_bg(gtk.STATE_NORMAL, COLOR_TOOLBAR_GREY.get_gdk_color()) + title.insert(WidgetItem(caption), -1) + + separator = gtk.SeparatorToolItem() + separator.props.draw = False + separator.set_expand(True) + title.insert(separator, -1) + + # create article button + + if custom: + create = ButtonItem('add', + label=_('Create'), + tooltip_text=_('Create new article')) + create.connect('clicked', self._create_cb) + title.insert(create, -1) + else: + logger.debug('BookView(%s): listen for new articles' % name) + self.book.connect('article-added', self._article_added_cb) + + # delete article button + + delete = ButtonItem('edit-delete', + label=_('Delete'), + tooltip_text=_('Delete current article')) + delete.connect('clicked', self._delete_cb) + title.insert(delete, -1) + + # move buttons + + downward = ButtonItem('down', + label=_('Move downward'), + tooltip_text=_('Move article downward')) + downward.connect('clicked', self._swap_cb, +1) + title.insert(downward, -1) + upward = ButtonItem('up', + label=_('Move upward'), + tooltip_text=_('Move article upward')) + upward.connect('clicked', self._swap_cb, -1) + title.insert(upward, -1) + + # tree + + self.store = gtk.ListStore(bool, str) + self.tree = gtk.TreeView(self.store) + self.tree.props.headers_visible = False + self.tree.connect('cursor-changed', self._cursor_changed_cb) + + cell = gtk.CellRendererToggle() + cell.connect('toggled', self._cell_toggled_cb) + cell.props.activatable = True + + column = self.tree.insert_column_with_attributes(0, '', cell, active=0) + column.props.sizing = gtk.TREE_VIEW_COLUMN_FIXED + column.props.fixed_width = 50 + column.props.visible = custom + + cell = gtk.CellRendererText() + cell.connect('edited', self._cell_edited_cb) + cell.props.editable = True + self.tree.insert_column_with_attributes(1, '', cell, text=1) + + for i in self.book.index: + self.store.append((i['ready'], i['title'])) + + # scrolled tree + + tree_scroll = gtk.ScrolledWindow() + tree_scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + tree_scroll.add(self.tree) + + self.pack_start(title, False) + self.pack_start(tree_scroll) + + if len(self.store): + self.tree.set_cursor(0, self.tree.get_column(1), False) + if custom: + self._update_check(self.store[0][PUBLISH]) + + self.show_all() + + def _article_added_cb(self, book, article): + logger.debug('_article_added_cb: new article %s' % article) + + self.book.props.article = article + self.store.append((False, article)) + self.tree.set_cursor(len(self.store)-1, self.tree.get_column(1), False) + + def _create_cb(self, widget): + def find_name(list, prefix, uniq): + name = uniq == 0 and prefix or ('%s %d' % (prefix, uniq)) + if not [i for i in list if i[TITLE] == name]: + return name + return find_name(list, prefix, uniq+1) + + if self._changing: + gobject.source_remove(self._changing) + self._changing = None + + name = find_name(self.store, _('New article'), 0) + self.book.props.article = name + self.store.append((False, name)) + self.tree.set_cursor(len(self.store)-1, self.tree.get_column(1), True) + self._update_check(self.store[-1][PUBLISH]) + + def _delete_cb(self, widget): + index, column = self.tree.get_cursor() + if not index: + return + index = index[0] + + if self._changing: + gobject.source_remove(self._changing) + self._changing = None + + self.book.remove(self.store[index][TITLE]) + self.store.remove(self.tree.props.model.get_iter(index)) + + if len(self.store): + if index >= len(self.store): + index -= 1 + self.tree.set_cursor(index, self.tree.get_column(1), False) + self._update_check(self.store[index][PUBLISH]) + + def _swap_cb(self, widget, delta): + old_index, column = self.tree.get_cursor() + if not old_index: + return + + old_index = old_index[0] + new_index = old_index + delta + + if new_index < 0: + new_index = len(self.store)-1 + elif new_index >= len(self.store): + new_index = 0 + + self.book.index[old_index], self.book.index[new_index] = \ + self.book.index[new_index], self.book.index[old_index] + self.store.swap(self.tree.props.model.get_iter(old_index), + self.tree.props.model.get_iter(new_index)) + + def _check_toggled_cb(self, widget): + for i, entry in enumerate(self.store): + entry[PUBLISH] = widget.props.active + self.book.index[i]['ready'] = widget.props.active + self._check.props.inconsistent = False + + def _update_check(self, value): + if not self._check: + return + + for i in self.store: + if i[PUBLISH] != value: + self._check.props.inconsistent = True + return + self._check.props.inconsistent = False + self._check.props.active = value + + def _cell_toggled_cb(self, cell, index): + value = not self.store[index][PUBLISH] + self.store[index][PUBLISH] = value + self.book.index[int(index)]['ready'] = value + self._update_check(value) + + def _cursor_changed_cb(self, widget): + if self._changing: + gobject.source_remove(self._changing) + + index, column = self.tree.get_cursor() + + if index != None: + self._changing = gobject.timeout_add(500, self._cursor_changed, + index) + + def _cursor_changed(self, index): + self.book.props.article = self.store[index][TITLE] + self._changing = None + return False + + def _cell_edited_cb(self, cell, index, newtext): + logger.debug('_cell_edited_cb(%s, %s)' % (index, newtext)) + + # Disallowed chars are < > and & + if newtext == "" or newtext.isspace() or '&' in newtext \ + or '<' in newtext or '>' in newtext: + return + + # If there is already an article with the new name in the theme, + # then we ignore the name change and highlight the existing article + overides = [i for i, row in enumerate(self.store) + if row[TITLE] == newtext] + if overides: + self.tree.set_cursor(overides[0], self.tree.get_column(1), False) + return + + self.book.props.article.article_title = newtext + self.store[index][TITLE] = newtext |