# gcompris - board_list.py
#
# Copyright (C) 2005, 2008 Yves Combe
#
# 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, see .
#
import goocanvas
import gcompris
import gcompris.utils
import gcompris.skin
import gcompris.admin
import gtk
import gtk.gdk
import gobject
from gcompris import gcompris_gettext as _
# Board Management
(
COLUMN_BOARDICON,
COLUMN_BOARDNAME
) = range(2)
class Board_list:
"""GCompris Boards List Table"""
# area is the drawing area for the list
def __init__(self, db_connect, db_cursor, frame):
self.frame = frame
self.cur = db_cursor
self.con = db_connect
def init(self):
# ---------------
# Boards Management
# ---------------
# Create the profiles Combo
self.profiles_list = gcompris.admin.get_profiles_list()
if not self.profiles_list:
return
# Get default pofile id.
self.cur.execute('SELECT profile_id FROM informations;')
self.con.commit()
self.default_profile_id = self.cur.fetchall()[0][0]
self.out_dict = self.get_boards_out_by_profile()
self.difficulty = [1, 6]
# Main box is vertical
top_box = gtk.VBox(False, 8)
top_box.show()
self.frame.add(top_box)
box1 = gtk.HBox(False, 8)
box1.show()
box2 = gtk.HBox(False, 8)
box2.show()
box3 = gtk.VBox(False, 8)
box3.show()
top_box.pack_start(box1, False, False, 0)
top_box.pack_start(box2, True, True, 0)
box2.pack_end(box3, False, False, 0)
label = gtk.Label(_('Select a profile:'))
label.show()
box1.pack_start(label,False, False, 0)
combobox = gtk.combo_box_new_text()
combobox.show()
box1.pack_start(combobox, False, False, 0)
for profile in self.profiles_list:
combobox.append_text(profile.name)
if profile.profile_id == self.default_profile_id:
combobox.set_active(self.profiles_list.index(profile))
self.active_profile = self.profiles_list[combobox.get_active()]
self.progressbar = gtk.ProgressBar(adjustment=None)
box1.pack_start(self.progressbar, False, False, 0)
# Create the table
sw = gtk.ScrolledWindow()
sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
# sw.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
# create tree model
self.model = self.__create_model()
# update the combobox
combobox.connect('changed', self.changed_cb)
# create tree view
treeview = gtk.TreeView(self.model)
treeview.set_rules_hint(True)
treeview.set_search_column(COLUMN_BOARDNAME)
sw.add(treeview)
# Some constants for the layout
#but_height = hgap * 2
#but_width = hgap * 6
box2.pack_start(sw, True, True, 0)
sw.show()
treeview.show()
# add columns to the tree view
self.__add_columns(treeview)
# Add buttons
self.button_configure = gtk.Button(stock=gtk.STOCK_PREFERENCES)
self.button_configure.connect("clicked", self.configure_board)
self.button_configure.show()
box3.pack_start(self.button_configure, False, False, 0)
self.button_configure.set_sensitive(False)
self.button_filter = gtk.Button(_('Filter'))
self.button_filter.connect("clicked", self.filter_boards)
self.button_filter.show()
box3.pack_start(self.button_filter, False, False, 0)
self.button_select_all = gtk.Button(_('Select all'))
self.button_select_all.connect("clicked", self.select_all_boards, True)
self.button_select_all.show()
box3.pack_start(self.button_select_all, False, False, 0)
self.button_unselect_all = gtk.Button(_('Unselect all'))
self.button_unselect_all.connect("clicked", self.select_all_boards, False)
self.button_unselect_all.show()
box3.pack_start(self.button_unselect_all, False, False, 0)
self.button_locales = gtk.Button(_('Locales'))
self.button_locales.connect("clicked", self.locales)
self.button_locales.show()
box3.pack_end(self.button_locales, False, False, 0)
self.button_locales_sound = gtk.Button(_('Locales sound'))
self.button_locales_sound.connect("clicked", self.locales_sound)
self.button_locales_sound.show()
box3.pack_end(self.button_locales_sound, False, False, 0)
self.button_login = gtk.Button(_('Login'))
self.button_login.connect("clicked", self.login_configure)
self.button_login.show()
box3.pack_end(self.button_login, False, False, 0)
def show(self, db_connect, db_cursor):
self.cur = db_cursor
self.con = db_connect
self.frame.show()
def hide(self):
self.frame.hide()
# -------------------
# Board Management
# -------------------
# Add boards in the model
def get_board_by_name(self, name, list):
for board in list:
if (board.section + '/' + board.name) == name:
return board
return None
def get_board_from_menu(self, menu, list):
if menu.name =='':
section = ''
else:
section = menu.section + '/' + menu.name
return_list = []
for board in list:
if board.section == section:
return_list.append([section, board])
return return_list
def add_boards_in_model(self, model, boards_list):
root_menu = '/'
root = self.get_board_by_name(root_menu, boards_list)
boards_list.remove(root)
menu_list = [[ None, root ]]
list = menu_list[:]
while len(list) > 0:
menu = list.pop(0)[1]
list_board = self.get_board_from_menu(menu, boards_list)
menu_list = menu_list + list_board
for board_cell in list_board:
if board_cell[1].type == 'menu':
list.append(board_cell)
row_dict = {}
self.board_dict = {}
height = 24
self.progressbar.show()
index = 0.0
for board_cell in menu_list:
self.board_dict['%s/%s' % (board_cell[1].section,board_cell[1].name)] = board_cell[1]
self.progressbar.set_fraction(index / len(menu_list))
index = index + 1
while gtk.events_pending():
gtk.main_iteration(False)
if board_cell[0] == None:
row_dict[''] = \
model.append(None,
[self.pixbuf_admin_at_height('administration/tuxplane.svg', height),
_('Main menu') + '\n' + '/',
not board_cell[1].board_id in self.out_dict[self.active_profile.profile_id],
'%s/%s' % (board_cell[1].section,board_cell[1].name), self.pixbuf_configurable(board_cell[1])])
else:
row_dict['%s/%s' % (board_cell[1].section,board_cell[1].name)] = \
model.append(row_dict[board_cell[1].section],
[self.pixbuf_at_height(board_cell[1].icon_name, height),
_(board_cell[1].title) + '\n' + '%s/%s' % (board_cell[1].section,board_cell[1].name),
not board_cell[1].board_id in self.out_dict[self.active_profile.profile_id],
'%s/%s' % (board_cell[1].section,board_cell[1].name), self.pixbuf_configurable(board_cell[1])])
self.progressbar.hide()
def pixbuf_admin_at_height(self, file, height):
pixbuf = gcompris.utils.load_pixmap(file)
width = pixbuf.get_width()* height / pixbuf.get_height()
del pixbuf
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(gcompris.DATA_DIR + '/' + file,
width, height)
return pixbuf
def pixbuf_at_height(self, file, height):
pixbuf = gcompris.utils.load_pixmap(file)
width = pixbuf.get_width()* height / pixbuf.get_height()
del pixbuf
pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(gcompris.DATA_DIR + '/' + file,
width, height)
return pixbuf
def __create_model(self):
model = gtk.TreeStore(
gtk.gdk.Pixbuf,
gobject.TYPE_STRING,
gobject.TYPE_BOOLEAN,
gobject.TYPE_STRING,
gobject.TYPE_STRING,
)
self.boards_list = gcompris.admin.get_boards_list()
self.add_boards_in_model(model, self.boards_list)
return model
def __add_columns(self, treeview):
model = treeview.get_model()
# Render for Board name with icon.
cell_board_icon = gtk.CellRendererPixbuf()
cell_board_title = gtk.CellRendererText()
cell_active_board = gtk.CellRendererToggle()
cell_active_board.set_property('activatable', True)
cell_active_board.connect( 'toggled', self.board_acive_cb, model )
cell_board_configure = gtk.CellRendererPixbuf()
# columns for Board name
# column_pref = gtk.TreeViewColumn(_('Conf'))
# image = gtk.image_new_from_stock(gtk.STOCK_PREFERENCES, gtk.ICON_SIZE_MENU)
# image.show()
# column_pref.set_widget(image)
column_active = gtk.TreeViewColumn(_('Active'))
column_title = gtk.TreeViewColumn(_('Board title'))
column_title.pack_start(cell_board_icon, False)
column_active.pack_start(cell_board_configure, False)
column_title.pack_start(cell_board_title, True)
column_active.pack_start(cell_active_board, False)
treeview.append_column(column_active)
treeview.append_column(column_title)
column_title.add_attribute(cell_board_icon, 'pixbuf', 0)
column_title.add_attribute(cell_board_title, 'text', 1)
column_active.add_attribute(cell_active_board, 'active', 2)
column_active.set_attributes(cell_board_configure, stock_id=4)
treeview.connect("cursor-changed", self.row_selected, model)
def board_acive_cb(self, cell, path, model):
model[path][2] = not model[path][2]
if model[path][2]:
self.update_parent(model[path].parent)
else:
self.check_parent_active(model[path].parent)
try:
self.update_child(model[path].iterchildren().next(), model[path][2])
except StopIteration:
pass
self.update_selected(model, path)
def update_selected(self, model, path):
if model[path][2]:
self.cur.execute('DELETE FROM activities_out WHERE board_id=%d AND out_id=%d' % (
self.board_dict[model[path][3]].board_id,
self.active_profile.profile_id
))
else:
self.cur.execute('INSERT INTO activities_out (board_id, out_id) VALUES (%d, %d)' % (
self.board_dict[model[path][3]].board_id,
self.active_profile.profile_id
))
self.con.commit()
# update infos
self.out_dict = self.get_boards_out_by_profile()
return
def dict_from_list(self, list):
dict = {}
for profile in self.profiles_list:
dict[profile.profile_id] = []
for l in list:
dict[l[1]].append(l[0])
return dict
def changed_cb(self, combobox):
index = combobox.get_active()
if(index<0):
return
self.active_profile = self.profiles_list[index]
self.model.foreach(self.update_active)
def update_active(self, model, path, iter):
model[path][2] = not self.board_dict[model[path][3]].board_id in self.out_dict[self.active_profile.profile_id]
def get_boards_out_by_profile(self):
# Grab the user data
self.cur.execute('select board_id, out_id from activities_out')
return self.dict_from_list(self.cur.fetchall())
def pixbuf_configurable(self, board):
if board.is_configurable and board.type != "menu":
return gtk.STOCK_PREFERENCES
else:
return None
def preference_clicked(self, widget, event, board):
pass
def row_selected(self, treeview, model):
if treeview.get_selection().count_selected_rows() != 1:
return
path = model.get_path(treeview.get_selection().get_selected()[1])
self.selected_board = self.board_dict[model[path][3]]
if self.selected_board.is_configurable:
self.button_configure.set_sensitive(True)
else:
self.button_configure.set_sensitive(False)
def configure_board(self, button):
gcompris.admin.board_config_start(self.selected_board,
self.active_profile)
def select_all_boards(self, button, Value):
self.model.foreach(self.update_all, Value)
def update_all(self, model, path, iter, Value):
model[path][2] = Value
self.update_selected( model, path)
def filter_boards(self, button):
window = gtk.Window()
window.set_title(_("Filter Boards difficulty for profile %s") % (self.active_profile.name))
window.set_border_width(8)
window.set_default_size(320, 350)
window.set_transient_for(self.frame.get_toplevel())
window.set_modal(True)
window.show()
button_close = gtk.Button(stock=gtk.STOCK_CLOSE)
button_close.connect("clicked", self.filter_close, window)
button_close.show()
button_apply = gtk.Button(stock=gtk.STOCK_APPLY)
button_apply.connect("clicked", self.filter_apply)
button_apply.show()
main_box = gtk.VBox(False, 8)
main_box.show()
window.add(main_box)
box_bottom = gtk.HBox(False, 0)
box_bottom.show()
main_box.pack_end(box_bottom, False, False, 0)
sep = gtk.HSeparator()
sep.show()
main_box.pack_end(sep, False, False, 8)
box_bottom.pack_end(button_close, False, False, 0)
box_bottom.pack_start(button_apply, False, False, 0)
label = gtk.Label()
label.set_markup(_(" Select the difficulty range \nfor profile %s") % self.active_profile.name)
label.show()
label.set_line_wrap(True)
label.set_justify(gtk.JUSTIFY_CENTER)
main_box.pack_start(label, False, False, 0)
symbols_box = gtk.HBox(False, 0)
symbols_box.show()
main_box.pack_start(symbols_box, False, False, 0)
arrows_box = gtk.HBox(False, 0)
arrows_box.show()
main_box.pack_start(arrows_box, False, False, 0)
self.stars = {}
for i in range(1,7):
box = gtk.VBox(False, 8)
box.show()
symbols_box.pack_start(box, True, False, 0)
self.stars[i] = gtk.Image()
self.stars[i].set_from_pixbuf(gcompris.utils.load_pixmap('administration/difficulty%d.svg' % (i)))
self.stars[i].show()
box.pack_start(self.stars[i], False, False, 0)
i_label = gtk.Label()
i_label.set_markup("%d" % i)
i_label.show()
box.pack_start(i_label, False, False, 0)
self.arrows = {}
self.arrows[1] = self.create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_IN)
self.arrows[2] = self.create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_IN)
self.arrows[3] = self.create_arrow_button(gtk.ARROW_LEFT, gtk.SHADOW_IN)
self.arrows[4] = self.create_arrow_button(gtk.ARROW_RIGHT, gtk.SHADOW_IN)
arrows_box.pack_start(self.arrows[1], False, False, 3)
arrows_box.pack_start(self.arrows[2], False, False, 3)
arrows_box.pack_end(self.arrows[4], False, False, 3)
arrows_box.pack_end(self.arrows[3], False, False, 3)
for i in range (1,5):
self.arrows[i].connect("clicked", self.arrow_clicked, i)
self.update_arrows_active()
def filter_close(self, button, window):
window.destroy()
def create_arrow_button(self, arrow_type, shadow_type):
button = gtk.Button();
arrow = gtk.Arrow(arrow_type, shadow_type);
button.add(arrow)
button.show()
arrow.show()
return button
def update_arrows_active(self):
if self.difficulty[0] == 1:
self.arrows[1].set_sensitive(False)
else:
self.arrows[1].set_sensitive(True)
if self.difficulty[1] == 6:
self.arrows[4].set_sensitive(False)
else:
self.arrows[4].set_sensitive(True)
if self.difficulty[1] == 1:
self.arrows[3].set_sensitive(False)
else:
self.arrows[3].set_sensitive(True)
if self.difficulty[0] == 6:
self.arrows[2].set_sensitive(False)
else:
self.arrows[2].set_sensitive(True)
if self.difficulty[0] == self.difficulty[1]:
self.arrows[2].set_sensitive(False)
self.arrows[3].set_sensitive(False)
for i in range(1,7):
if i in range( self.difficulty[0], self.difficulty[1]+1):
self.stars[i].set_sensitive(True)
else:
self.stars[i].set_sensitive(False)
def arrow_clicked(self, arrow, i):
if i < 3:
value = 0
limits = [1, self.difficulty[1]]
else:
value = 1
limits = [self.difficulty[0], 6]
if (i % 2 == 0):
if self.difficulty[value] == limits[1]:
return
else:
self.difficulty[value] = self.difficulty[value] + 1
else:
if self.difficulty[value] == limits[0]:
return
else:
self.difficulty[value] = self.difficulty[value] - 1
self.update_arrows_active()
def filter_apply(self, button):
self.model.foreach(self.blank)
self.model.foreach(self.board_filter)
# Apply the filter as asked.
def board_filter(self, model, path, iter):
if self.board_dict[model[path][3]].type != "menu":
model[path][2] = ( eval(self.board_dict[model[path][3]].difficulty) \
in range( self.difficulty[0],
self.difficulty[1]+1))
if model[path][2]:
self.update_parent(model[path].parent)
self.update_selected( model, path)
# toggled off.
def blank(self, model, path, iter):
model[path][2] = False
# This function toggles parents when a child is toggled.
def update_parent( self, row):
if row == None:
return
if row[2]:
return
row[2] = True
self.update_parent( row.parent)
self.update_selected(row.model, row.path)
# This function toggles parents off when all childs are toggled off.
def check_parent_active( self, row):
if row == None:
return
# should never appends
if not row[2]:
return
child = row.iterchildren().next()
select = False
while child != None:
if child[2]:
select = True
break
child = child.next
if not select:
row[2] = False
self.check_parent_active(row.parent)
self.update_selected(row.model, row.path)
# This function recursively update childs
def update_child( self, row, value):
if row[2] == value:
return
row[2] = value
try:
self.update_child(row.iterchildren().next(), value)
except StopIteration:
pass
if row.next != None:
self.update_child(row.next, value)
self.update_selected(row.model, row.path)
########################################################
########################################################
def locales(self, button):
conf_locales = self.get_configured(self.active_profile, 'locale', 'NULL')
bconf = gcompris.configuration_window ( \
_('{config} configuration\n for profile {profile}').format(config='Locale',
profile=self.active_profile.name),
self.ok_callback
)
gcompris.combo_locales(bconf, conf_locales)
def locales_sound(self, button):
conf_locales = self.get_configured(self.active_profile,
'locale_sound', 'NULL')
bconf = gcompris.configuration_window ( \
_('{config} configuration\n for profile {profile}').format(config='Locale sound',
profile=self.active_profile.name),
self.ok_callback
)
gcompris.combo_locales_asset( bconf,
_("Select sound locale"),
conf_locales,
"voices/$LOCALE/colors/red.ogg" )
def ok_callback(self, dict):
if not dict:
return
for key, value in dict.iteritems():
if key in self.already_conf:
req = 'UPDATE board_profile_conf SET conf_value=\'%s\' WHERE profile_id=%d AND board_id=-1 AND conf_key=\'%s\'' % (value, self.active_profile.profile_id, key)
else:
req = 'INSERT INTO board_profile_conf (profile_id, board_id, conf_key, conf_value) VALUES (%d, -1, \'%s\', \'%s\')' % (self.active_profile.profile_id, key, value)
self.cur.execute(req)
self.con.commit()
def get_configured(self, profile, key, if_not):
self.cur.execute('select conf_value from board_profile_conf where profile_id=%d and board_id=-1 and conf_key =\'%s\' '
% (profile.profile_id, key))
value = self.cur.fetchall()
try:
s = self.already_conf
except:
self.already_conf = []
if len(value)==1:
self.already_conf.append(key)
return value[0][0]
else:
return if_not
def login_configure(self, button):
board_log = self.get_board_by_name('/login/login', self.boards_list)
gcompris.admin.board_config_start(board_log, self.active_profile)