diff options
author | George 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) |
commit | b5dcd4cbab884bdc6cf932a636173dfcf80dbe5f (patch) | |
tree | 4226793cf259503b4a5d5c0d18c03587bfbbb051 | |
parent | 1f8c0e41ce4869531394d0bd6e1b5cb9bd4ddb7b (diff) |
changes made in St John, still some gtk/pygame sync startup problems
37 files changed, 1483 insertions, 112 deletions
@@ -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 @@ -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""" @@ -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 Binary files differindex d12925e..9a0c241 100644 --- a/dist/XoPhoto-2.xo +++ b/dist/XoPhoto-2.xo 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 @@ -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 Binary files differnew file mode 100644 index 0000000..a5eb36e --- /dev/null +++ b/startup_images/190x152shadow.png diff --git a/startup_images/190x152shadow.tiff b/startup_images/190x152shadow.tiff Binary files differnew file mode 100644 index 0000000..aea5f59 --- /dev/null +++ b/startup_images/190x152shadow.tiff diff --git a/startup_images/190x152shadow_1.tiff b/startup_images/190x152shadow_1.tiff Binary files differnew file mode 100644 index 0000000..658b7b8 --- /dev/null +++ b/startup_images/190x152shadow_1.tiff diff --git a/startup_images/2596796843_41a240f6b8_o.jpg b/startup_images/2596796843_41a240f6b8_o.jpg Binary files differnew file mode 100644 index 0000000..0bef33a --- /dev/null +++ b/startup_images/2596796843_41a240f6b8_o.jpg diff --git a/startup_images/2606362543_1598e7efc0_o.jpg b/startup_images/2606362543_1598e7efc0_o.jpg Binary files differnew file mode 100644 index 0000000..213108f --- /dev/null +++ b/startup_images/2606362543_1598e7efc0_o.jpg diff --git a/startup_images/2611672629_5f0e2c0e63_o.jpg b/startup_images/2611672629_5f0e2c0e63_o.jpg Binary files differnew file mode 100644 index 0000000..230212b --- /dev/null +++ b/startup_images/2611672629_5f0e2c0e63_o.jpg diff --git a/startup_images/2612132968_fcba550e13_o.jpg b/startup_images/2612132968_fcba550e13_o.jpg Binary files differnew file mode 100644 index 0000000..4770065 --- /dev/null +++ b/startup_images/2612132968_fcba550e13_o.jpg diff --git a/startup_images/2630825026_061177dc7d.jpg b/startup_images/2630825026_061177dc7d.jpg Binary files differnew file mode 100644 index 0000000..aa66bc1 --- /dev/null +++ b/startup_images/2630825026_061177dc7d.jpg diff --git a/startup_images/2907401406_0d6d1e0bed.jpg b/startup_images/2907401406_0d6d1e0bed.jpg Binary files differnew file mode 100644 index 0000000..8368bf8 --- /dev/null +++ b/startup_images/2907401406_0d6d1e0bed.jpg diff --git a/startup_images/2928908291_c227faca09.jpg b/startup_images/2928908291_c227faca09.jpg Binary files differnew file mode 100644 index 0000000..e1154c1 --- /dev/null +++ b/startup_images/2928908291_c227faca09.jpg diff --git a/startup_images/2946277091_0675b569ff_b.jpg b/startup_images/2946277091_0675b569ff_b.jpg Binary files differnew file mode 100644 index 0000000..666d9fa --- /dev/null +++ b/startup_images/2946277091_0675b569ff_b.jpg diff --git a/startup_images/2947130964_3019253782_b.jpg b/startup_images/2947130964_3019253782_b.jpg Binary files differnew file mode 100644 index 0000000..f509ac3 --- /dev/null +++ b/startup_images/2947130964_3019253782_b.jpg diff --git a/startup_images/3079782689_8ca8a237da.jpg b/startup_images/3079782689_8ca8a237da.jpg Binary files differnew file mode 100644 index 0000000..d754082 --- /dev/null +++ b/startup_images/3079782689_8ca8a237da.jpg diff --git a/startup_images/3080618900_c90371ec9a.jpg b/startup_images/3080618900_c90371ec9a.jpg Binary files differnew file mode 100644 index 0000000..b588c59 --- /dev/null +++ b/startup_images/3080618900_c90371ec9a.jpg 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 Binary files differnew file mode 100644 index 0000000..e04d6d3 --- /dev/null +++ b/startup_images/ezscrollv10.zip diff --git a/startup_images/reuiideasmynewxo.zip b/startup_images/reuiideasmynewxo.zip Binary files differnew file mode 100644 index 0000000..3e19fa2 --- /dev/null +++ b/startup_images/reuiideasmynewxo.zip diff --git a/startup_images/stack_background.png b/startup_images/stack_background.png Binary files differnew file mode 100644 index 0000000..1aa0c95 --- /dev/null +++ b/startup_images/stack_background.png diff --git a/startup_images/stack_background.tiff b/startup_images/stack_background.tiff Binary files differnew file mode 100644 index 0000000..ea10d70 --- /dev/null +++ b/startup_images/stack_background.tiff diff --git a/startup_images/stack_background_1.tiff b/startup_images/stack_background_1.tiff Binary files differnew file mode 100644 index 0000000..ed2b4c8 --- /dev/null +++ b/startup_images/stack_background_1.tiff 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 Binary files differindex fb71ec5..b31e1f2 100644 --- a/xophoto.sqlite +++ b/xophoto.sqlite diff --git a/xophoto.sqlite.template b/xophoto.sqlite.template Binary files differnew file mode 100644 index 0000000..b66fb47 --- /dev/null +++ b/xophoto.sqlite.template 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') + + |