Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Hunt <ghunt@ghunt-desktop.(none)>2010-06-03 21:49:22 (GMT)
committer George Hunt <ghunt@ghunt-desktop.(none)>2010-06-03 21:49:22 (GMT)
commitb5dcd4cbab884bdc6cf932a636173dfcf80dbe5f (patch)
tree4226793cf259503b4a5d5c0d18c03587bfbbb051
parent1f8c0e41ce4869531394d0bd6e1b5cb9bd4ddb7b (diff)
changes made in St John, still some gtk/pygame sync startup problems
-rw-r--r--MANIFEST10
-rw-r--r--dbphoto.py53
-rw-r--r--display.py169
-rw-r--r--dist/XoPhoto-2.xobin5581311 -> 4273950 bytes
-rw-r--r--ezscroll/examples.py148
-rw-r--r--ezscroll/ezscroll.py268
-rw-r--r--ezscroll/inlineScroll.py68
-rw-r--r--photo_toolbar.py31
-rw-r--r--sinks.py70
-rw-r--r--sources.py55
-rw-r--r--startup_images/190x152shadow.pngbin0 -> 1981 bytes
-rw-r--r--startup_images/190x152shadow.tiffbin0 -> 24455 bytes
-rw-r--r--startup_images/190x152shadow_1.tiffbin0 -> 26856 bytes
-rw-r--r--startup_images/2596796843_41a240f6b8_o.jpgbin0 -> 159013 bytes
-rw-r--r--startup_images/2606362543_1598e7efc0_o.jpgbin0 -> 243776 bytes
-rw-r--r--startup_images/2611672629_5f0e2c0e63_o.jpgbin0 -> 73064 bytes
-rw-r--r--startup_images/2612132968_fcba550e13_o.jpgbin0 -> 255936 bytes
-rw-r--r--startup_images/2630825026_061177dc7d.jpgbin0 -> 137820 bytes
-rw-r--r--startup_images/2907401406_0d6d1e0bed.jpgbin0 -> 176745 bytes
-rw-r--r--startup_images/2928908291_c227faca09.jpgbin0 -> 165229 bytes
-rw-r--r--startup_images/2946277091_0675b569ff_b.jpgbin0 -> 546259 bytes
-rw-r--r--startup_images/2947130964_3019253782_b.jpgbin0 -> 283423 bytes
-rw-r--r--startup_images/3079782689_8ca8a237da.jpgbin0 -> 173823 bytes
-rw-r--r--startup_images/3080618900_c90371ec9a.jpgbin0 -> 151290 bytes
-rw-r--r--startup_images/ezscroll/examples.py148
-rw-r--r--startup_images/ezscroll/ezscroll.py268
-rw-r--r--startup_images/ezscroll/inlineScroll.py68
-rw-r--r--startup_images/ezscrollv10.zipbin0 -> 5240 bytes
-rw-r--r--startup_images/reuiideasmynewxo.zipbin0 -> 57363 bytes
-rw-r--r--startup_images/stack_background.pngbin0 -> 11113 bytes
-rw-r--r--startup_images/stack_background.tiffbin0 -> 35208 bytes
-rw-r--r--startup_images/stack_background_1.tiffbin0 -> 68536 bytes
-rw-r--r--startup_images/xophoto.sql18
-rw-r--r--sugargame/canvas.py2
-rw-r--r--xophoto.sqlitebin6885376 -> 2486272 bytes
-rw-r--r--xophoto.sqlite.templatebin0 -> 12288 bytes
-rw-r--r--xophotoactivity.py219
37 files changed, 1483 insertions, 112 deletions
diff --git a/MANIFEST b/MANIFEST
index 9f05c79..3a46547 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -2,9 +2,11 @@ xophoto.sqlite
dbphoto.py
photo_toolbar.pyo
sinks.py
+to_home
photo_toolbar.py
ezscrollv10.zip
sinks.pyo
+xophoto.sqlite.template
display.py
dbphoto.pyo
sources.py
@@ -17,6 +19,7 @@ startup_images/190x152shadow_1.tiff
startup_images/stack_background_1.tiff
startup_images/190x152shadow.tiff
startup_images/2946277091_0675b569ff_b.jpg
+startup_images/ezscrollv10.zip
startup_images/2612132968_fcba550e13_o.jpg
startup_images/reuiideasmynewxo.zip
startup_images/190x152shadow.png
@@ -30,13 +33,20 @@ startup_images/2907401406_0d6d1e0bed.jpg
startup_images/2611672629_5f0e2c0e63_o.jpg
startup_images/stack_background.tiff
startup_images/2928908291_c227faca09.jpg
+startup_images/xophoto.sql
startup_images/2630825026_061177dc7d.jpg
+startup_images/ezscroll/inlineScroll.py
+startup_images/ezscroll/examples.py
+startup_images/ezscroll/ezscroll.py
ezscroll/inlineScroll.py
ezscroll/examples.py
ezscroll/ezscroll.py
+activity/scommander.svg
activity/activity.info
activity/XoPhoto.svg
+activity/activity.save
activity/activity.info.gh
+activity/XoPhotoXPs.svg
hide/image_datastore.py
hide/dbaccess.py
hide/TestGame.py
diff --git a/dbphoto.py b/dbphoto.py
index 247810a..586a232 100644
--- a/dbphoto.py
+++ b/dbphoto.py
@@ -38,8 +38,8 @@ _logger = logging.getLogger('xophoto')
_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(name)s %(levelname)s %(funcName)s: %(lineno)d||| %(message)s')
-console_handler.setFormatter(console_formatter)
-_logger.addHandler(console_handler)
+#console_handler.setFormatter(console_formatter)
+#_logger.addHandler(console_handler)
class DbAccess():
@@ -48,10 +48,13 @@ class DbAccess():
def __init__(self,fn):
self.opendb(fn)
self.added = 0
+ self.error = ''
def opendb(self,dbfilename):
try:
- _logger.debug('opening database cwd:%s filename %s'%(os.getcwd(),dbfilename,))
+ if not os.path.isfile(dbfilename):
+ _logger.debug('trying to open database cwd:%s filename %s'%(os.getcwd(),dbfilename,))
+ dbfilename = os.path.join(os.getcwd(),dbfilename)
self.con = sqlite3.connect(dbfilename)
self.con.row_factory = sqlite3.Row
self.con.text_factory = str
@@ -65,6 +68,9 @@ class DbAccess():
def is_open(self):
if self.con: return True
return False
+
+ def get_error(self):
+ return self.error
def closedb(self):
if self.con:self.con.close()
@@ -96,6 +102,7 @@ class DbAccess():
"""create a record in picture pointing to unique pictures in the journal.
Use md5 checksum to test for uniqueness
For non unique entries, add a copy number (fieldname:duplicate) greater than 0
+ returns number of records added
"""
_logger.debug('create_picture_record object_id:%s file: %s'%(object_id,fn,))
#if object_id == '': return
@@ -113,15 +120,34 @@ class DbAccess():
rows = self.cur.fetchall()
#_logger.debug('rowcount %s object_id %s'%(len(rows),object_id))
#the object_id is supposed to be unique, so add only new object_id's
+ info = os.stat(fn)
if len(rows) == 0:
- info = os.stat(fn)
sql = """insert into picture \
(in_ds, mount_point, orig_size, create_date,jobject_id, md5_sum, duplicate) \
values (%s,'%s',%s,'%s','%s','%s',%s)""" % \
(1, fn, info.st_size, info.st_ctime, object_id, md5_hash,len(rows_md5),)
- _logger.debug('sql: %s'%sql)
- self.con.execute(sql)
-
+ cursor = self.con.cursor()
+ cursor.execute(sql)
+ self.con.commit()
+ return 1
+ elif len(rows) == 1:
+ sql = """update picture set in_ds = ?, mount_point = ?, orig_size = ?, \
+ create_date = ?, md5_sum = ?, duplicate = ?"""
+ cursor = self.con.cursor()
+ cursor.execute(sql,(1, fn, info.st_size, info.st_ctime, md5_hash,len(rows_md5)))
+ self.con.commit()
+ return 0
+
+ def put_ds_into_picture(self,jobject_id):
+ self.cur.execute("select * from picture where jobject_id = ?",(jobject_id,))
+ rows = self.cur.fetchall()
+ #_logger.debug('rowcount %s object_id %s'%(len(rows),object_id))
+ #the object_id is supposed to be unique, so add only new object_id's
+ if len(rows) == 0:
+ cursor = self.con.cursor()
+ cursor.execute('insert into picture (jobject_id) values (?)',(str(jobject_id),))
+ self.con.commit()
+
def clear_in_ds(self):
self.con.execute('update picture set in_ds = 0')
@@ -139,8 +165,11 @@ class DbAccess():
cursor = self.con.cursor()
cursor.execute("select * from config where name = 'last_album'")
rows = cursor.fetchmany()
- if len(rows)>0:
+ if len(rows) == 1:
return (rows[0]['value'],rows[0]['id'],)
+ elif len(rows) > 1:
+ _logger.debug('somehow got more than one last_album record')
+ #cursor.execute("delete from config where name = 'last_album'")
return None,0
def set_last_album(self,album_id):
@@ -207,10 +236,10 @@ class DbAccess():
cur.execute(sql)
return cur.fetchall(), cur
#self.con.commit()
- except sqlite.Error, e:
- print 'An sqlite error:',e.args[0]
- print sql+'\n'
- return [],str(e)
+ except sqlite.Error, e:
+ _logger.debug( 'An sqlite error:%s; sql:%s'%(e,sql,))
+ self.error = str(e)
+ raise PhotoException(self.error)
def dbtry(self,sql):
""" execute a sql statement return true if no error"""
diff --git a/display.py b/display.py
index 9434f54..1d0f4de 100644
--- a/display.py
+++ b/display.py
@@ -1,6 +1,16 @@
#!/usr/bin/env python
# display.py
#
+"""to do list
+reorder thumbnails3
+change album name2
+hover display annotation
+function on build 802--4.5
+proprietary jobject_id for journal thumbnails5
+gtk-idle-add for thumbnail processing6
+pygame scrolling1
+start slide show roughing out4
+"""
# Copyright (C) 2010 George Hunt
#
# This program is free software; you can redistribute it and/or modify
@@ -33,6 +43,7 @@ import hashlib
import time
from threading import Timer
import datetime
+import gobject
#application imports
from dbphoto import *
@@ -49,6 +60,7 @@ album_selected_color = (210,210,210)
selected_color = (0,230,0)
mouse_timer = time.time()
in_click_delay = False
+in_db_wait = False
in_drag = False
screen_h = 0
screen_w = 0
@@ -121,14 +133,14 @@ class DisplayOne():
w = row['scaled_x']
h = row['scaled_y']
transform_max = max(w,h)
- _logger.debug('transform rec max: %s request max: %s'%(transform_max,max_dim,))
+ #_logger.debug('transform rec max: %s request max: %s'%(transform_max,max_dim,))
if max_dim == transform_max:
self.x_thumb = w
self.y_thumb = h
self.aspect = float(w)/h
blob =row['thumb']
surf = pygame.image.frombuffer(blob,(w,h),'RGB')
- _logger.debug('retrieved thumbnail from database')
+ #_logger.debug('retrieved thumbnail from database')
return surf
try:
ds_obj = datastore.get(id)
@@ -142,6 +154,11 @@ class DisplayOne():
except Exception,e:
print('scale_image failed to load %s'%fn)
return None
+ try:
+ self.db.create_picture_record(ds_obj.object_id,fn)
+ except PhotoException,e:
+ _logger.debug('create_picture_record returned exception %s'%e)
+ return None
finally:
ds_obj.destroy()
self.surf.convert
@@ -527,7 +544,7 @@ class DisplayAlbums():
screen.blit(self.album_surface,(0,0))
def refresh_album_rows(self):
- sql = "select * from groups where category = 'albums'"
+ sql = "select * from groups where category = 'albums' order by id"
rows,cur = self.db.dbdo(sql)
self.number_of_albums = len(rows)
#keep a permanent reference to the list of albums
@@ -549,19 +566,26 @@ class DisplayAlbums():
self.paint_albums()
#now change the thumbnail side of the screen
try:
- album_name = self.album_rows[self.selected_index]['subcategory']
- except:
+ album_name = self.album_rows[int(self.selected_index)]['subcategory']
+ except Exception,e:
album_name = '20100521T10:42' #the journal
+ _logger.debug('exception fetching thumbnails %s'%e)
_logger.debug('now display the thumbnails with the album identifier %s'%album_name)
self.display_thumbnails(album_name)
def add_to_current_album(self,jobject_id,name=None):
"""if no current album create one. if name supplied use it
if there is a current album,and name but no jobject_id, change name
+ NOTE: Albums are stored in the table - 'groups' as follows:
+ --category = 'albums'
+ --subcategory = <unique string based upon date-time album was created
+ --Album name = Stored in the jobject_id field
+ --seq = modified as the order of the pictures is modified
"""
if not name: name = _("Unnamed Stack")
conn = self.db.get_connection()
cursor = conn.cursor()
+ self.accumulation_target,id = self.db.get_last_album()
if not self.accumulation_target:
self.accumulation_target = str(datetime.datetime.today())
_logger.debug('new album is:%s'%self.accumulation_target)
@@ -599,11 +623,53 @@ class DisplayAlbums():
"""create a 'current' album (if necessary) and name it"""
self.add_to_current_album('',name)
+ def get_current_album_identifier(self):
+ return self.album_rows[self.selected_index]['subcategory']
+
+ def get_current_album_name(self):
+ return self.album_rows[self.selected_index]['jobject_id']
+
def add_album_at_xy(self,x,y):
jobject_id = self.disp_many.get_jobject_id_at_xy(x,y)
if jobject_id:
self.add_to_current_album(jobject_id)
+ ##################### ALERT ROUTINES ##################################
+
+ def alert(self,msg,title=None):
+ alert = NotifyAlert(0)
+ if title != None:
+ alert.props.title=_('There is no Activity file')
+ alert.props.msg = msg
+ alert.connect('response',self.no_file_cb)
+ self.add_alert(alert)
+ return alert
+
+ def no_file_cb(self,alert,response_id):
+ self.remove_alert(alert)
+
+ from sugar.graphics.alert import ConfirmationAlert
+
+ def confirmation_alert(self,msg,title=None,confirmation_cb = None):
+ alert = ConfirmationAlert()
+ alert.props.title=title
+ alert.props.msg = msg
+ alert.callback_function = confirmation_cb
+ alert.connect('response', self._alert_response_cb)
+ self.add_alert(alert)
+ return alert
+
+ #### Method: _alert_response_cb, called when an alert object throws a
+ #response event.
+ def _alert_response_cb(self, alert, response_id):
+ #remove the alert from the screen, since either a response button
+ #was clicked or there was a timeout
+ this_alert = alert #keep a reference to it
+ self.remove_alert(alert)
+ #Do any work that is specific to the type of button clicked.
+ if response_id is gtk.RESPONSE_OK and this_alert.callback_function != None:
+ this_alert.callback_function (this_alert, response_id)
+
def toggle(self,x,y):
"""change the number of albums displayed"""
pass
@@ -627,19 +693,11 @@ class DisplayAlbums():
class Application():
#how far does a drag need to be not to be ignored?
drag_threshold = 10
- def __init__(self):
- self.db = DbAccess('xophoto.sqlite')
- if not self.db.is_open():
- _logger.debug('failed to open "xophoto.sqlite" database')
- exit()
- self.ds_sql = Datastore_SQLite(self.db)
- ds_count, added = self.ds_sql.check_for_recent_images()
- #if the picture table is empty, populate it from the journal, and initialize
- if ds_count < 10:
- self.first_run_setup()
-
- def first_run_setup(self):
-
+ db = None
+ def __init__(self, activity):
+ self._activity = activity
+
+ def first_run_setup(self):
#scan the datastore and add new images as required
#the following call takes too long during startup, just do it during import
number_of_pictures = self.ds_sql.scan_images()
@@ -655,8 +713,48 @@ class Application():
global in_click_delay
global screen_w
global screen_h
+ global in_db_wait
if True:
+ #moved the database functionality here because of sync problems with journal
+ if not self._activity.DbAccess_object: #we need to wait for the read-file to finish
+ Timer(25.0, self.end_db_delay, ()).start()
+ in_db_wait = True
+ while not self._activity.DbAccess_object and in_db_wait:
+ gtk.main_iteration()
+ if not self._activity.DbAccess_object:
+ _logger.error('db object not open after timeout in Appplication.run')
+ exit()
+
+ self.db = self._activity.DbAccess_object
+ if not self.db.is_open():
+ _logger.debug('failed to open "xophoto.sqlite" database')
+ exit()
+ self.ds_sql = Datastore_SQLite(self.db)
+ try:
+ ds_count, added = self.ds_sql.check_for_recent_images()
+ except PhotoException,e:
+ #This is a corrupted copy the sqlite database, start over
+ self.db.close()
+ source = os.path.join(os.getcwd(),'xophoto.sqlite.template')
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ try:
+ shutil.copy(source,dest)
+ except Exception,e:
+ _logger.debug('database template failed to copy error:%s'%e)
+ exit()
+ try:
+ self.DbAccess_object = DbAccess(dest)
+ except Exception,e:
+ _logger.debug('database failed to open in read file. error:%s'%e)
+ exit()
+ self.db = self.DbAccess_object
+
+ #if the picture table is empty, populate it from the journal, and initialize
+ if ds_count < 10:
+ self.first_run_setup()
+
+
running = True
do_display = True
screen = pygame.display.get_surface()
@@ -664,29 +762,26 @@ class Application():
screen_w = info.current_w
screen_h = info.current_h
_logger.debug('startup screen sizes w:%s h:%s '%(screen_w,screen_h,))
+ """
if screen_h < 400:
screen_h = 780
screen_w = 1200
#there is a startup bug which causes this intermittentl
#return
-
+ """
# Clear Display
screen.fill((255,255,255)) #255 for white
pygame.display.flip()
- """#fetch the album (array of album records)
- sql = 'select * from picture'
- rows,cur = self.db.dbdo(sql)
- self.dm = DisplayMany(rows,self.db)
- self.dm.num_per_row(8)
- self.dm.number_of_rows(6)
- """
+
self.albums = DisplayAlbums(self.db)
self.albums.paint_albums()
- #self.dm.paint()
- #self.dm.display_album('journal')
+
# Flip Display
- pygame.display.flip()
+ pygame.display.flip()
+
+ # start processing any datastore images that don't have thumbnails
+ gobject.idle_add(self.ds_sql.make_one_thumbnail)
while running:
@@ -779,14 +874,28 @@ class Application():
def end_delay(self):
global in_click_delay
in_click_delay = False
+
+ def end_db_delay(self):
+ global in_db_wait
+ in_db_wait = False
+class shim():
+ def __init__(self):
+ self.DbAccess_object = DbAccess('/home/olpc/.sugar/default/org.laptop.PyDebug/data/pydebug/playpen/XoPhoto.activity/xophoto.sqlite')
+
def main():
pygame.init()
pygame.display.set_mode((0, 0), pygame.RESIZABLE)
- ap = Application()
+ dummy = shim()
+ ap = Application(dummy)
ap.run()
if __name__ == '__main__':
+ local_path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ source = 'xophoto.sqlite'
+ shutil.copy(source,local_path)
+ #DbAccess_object = DbAccess(local_path)
+
main()
diff --git a/dist/XoPhoto-2.xo b/dist/XoPhoto-2.xo
index d12925e..9a0c241 100644
--- a/dist/XoPhoto-2.xo
+++ b/dist/XoPhoto-2.xo
Binary files differ
diff --git a/ezscroll/examples.py b/ezscroll/examples.py
new file mode 100644
index 0000000..6031145
--- /dev/null
+++ b/ezscroll/examples.py
@@ -0,0 +1,148 @@
+import sys
+import pygame
+import ezscroll
+from ezscroll import N,S,E,W, ScrollBar, ScrollPane, BGCOLOR
+
+ScrSize = (300,600)
+Origin = (0,0)
+Gray = (200,200,200)
+
+def examples():
+ """ Examples of how to use ezscroll.
+ One is a scrollpane, the other is a scrollbar.
+ The scrollpane handles some things like offsets,
+ puts the scrollbars in a sprite group, and blits the world.
+ If you just want one scrollbar, still may be easier to
+ use ScrollPane and pass [S] or [E], etc.
+ Closing window of proceeds through examples.
+ """
+ pygame.init()
+ screen = pygame.display.set_mode(ScrSize)
+ world = pygame.Surface((ScrSize[0]*2, ScrSize[1]*2))
+ world.fill(Gray)
+ for x in xrange(100, world.get_size()[0], 200):
+ for y in xrange(100, world.get_size()[1], 200):
+ pygame.draw.circle(world, (225,34,43), (x,y), 100, 10)
+ bg = pygame.Surface(ScrSize).convert()
+
+
+ ### EXAMPLE 1
+ bg.fill(BGCOLOR)
+ pygame.display.set_caption("Example 1: ScrollPane")
+ initRect = pygame.Rect(screen.get_rect())
+ sp = ScrollPane(
+ world.get_size(),
+ initRect,
+ world,
+ bg,
+ [S, W, N],
+ 3,
+ True,
+ 20)
+ sp.draw(bg)
+ screen.blit(bg,Origin)
+ pygame.display.flip()
+ while True:
+ event = pygame.event.wait()
+ if event.type is pygame.QUIT: break
+ sp.clear()
+ sp.update(event)
+ changes = sp.draw(bg)
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+
+
+ ### EXAMPLE 2
+ pygame.display.set_caption("Example 2: ScrollBar")
+ thick = 20
+ scrollRect = pygame.Rect(0, 0, ScrSize[0], thick)
+ excludes = ((0, thick), ScrSize) # rect where sb update is a pass
+ group = pygame.sprite.RenderPlain()
+ sb = ScrollBar(
+ group,
+ world.get_width(),
+ scrollRect,
+ bg,
+ 0,
+ excludes,
+ 4,
+ True,
+ thick,
+ (170,220,180),
+ (200,210,225),
+ (240,240,250),
+ (0,55,100))
+ sb.draw(bg)
+ bg.blit(world, (0,thick),
+ (sb.get_scrolled(),(ScrSize[0],ScrSize[1]-thick)))
+ screen.blit(bg, Origin)
+ pygame.display.flip()
+ while True:
+ event = pygame.event.wait()
+ if event.type is pygame.QUIT: break
+ sb.update(event)
+ changes = sb.draw(bg)
+ if len(changes) > 0:
+ changes.append(bg.blit(world, (0,thick),
+ (sb.get_scrolled(),(ScrSize[0],ScrSize[1]-thick))))
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+
+## # you can skip even sending any events in the view area
+## try:
+## if not sb.exclude.collidepoint(event.pos):
+## sb.update(event)
+## ...
+
+ ### EXAMPLE 3
+ import random
+ pygame.display.set_caption("Example 3: ScrollBar")
+ thick = 20
+ scrollRect = pygame.Rect(0, 0, thick,ScrSize[1])
+ excludes = ((thick, 0), ScrSize) # rect where sb update is a pass
+ group = pygame.sprite.RenderPlain()
+ sb = ScrollBar(
+ group,
+ world.get_height(),
+ scrollRect,
+ bg,
+ 1,
+ excludes,
+ 4,
+ False,
+ thick,
+ (120,120,160,10),
+ (88,57,99,214))
+ sb.draw(bg)
+ bg.blit(world, (thick,0),(sb.get_scrolled(),
+ (ScrSize[0]-thick,ScrSize[1])))
+ screen.blit(bg, Origin)
+ pygame.display.flip()
+ clock = pygame.time.Clock()
+ counter = 0
+ while True:
+ counter += clock.tick()
+ if counter > 1000: chichi = 0
+ if counter % 100 == 0:
+ scrollAmount = random.randrange(-20, 20, 1)
+ sb.scroll(scrollAmount)
+ changes = sb.draw(bg)
+ if len(changes) > 0:
+ scrolled = sb.get_scrolled()
+ changes.append(bg.blit(
+ world,
+ (thick,0),
+ (scrolled[0]+thick,
+ scrolled[1],
+ ScrSize[0],ScrSize[1])))
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+ for event in pygame.event.get():
+ if event.type is pygame.QUIT:
+ pygame.quit()
+ sys.exit(0)
+
+
+
+if __name__ == '__main__':
+ examples()
diff --git a/ezscroll/ezscroll.py b/ezscroll/ezscroll.py
new file mode 100644
index 0000000..cc842be
--- /dev/null
+++ b/ezscroll/ezscroll.py
@@ -0,0 +1,268 @@
+#! %PYTHONPATH%\python
+import os
+import sys
+import pygame
+from pygame import *
+
+FGCOLOR = 220,220,200
+BGCOLOR = 235,235,230
+HICOLOR = 250,250,245
+LOCOLOR = 40,40,70
+N='N'
+S='S'
+E='E'
+W='W'
+
+
+class ScrollPane():
+ """ Coordinates up to four scrollbars on a panel.
+ Uses two ScrollBars offset, and blits world view on top.
+ Use like a sprite group: update(), draw(). See examples.py
+ """
+
+ def __init__(
+ self,
+ worldSize,
+ initRect,
+ world,
+ pane=None,
+ nsew=[S,E],
+ pad=0,
+ pretty=False,
+ thick=20,
+ fgColor=FGCOLOR,
+ bgColor=BGCOLOR,
+ hiColor=HICOLOR,
+ loColor=LOCOLOR):
+ """ Figures layout and inits ScrollBars """
+
+ self.world = world
+ self.pane = pane
+ self.group = pygame.sprite.RenderUpdates()
+ self.nsew = nsew
+ self.pad = pad
+ self.thick = thick
+ self.pretty = pretty
+ self.fgColor = fgColor
+ self.bgColor = bgColor
+ self.hiColor = hiColor
+ self.loColor = loColor
+
+ self.viewRect = self.initViewRect(initRect, self.nsew, self.thick)
+ win = self.viewRect
+ self.sprites = [] # the scrollbars
+ if E in self.nsew or W in self.nsew:
+ scrollRect = pygame.Rect(0, win.top, initRect.width, win.height)
+ exclude = win.inflate(0, self.thick).move(0,-self.thick//2)
+ sb = ScrollBar(self.group, worldSize[1], scrollRect, self.pane, 1,
+ exclude, self.pad, self.pretty, self.thick,
+ fgColor, bgColor, hiColor, loColor)
+ self.sprites.append(sb)
+
+ if N in self.nsew or S in self.nsew:
+ scrollRect = pygame.Rect(win.left, 0, win.width, initRect.height)
+ exclude = win.inflate(self.thick, 0).move(-self.thick//2,0)
+ sb = ScrollBar(self.group, worldSize[0], scrollRect, self.pane, 0,
+ exclude, self.pad, self.pretty, self.thick,
+ fgColor, bgColor, hiColor, loColor)
+ self.sprites.append(sb)
+
+## self.clearArchive = pygame.Surface(initRect.size).convert()
+## self.clearArchive.fill((255,0,0))
+
+ def initViewRect(self, initRect, nsew, thick):
+ """ Used by init(), subtract width of scrollbars from viewable area """
+ win = pygame.Rect(initRect)
+ if N in nsew:
+ win.top = thick
+ win.height -= thick
+ if S in nsew:
+ win.height -= thick
+ if E in nsew:
+ win.width -= thick
+ if W in nsew:
+ win.left = thick
+ win.width -= thick
+ return win
+
+ def clear(self): #does nothing?
+ pass # self.group.clear(self.pane, self.clearArchive)
+
+ def update(self, event):
+ """ Called by end user to update scroll state """
+ for sb in self.sprites:
+ sb.update(event)
+
+ def draw(self, surface):
+ """ Called by end user to draw state to the surface """
+ offsets = [0,0]
+ changes = []
+ for sb in self.sprites:
+ offsets[sb.axis] = sb.get_scrolled()[sb.axis]
+ if sb.dirty:
+ changes.extend(sb.draw(surface))
+ if changes:
+ # Comment out this blit to see just the scrollbars.
+ # To date, don't add to changes since the sb includes it.
+ surface.blit(self.world, self.viewRect.topleft,
+ (offsets, self.viewRect.size))
+ if self.pad and not self.pretty:
+ pygame.draw.rect(
+ self.pane, self.bgColor,
+ self.viewRect.inflate(self.pad+1,self.pad+1), self.pad)
+
+ return changes
+
+ def get_pane(self):
+ """ Called by end user to get the scroll pane results """
+ return self.pane
+
+
+class ScrollBar(pygame.sprite.DirtySprite):
+ """ Same interface as sprite.Group.
+ Get result of update() in pixels scrolled, from get_scrolled()
+ """
+
+ def __init__(
+ self,
+ group,
+ worldDim,
+ initRect,
+ surface=None,
+ axis=0,
+ exclude=(0,0,0,0),
+ pad=0,
+ pretty=False,
+ thick=20,
+ fgColor=FGCOLOR,
+ bgColor=BGCOLOR,
+ hiColor=HICOLOR,
+ loColor=LOCOLOR):
+
+ pygame.sprite.Sprite.__init__(self,group)
+ self.initTopleft = initRect.topleft
+ self.exclude = pygame.Rect(exclude)
+ self.image = pygame.Surface(initRect.size).convert()
+ self.rect = self.image.get_rect()
+ self.surface = surface
+ self.axis = axis
+ self.fgColor = fgColor
+ self.bgColor = bgColor
+ self.hiColor = hiColor
+ self.loColor = loColor
+ self.knob = pygame.Rect(self.rect)
+ self.ratio = 1.0 * initRect.size[self.axis] / worldDim
+ knoblist = list(self.knob.size)
+ knoblist[self.axis] = (self.knob.size[self.axis] * self.ratio)
+ self.knob.size = knoblist
+ self.scrolling = False
+ self.leftTop = [0,0]
+ self.diff = [0,0]
+ self.diff[self.axis] = self.initTopleft[self.axis]
+ self.dirty = True
+ self.pad = pad
+ self.pretty = pretty
+ self.thick = thick
+ self.oppAxis = cmp(0,self.axis)+1
+ self.prettySize = [
+ self.knob.width - (pad * 2), self.knob.height - (pad * 2)]
+ self.prettySize[self.oppAxis] = self.thick - (2 * pad)
+
+ def update(self, event): # event must not be None
+ """ Called by user with mouse events. event must not be none. """
+ if event.type is MOUSEMOTION and self.scrolling:
+ self.scroll(event.rel[self.axis])
+
+ elif event.type is MOUSEBUTTONDOWN and (
+ self.knob.move(self.diff).collidepoint(event.pos) and not (
+ self.exclude.collidepoint(event.pos))):
+ self.scrolling = True
+
+ elif event.type is MOUSEBUTTONUP:
+ self.scrolling = False
+
+ def scroll(self, numPixels):
+ """ Moves knob based on mouse events rel change along axis.
+ Called internally by update(). Knob travel limited to track.
+ """
+ if numPixels and numPixels != 0:
+ axis = self.axis
+ rect = self.rect
+ knob = self.knob
+ knobMove = max(
+ numPixels, rect.topleft[axis] - knob.topleft[axis])
+ knobMove = min(
+ knobMove, rect.bottomright[axis] - knob.bottomright[axis])
+ knobMoves = [0,0]
+ knobMoves[axis] = knobMove
+ self.knob.move_ip(knobMoves)
+ self.leftTop[self.axis] += knobMove / self.ratio
+ self.dirty = True
+
+ def draw(self, surface):
+ """ Blits sprite image to a surface if it exists.
+ todo: Called by update()>updateViews() if self.auto is True.
+ Also mimics group.draw, returning rectangle.
+ """
+ if self.dirty and surface:
+ self.dirty = False
+ pygame.draw.rect(self.image, self.bgColor, self.rect, 0)
+ if self.pretty:
+ self.drawPretty()
+ else:
+ pygame.draw.rect(self.image, self.fgColor, self.knob, 0)
+ if self.pad:
+ pygame.draw.rect(self.image,
+ self.bgColor, self.knob, self.pad)
+ return [surface.blit(self.image, self.initTopleft)]
+ else:
+ return []
+
+ def get_scrolled(self):
+ """ Called by end user to get pixels scrolled,
+ as result of update()
+ """
+ return self.leftTop
+
+ def moveRects(self,rects,moves):
+ for rect in rects:
+ rect.move_ip(moves)
+
+ def drawRects(self,rectInfo, surf):
+ for item in rectInfo:
+ pygame.draw.rect(surf, item[0], item[1], item[2])
+
+
+ def drawPretty(self):
+
+ """ Used internally. Draws drop-shadowed knob if self.pretty
+ This drawing method requires the rendering of 6 rects.
+ Three for each knob end, overlapping HiColor, LoColor, FgColor
+ Both are drawn regardless if hidden.
+ Comment out the blit of world here to see exactly.
+ """
+ axis = self.axis
+ surf = self.image
+ oppAxis = self.oppAxis
+ pad = self.pad
+ knob = self.knob
+ psize = self.prettySize
+ hiRect = pygame.Rect((knob.left + pad, knob.top + pad), psize )
+ loRect = hiRect.inflate(-1,-1).move(1,1)
+ fgRect = loRect.inflate(-1,-1)
+ rectInfo = ((self.hiColor, hiRect, 1),
+ (self.loColor, loRect, 1),
+ (self.fgColor, fgRect, 0))
+ self.drawRects(rectInfo, surf)
+ moves = [0,0]
+ moves[oppAxis] = knob.size[oppAxis] - psize[oppAxis] - (2 * pad)
+ if moves[oppAxis] > 2 * self.thick: # avoid overlapping bars
+ self.moveRects((hiRect, loRect, fgRect), moves)
+ self.drawRects(rectInfo,surf)
+
+
+
+if __name__ == '__main__':
+ import examples
+ examples.examples()
+
diff --git a/ezscroll/inlineScroll.py b/ezscroll/inlineScroll.py
new file mode 100644
index 0000000..d9c7f58
--- /dev/null
+++ b/ezscroll/inlineScroll.py
@@ -0,0 +1,68 @@
+#! %PYTHONPATH%\python
+import os
+import sys
+import pygame
+from pygame import *
+
+ScrSize = (300,400)
+Origin = (0,0)
+Gray = (200,200,200)
+Red = (250,20,20)
+Blue = (20,20,100)
+Buff = (200,180,180)
+def main():
+ """ A basic example of scrollknob code inline.
+ Does not use ezscroll module.
+ """
+
+ pygame.init()
+ screen = pygame.display.set_mode(ScrSize)
+ screenRect = screen.get_rect()
+ world = pygame.Surface((ScrSize[0]*2, ScrSize[1]*2))
+ world.fill(Gray)
+ for x in xrange(100, world.get_size()[0], 200):
+ for y in xrange(100, world.get_size()[1], 200):
+ pygame.draw.circle(world, Red, (x,y), 100, 10)
+
+######
+ ratio = (1.0 * screenRect.width) / world.get_width()
+ scrollThick = 20
+ track = pygame.Rect(screenRect.left,screenRect.bottom - scrollThick,screenRect.width,scrollThick)
+ knob = pygame.Rect(track)
+ knob.width = track.width * ratio
+ scrolling = False
+######
+
+ while 1:
+
+ event = pygame.event.wait()
+ screen.fill( (192,188,180) )
+
+ if event.type == QUIT:
+ pygame.quit()
+ sys.exit()
+######
+ elif ( event.type == MOUSEMOTION and scrolling):
+
+ if event.rel[0] != 0:
+ move = max(event.rel[0], track.left - knob.left)
+ move = min(move, track.right - knob.right)
+
+ if move != 0:
+ knob.move_ip((move, 0))
+
+ elif event.type == MOUSEBUTTONDOWN and knob.collidepoint(event.pos):
+ scrolling = True
+
+ elif event.type == MOUSEBUTTONUP:
+ scrolling = False
+
+ screen.blit(world, ((knob.left / ratio) * -1 , 0))
+ pygame.draw.rect(screen, Buff, track, 0 )
+ pygame.draw.rect(screen, Blue, knob.inflate(0,-5), 2)
+######
+
+ pygame.display.flip()
+
+### Tells what to launch in IDE and windows double click of file.
+if __name__ == '__main__': main()
diff --git a/photo_toolbar.py b/photo_toolbar.py
index 964b679..5190ddf 100644
--- a/photo_toolbar.py
+++ b/photo_toolbar.py
@@ -47,6 +47,10 @@ class ActivityToolbar(gtk.Toolbar):
"""
#if activity.metadata:
if True:
+ label = gtk.Label(_('New Album Name:'))
+ label.show()
+ self._add_widget(label)
+
self.title = gtk.Entry()
self.title.set_size_request(int(gtk.gdk.screen_width() / 6), -1)
if activity.metadata:
@@ -58,10 +62,12 @@ class ActivityToolbar(gtk.Toolbar):
self.add_album = ToolButton('list-add')
self.add_album.set_tooltip(_("Add Album"))
self.add_album.show()
+ self.add_album.connect('clicked', self.__add_album_clicked_cb)
self.insert(self.add_album,-1)
self.delete_album = ToolButton('list-remove')
self.delete_album.set_tooltip(_("Remove Album"))
+ self.delete_album.connect('clicked', self.__delete_album_clicked_cb)
self.delete_album.show()
self.insert(self.delete_album,-1)
@@ -84,24 +90,24 @@ class ActivityToolbar(gtk.Toolbar):
self._update_share()
"""
+ separator = gtk.SeparatorToolItem()
+ separator.props.draw = False
+ separator.set_expand(True)
+ self.insert(separator, -1)
+ separator.show()
+
self.keep = ToolButton(tooltip=_('Keep'))
#client = gconf.client_get_default()
#color = XoColor(client.get_string('/desktop/sugar/user/color'))
#keep_icon = Icon(icon_name='document-save', xo_color=color)
keep_icon = Icon(icon_name='document-save')
- self.keep.set_icon_widget(keep_icon)
keep_icon.show()
+ self.keep.set_icon_widget(keep_icon)
self.keep.props.accelerator = '<Ctrl>S'
self.keep.connect('clicked', self.__keep_clicked_cb)
self.insert(self.keep, -1)
- self.keep.hide()
+ self.keep.show()
- separator = gtk.SeparatorToolItem()
- separator.props.draw = False
- separator.set_expand(True)
- self.insert(separator, -1)
- separator.show()
-
self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
self.stop.props.accelerator = '<Ctrl>Q'
self.stop.connect('clicked', self.__stop_clicked_cb)
@@ -124,7 +130,14 @@ class ActivityToolbar(gtk.Toolbar):
self.share.combo.set_active(0)
self._updating_share = False
-
+
+ def __add_album_clicked_cb (self,button):
+ title = self.title.get_text()
+ self._activity.activity_toolbar_add_album_cb(title)
+
+ def __delete_album_clicked_cb (self,button):
+ self._activity.activity_toolbar_delete_album_cb()
+
def __traceback_changed_cb(self, combo):
model = self.share.combo.get_model()
it = self.share.combo.get_active_iter()
diff --git a/sinks.py b/sinks.py
new file mode 100644
index 0000000..bbd41fc
--- /dev/null
+++ b/sinks.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# sinks.py
+#
+# Copyright (C) 2010 George Hunt
+#
+# 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
+#
+from gettext import gettext as _
+
+import pygame
+from pygame.locals import *
+
+from sugar.datastore import datastore
+import sys, os
+import gtk
+import shutil
+
+#application imports
+from dbphoto import *
+from sources import *
+
+#pick up activity globals
+from xophotoactivity import *
+
+class ExportAlbum():
+
+ def __init__(self,rows,db,path):
+ """inputs =rows is an array or records from table xophoto.sqlite.groups
+ =db is a class object which has functions for reading database
+ =sources is a class object which has functions for getting data
+ =path is writeable path indicating location for new exported images
+ """
+ self.rows = rows
+ self.db = db
+ self.sources = Datastore_SQLite(db)
+ self.path = path
+
+ def do_export(self):
+ if not os.path.isdir(self.path):
+ try:
+ os.makedirs(self.path)
+ except:
+ raise PhotoException('cannot create directory(s) at %s'%self.target)
+ for row in self.rows:
+ jobject_id = row['jobject_id']
+ fn = self.sources.get_filename_from_jobject_id(jobject_id)
+ mime_type = self.db.get_mime_type(jobject_id)
+ lookup = {'image/png':'.png','image/jpg':'.jpg','image/gif':'.gif','image/tif':'.tif'}
+ base = os.path.basename(fn).split('.')
+ #don't override a suffix that exists
+ if len(base) == 1:
+ base = base[0] + lookup.get(mime_type,'')
+ else:
+ base = os.path.basename(fn)
+ _logger.debug('exporting %s to %s'%(fn,os.path.join(self.path,base),))
+ shutil.copy(fn,os.path.join(self.path,base))
+
+ \ No newline at end of file
diff --git a/sources.py b/sources.py
index 3108389..97605af 100644
--- a/sources.py
+++ b/sources.py
@@ -36,8 +36,14 @@ _logger = logging.getLogger('xophoto')
_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(name)s %(levelname)s %(funcName)s: %(lineno)d||| %(message)s')
-console_handler.setFormatter(console_formatter)
+#console_handler.setFormatter(console_formatter)
#_logger.addHandler(console_handler)
+"""
+Notes to myself:
+need a new structure which records the ds object_ids quickly
+then a routine which creates at least n thumbnails, and
+another routine which will create a single thumbnail and store it- called from gtk idle loop
+"""
class Datastore_SQLite():
"""class for interfacing between the Journal and an SQLite database"""
@@ -45,6 +51,8 @@ class Datastore_SQLite():
"""receives an open dbaccess object (defined in dbphoto) """
#self.db = dbaccess(fn)
self.db = database_access_object
+ self.datastore_to_process = None
+ self.datastore_process_index = -1
def ok(self):
if self.db.is_open():return True
@@ -60,8 +68,6 @@ class Datastore_SQLite():
(results,count) = datastore.find({})
for f in results:
dict = f.get_metadata().get_dictionary()
- if dict["mime_type"].find('jpg')>-1:
- _logger.debug('found jpg: %s in mime_list %r'%(dict["mime_type"],mime_list,))
if dict["mime_type"] in mime_list:
#record the id, file size, file date, in_ds
self.db.create_picture_record(f.object_id, f.get_file_path())
@@ -72,22 +78,44 @@ class Datastore_SQLite():
return rtn
def check_for_recent_images(self):
+ """scans the journal for pictures that are not in database, records object_id if found"""
find_spec = {'mime_type':['image/png','image/jpg','image/tif','image/bmp','image/gif']}
(results,count) = datastore.find(find_spec)
_logger.debug('directed image datastore found:%s'%count)
added = 0
+ a_row_found = False
+ cursor = self.db.get_connection().cursor()
for ds in results:
- #at least for now assume that the newest images are tetured first
- sql = "select * from picture where jobject_id ='%s'"%ds.object_id
- rows,cur = self.db.dbdo(sql)
- if len(rows) == 0:
- self.db.create_picture_record(ds.object_id, ds.get_file_path())
- added += 1
+ #at least for now assume that the newest images are returned first
+ if not a_row_found:
+ cursor.execute('select * from picture where jobject_id = ?',(str(ds.object_id),))
+ rows = cursor.fetchall()
+ if len(rows) == 0:
+ #may need to add date entered into ds (create date could be confusing)
+ self.db.put_ds_into_picture(ds.object_id)
+ added += 1
+ else: #assume that pictures are returned in last in first out order
+ a_row_found = True
ds.destroy()
- _logger.debug('added %s images from datastore to picture'%added)
+ _logger.debug('added %s datastore object ids from datastore to picture'%added)
return (count,added,)
-
+ def make_one_thumbnail(self):
+ if not self.datastore_to_process:
+ cursor = self.db.get_connection().cursor()
+ cursor.execute('select * from picture where md5_sum = null')
+ self.datastore_to_process = cursor.fetchall()
+ self.datastore_process_index = 0
+ if self.datastore_to_process and self.datastore_process_index > -1:
+ jobject_id = self.datastore_to_process[self.datastore_process_index]['jobject_id']
+ fn =get_filename_from_jobject_id(jobject_id)
+ if fn:
+ self.db.create_picture_record(f.object_id, fn)
+ self.datastore_process_index += 1
+ if self.datastore_process_index > len(self.datastore_to_process):
+ self.datastore_process_index = -1
+ return True #we want to continue to process in gtk_idle_loop
+
def get_filename_from_jobject_id(self, id):
try:
ds_obj = datastore.get(id)
@@ -183,10 +211,11 @@ class FileTree():
if __name__ == '__main__':
- db = DbAccess('xophoto.sqlite')
+ db = DbAccess('/home/olpc/.sugar/default/org.laptop.XoPhoto/data/xophoto.sqlite')
if db.is_open():
ds_sql = Datastore_SQLite(db)
- imagelist = ds_sql.scan_images()
+ #count = ds_sql.scan_images()
+ count,added = ds_sql.check_for_recent_images()
exit()
for i in imagelist:
print('\n%s'%ds.get_filename_from_jobject_id(i))
diff --git a/startup_images/190x152shadow.png b/startup_images/190x152shadow.png
new file mode 100644
index 0000000..a5eb36e
--- /dev/null
+++ b/startup_images/190x152shadow.png
Binary files differ
diff --git a/startup_images/190x152shadow.tiff b/startup_images/190x152shadow.tiff
new file mode 100644
index 0000000..aea5f59
--- /dev/null
+++ b/startup_images/190x152shadow.tiff
Binary files differ
diff --git a/startup_images/190x152shadow_1.tiff b/startup_images/190x152shadow_1.tiff
new file mode 100644
index 0000000..658b7b8
--- /dev/null
+++ b/startup_images/190x152shadow_1.tiff
Binary files differ
diff --git a/startup_images/2596796843_41a240f6b8_o.jpg b/startup_images/2596796843_41a240f6b8_o.jpg
new file mode 100644
index 0000000..0bef33a
--- /dev/null
+++ b/startup_images/2596796843_41a240f6b8_o.jpg
Binary files differ
diff --git a/startup_images/2606362543_1598e7efc0_o.jpg b/startup_images/2606362543_1598e7efc0_o.jpg
new file mode 100644
index 0000000..213108f
--- /dev/null
+++ b/startup_images/2606362543_1598e7efc0_o.jpg
Binary files differ
diff --git a/startup_images/2611672629_5f0e2c0e63_o.jpg b/startup_images/2611672629_5f0e2c0e63_o.jpg
new file mode 100644
index 0000000..230212b
--- /dev/null
+++ b/startup_images/2611672629_5f0e2c0e63_o.jpg
Binary files differ
diff --git a/startup_images/2612132968_fcba550e13_o.jpg b/startup_images/2612132968_fcba550e13_o.jpg
new file mode 100644
index 0000000..4770065
--- /dev/null
+++ b/startup_images/2612132968_fcba550e13_o.jpg
Binary files differ
diff --git a/startup_images/2630825026_061177dc7d.jpg b/startup_images/2630825026_061177dc7d.jpg
new file mode 100644
index 0000000..aa66bc1
--- /dev/null
+++ b/startup_images/2630825026_061177dc7d.jpg
Binary files differ
diff --git a/startup_images/2907401406_0d6d1e0bed.jpg b/startup_images/2907401406_0d6d1e0bed.jpg
new file mode 100644
index 0000000..8368bf8
--- /dev/null
+++ b/startup_images/2907401406_0d6d1e0bed.jpg
Binary files differ
diff --git a/startup_images/2928908291_c227faca09.jpg b/startup_images/2928908291_c227faca09.jpg
new file mode 100644
index 0000000..e1154c1
--- /dev/null
+++ b/startup_images/2928908291_c227faca09.jpg
Binary files differ
diff --git a/startup_images/2946277091_0675b569ff_b.jpg b/startup_images/2946277091_0675b569ff_b.jpg
new file mode 100644
index 0000000..666d9fa
--- /dev/null
+++ b/startup_images/2946277091_0675b569ff_b.jpg
Binary files differ
diff --git a/startup_images/2947130964_3019253782_b.jpg b/startup_images/2947130964_3019253782_b.jpg
new file mode 100644
index 0000000..f509ac3
--- /dev/null
+++ b/startup_images/2947130964_3019253782_b.jpg
Binary files differ
diff --git a/startup_images/3079782689_8ca8a237da.jpg b/startup_images/3079782689_8ca8a237da.jpg
new file mode 100644
index 0000000..d754082
--- /dev/null
+++ b/startup_images/3079782689_8ca8a237da.jpg
Binary files differ
diff --git a/startup_images/3080618900_c90371ec9a.jpg b/startup_images/3080618900_c90371ec9a.jpg
new file mode 100644
index 0000000..b588c59
--- /dev/null
+++ b/startup_images/3080618900_c90371ec9a.jpg
Binary files differ
diff --git a/startup_images/ezscroll/examples.py b/startup_images/ezscroll/examples.py
new file mode 100644
index 0000000..6031145
--- /dev/null
+++ b/startup_images/ezscroll/examples.py
@@ -0,0 +1,148 @@
+import sys
+import pygame
+import ezscroll
+from ezscroll import N,S,E,W, ScrollBar, ScrollPane, BGCOLOR
+
+ScrSize = (300,600)
+Origin = (0,0)
+Gray = (200,200,200)
+
+def examples():
+ """ Examples of how to use ezscroll.
+ One is a scrollpane, the other is a scrollbar.
+ The scrollpane handles some things like offsets,
+ puts the scrollbars in a sprite group, and blits the world.
+ If you just want one scrollbar, still may be easier to
+ use ScrollPane and pass [S] or [E], etc.
+ Closing window of proceeds through examples.
+ """
+ pygame.init()
+ screen = pygame.display.set_mode(ScrSize)
+ world = pygame.Surface((ScrSize[0]*2, ScrSize[1]*2))
+ world.fill(Gray)
+ for x in xrange(100, world.get_size()[0], 200):
+ for y in xrange(100, world.get_size()[1], 200):
+ pygame.draw.circle(world, (225,34,43), (x,y), 100, 10)
+ bg = pygame.Surface(ScrSize).convert()
+
+
+ ### EXAMPLE 1
+ bg.fill(BGCOLOR)
+ pygame.display.set_caption("Example 1: ScrollPane")
+ initRect = pygame.Rect(screen.get_rect())
+ sp = ScrollPane(
+ world.get_size(),
+ initRect,
+ world,
+ bg,
+ [S, W, N],
+ 3,
+ True,
+ 20)
+ sp.draw(bg)
+ screen.blit(bg,Origin)
+ pygame.display.flip()
+ while True:
+ event = pygame.event.wait()
+ if event.type is pygame.QUIT: break
+ sp.clear()
+ sp.update(event)
+ changes = sp.draw(bg)
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+
+
+ ### EXAMPLE 2
+ pygame.display.set_caption("Example 2: ScrollBar")
+ thick = 20
+ scrollRect = pygame.Rect(0, 0, ScrSize[0], thick)
+ excludes = ((0, thick), ScrSize) # rect where sb update is a pass
+ group = pygame.sprite.RenderPlain()
+ sb = ScrollBar(
+ group,
+ world.get_width(),
+ scrollRect,
+ bg,
+ 0,
+ excludes,
+ 4,
+ True,
+ thick,
+ (170,220,180),
+ (200,210,225),
+ (240,240,250),
+ (0,55,100))
+ sb.draw(bg)
+ bg.blit(world, (0,thick),
+ (sb.get_scrolled(),(ScrSize[0],ScrSize[1]-thick)))
+ screen.blit(bg, Origin)
+ pygame.display.flip()
+ while True:
+ event = pygame.event.wait()
+ if event.type is pygame.QUIT: break
+ sb.update(event)
+ changes = sb.draw(bg)
+ if len(changes) > 0:
+ changes.append(bg.blit(world, (0,thick),
+ (sb.get_scrolled(),(ScrSize[0],ScrSize[1]-thick))))
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+
+## # you can skip even sending any events in the view area
+## try:
+## if not sb.exclude.collidepoint(event.pos):
+## sb.update(event)
+## ...
+
+ ### EXAMPLE 3
+ import random
+ pygame.display.set_caption("Example 3: ScrollBar")
+ thick = 20
+ scrollRect = pygame.Rect(0, 0, thick,ScrSize[1])
+ excludes = ((thick, 0), ScrSize) # rect where sb update is a pass
+ group = pygame.sprite.RenderPlain()
+ sb = ScrollBar(
+ group,
+ world.get_height(),
+ scrollRect,
+ bg,
+ 1,
+ excludes,
+ 4,
+ False,
+ thick,
+ (120,120,160,10),
+ (88,57,99,214))
+ sb.draw(bg)
+ bg.blit(world, (thick,0),(sb.get_scrolled(),
+ (ScrSize[0]-thick,ScrSize[1])))
+ screen.blit(bg, Origin)
+ pygame.display.flip()
+ clock = pygame.time.Clock()
+ counter = 0
+ while True:
+ counter += clock.tick()
+ if counter > 1000: chichi = 0
+ if counter % 100 == 0:
+ scrollAmount = random.randrange(-20, 20, 1)
+ sb.scroll(scrollAmount)
+ changes = sb.draw(bg)
+ if len(changes) > 0:
+ scrolled = sb.get_scrolled()
+ changes.append(bg.blit(
+ world,
+ (thick,0),
+ (scrolled[0]+thick,
+ scrolled[1],
+ ScrSize[0],ScrSize[1])))
+ screen.blit(bg,Origin)
+ pygame.display.update(changes)
+ for event in pygame.event.get():
+ if event.type is pygame.QUIT:
+ pygame.quit()
+ sys.exit(0)
+
+
+
+if __name__ == '__main__':
+ examples()
diff --git a/startup_images/ezscroll/ezscroll.py b/startup_images/ezscroll/ezscroll.py
new file mode 100644
index 0000000..cc842be
--- /dev/null
+++ b/startup_images/ezscroll/ezscroll.py
@@ -0,0 +1,268 @@
+#! %PYTHONPATH%\python
+import os
+import sys
+import pygame
+from pygame import *
+
+FGCOLOR = 220,220,200
+BGCOLOR = 235,235,230
+HICOLOR = 250,250,245
+LOCOLOR = 40,40,70
+N='N'
+S='S'
+E='E'
+W='W'
+
+
+class ScrollPane():
+ """ Coordinates up to four scrollbars on a panel.
+ Uses two ScrollBars offset, and blits world view on top.
+ Use like a sprite group: update(), draw(). See examples.py
+ """
+
+ def __init__(
+ self,
+ worldSize,
+ initRect,
+ world,
+ pane=None,
+ nsew=[S,E],
+ pad=0,
+ pretty=False,
+ thick=20,
+ fgColor=FGCOLOR,
+ bgColor=BGCOLOR,
+ hiColor=HICOLOR,
+ loColor=LOCOLOR):
+ """ Figures layout and inits ScrollBars """
+
+ self.world = world
+ self.pane = pane
+ self.group = pygame.sprite.RenderUpdates()
+ self.nsew = nsew
+ self.pad = pad
+ self.thick = thick
+ self.pretty = pretty
+ self.fgColor = fgColor
+ self.bgColor = bgColor
+ self.hiColor = hiColor
+ self.loColor = loColor
+
+ self.viewRect = self.initViewRect(initRect, self.nsew, self.thick)
+ win = self.viewRect
+ self.sprites = [] # the scrollbars
+ if E in self.nsew or W in self.nsew:
+ scrollRect = pygame.Rect(0, win.top, initRect.width, win.height)
+ exclude = win.inflate(0, self.thick).move(0,-self.thick//2)
+ sb = ScrollBar(self.group, worldSize[1], scrollRect, self.pane, 1,
+ exclude, self.pad, self.pretty, self.thick,
+ fgColor, bgColor, hiColor, loColor)
+ self.sprites.append(sb)
+
+ if N in self.nsew or S in self.nsew:
+ scrollRect = pygame.Rect(win.left, 0, win.width, initRect.height)
+ exclude = win.inflate(self.thick, 0).move(-self.thick//2,0)
+ sb = ScrollBar(self.group, worldSize[0], scrollRect, self.pane, 0,
+ exclude, self.pad, self.pretty, self.thick,
+ fgColor, bgColor, hiColor, loColor)
+ self.sprites.append(sb)
+
+## self.clearArchive = pygame.Surface(initRect.size).convert()
+## self.clearArchive.fill((255,0,0))
+
+ def initViewRect(self, initRect, nsew, thick):
+ """ Used by init(), subtract width of scrollbars from viewable area """
+ win = pygame.Rect(initRect)
+ if N in nsew:
+ win.top = thick
+ win.height -= thick
+ if S in nsew:
+ win.height -= thick
+ if E in nsew:
+ win.width -= thick
+ if W in nsew:
+ win.left = thick
+ win.width -= thick
+ return win
+
+ def clear(self): #does nothing?
+ pass # self.group.clear(self.pane, self.clearArchive)
+
+ def update(self, event):
+ """ Called by end user to update scroll state """
+ for sb in self.sprites:
+ sb.update(event)
+
+ def draw(self, surface):
+ """ Called by end user to draw state to the surface """
+ offsets = [0,0]
+ changes = []
+ for sb in self.sprites:
+ offsets[sb.axis] = sb.get_scrolled()[sb.axis]
+ if sb.dirty:
+ changes.extend(sb.draw(surface))
+ if changes:
+ # Comment out this blit to see just the scrollbars.
+ # To date, don't add to changes since the sb includes it.
+ surface.blit(self.world, self.viewRect.topleft,
+ (offsets, self.viewRect.size))
+ if self.pad and not self.pretty:
+ pygame.draw.rect(
+ self.pane, self.bgColor,
+ self.viewRect.inflate(self.pad+1,self.pad+1), self.pad)
+
+ return changes
+
+ def get_pane(self):
+ """ Called by end user to get the scroll pane results """
+ return self.pane
+
+
+class ScrollBar(pygame.sprite.DirtySprite):
+ """ Same interface as sprite.Group.
+ Get result of update() in pixels scrolled, from get_scrolled()
+ """
+
+ def __init__(
+ self,
+ group,
+ worldDim,
+ initRect,
+ surface=None,
+ axis=0,
+ exclude=(0,0,0,0),
+ pad=0,
+ pretty=False,
+ thick=20,
+ fgColor=FGCOLOR,
+ bgColor=BGCOLOR,
+ hiColor=HICOLOR,
+ loColor=LOCOLOR):
+
+ pygame.sprite.Sprite.__init__(self,group)
+ self.initTopleft = initRect.topleft
+ self.exclude = pygame.Rect(exclude)
+ self.image = pygame.Surface(initRect.size).convert()
+ self.rect = self.image.get_rect()
+ self.surface = surface
+ self.axis = axis
+ self.fgColor = fgColor
+ self.bgColor = bgColor
+ self.hiColor = hiColor
+ self.loColor = loColor
+ self.knob = pygame.Rect(self.rect)
+ self.ratio = 1.0 * initRect.size[self.axis] / worldDim
+ knoblist = list(self.knob.size)
+ knoblist[self.axis] = (self.knob.size[self.axis] * self.ratio)
+ self.knob.size = knoblist
+ self.scrolling = False
+ self.leftTop = [0,0]
+ self.diff = [0,0]
+ self.diff[self.axis] = self.initTopleft[self.axis]
+ self.dirty = True
+ self.pad = pad
+ self.pretty = pretty
+ self.thick = thick
+ self.oppAxis = cmp(0,self.axis)+1
+ self.prettySize = [
+ self.knob.width - (pad * 2), self.knob.height - (pad * 2)]
+ self.prettySize[self.oppAxis] = self.thick - (2 * pad)
+
+ def update(self, event): # event must not be None
+ """ Called by user with mouse events. event must not be none. """
+ if event.type is MOUSEMOTION and self.scrolling:
+ self.scroll(event.rel[self.axis])
+
+ elif event.type is MOUSEBUTTONDOWN and (
+ self.knob.move(self.diff).collidepoint(event.pos) and not (
+ self.exclude.collidepoint(event.pos))):
+ self.scrolling = True
+
+ elif event.type is MOUSEBUTTONUP:
+ self.scrolling = False
+
+ def scroll(self, numPixels):
+ """ Moves knob based on mouse events rel change along axis.
+ Called internally by update(). Knob travel limited to track.
+ """
+ if numPixels and numPixels != 0:
+ axis = self.axis
+ rect = self.rect
+ knob = self.knob
+ knobMove = max(
+ numPixels, rect.topleft[axis] - knob.topleft[axis])
+ knobMove = min(
+ knobMove, rect.bottomright[axis] - knob.bottomright[axis])
+ knobMoves = [0,0]
+ knobMoves[axis] = knobMove
+ self.knob.move_ip(knobMoves)
+ self.leftTop[self.axis] += knobMove / self.ratio
+ self.dirty = True
+
+ def draw(self, surface):
+ """ Blits sprite image to a surface if it exists.
+ todo: Called by update()>updateViews() if self.auto is True.
+ Also mimics group.draw, returning rectangle.
+ """
+ if self.dirty and surface:
+ self.dirty = False
+ pygame.draw.rect(self.image, self.bgColor, self.rect, 0)
+ if self.pretty:
+ self.drawPretty()
+ else:
+ pygame.draw.rect(self.image, self.fgColor, self.knob, 0)
+ if self.pad:
+ pygame.draw.rect(self.image,
+ self.bgColor, self.knob, self.pad)
+ return [surface.blit(self.image, self.initTopleft)]
+ else:
+ return []
+
+ def get_scrolled(self):
+ """ Called by end user to get pixels scrolled,
+ as result of update()
+ """
+ return self.leftTop
+
+ def moveRects(self,rects,moves):
+ for rect in rects:
+ rect.move_ip(moves)
+
+ def drawRects(self,rectInfo, surf):
+ for item in rectInfo:
+ pygame.draw.rect(surf, item[0], item[1], item[2])
+
+
+ def drawPretty(self):
+
+ """ Used internally. Draws drop-shadowed knob if self.pretty
+ This drawing method requires the rendering of 6 rects.
+ Three for each knob end, overlapping HiColor, LoColor, FgColor
+ Both are drawn regardless if hidden.
+ Comment out the blit of world here to see exactly.
+ """
+ axis = self.axis
+ surf = self.image
+ oppAxis = self.oppAxis
+ pad = self.pad
+ knob = self.knob
+ psize = self.prettySize
+ hiRect = pygame.Rect((knob.left + pad, knob.top + pad), psize )
+ loRect = hiRect.inflate(-1,-1).move(1,1)
+ fgRect = loRect.inflate(-1,-1)
+ rectInfo = ((self.hiColor, hiRect, 1),
+ (self.loColor, loRect, 1),
+ (self.fgColor, fgRect, 0))
+ self.drawRects(rectInfo, surf)
+ moves = [0,0]
+ moves[oppAxis] = knob.size[oppAxis] - psize[oppAxis] - (2 * pad)
+ if moves[oppAxis] > 2 * self.thick: # avoid overlapping bars
+ self.moveRects((hiRect, loRect, fgRect), moves)
+ self.drawRects(rectInfo,surf)
+
+
+
+if __name__ == '__main__':
+ import examples
+ examples.examples()
+
diff --git a/startup_images/ezscroll/inlineScroll.py b/startup_images/ezscroll/inlineScroll.py
new file mode 100644
index 0000000..d9c7f58
--- /dev/null
+++ b/startup_images/ezscroll/inlineScroll.py
@@ -0,0 +1,68 @@
+#! %PYTHONPATH%\python
+import os
+import sys
+import pygame
+from pygame import *
+
+ScrSize = (300,400)
+Origin = (0,0)
+Gray = (200,200,200)
+Red = (250,20,20)
+Blue = (20,20,100)
+Buff = (200,180,180)
+def main():
+ """ A basic example of scrollknob code inline.
+ Does not use ezscroll module.
+ """
+
+ pygame.init()
+ screen = pygame.display.set_mode(ScrSize)
+ screenRect = screen.get_rect()
+ world = pygame.Surface((ScrSize[0]*2, ScrSize[1]*2))
+ world.fill(Gray)
+ for x in xrange(100, world.get_size()[0], 200):
+ for y in xrange(100, world.get_size()[1], 200):
+ pygame.draw.circle(world, Red, (x,y), 100, 10)
+
+######
+ ratio = (1.0 * screenRect.width) / world.get_width()
+ scrollThick = 20
+ track = pygame.Rect(screenRect.left,screenRect.bottom - scrollThick,screenRect.width,scrollThick)
+ knob = pygame.Rect(track)
+ knob.width = track.width * ratio
+ scrolling = False
+######
+
+ while 1:
+
+ event = pygame.event.wait()
+ screen.fill( (192,188,180) )
+
+ if event.type == QUIT:
+ pygame.quit()
+ sys.exit()
+######
+ elif ( event.type == MOUSEMOTION and scrolling):
+
+ if event.rel[0] != 0:
+ move = max(event.rel[0], track.left - knob.left)
+ move = min(move, track.right - knob.right)
+
+ if move != 0:
+ knob.move_ip((move, 0))
+
+ elif event.type == MOUSEBUTTONDOWN and knob.collidepoint(event.pos):
+ scrolling = True
+
+ elif event.type == MOUSEBUTTONUP:
+ scrolling = False
+
+ screen.blit(world, ((knob.left / ratio) * -1 , 0))
+ pygame.draw.rect(screen, Buff, track, 0 )
+ pygame.draw.rect(screen, Blue, knob.inflate(0,-5), 2)
+######
+
+ pygame.display.flip()
+
+### Tells what to launch in IDE and windows double click of file.
+if __name__ == '__main__': main()
diff --git a/startup_images/ezscrollv10.zip b/startup_images/ezscrollv10.zip
new file mode 100644
index 0000000..e04d6d3
--- /dev/null
+++ b/startup_images/ezscrollv10.zip
Binary files differ
diff --git a/startup_images/reuiideasmynewxo.zip b/startup_images/reuiideasmynewxo.zip
new file mode 100644
index 0000000..3e19fa2
--- /dev/null
+++ b/startup_images/reuiideasmynewxo.zip
Binary files differ
diff --git a/startup_images/stack_background.png b/startup_images/stack_background.png
new file mode 100644
index 0000000..1aa0c95
--- /dev/null
+++ b/startup_images/stack_background.png
Binary files differ
diff --git a/startup_images/stack_background.tiff b/startup_images/stack_background.tiff
new file mode 100644
index 0000000..ea10d70
--- /dev/null
+++ b/startup_images/stack_background.tiff
Binary files differ
diff --git a/startup_images/stack_background_1.tiff b/startup_images/stack_background_1.tiff
new file mode 100644
index 0000000..ed2b4c8
--- /dev/null
+++ b/startup_images/stack_background_1.tiff
Binary files differ
diff --git a/startup_images/xophoto.sql b/startup_images/xophoto.sql
new file mode 100644
index 0000000..fc5189b
--- /dev/null
+++ b/startup_images/xophoto.sql
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS "config";
+CREATE TABLE "config" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL , "name" TEXT NOT NULL , "value" TEXT, "int" INTEGER, "real" FLOAT, "blob" BLOB, "date" DATETIME);
+INSERT INTO "config" VALUES(1,'mime_type','image/png',NULL,NULL,NULL,NULL);
+INSERT INTO "config" VALUES(2,'mime_type','image/jpg',NULL,NULL,NULL,NULL);
+INSERT INTO "config" VALUES(3,'mime_type','image/gif',NULL,NULL,NULL,NULL);
+DROP TABLE IF EXISTS "groups";
+CREATE TABLE "groups" ("id" INTEGER PRIMARY KEY NOT NULL ,"category" TEXT,"subcategory" TEXT,"jobject_id" TEXT,"seq" INTEGER,"newseq" INTEGER);
+DROP TABLE IF EXISTS "picture";
+CREATE TABLE "picture" ("jobject_id" TEXT NOT NULL ,"mount_point" TEXT,"orig_width" INTEGER,"orig_height" INTEGER,"mime_type" TEXT,"create_date" DATETIME,"title" TEXT,"comment" TEXT,"id" INTEGER PRIMARY KEY NOT NULL ,"seq" INTEGER,"orig_size" DOUBLE,"album" TEXT,"in_ds" INTEGER, "md5_sum" TEXT, "longitude" FLOAT, "latitude" FLOAT, "duplicate" INTEGER DEFAULT 0);
+DROP TABLE IF EXISTS "sqlite_sequence";
+CREATE TABLE sqlite_sequence(name,seq);
+INSERT INTO "sqlite_sequence" VALUES('config',3);
+DROP TABLE IF EXISTS "transforms";
+CREATE TABLE "transforms" ("id" INTEGER PRIMARY KEY NOT NULL ,"jobject_id" TEXT,"original_x" INTEGER,"original_y" INTEGER,"scaled_x" INTEGER,"scaled_y" INTEGER,"thumb" blob);
+CREATE INDEX "grp_order" ON "groups" ("category" ASC, "subcategory" ASC, "seq" ASC);
+CREATE UNIQUE INDEX "jobject_id" ON "picture" ("jobject_id" ASC);
+CREATE INDEX "name" ON "config" ("name" ASC, "int" ASC);
+CREATE UNIQUE INDEX "path" ON "picture" ("mount_point" ASC, "orig_size" ASC);
diff --git a/sugargame/canvas.py b/sugargame/canvas.py
index cf99a13..07ab58e 100644
--- a/sugargame/canvas.py
+++ b/sugargame/canvas.py
@@ -43,7 +43,7 @@ class PygameCanvas(gtk.EventBox):
# Initialize the Pygame window.
r = self.get_allocation()
pygame.display.set_mode((r.width, r.height), pygame.RESIZABLE)
-
+
# Hook certain Pygame functions with GTK equivalents.
translator = event.Translator(self._mainwindow, self)
translator.hook_pygame()
diff --git a/xophoto.sqlite b/xophoto.sqlite
index fb71ec5..b31e1f2 100644
--- a/xophoto.sqlite
+++ b/xophoto.sqlite
Binary files differ
diff --git a/xophoto.sqlite.template b/xophoto.sqlite.template
new file mode 100644
index 0000000..b66fb47
--- /dev/null
+++ b/xophoto.sqlite.template
Binary files differ
diff --git a/xophotoactivity.py b/xophotoactivity.py
index 5fce101..bf47f01 100644
--- a/xophotoactivity.py
+++ b/xophotoactivity.py
@@ -42,61 +42,87 @@ import gobject
import sugargame.canvas
import os
import shutil
+from threading import Timer
import display
import photo_toolbar
from sources import *
from sinks import *
+import dbphoto
#Application Globals
album_column_width = 200
+#db can be resumed, new instance, or recovering from db error
import logging
_logger = logging.getLogger('xophoto')
_logger.setLevel(logging.DEBUG)
console_handler = logging.StreamHandler()
console_formatter = logging.Formatter('%(name)s %(levelname)s %(funcName)s: %(lineno)d||| %(message)s')
-console_handler.setFormatter(console_formatter)
+#console_handler.setFormatter(console_formatter)
#_logger.addHandler(console_handler)
class XoPhotoActivity(activity.Activity):
+ DbAccess_object = None
def __init__(self, handle):
- if handle and handle.object_id and handle.object_id != '':
+ #initialize variables
+ self.file_tree = None
+ self.use_db_template = False
+ self._activity = self
+ self.interactive_close = False
+ self.timed_out = False
+ self.realized = False
+ self.game = None
+
+ if handle and handle.object_id and handle.object_id != '' and not self.use_db_template:
_logger.debug('At activity startup, handle.object_id is %s'%handle.object_id)
- make_jobject = False
+ self.make_jobject = False
else:
- make_jobject = True
+ self.make_jobject = True
_logger.debug('At activity startup, handle.object_id is None. Making a new datastore entry')
- #This is a new invocation, copy the sqlite database to the data directory
- source = os.path.join(os.getcwd(),'xophoto.sqlite.template')
- dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
- if handle.object_id == None and source != dest:
- shutil.copy('./xophoto.sqlite',dest)
-
- activity.Activity.__init__(self, handle, create_jobject = make_jobject)
+ activity.Activity.__init__(self, handle, create_jobject = self.make_jobject)
- #initialize variables
- self.file_tree = None
-
# Build the activity toolbar.
self.build_toolbar()
-
+
+ """
+ #wait for the gtk window to realize
+ self.connect('realize',self.realized_cb)
+ Timer(5.0, self.end_realize_delay, ()).start()
+
+ while not self.timed_out and not self.realized:
+ gtk.main_iteration()
+
+ if self.timed_out:
+ _logger.debug('gtk window not realized')
+ exit()
+ """
+
# Build the Pygame canvas.
self._pygamecanvas = sugargame.canvas.PygameCanvas(self)
+
# Note that set_canvas implicitly calls read_file when resuming from the Journal.
self.set_canvas(self._pygamecanvas)
# Create the game instance.
- self.game = display.Application()
+ self.game = display.Application(self)
# Start the game running.
self._pygamecanvas.run_pygame(self.game.run)
+
+ def end_realize_delay(self):
+ self.timed_out = True
+
+ def realized_cb(self):
+ self.realized = True
+
def build_toolbar(self):
toolbox = photo_toolbar.ActivityToolbox(self)
activity_toolbar = toolbox.get_activity_toolbar()
+ """
label = gtk.Label(_('New Album Name:'))
tool_item = gtk.ToolItem()
tool_item.set_expand(False)
@@ -106,13 +132,16 @@ class XoPhotoActivity(activity.Activity):
tool_item.show()
activity_toolbar._add_widget(label)
- activity_toolbar.keep.props.visible = False
+ """
+ activity_toolbar.keep.props.visible = True
#activity_toolbar.share.props.visible = False
self.edit_toolbar = EditToolbar()
toolbox.add_toolbar(_('Edit'), self.edit_toolbar)
self.edit_toolbar.connect('do-import',
self.edit_toolbar_doimport_cb)
+ self.edit_toolbar.connect('do-stop',
+ self.__stop_clicked_cb)
self.edit_toolbar.show()
self.use_toolbar = UseToolbar()
@@ -123,11 +152,56 @@ class XoPhotoActivity(activity.Activity):
self.use_toolbar_doupload_cb)
self.use_toolbar.connect('do-slideshow',
self.use_toolbar_doslideshow_cb)
+ self.use_toolbar.connect('do-stop',
+ self.__stop_clicked_cb)
self.use_toolbar.show()
toolbox.show()
self.set_toolbox(toolbox)
+
+
+ def activity_toolbar_add_album_cb(self,album_name):
+ self.game.albums.change_name_of_current_album(album_name )
+
+ def activity_toolbar_delete_album_cb(self):
+ album = self.game.albums.get_current_album_name()
+ self.alert('Are you sure you want to delete %s?'%album)
+
+ def confirm_delete_album_cb(self,response):
+ album = self.game.albums.get_current_album_identifier()
+ if not response in (gtk.RESPONSE_OK):return
+ sql = 'delete from groups where subcategory = ?'
+ cursor = self.game.db.conn.cursor()
+ cursor.execute(sql,())
+
+ def copy(self):
+ _logger.debug('entered copy which will save and reinit sql database')
+ dict = self.get_metadata()
+ self.save()
+ if dict.get('dbcorrupted','False') == 'False':
+ #try to save all the time/computation involved in making thumbnails
+ pass
+ else:
+ #just copy in the template and save it into the journal
+ source = os.path.join(os.getcwd(),'xophoto.sqlite.template')
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ shutil.copy(source,dest)
+ try:
+ self.DbAccess_object = dbphoto.DbAccess(dest)
+ except Exception,e:
+ _logger.debug('database template failed to open error:%s'%e)
+ exit()
+ source = dest
+ ds = datastore.create()
+ ds.metadata['title'] = _('Unnamed Pictures')
+ ds.metadata['mime_type'] = 'application/binary'
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'instance','xophoto.sqlite')
+ shutil.copyfile(source,dest)
+ ds.set_file_path(dest)
+ datastore.write(ds,transfer_ownership=True)
+ ds.destroy()
+
def edit_toolbar_doimport_cb(self, view_toolbar):
if not self.file_tree:
self.file_tree = FileTree(self.game.db)
@@ -141,17 +215,23 @@ class XoPhotoActivity(activity.Activity):
if not self.file_tree:
self.file_tree = FileTree(self.game.db)
path = self.file_tree.get_path()
+
+ #think about writing the whole journal, and the trash (would need to add these to the selectable paths)
pygame.display.flip
if path:
_logger.debug("write selected album to %s"%path)
-
-
+
#figure out how to access correct object model:album_name = self.album_rows[self.selected_index]['subcategory']
+ #generate a list of dictionary rows which contain the info about images to write
album_object = self.game.albums
- album_name = album_object.album_rows[album_object.selected_index]['subcategory']
- sql = "select pict.*, grp.* from picture as pict, groups as grp where grp.category = '%s' and grp.jobject_id = pict.jobject_id"%album
- rows,cur = album_object.db.dbdo(sql)
- _logger.debug('album to display: %s. Number of pictures found: %s'%(album,len(rows),))
+ album_name = album_object.album_rows[int(album_object.selected_index)]['subcategory']
+ sql = """select pict.*, grp.* from picture as pict, groups as grp \
+ where grp.category = ? and grp.jobject_id = pict.jobject_id"""
+ cursor = album_object.db.con.cursor()
+ cursor.execute(sql,(album_name,))
+ rows = cursor.fetchall()
+
+ _logger.debug('album to export: %s. Number of pictures found: %s'%(album_name,len(rows),))
#def __init__(self,rows,db,sources,path):
exporter = ExportAlbum(rows,self.game.db,path)
exporter.do_export()
@@ -164,43 +244,76 @@ class XoPhotoActivity(activity.Activity):
pass
def read_file(self, file_path):
- _logger.debug('read_file %s'%file_path)
-
- dict = self.get_metadata()
- _logger.debug('title was %s'%dict.get('title','no title given'))
- sql_file = open(file_path, "rb")
- local_path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
- f = open(local_path, 'wb')
- _logger.debug('reading from %s and writeing to %s'%(file_path,local_path,))
+ _logger.debug('started read_file %s. make_file flag %s'%(file_path,self.make_jobject))
+ if self.make_jobject: #make jobject is flag signifying that we are not resuming activity
+ _logger.debug(' copied template rather than resuming')
+ #This is a new invocation, copy the sqlite database to the data directory
+ source = os.path.join(os.getcwd(),'xophoto.sqlite.template')
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ try:
+ shutil.copy(source,dest)
+ except Exception,e:
+ _logger.debug('database template failed to copy error:%s'%e)
+ exit()
+ else:
+ if self.DbAccess_object: #if the database is open don't overwrite and confuse it
+ _logger.debug('in read-file, db was already open')
+ return
+ dict = self.get_metadata()
+ _logger.debug('title was %s'%dict.get('title','no title given'))
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ _logger.debug('reading from %s and writeing to %s'%(file_path,dest,))
+ try:
+ shutil.copy(file_path, dest)
+ _logger.debug('completed writing the sqlite file')
+
+ except Exception, e:
+ _logger.debug('read sqlite file to local error %s'%e)
+ return
try:
- while sql_file:
- block = sql_file.read(4096)
- f.write(block)
+ self.DbAccess_object = DbAccess(dest)
+ except Exception,e:
+ _logger.debug('database failed to open in read file. error:%s'%e)
+ exit()
+ _logger.debug('completed read_file. DbAccess_jobject is created')
- except IOError, e:
- _logger.debug('read sqlite file to local error %s'%e)
- return
- finally:
- f.close
- sql_file.close()
- self.game.db.opendb(f)
def write_file(self, file_path):
+
try:
- self.game.db.closedb()
+ if self.DbAccess_object:
+ if self.DbAccess_object.get_error(): return #dont save a corrupted database
+ self.DbAccess_object.closedb()
+ if self.game and self.game.db:
+ self.game.db = None
+ self.DbAccess_object = None
local_path = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
#local_path = os.path.join(os.environ['SUGAR_BUNDLE_PATH'],'xophoto.sqlite')
self.metadata['filename'] = local_path
self.metadata['mime_type'] = 'application/binary'
- #dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'instance',f)
_logger.debug('write_file %s to %s'%(local_path,file_path,))
shutil.copyfile(local_path,file_path)
- #self.set_file_path(dest)
except Exception,e:
_logger.debug('write_file exception %s'%e)
raise e
+ if self.interactive_close:
+ try: #putting in an empty template makes it easier to make a distributable activity
+ source = os.path.join(os.getcwd(),'xophoto.sqlite.template')
+ shutil.copy(source,local_path)
+ except Exception,e:
+ _logger.debug('database template failed to copy error:%s'%e)
+ exit()
+ else:
+ dest = os.path.join(os.environ['SUGAR_ACTIVITY_ROOT'],'data','xophoto.sqlite')
+ try:
+ self.DbAccess_object = DbAccess(dest)
+ except Exception,e:
+ _logger.debug('database failed to re-open in write file. error:%s'%e)
+ exit()
+ _logger.debug('sqlite datbase re-opened successfully')
def __stop_clicked_cb(self, button):
+ self.interactive_close = True
self._activity.close()
@@ -214,6 +327,9 @@ class EditToolbar(gtk.Toolbar):
([])),
'do-import': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
+ ([])),
+ 'do-stop': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
([]))
}
@@ -261,14 +377,16 @@ class EditToolbar(gtk.Toolbar):
self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
self.stop.props.accelerator = '<Ctrl>Q'
- #self.stop.connect('clicked', self.__stop_clicked_cb)
+ self.stop.connect('clicked', self.dostop_cb)
self.insert(self.stop, -1)
self.stop.show()
-
def doimport_cb(self, button):
self.emit('do-import')
+ def dostop_cb(self, button):
+ self.emit('do-stop')
+
class UseToolbar(gtk.Toolbar):
__gtype_name__ = 'UseToolbar'
@@ -281,6 +399,9 @@ class UseToolbar(gtk.Toolbar):
([])),
'do-slideshow': (gobject.SIGNAL_RUN_FIRST,
gobject.TYPE_NONE,
+ ([])),
+ 'do-stop': (gobject.SIGNAL_RUN_FIRST,
+ gobject.TYPE_NONE,
([]))
}
@@ -325,7 +446,7 @@ class UseToolbar(gtk.Toolbar):
self.stop = ToolButton('activity-stop', tooltip=_('Stop'))
self.stop.props.accelerator = '<Ctrl>Q'
- #self.stop.connect('clicked', self.__stop_clicked_cb)
+ self.stop.connect('clicked', self.dostop_cb)
self.insert(self.stop, -1)
self.stop.show()
@@ -338,3 +459,7 @@ class UseToolbar(gtk.Toolbar):
def doslideshow_cb(self, button):
self.emit('do-slideshow')
+ def dostop_cb(self, button):
+ self.emit('do-stop')
+
+