# Copyright (C) 2011 Walter Bender
#
# 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 glob
import hashlib
from gi.repository import Gtk
from sugar3 import profile
from sugar3.activity import bundlebuilder
from sugar3.datastore import datastore
from sugar3.env import get_user_activities_path
import logging
_logger = logging.getLogger('ViewSource')
BADGE_SUBPATH = 'emblems/emblem-view-source.svg'
BADGE_TRANSFORM = ' \n'
ICON_TRANSFORM = ' \n'
XML_HEADER = ' \
\n\
\n]>\n'
SVG_START = '\n'
def generate_unique_id():
"""Generate an id based on the user's nick name and their public key
(Based on schema used by IRC activity).
"""
nick = profile.get_nick_name()
pubkey = profile.get_pubkey()
m = hashlib.sha1()
m.update(pubkey)
hexhash = m.hexdigest()
nick_letters = "".join([x for x in nick if x.isalpha()])
if not nick_letters:
nick_letters = 'XO'
return nick_letters + '_' + hexhash[:4]
def generate_bundle(nick, new_basename):
"""Generate a new .xo bundle for the activity and copy it into the
Journal.
"""
new_activity_name = _customize_activity_info(
nick, new_basename)
user_activities_path = get_user_activities_path()
if os.path.exists(os.path.join(user_activities_path, new_basename,
'dist')):
for path in glob.glob(os.path.join(user_activities_path, new_basename,
'dist', '*')):
os.remove(path)
config = bundlebuilder.Config(source_dir=os.path.join(
user_activities_path, new_basename),
dist_name='%s-1.xo' % (new_activity_name))
bundlebuilder.cmd_dist_xo(config, None)
dsobject = datastore.create()
dsobject.metadata['title'] = '%s-1.xo' % (new_activity_name)
dsobject.metadata['mime_type'] = 'application/vnd.olpc-sugar'
dsobject.set_file_path(os.path.join(
user_activities_path, new_basename, 'dist',
'%s-1.xo' % (new_activity_name)))
datastore.write(dsobject)
dsobject.destroy()
def _customize_activity_info(nick, new_basename):
"""Modify bundle_id in new activity.info file:
(1) change the bundle_id to bundle_id_[NICKNAME];
(2) change the activity_icon [NICKNAME]-activity-icon.svg;
(3) set activity_version to 1;
(4) modify the activity icon by applying a customize overlay.
"""
new_activity_name = ''
user_activities_path = get_user_activities_path()
info_old = open(os.path.join(user_activities_path, new_basename,
'activity', 'activity.info'), 'r')
info_new = open(os.path.join(user_activities_path, new_basename,
'activity', 'new_activity.info'), 'w')
for line in info_old:
if line.find('=') < 0:
info_new.write(line)
continue
name, value = [token.strip() for token in line.split('=', 1)]
if name == 'bundle_id':
new_value = '%s_%s' % (value, nick)
elif name == 'activity_version':
new_value = '1'
elif name == 'icon':
new_value = value
icon_name = value
elif name == 'name':
new_value = '%s_copy_of_%s' % (nick, value)
new_activity_name = new_value
else:
info_new.write(line)
continue
info_new.write('%s = %s\n' % (name, new_value))
info_old.close()
info_new.close()
os.rename(os.path.join(user_activities_path, new_basename,
'activity', 'new_activity.info'),
os.path.join(user_activities_path, new_basename,
'activity', 'activity.info'))
_create_custom_icon(new_basename, icon_name)
return new_activity_name
def _create_custom_icon(new_basename, icon_name):
"""Modify activity icon by overlaying a badge:
(1) Extract the payload from the badge icon;
(2) Add a transform to resize it and position it;
(3) Insert it into the activity icon.
"""
user_activities_path = get_user_activities_path()
badge_path = None
for path in Gtk.IconTheme.get_default().get_search_path():
if os.path.exists(os.path.join(path, 'sugar', 'scalable',
BADGE_SUBPATH)):
badge_path = path
break
if badge_path is None:
_logger.debug('%s not found', BADGE_SUBPATH)
return
badge_fd = open(os.path.join(badge_path, 'sugar', 'scalable',
BADGE_SUBPATH), 'r')
badge_payload = _extract_svg_payload(badge_fd)
badge_fd.close()
badge_svg = BADGE_TRANSFORM + badge_payload + '\n'
icon_path = os.path.join(user_activities_path, new_basename, 'activity',
icon_name + '.svg')
icon_fd = open(icon_path, 'r')
icon_payload = _extract_svg_payload(icon_fd)
icon_fd.close()
icon_svg = ICON_TRANSFORM + icon_payload + '\n'
tmp_path = os.path.join(user_activities_path, new_basename, 'activity',
'tmp.svg')
tmp_icon_fd = open(tmp_path, 'w')
tmp_icon_fd.write(XML_HEADER)
tmp_icon_fd.write(SVG_START)
tmp_icon_fd.write(icon_svg)
tmp_icon_fd.write(badge_svg)
tmp_icon_fd.write(SVG_END)
tmp_icon_fd.close()
os.remove(icon_path)
os.rename(tmp_path, icon_path)
def _extract_svg_payload(fd):
"""Returns everything between """
payload = ''
looking_for_start_svg_token = True
looking_for_close_token = True
looking_for_end_svg_token = True
for line in fd:
if looking_for_start_svg_token:
if line.find('') < 0:
payload += line
continue
payload += line.split('')[0]
break
return payload