Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--activity/activity.info4
-rwxr-xr-ximagethumbnail.py1265
-rwxr-xr-xsetup.py2
4 files changed, 657 insertions, 618 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..9edc773
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+*.pyc
+*.pyo
+*.bak
+*.py~
diff --git a/activity/activity.info b/activity/activity.info
index 640b664..09a1c9d 100644
--- a/activity/activity.info
+++ b/activity/activity.info
@@ -1,9 +1,9 @@
[Activity]
name = Image Thumbnail
-service_name = org.laptop.ImageThumbnail
+bundle_id = org.laptop.ImageThumbnail
icon = imageviewer
exec = sugar-activity imagethumbnail.ImageThumbnail
show_launcher = yes
-activity_version = 7
+activity_version = 7
mime_types = image/bmp;image/gif;image/jpeg;image/png;image/tiff
license = GPLv2+
diff --git a/imagethumbnail.py b/imagethumbnail.py
index 536a6af..6f5746b 100755
--- a/imagethumbnail.py
+++ b/imagethumbnail.py
@@ -1,3 +1,6 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
# ImageThumbnail.py
# Copyright (C) 2010 OLPC
# Incorporates journal viewer from SugarCommander.activity by James D. Simmons
@@ -14,653 +17,685 @@
# 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 logging
-import os, sys
-import pygtk
-pygtk.require('2.0')
+
+import os
+import sys
import gtk
-from glib import GError
+import logging
import pango
import zipfile
-#import gconf,gio
import time
import traceback
+import gobject
+from subprocess import Popen, PIPE
+
+from glib import GError
+
from sugar import mime
from sugar.activity import activity
from sugar.datastore import datastore
from sugar.graphics import style
-from gettext import gettext as _
-import gobject
-from subprocess import Popen, PIPE
+
+from gettext import gettext as _
+
#from jarabe.journal.journaltoolbox import MainToolbox, DetailToolbox
#from jarabe.journal.detailview import DetailView
COLUMN_TITLE = 0
-COLUMN_JOBJECT =3
-COLUMN_IMAGE=0
-COLUMN_PATH=1
-COLUMN_MTIME=2
-max_file=1000
+COLUMN_JOBJECT = 3
+COLUMN_IMAGE = 0
+COLUMN_PATH = 1
+COLUMN_MTIME = 2
+max_file = 1000
_logger = logging.getLogger('image-thumbnail')
class ImageThumbnail(activity.Activity):
- def __init__(self, handle, create_jobject=True):
- "The entry point to the Activity"
- activity.Activity.__init__(self, handle)
- self.selected_journal_entry = None
- self.selected_path = None
- self.canvas = gtk.Notebook()
- self.canvas.props.show_border = True
- self.canvas.props.show_tabs = True
- self.canvas.show()
- self.last_col=0
- cols=3
- ds_mounts = datastore.mounts()
- #check if externmal media used in journal
- if len(ds_mounts)==1 and ds_mounts[0]['id']==1:cols=4
- self.ls_journal=[]
- self.tv_journal=[]
- self.col_journal=[]
- self.column_table=[]
- self.scroll=[]
- self.vbox=[]
- self.hidden=[]
- self.image=[[],[],[],[],[]]
- self.btn_delete=[[],[],[],[],[]]
- self.btn_show=[[],[],[],[],[]]
- self.title_entry=[[],[],[],[],[]]
- self.tab_label=[]
- for col in range(cols):
-
- self.ls_journal.append( gtk.ListStore(gobject.TYPE_STRING,
- gobject.TYPE_UINT64,
- gobject.TYPE_STRING,
- gobject.TYPE_PYOBJECT))
- self.tv_journal.append( gtk.TreeView(self.ls_journal[col]))
- self.tv_journal[col].set_rules_hint(True)
- self.tv_journal[col].set_search_column(COLUMN_TITLE)
- renderer = gtk.CellRendererText()
- renderer.set_property('wrap-mode', gtk.WRAP_WORD)
- renderer.set_property('wrap-width', 500)
- renderer.set_property('width', 500)
- self.col_journal.append(gtk.TreeViewColumn(_('Title'), renderer,
- text=COLUMN_TITLE))
- self.col_journal[col].set_sort_column_id(COLUMN_MTIME)
- self.tv_journal[col].append_column(self.col_journal[col])
-
- label_attributes = pango.AttrList()
- label_attributes.insert(pango.AttrSize(14000, 0, -1))
- label_attributes.insert(pango.AttrForeground(65535, 65535, 65535, 0, -1))
- if col==0:
- self.tab_label.append(gtk.Label(_("Journal")))
- elif col==1:
- self.tab_label.append(gtk.Label(_("Files")))
-
- elif (cols==4 and col==2):
- self.tab_label.append(gtk.Label(_("External")))
-
- else:
- self.tab_label.append(gtk.Label(_("Read Only")))
-
- self.tab_label[col].set_attributes(label_attributes)
- #self.tab_label[col].show()
- #self.tv_journal[col].show()
- if col==0:self.load_journal_table(col)
- else: self.load_file_table(col)
- num=self.ls_journal[col].iter_n_children(None)
- if num==0:
- #dummy elements for no external files
- self.column_table.append( gtk.Table(1,1, homogeneous=False))
- self.scroll.append(gtk.ScrolledWindow(
- hadjustment=None, vadjustment=None))
- self.vbox.append(gtk.VBox(homogeneous=True, spacing=5))
- self.canvas.append_page(self.vbox[col],self.tab_label[col])
- self.tab_label[col].hide()
- self.vbox[col].hide()
- self.hidden.append(col)
- else:
- self.tab_label[col].show()
- self.tv_journal[col].show()
-
- self.column_table.append( gtk.Table(rows=num, columns=3, homogeneous=False))
- self.scroll.append(gtk.ScrolledWindow(
- hadjustment=None, vadjustment=None))
- self.scroll[col].set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
-
- iter = self.ls_journal[col].get_iter_first()
- n=0
- while(iter!=None):
- tv=self.tv_journal[col]
- model = tv.get_model()
-
- jobject = model.get_value(iter,COLUMN_JOBJECT)
-
- i=n-(3*int(n/3))
- j=2*int(n/3)
- image_table = gtk.Table(rows=2, columns=2, homogeneous=False)
-
- self.image[col].append( gtk.Image())
- image_table.attach(self.image[col][n], 0, 2, 0, 1, xoptions=gtk.FILL|gtk.SHRINK,
- yoptions=gtk.FILL|gtk.SHRINK, xpadding=5, ypadding=5)
- self.btn_show[col].append(gtk.Button(_("Show File")))
- self.btn_show[col][n].connect('button_press_event',
- self.show_button_press_event_cb, col,n)
- image_table.attach(self.btn_show[col][n], 0,1, 1, 2, xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
- self.btn_show[col][n].show()
-
- if col<cols-1:
- self.btn_delete[col].append(gtk.Button(_("Delete")))
- self.btn_delete[col][n].connect('button_press_event',
- self.delete_button_press_event_cb, col,n)
- image_table.attach(self.btn_delete[col][n], 1, 2, 1, 2, xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
- self.btn_delete[col][n].show()
- self.btn_delete[col][n].props.sensitive = True
-
- image_table.show()
-
- self.column_table[col].attach(image_table, i,i+1, j+1,j+2,
- xoptions=gtk.FILL|gtk.EXPAND|gtk.SHRINK,
- yoptions=gtk.FILL|gtk.EXPAND|gtk.SHRINK,
- xpadding=5, ypadding=5)
- self.set_form_fields(jobject,col,n)
- self.btn_show[col][n].props.sensitive = True
-
- iter=self.ls_journal[col].iter_next(iter)
- n+=1
-
- self.scroll[col].add_with_viewport(self.column_table[col])
- self.scroll[col].set_events(gtk.gdk.POINTER_MOTION_MASK)
- self.scroll[col].show()
-
- self.vbox.append(gtk.VBox(homogeneous=True, spacing=5))
- self.vbox[col].pack_start(self.scroll[col])
+ """The entry point to the Activity"""
+
+ def __init__(self, handle, create_jobject=True):
+
+ activity.Activity.__init__(self, handle)
+
+ self.selected_journal_entry = None
+ self.selected_path = None
+
+ self.canvas = gtk.Notebook()
+ self.canvas.props.show_border = True
+ self.canvas.props.show_tabs = True
+ self.canvas.show()
+
+ self.last_col=0
+ cols=3
+ ds_mounts = datastore.mounts()
+ #check if externmal media used in journal
+ if len(ds_mounts)==1 and ds_mounts[0]['id']==1:cols=4
+
+ self.ls_journal=[]
+ self.tv_journal=[]
+ self.col_journal=[]
+ self.column_table=[]
+ self.scroll=[]
+ self.vbox=[]
+ self.hidden=[]
+ self.image=[[],[],[],[],[]]
+ self.btn_delete=[[],[],[],[],[]]
+ self.btn_show=[[],[],[],[],[]]
+ self.title_entry=[[],[],[],[],[]]
+ self.tab_label=[]
+
+ for col in range(cols):
- self.canvas.append_page(self.vbox[col], self.tab_label[col])
+ self.ls_journal.append( gtk.ListStore(gobject.TYPE_STRING,
+ gobject.TYPE_UINT64,
+ gobject.TYPE_STRING,
+ gobject.TYPE_PYOBJECT))
- self.tab_label.append(gtk.Label(_("File Viewer")))
-
- self.tab_label[cols].set_attributes(label_attributes)
- self.tab_label[cols].show()
- self.vbox_view=self.draw_metatable(cols)
- self.canvas.append_page(self.vbox_view, self.tab_label[cols])
-
-
- self.set_canvas(self.canvas)
- self.show_all()
- self.vbox_view.hide()
- self.tab_label[cols].hide()
- toolbox = activity.ActivityToolbox(self)
- activity_toolbar = toolbox.get_activity_toolbar()
- activity_toolbar.keep.props.visible = False
- activity_toolbar.share.props.visible = False
- self.set_toolbox(toolbox)
- toolbox.show()
- for n in self.hidden:
- self.tab_label[n].hide()
- self.vbox[n].hide()
- #can use in future to load in background
-
- def motion_notify_event(self,widget,event,col):
- self.tv_journal[col].show()
- self.scroll[col]= gtk.ScrolledWindow(
- hadjustment=None, vadjustment=None)
- self.scroll[col].set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.menu_file()
- self.scroll[col].show()
- self.vbox[col] = gtk.VBox(homogeneous=True, spacing=5)
- self.vbox[col].pack_start(self.scroll[col])
-
- widget.append_page(sef.vbox[col], self.tab_label[col])
- widget.show()
-
-
- #reload
-
- def remove_image(self, col,id):
- iter = self.ls_journal[col].get_iter_first()
- n=0
- tv = self.tv_journal[col]
- model = tv.get_model()
- self.image[col][id].hide()
+ self.tv_journal.append( gtk.TreeView(self.ls_journal[col]))
+ self.tv_journal[col].set_rules_hint(True)
+ self.tv_journal[col].set_search_column(COLUMN_TITLE)
+
+ renderer = gtk.CellRendererText()
+ renderer.set_property('wrap-mode', gtk.WRAP_WORD)
+ renderer.set_property('wrap-width', 500)
+ renderer.set_property('width', 500)
+
+ self.col_journal.append(gtk.TreeViewColumn(_('Title'), renderer,
+ text=COLUMN_TITLE))
+ self.col_journal[col].set_sort_column_id(COLUMN_MTIME)
+ self.tv_journal[col].append_column(self.col_journal[col])
+
+ label_attributes = pango.AttrList()
+ label_attributes.insert(pango.AttrSize(14000, 0, -1))
+ label_attributes.insert(pango.AttrForeground(65535, 65535, 65535, 0, -1))
+
+ if col==0:
+ self.tab_label.append(gtk.Label(_("Journal")))
+
+ elif col==1:
+ self.tab_label.append(gtk.Label(_("Files")))
+
+ elif (cols==4 and col==2):
+ self.tab_label.append(gtk.Label(_("External")))
+
+ else:
+ self.tab_label.append(gtk.Label(_("Read Only")))
+
+ self.tab_label[col].set_attributes(label_attributes)
+ #self.tab_label[col].show()
+ #self.tv_journal[col].show()
+ if col==0:self.load_journal_table(col)
+ else: self.load_file_table(col)
+
+ num=self.ls_journal[col].iter_n_children(None)
+
+ if num==0:
+ #dummy elements for no external files
+ self.column_table.append( gtk.Table(1,1, homogeneous=False))
+ self.scroll.append(gtk.ScrolledWindow(hadjustment=None, vadjustment=None))
+ self.vbox.append(gtk.VBox(homogeneous=True, spacing=5))
+ self.canvas.append_page(self.vbox[col],self.tab_label[col])
+ self.tab_label[col].hide()
+ self.vbox[col].hide()
+ self.hidden.append(col)
+
+ else:
+ self.tab_label[col].show()
+ self.tv_journal[col].show()
+
+ self.column_table.append( gtk.Table(rows=num, columns=3, homogeneous=False))
+ self.scroll.append(gtk.ScrolledWindow( hadjustment=None, vadjustment=None))
+ self.scroll[col].set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+
+ iter = self.ls_journal[col].get_iter_first()
+ n=0
+
+ while(iter!=None):
+ tv=self.tv_journal[col]
+ model = tv.get_model()
+
+ jobject = model.get_value(iter,COLUMN_JOBJECT)
+
+ i=n-(3*int(n/3))
+ j=2*int(n/3)
+ image_table = gtk.Table(rows=2, columns=2, homogeneous=False)
+
+ self.image[col].append( gtk.Image())
+ image_table.attach(self.image[col][n], 0, 2, 0, 1, xoptions=gtk.FILL|gtk.SHRINK,
+ yoptions=gtk.FILL|gtk.SHRINK, xpadding=5, ypadding=5)
+ self.btn_show[col].append(gtk.Button(_("Show File")))
+ self.btn_show[col][n].connect('button_press_event',
+ self.show_button_press_event_cb, col,n)
+ image_table.attach(self.btn_show[col][n], 0,1, 1, 2, xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
+ self.btn_show[col][n].show()
+
+ if col<cols-1:
+ self.btn_delete[col].append(gtk.Button(_("Delete")))
+ self.btn_delete[col][n].connect('button_press_event',
+ self.delete_button_press_event_cb, col,n)
+ image_table.attach(self.btn_delete[col][n], 1, 2, 1, 2, xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK, xpadding=5, ypadding=5)
+ self.btn_delete[col][n].show()
+ self.btn_delete[col][n].props.sensitive = True
+
+ image_table.show()
+
+ self.column_table[col].attach(image_table, i,i+1, j+1,j+2,
+ xoptions=gtk.FILL|gtk.EXPAND|gtk.SHRINK,
+ yoptions=gtk.FILL|gtk.EXPAND|gtk.SHRINK,
+ xpadding=5, ypadding=5)
+ self.set_form_fields(jobject,col,n)
+ self.btn_show[col][n].props.sensitive = True
+
+ iter=self.ls_journal[col].iter_next(iter)
+ n+=1
+
+ self.scroll[col].add_with_viewport(self.column_table[col])
+ self.scroll[col].set_events(gtk.gdk.POINTER_MOTION_MASK)
+ self.scroll[col].show()
+ self.vbox.append(gtk.VBox(homogeneous=True, spacing=5))
+ self.vbox[col].pack_start(self.scroll[col])
+ self.canvas.append_page(self.vbox[col], self.tab_label[col])
+
+ self.tab_label.append(gtk.Label(_("File Viewer")))
+ self.tab_label[cols].set_attributes(label_attributes)
+ self.tab_label[cols].show()
+ self.vbox_view=self.draw_metatable(cols)
+ self.canvas.append_page(self.vbox_view, self.tab_label[cols])
+
+ self.set_canvas(self.canvas)
+ self.show_all()
+ self.vbox_view.hide()
+ self.tab_label[cols].hide()
+ toolbox = activity.ActivityToolbox(self)
+ activity_toolbar = toolbox.get_activity_toolbar()
+ activity_toolbar.keep.props.visible = False
+ activity_toolbar.share.props.visible = False
+ self.set_toolbox(toolbox)
+ toolbox.show()
+
+ for n in self.hidden:
+ self.tab_label[n].hide()
+ self.vbox[n].hide()
+ #can use in future to load in background
- def draw_metatable(self, col):
- self._secondary_view = gtk.VBox()
+ def motion_notify_event(self,widget,event,col):
+
+ self.tv_journal[col].show()
+ self.scroll[col]= gtk.ScrolledWindow(
+ hadjustment=None, vadjustment=None)
+ self.scroll[col].set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.menu_file()
+ self.scroll[col].show()
+ self.vbox[col] = gtk.VBox(homogeneous=True, spacing=5)
+ self.vbox[col].pack_start(self.scroll[col])
+
+ widget.append_page(sef.vbox[col], self.tab_label[col])
+ widget.show()
+ #reload
- self.detail_view = gtk.Table(5,5, homogeneous= False)
- go_back=gtk.Button(_("back"))
- go_back.connect('button_press_event', self._go_back_clicked_cb, col)
- go_back.show()
- self.detail_view.attach(go_back,0,1,0,1,xoptions=gtk.FILL|gtk.SHRINK,
+ def remove_image(self, col,id):
+
+ iter = self.ls_journal[col].get_iter_first()
+ n=0
+ tv = self.tv_journal[col]
+ model = tv.get_model()
+ self.image[col][id].hide()
+
+ def draw_metatable(self, col):
+
+ self._secondary_view = gtk.VBox()
+ self.detail_view = gtk.Table(5,5, homogeneous= False)
+ go_back=gtk.Button(_("back"))
+ go_back.connect('button_press_event', self._go_back_clicked_cb, col)
+ go_back.show()
+
+ self.detail_view.attach(go_back,0,1,0,1,xoptions=gtk.FILL|gtk.SHRINK,
yoptions=gtk.FILL|gtk.SHRINK, xpadding=5, ypadding=5)
- #image
- self.large_image=gtk.Image()
- self.detail_view.attach(self.large_image,0,3,1,5,xoptions=gtk.FILL|gtk.SHRINK,
+ #image
+ self.large_image=gtk.Image()
+ self.detail_view.attach(self.large_image,0,3,1,5,xoptions=gtk.FILL|gtk.SHRINK,
yoptions=gtk.FILL|gtk.SHRINK, xpadding=5, ypadding=5)
- self.large_image.show()
-
- #filename
- title_label = gtk.Label(_("Title"))
- self.detail_view.attach(title_label, 3,4, 0, 1,
- xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK,
- xpadding=10, ypadding=10)
- title_label.show()
-
- self.title_textview = gtk.TextView()
- self.title_textview.set_wrap_mode(gtk.WRAP_WORD)
- self.detail_view.attach(self.title_textview, 4,5, 0, 1,
- xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- xpadding=10, ypadding=10)
- self.title_textview.props.accepts_tab = False
- self.title_textview.show()
-
-
- #filepath
- description_label = gtk.Label(_("Description"))
- self.detail_view.attach(description_label, 3,4, 1, 2,
- xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK,
- xpadding=10, ypadding=10)
- description_label.show()
-
- self.description_textview = gtk.TextView()
- self.description_textview.set_wrap_mode(gtk.WRAP_WORD)
- self.detail_view.attach(self.description_textview, 4,5, 1, 2,
- xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- xpadding=10, ypadding=10)
- self.description_textview.props.accepts_tab = False
- self.description_textview.show()
-
- #mtime
- mtime_label = gtk.Label(_("Created"))
- self.detail_view.attach(mtime_label, 3,4, 2,3,
- xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK,
- xpadding=10, ypadding=10)
- mtime_label.show()
-
- self.mtime_textview = gtk.TextView()
- self.mtime_textview.set_wrap_mode(gtk.WRAP_WORD)
- self.detail_view.attach(self.mtime_textview, 4,5, 2,3,
- xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- xpadding=10, ypadding=10)
- self.mtime_textview.props.accepts_tab = False
- self.mtime_textview.show()
-
- #mime_type
- mime_label= gtk.Label(_("Type"))
- self.detail_view.attach(mime_label, 3,4, 3,4,
- xoptions=gtk.SHRINK,
- yoptions=gtk.SHRINK,
- xpadding=10, ypadding=10)
- mime_label.show()
-
- self.mime_textview = gtk.TextView()
- self.mime_textview.set_wrap_mode(gtk.WRAP_WORD)
- self.detail_view.attach(self.mime_textview, 4,5, 3,4,
- xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
- xpadding=10, ypadding=10)
- self.mime_textview.props.accepts_tab = False
- self.mime_textview.show()
-
+ self.large_image.show()
+
+ #filename
+ title_label = gtk.Label(_("Title"))
+ self.detail_view.attach(title_label, 3,4, 0, 1,
+ xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ title_label.show()
+
+ self.title_textview = gtk.TextView()
+ self.title_textview.set_wrap_mode(gtk.WRAP_WORD)
+ self.detail_view.attach(self.title_textview, 4,5, 0, 1,
+ xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ self.title_textview.props.accepts_tab = False
+ self.title_textview.show()
+
+ #filepath
+ description_label = gtk.Label(_("Description"))
+ self.detail_view.attach(description_label, 3,4, 1, 2,
+ xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ description_label.show()
+
+ self.description_textview = gtk.TextView()
+ self.description_textview.set_wrap_mode(gtk.WRAP_WORD)
+ self.detail_view.attach(self.description_textview, 4,5, 1, 2,
+ xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ self.description_textview.props.accepts_tab = False
+ self.description_textview.show()
+
+ #mtime
+ mtime_label = gtk.Label(_("Created"))
+ self.detail_view.attach(mtime_label, 3,4, 2,3,
+ xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ mtime_label.show()
+
+ self.mtime_textview = gtk.TextView()
+ self.mtime_textview.set_wrap_mode(gtk.WRAP_WORD)
+ self.detail_view.attach(self.mtime_textview, 4,5, 2,3,
+ xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ self.mtime_textview.props.accepts_tab = False
+ self.mtime_textview.show()
+
+ #mime_type
+ mime_label= gtk.Label(_("Type"))
+ self.detail_view.attach(mime_label, 3,4, 3,4,
+ xoptions=gtk.SHRINK,
+ yoptions=gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ mime_label.show()
+
+ self.mime_textview = gtk.TextView()
+ self.mime_textview.set_wrap_mode(gtk.WRAP_WORD)
+ self.detail_view.attach(self.mime_textview, 4,5, 3,4,
+ xoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ yoptions=gtk.EXPAND|gtk.FILL|gtk.SHRINK,
+ xpadding=10, ypadding=10)
+ self.mime_textview.props.accepts_tab = False
+ self.mime_textview.show()
+
+ self._secondary_view.pack_end(self.detail_view)
+ self.detail_view.show()
+ return self._secondary_view
- self._secondary_view.pack_end(self.detail_view)
- self.detail_view.show()
- return self._secondary_view
-
- def show_button_press_event_cb(self, entry, event, col,row):
+ def show_button_press_event_cb(self, entry, event, col,row):
+
# Need to get the full set of properties
- iter = self.ls_journal[col].get_iter_first()
- n=0
- tv = self.tv_journal[col]
- model = tv.get_model()
- while(iter!=None and n<(row)):
- iter=self.ls_journal[col].iter_next(iter)
- n+=1
- jobject = model.get_value(iter,COLUMN_JOBJECT)
- object_id=jobject.get_object_id()
-
- metadata=jobject.get_file_metadata()
-
- try:
- scaled_buf=self.show_image(jobject.get_file_path())
- self.large_image.set_from_pixbuf(scaled_buf)
-
- except Exception:
- logging.error('Exception while displaying entry:\n' + \
- ''.join(traceback.format_exception(*sys.exc_info())))
-
- title_textbuf=self.title_textview.get_buffer()
- if metadata['title']!=None: title_textbuf.set_text(metadata['title'])
-
-
- desc_textbuf=self.description_textview.get_buffer()
- if metadata['description']!=None: desc_textbuf.set_text(metadata['description'])
-
- mime_textbuf=self.mime_textview.get_buffer()
- mime_textbuf.set_text(metadata['mime_type'])
-
- mtime_textbuf=self.mtime_textview.get_buffer()
- #time from curent
- mtime=time.asctime(time.localtime(float(metadata['timestamp'])))
- mtime_textbuf.set_text(str(mtime))
- self._secondary_view.show()
- self.vbox_view.show()
- self.canvas.set_current_page(len(self.vbox))
- self.last_col=col
-
- def _go_back_clicked_cb(self,entry,event,col):
- self.tab_label[col].hide()
- self.vbox_view.hide()
- self.canvas.set_current_page(self.last_col)
- def delete_button_press_event_cb(self, entry, event, col,id):
- i=0
- tv = self.tv_journal[col]
- model = tv.get_model()
- iter = self.ls_journal[col].get_iter_first()
- while(i<id):
- iter = self.ls_journal[col].iter_next(iter)
- i+=1
- if not iter==None:
- jobject = model.get_value(iter,COLUMN_JOBJECT)
- self.ls_journal[col].remove(iter)
- if col==0:
- datastore.delete(jobject.get_object_id())
-
- else:
- try:
- os.remove(jobject.get_file_path())
- print 'Deleted %s' % (jobject.get_file_path())
-
- except OSError: print 'Cannot delete %s' % (jobject.get_file_path())
- self.remove_image(col,id)
- self.tv_journal[col].grab_focus()
- self.last_col=col
-
-
-
-
-
-
- def close(self, skip_save=False):
- "Override the close method so we don't try to create a Journal entry."
- activity.Activity.close(self, True)
-
-
- def set_form_fields(self, jobject, col=0,id=0):
- #no title
- #self.title_entry[col][id].set_text(jobject.get_title())
- if col==0:
- self.create_preview(jobject.get_object_id(),col,id)
- else:
- filename=jobject.get_file_path()
- self.show_image(filename,col,id)
-
-
- def create_preview(self, object_id,col,id):
- jobject = datastore.get(object_id)
-
- if jobject.metadata.has_key('preview'):
- preview = jobject.metadata['preview']
- if preview is None or preview == '' or preview == 'None':
- if (jobject.metadata['mime_type'].startswith('image/')):
-# or (jobject.metadata['mime_type'].startswith('video')):
- filename = jobject.get_file_path()
- self.show_image(filename,col,id)
- return
-
- if jobject.metadata.has_key('preview') and \
- len(jobject.metadata['preview']) > 4:
-
- if jobject.metadata['preview'][1:4] == 'PNG':
- preview_data = jobject.metadata['preview']
- else:
- import base64
- preview_data = base64.b64decode(jobject.metadata['preview'])
-
- loader = gtk.gdk.PixbufLoader()
- loader.write(preview_data)
- scaled_buf = loader.get_pixbuf()
- loader.close()
- self.image[col][id].set_from_pixbuf(scaled_buf)
- self.image[col][id].show()
- else:
- self.image[col][id].clear()
- self.image[col][id].show()
-
- def load_file_table(self,col):
- self.num=0
- if col==2:
- ds_mounts = datastore.mounts()
- #check if externmal media used in journal
- if len(ds_mounts)==1 and ds_mounts[0]['id']==1:
-
- #file= Popen(["./test.sh",""],stdout=PIPE)
- #test=file.stdout
- self.load_files('/media',col)
- if self.num==0:
- self.tab_label[col].hide()
- elif col==1:
- self.load_files('/home/olpc',col)
- else:
- f=open('olpc.files','r')
- for line in f:
- line=line.strip()
- print self.num
- self.load_files('/home/olpc/'+line,col)
- if self.num>max_file:
- break
- f.close()
- self.ls_journal[col].set_sort_column_id(COLUMN_MTIME, gtk.SORT_DESCENDING)
-
- def load_files(self,dir,col):
- for path, dirnames, filenames in os.walk(dir,True):
- if dir=='/media':
- f=open('media.files','r')
- for line in f:
- line=line.strip()
- if line in dirnames:
- dirnames.remove(line)
- f.close()
- if dir=='/home/olpc' :
- f=open('olpc.files','r')
- for line in f:
- line=line.strip()
- if line in dirnames:
- dirnames.remove(line)
- f.close()
- for filename in filenames:
- file_name=os.path.join(path,filename)
- #remove hidden file_nameexcept for readonly
- pos=str.find(file_name,'/.')
- if col==3:pos=-1
- name=str.find(file_name,'Cache')
- if ((pos==-1) or name>0) and not( os.path.islink(file_name)):
- if self.num>max_file: return
- try:
- file_mimetype = mime.get_for_file(os.path.join(path,filename))
-
- if (file_mimetype.startswith('image/')) :
-#or (file_mimetype.startswith('video/')):
- #check for new files
- self.num+=1
- mtime=os.path.getmtime(file_name)
- iter = self.ls_journal[col].append()
- jobject_wrapper = JobjectWrapper()
- jobject_wrapper.set_file_path(os.path.join(path, filename))
- jobject_wrapper.set_object_id(file_name)
- jobject_wrapper.set_title(filename)
- jobject_wrapper.set_mime_type(file_mimetype)
- jobject_wrapper.set_timestamp(mtime)
- jobject_wrapper.set_description(file_name)
-
- self.ls_journal[col].set(iter, COLUMN_TITLE, filename)
- self.ls_journal[col].set(iter, COLUMN_MTIME,mtime)
- self.ls_journal[col].set(iter, COLUMN_JOBJECT, jobject_wrapper)
- except IOError: print 'No mimetype for : %s' % (file_name)
-
-
- def load_journal_table(self,col):
- ds_mounts = datastore.mounts()
- mountpoint_id = None
- if len(ds_mounts) == 1 and ds_mounts[0]['id'] == 1:
- pass
- else:
- for mountpoint in ds_mounts:
- id = mountpoint['id']
- uri = mountpoint['uri']
- if uri.startswith('/home'):
- mountpoint_id = id
-
- query = {}
- if mountpoint_id is not None:
- query['mountpoints'] = [ mountpoint_id ]
- ds_objects, num_objects = datastore.find(query, properties=['uid','timestamp',
- 'title', 'mime_type','description'],sorting='-timestamp')
-
- self.ls_journal[col].clear()
- for i in xrange (0, num_objects, 1):
- mime = ds_objects[i].metadata['mime_type']
-
- if mime.startswith('image/') or mime.startswith('video/') :
- iter = self.ls_journal[col].append()
- title = ds_objects[i].metadata['title']
- self.ls_journal[col].set(iter, COLUMN_TITLE, title)
- jobject_wrapper=JobjectWrapper()
- jobject_wrapper.set_jobject(ds_objects[i])
- jobject_wrapper.set_mime_type(mime)
- mtime= ds_objects[i].metadata.get('timestamp')
- jobject_wrapper.set_timestamp(mtime)
- desc= ds_objects[i].metadata.get('description')
- jobject_wrapper.set_description(desc)
- title= ds_objects[i].metadata.get('uid')
- jobject_wrapper.set_title(title)
-
-
-
-
- self.ls_journal[col].set(iter, COLUMN_MTIME, mtime)
- self.ls_journal[col].set(iter, COLUMN_JOBJECT, jobject_wrapper)
- size = self.get_size(ds_objects[i]) / 1024
-
- self.ls_journal[col].set_sort_column_id(COLUMN_MTIME, gtk.SORT_DESCENDING)
-
- def get_size(self, jobject):
- """Return the file size for a Journal object."""
- logging.debug('get_file_size %r', jobject.object_id)
- path = jobject.get_file_path()
- if not path:
- return 0
-
- return os.stat(path).st_size
-
-
- def show_image(self, filename,col=-1, id=0):
- "display a resized image in a preview"
- try:
- if filename==None:return
-
- if col==-1:
- scaled_buf = gtk.gdk.pixbuf_new_from_file_at_size(filename, style.zoom(930), style.zoom(700))
- return scaled_buf
-
- else:
- scaled_buf = gtk.gdk.pixbuf_new_from_file_at_size(filename, style.zoom(320), style.zoom(240))
- self.image[col][id].set_from_pixbuf(scaled_buf)
- self.image[col][id].show()
- except IOError: print 'Failed to open image %s' % (filename)
- except GError: print 'Failed zoom image %s' % (filename)
-
-
-
+ iter = self.ls_journal[col].get_iter_first()
+ n=0
+ tv = self.tv_journal[col]
+ model = tv.get_model()
+
+ while(iter!=None and n<(row)):
+ iter=self.ls_journal[col].iter_next(iter)
+ n+=1
+ jobject = model.get_value(iter,COLUMN_JOBJECT)
+
+ object_id=jobject.get_object_id()
+ metadata=jobject.get_file_metadata()
+
+ try:
+ scaled_buf=self.show_image(jobject.get_file_path())
+ self.large_image.set_from_pixbuf(scaled_buf)
+ except Exception:
+ logging.error('Exception while displaying entry:\n' + \
+ ''.join(traceback.format_exception(*sys.exc_info())))
+
+ title_textbuf=self.title_textview.get_buffer()
+ if metadata['title']!=None: title_textbuf.set_text(metadata['title'])
+ desc_textbuf=self.description_textview.get_buffer()
+
+ if metadata['description']!=None:
+ desc_textbuf.set_text(metadata['description'])
+
+ mime_textbuf=self.mime_textview.get_buffer()
+ mime_textbuf.set_text(metadata['mime_type'])
+ mtime_textbuf=self.mtime_textview.get_buffer()
+ #time from curent
+ mtime=time.asctime(time.localtime(float(metadata['timestamp'])))
+ mtime_textbuf.set_text(str(mtime))
+
+ self._secondary_view.show()
+ self.vbox_view.show()
+ self.canvas.set_current_page(len(self.vbox))
+ self.last_col=col
+
+ def _go_back_clicked_cb(self,entry,event,col):
+
+ self.tab_label[col].hide()
+ self.vbox_view.hide()
+ self.canvas.set_current_page(self.last_col)
+
+ def delete_button_press_event_cb(self, entry, event, col,id):
+
+ i=0
+ tv = self.tv_journal[col]
+ model = tv.get_model()
+ iter = self.ls_journal[col].get_iter_first()
+
+ while(i<id):
+ iter = self.ls_journal[col].iter_next(iter)
+ i+=1
+
+ if not iter==None:
+ jobject = model.get_value(iter,COLUMN_JOBJECT)
+ self.ls_journal[col].remove(iter)
+
+ if col==0:
+ datastore.delete(jobject.get_object_id())
+
+ else:
+ try:
+ os.remove(jobject.get_file_path())
+ print 'Deleted %s' % (jobject.get_file_path())
+ except OSError: print 'Cannot delete %s' % (jobject.get_file_path())
+
+ self.remove_image(col,id)
+ self.tv_journal[col].grab_focus()
+ self.last_col=col
+
+ def close(self, skip_save=False):
+ "Override the close method so we don't try to create a Journal entry."
+
+ activity.Activity.close(self, True)
+
+ def set_form_fields(self, jobject, col=0,id=0):
+ #no title
+ #self.title_entry[col][id].set_text(jobject.get_title())
+ if col==0:
+ self.create_preview(jobject.get_object_id(),col,id)
+ else:
+ filename=jobject.get_file_path()
+ self.show_image(filename,col,id)
+
+ def create_preview(self, object_id,col,id):
+
+ jobject = datastore.get(object_id)
+
+ if jobject.metadata.has_key('preview'):
+ preview = jobject.metadata['preview']
+ if preview is None or preview == '' or preview == 'None':
+ if (jobject.metadata['mime_type'].startswith('image/')):
+ # or (jobject.metadata['mime_type'].startswith('video')):
+ filename = jobject.get_file_path()
+ self.show_image(filename,col,id)
+ return
+
+ if jobject.metadata.has_key('preview') and \
+ len(jobject.metadata['preview']) > 4:
+
+ if jobject.metadata['preview'][1:4] == 'PNG':
+ preview_data = jobject.metadata['preview']
+ else:
+ import base64
+ preview_data = base64.b64decode(jobject.metadata['preview'])
+
+ loader = gtk.gdk.PixbufLoader()
+ loader.write(preview_data)
+ scaled_buf = loader.get_pixbuf()
+ loader.close()
+ self.image[col][id].set_from_pixbuf(scaled_buf)
+ self.image[col][id].show()
+ else:
+ self.image[col][id].clear()
+ self.image[col][id].show()
+
+ def load_file_table(self,col):
+
+ self.num=0
+ if col==2:
+ ds_mounts = datastore.mounts()
+ #check if externmal media used in journal
+ if len(ds_mounts)==1 and ds_mounts[0]['id']==1:
+ #file= Popen(["./test.sh",""],stdout=PIPE)
+ #test=file.stdout
+ self.load_files('/media',col)
+ if self.num==0:
+ self.tab_label[col].hide()
+
+ elif col==1:
+ self.load_files('/home/olpc',col)
+
+ else:
+ f=open('olpc.files','r')
+ for line in f:
+ line=line.strip()
+ print self.num
+ self.load_files('/home/olpc/'+line,col)
+ if self.num>max_file: break
+ f.close()
+
+ self.ls_journal[col].set_sort_column_id(COLUMN_MTIME, gtk.SORT_DESCENDING)
+
+ def load_files(self,dir,col):
+
+ for path, dirnames, filenames in os.walk(dir,True):
+ if dir=='/media':
+ f=open('media.files','r')
+ for line in f:
+ line=line.strip()
+ if line in dirnames:
+ dirnames.remove(line)
+ f.close()
+
+ if dir=='/home/olpc' :
+ f=open('olpc.files','r')
+ for line in f:
+ line=line.strip()
+ if line in dirnames:
+ dirnames.remove(line)
+ f.close()
+
+ for filename in filenames:
+ file_name=os.path.join(path,filename)
+ #remove hidden file_nameexcept for readonly
+ pos=str.find(file_name,'/.')
+ if col==3:pos=-1
+ name=str.find(file_name,'Cache')
+
+ if ((pos==-1) or name>0) and not( os.path.islink(file_name)):
+ if self.num>max_file: return
+ try:
+ file_mimetype = mime.get_for_file(os.path.join(path,filename))
+ if (file_mimetype.startswith('image/')) :
+ #or (file_mimetype.startswith('video/')):
+ #check for new files
+ self.num+=1
+ mtime=os.path.getmtime(file_name)
+ iter = self.ls_journal[col].append()
+ jobject_wrapper = JobjectWrapper()
+ jobject_wrapper.set_file_path(os.path.join(path, filename))
+ jobject_wrapper.set_object_id(file_name)
+ jobject_wrapper.set_title(filename)
+ jobject_wrapper.set_mime_type(file_mimetype)
+ jobject_wrapper.set_timestamp(mtime)
+ jobject_wrapper.set_description(file_name)
+ self.ls_journal[col].set(iter, COLUMN_TITLE, filename)
+ self.ls_journal[col].set(iter, COLUMN_MTIME,mtime)
+ self.ls_journal[col].set(iter, COLUMN_JOBJECT, jobject_wrapper)
+ except IOError: print 'No mimetype for : %s' % (file_name)
+
+ def load_journal_table(self,col):
+
+ ds_mounts = datastore.mounts()
+ mountpoint_id = None
+
+ if len(ds_mounts) == 1 and ds_mounts[0]['id'] == 1:
+ pass
+ else:
+ for mountpoint in ds_mounts:
+ id = mountpoint['id']
+ uri = mountpoint['uri']
+ if uri.startswith('/home'):
+ mountpoint_id = id
+
+ query = {}
+ if mountpoint_id is not None:
+ query['mountpoints'] = [ mountpoint_id ]
+ ds_objects, num_objects = datastore.find(query, properties=['uid','timestamp',
+ 'title', 'mime_type','description'],sorting='-timestamp')
+
+ self.ls_journal[col].clear()
+ for i in xrange (0, num_objects, 1):
+ mime = ds_objects[i].metadata['mime_type']
+
+ if mime.startswith('image/') or mime.startswith('video/') :
+ iter = self.ls_journal[col].append()
+ title = ds_objects[i].metadata['title']
+ self.ls_journal[col].set(iter, COLUMN_TITLE, title)
+ jobject_wrapper=JobjectWrapper()
+ jobject_wrapper.set_jobject(ds_objects[i])
+ jobject_wrapper.set_mime_type(mime)
+ mtime= ds_objects[i].metadata.get('timestamp')
+ jobject_wrapper.set_timestamp(mtime)
+ desc= ds_objects[i].metadata.get('description')
+ jobject_wrapper.set_description(desc)
+ title= ds_objects[i].metadata.get('uid')
+ jobject_wrapper.set_title(title)
+ self.ls_journal[col].set(iter, COLUMN_MTIME, mtime)
+ self.ls_journal[col].set(iter, COLUMN_JOBJECT, jobject_wrapper)
+ size = self.get_size(ds_objects[i]) / 1024
+
+ self.ls_journal[col].set_sort_column_id(COLUMN_MTIME, gtk.SORT_DESCENDING)
+
+ def get_size(self, jobject):
+ """Return the file size for a Journal object."""
+
+ logging.debug('get_file_size %r', jobject.object_id)
+ path = jobject.get_file_path()
+
+ if not path:
+ return 0
+
+ return os.stat(path).st_size
+
+ def show_image(self, filename,col=-1, id=0):
+ """display a resized image in a preview"""
+
+ try:
+ if filename==None:return
+ if col==-1:
+ scaled_buf = gtk.gdk.pixbuf_new_from_file_at_size(filename, style.zoom(930), style.zoom(700))
+ return scaled_buf
+ else:
+ scaled_buf = gtk.gdk.pixbuf_new_from_file_at_size(filename, style.zoom(320), style.zoom(240))
+ self.image[col][id].set_from_pixbuf(scaled_buf)
+ self.image[col][id].show()
+ except IOError: print 'Failed to open image %s' % (filename)
+ except GError: print 'Failed zoom image %s' % (filename)
+
class JobjectWrapper():
- def __init__(self):
- self.__jobject = None
- self.__file_path = None
-
- def set_jobject(self, jobject):
- self.__jobject = jobject
-
- def set_file_path(self, file_path):
- self.__file_path = file_path
-
- def set_title(self, filename):
- if self.__jobject != None:
- self.__jobject.metadata['title']=filename
- else:
-
- self.__title = filename
+
+ def __init__(self):
+
+ self.__jobject = None
+ self.__file_path = None
- def get_title(self):
- if self.__jobject != None:
- return self.__jobject.metadata['title']
- else:
- return self.__title
- def set_mime_type(self,mime_type):
- if self.__jobject != None:
- self.__jobject.metadata['mime_type']=mime_type
- else:
- self.__mime_type =mime_type
- def set_timestamp(self, time):
- if self.__jobject != None:
- self.__jobject.metadata['timestamp']=time
- else:
- self.__timestamp =time
+ def set_jobject(self, jobject):
+
+ self.__jobject = jobject
- def set_description(self, desc):
- if self.__jobject != None:
- self.__jobject.metadata['description']=desc
- else:
+ def set_file_path(self, file_path):
+
+ self.__file_path = file_path
- self.__description =desc
+ def set_title(self, filename):
+
+ if self.__jobject != None:
+ self.__jobject.metadata['title']=filename
+ else:
+ self.__title = filename
- def set_object_id(self,id):
- self.__object_id=id
+ def get_title(self):
+
+ if self.__jobject != None:
+ return self.__jobject.metadata['title']
+ else:
+ return self.__title
+
+ def set_mime_type(self,mime_type):
+
+ if self.__jobject != None:
+ self.__jobject.metadata['mime_type']=mime_type
+ else:
+ self.__mime_type =mime_type
+
+ def set_timestamp(self, time):
+
+ if self.__jobject != None:
+ self.__jobject.metadata['timestamp']=time
+ else:
+ self.__timestamp =time
- def get_file_path(self):
- if self.__jobject != None:
- return self.__jobject.get_file_path()
- else:
- return self.__file_path
- def get_timestamp(self):
- if self.__jobject != None:
- # may cause error
- return self.__jobject.metadata.get('timestamp')
- else:
- return self.__timestamp
- def get_file_metadata(self):
- if self.__jobject != None:
- # may cause error
- return self.__jobject.metadata
- else:
- #client = gconf.client_get_default()
- path=self.__file_path
- return {'uid': self.__object_id,
- 'title': self.__title,
- 'timestamp': self.__timestamp,
- 'mime_type': self.__mime_type,
- 'activity': '',
- 'activity_id': '',
- 'icon-color': '',
- 'description': self.__description}
+ def set_description(self, desc):
+
+ if self.__jobject != None:
+ self.__jobject.metadata['description']=desc
+ else:
+ self.__description =desc
+ def set_object_id(self,id):
+
+ self.__object_id=id
- def get_mime_type(self):
- if self.__jobject != None:
- return self.__jobject.metadata['mimetype']
- else:
- return self.__mime_type
+ def get_file_path(self):
+
+ if self.__jobject != None:
+ return self.__jobject.get_file_path()
+ else:
+ return self.__file_path
+
+ def get_timestamp(self):
+
+ if self.__jobject != None:
+ # may cause error
+ return self.__jobject.metadata.get('timestamp')
+ else:
+ return self.__timestamp
+
+ def get_file_metadata(self):
+
+ if self.__jobject != None:
+ # may cause error
+ return self.__jobject.metadata
+ else:
+ #client = gconf.client_get_default()
+ path=self.__file_path
+ return {
+ 'uid': self.__object_id,
+ 'title': self.__title,
+ 'timestamp': self.__timestamp,
+ 'mime_type': self.__mime_type,
+ 'activity': '',
+ 'activity_id': '',
+ 'icon-color': '',
+ 'description': self.__description
+ }
+
+ def get_mime_type(self):
+
+ if self.__jobject != None:
+ return self.__jobject.metadata['mimetype']
+ else:
+ return self.__mime_type
- def get_object_id(self):
- if self.__jobject != None:
- return self.__jobject.object_id
- else:
- return self.__object_id
+ def get_object_id(self):
+
+ if self.__jobject != None:
+ return self.__jobject.object_id
+ else:
+ return self.__object_id
diff --git a/setup.py b/setup.py
index 2f2c143..d3ab3a3 100755
--- a/setup.py
+++ b/setup.py
@@ -16,6 +16,6 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-from sugar3.activity import bundlebuilder
+from sugar.activity import bundlebuilder
bundlebuilder.start()