Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/jarabe/view/customizebundle.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/jarabe/view/customizebundle.py')
-rw-r--r--src/jarabe/view/customizebundle.py217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/jarabe/view/customizebundle.py b/src/jarabe/view/customizebundle.py
new file mode 100644
index 0000000..42da1b3
--- /dev/null
+++ b/src/jarabe/view/customizebundle.py
@@ -0,0 +1,217 @@
+# 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
+
+import gtk
+
+from sugar import profile
+from sugar.activity import bundlebuilder
+from sugar.datastore import datastore
+from sugar.env import get_user_activities_path
+
+import logging
+_logger = logging.getLogger('ViewSource')
+
+
+BADGE_SUBPATH = 'emblems/emblem-view-source.svg'
+BADGE_TRANSFORM = ' <g transform="matrix(0.45,0,0,0.45,32,32)">\n'
+ICON_TRANSFORM = ' <g transform="matrix(1.0,0,0,1.0,0,0)">\n'
+XML_HEADER = '<?xml version="1.0" ?> \
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" \
+"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [\n\
+<!ENTITY stroke_color "#010101">\n\
+<!ENTITY fill_color "#FFFFFF">\n]>\n'
+SVG_START = '<svg enable-background="new 0 0 55 55" height="55px" \
+version="1.1" viewBox="0 0 55 55" width="55px" x="0px" xml:space="preserve" \
+xmlns="http://www.w3.org/2000/svg" \
+xmlns:xlink="http://www.w3.org/1999/xlink" y="0px">\n'
+SVG_END = '</svg>\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.icon_theme_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</g>'
+
+ 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</g>'
+
+ 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 <svg ...> and </svg>"""
+ 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('<svg') < 0:
+ continue
+ looking_for_start_svg_token = False
+ line = line.split('<svg', 1)[1]
+ if looking_for_close_token:
+ if line.find('>') < 0:
+ continue
+ looking_for_close_token = False
+ line = line.split('>', 1)[1]
+ if looking_for_end_svg_token:
+ if line.find('</svg>') < 0:
+ payload += line
+ continue
+ payload += line.split('</svg>')[0]
+ break
+ return payload