[jbrout/el6] Clean up and some fixes.
Matej Cepl
mcepl at fedoraproject.org
Sun Jan 15 02:11:13 UTC 2012
commit 9b4ca1a3f6941dd33e3a6152cbfbdf86d4a21efa
Author: Matěj Cepl <mcepl at redhat.com>
Date: Sun Jan 15 03:13:13 2012 +0100
Clean up and some fixes.
.gitignore | 2 +-
...Reformatting-to-make-code-PEP8-compatible.patch | 2384 ++++++++++++++++++++
...rkill-solution-for-illegal-XML-characters.patch | 139 ++
0003-IPTC-charset-backtrace.patch | 35 +
0004-Gtk-Tooltips-depreceated.patch | 39 +
jbrout-no-pyexiv2-warning.patch | 34 +-
jbrout-purge-no-attribute-attrib.patch | 7 +-
jbrout.spec | 19 +-
8 files changed, 2635 insertions(+), 24 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index e54821b..d8edeeb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
jbrout-0.3.282.tar.xz
jbrout_0.3.284.tar.gz
jbrout.tar.bz2
-/jbrout.tar.bz2
+/jbrout
diff --git a/0001-Reformatting-to-make-code-PEP8-compatible.patch b/0001-Reformatting-to-make-code-PEP8-compatible.patch
new file mode 100644
index 0000000..6eeda4e
--- /dev/null
+++ b/0001-Reformatting-to-make-code-PEP8-compatible.patch
@@ -0,0 +1,2384 @@
+--- a/jbrout/jbrout/db.py
++++ b/jbrout/jbrout/db.py
+@@ -13,34 +13,33 @@
+ ## GNU General Public License for more details.
+ ##
+
+-from lxml.etree import Element,ElementTree
+-from xml.etree import ElementTree as et
+-import lxml
+-import traceback
+-from datetime import datetime
+-#~ import cElementTree as ElementTree
++from common import cd2d, cd2d
++from commongtk import Buffer, rgb, Img, Buffer, rgb, Img
++from libs.dict4ini import DictIni
++from lxml.etree import Element, ElementTree
++import lxml.etree as et
++from subprocess import Popen, PIPE, Popen, PIPE
++from tools import PhotoCmd, supportedFormats, PhotoCmd, supportedFormats
++import char_utils
+ import gc
+-
++import gobject
++import gtk
++import os
++import re
++import sys
++import thread
++import shutil
++import stat
++import string
+ import pygtk
+ pygtk.require('2.0')
+-import gtk
+-import gobject
+
+
+-from common import cd2d
+-from tools import PhotoCmd,supportedFormats
+-import os,re,sys,thread,shutil,stat,string
+-
+-from libs.dict4ini import DictIni
+-from commongtk import Buffer,rgb,Img
+-
+-from subprocess import Popen,PIPE
+-
+-def walktree (top = ".", depthfirst = True):
++def walktree (top=".", depthfirst=True):
+ try:
+ names = os.listdir(top)
+ except WindowsError: #protected dirs in win
+- names=[]
++ names = []
+
+ if not depthfirst:
+ yield top, names
+@@ -50,13 +49,15 @@ def walktree (top = ".", depthfirst = Tr
+ except os.error:
+ continue
+ if stat.S_ISDIR(st.st_mode) and not name.startswith("."):
+- for (newtop, children) in walktree (os.path.join(top, name), depthfirst):
++ for (newtop, children) in walktree(os.path.join(top, name),
++ depthfirst):
+ yield newtop, children
+ if depthfirst:
+ yield top, names
+
+-def dec(s): # ensure that a return from etree is in utf-8
+- if s!=None:
++
++def dec(s): # ensure that a return from etree is in utf-8
++ if s != None:
+ return s.decode("utf_8")
+
+
+@@ -66,7 +67,7 @@ class DBPhotos:
+ normalizeName = False
+ autorotAtImport = False
+
+- def __init__(self,file):
++ def __init__(self, file):
+ if os.path.isfile(file):
+ self.root = ElementTree(file=file).getroot()
+ else:
+@@ -81,52 +82,51 @@ class DBPhotos:
+ nodeB = None
+
+ if nodeB:
+- ln=nodeB.xpath("""/db/basket/p""")
+- nodeB.getparent().remove(nodeB) # adios old basket !
++ ln = nodeB.xpath("""/db/basket/p""")
++ nodeB.getparent().remove(nodeB) # adios old basket !
+ #==== simple basket convertion (without verification)
+
+-
+- def setNormalizeName(self,v):
+- assert v in (True,False)
++ def setNormalizeName(self, v):
++ assert v in (True, False)
+ DBPhotos.normalizeName = v
+
+- def setNormalizeNameFormat(self,v):
+- assert isinstance(v,basestring)
++ def setNormalizeNameFormat(self, v):
++ assert isinstance(v, basestring)
+ PhotoCmd.setNormalizeNameFormat(v)
+
+- def setAutorotAtImport(self,v):
+- assert v in (True,False)
++ def setAutorotAtImport(self, v):
++ assert v in (True, False)
+ DBPhotos.autorotAtImport = v
+
+-
+- def add(self,path,tags={}):
+- assert type(path)==unicode
++ def add(self, path, tags={}):
++ assert type(path) == unicode
+ assert os.path.isdir(path)
+ path = os.path.normpath(path)
+
+ ln = self.root.xpath(u"""//folder[@name="%s"]""" % path)
+- assert len(ln)<=1
++ assert len(ln) <= 1
+ if ln:
+ nodeFolder = ln[0]
+ filesInBasket = [i.file for i in self.getBasket(nodeFolder)]
+ nodeFolder.getparent().remove(nodeFolder)
+ else:
+- filesInBasket=[]
++ filesInBasket = []
+
+ files = []
+- for (basepath, children) in walktree(path,False):
+- dir=basepath
++ for (basepath, children) in walktree(path, False):
++ dir = basepath
+ try:
+ nodeDir = self.root.xpath(u"""//folder[@name="%s"]""" % dir)[0]
+ except:
+- nodeDir=None
++ nodeDir = None
+
+ if nodeDir is None:
+- rep=[]
++ rep = []
+ while True:
+ rep.append(dir)
+- dir,n = os.path.split(dir)
+- if not n: break
++ dir, n = os.path.split(dir)
++ if not n:
++ break
+ rep.reverse()
+
+ node = self.root
+@@ -135,44 +135,44 @@ class DBPhotos:
+ nodeDir = node.xpath(u"""folder[@name="%s"]""" % r)[0]
+ except:
+ nodeDir = Element("folder", name=r)
+- node.append( nodeDir )
++ node.append(nodeDir)
+
+- FolderNode(nodeDir)._updateInfo() # read comments
++ FolderNode(nodeDir)._updateInfo() # read comments
+
+ node = nodeDir
+- nodeDir=node
++ nodeDir = node
+
+ for child in children:
+- if child.split('.')[-1].lower() in supportedFormats :
++ if child.split('.')[-1].lower() in supportedFormats:
+ file = os.path.join(basepath, child)
+ if os.path.isfile(file):
+- files.append((file,nodeDir))
++ files.append((file, nodeDir))
+
+ yield len(files) # first yield is the total number of files
+
+- i=0
+- for (file,nodeDir) in files:
++ i = 0
++ for (file, nodeDir) in files:
+ yield i
+- i+=1
++ i += 1
+ #OLD TOOLS:
+ #file = PhotoCmd.prepareFile(file,
+ # needRename=DBPhotos.normalizeName,
+ # needAutoRot=DBPhotos.autorotAtImport,
+ # )
+- self.__addPhoto( nodeDir,file ,tags,filesInBasket)
++ self.__addPhoto(nodeDir, file, tags, filesInBasket)
+
+ ln = self.root.xpath(u"""//folder[@name="%s"]""" % path)
+ if ln:
+- yield FolderNode( ln[0] )
++ yield FolderNode(ln[0])
+ else:
+ yield None
+
+- def __addPhoto(self,nodeDir,file,tags,filesInBasket):
+- assert type(file)==unicode
+- dir,name= os.path.split(file)
++ def __addPhoto(self, nodeDir, file, tags, filesInBasket):
++ assert type(file) == unicode
++ dir, name = os.path.split(file)
+
+ newNode = Element("photo")
+- nodeDir.append( newNode )
++ nodeDir.append(newNode)
+
+ node = PhotoNode(newNode)
+ if file in filesInBasket:
+@@ -183,42 +183,45 @@ class DBPhotos:
+ needAutoRename=DBPhotos.normalizeName,
+ needAutoRotation=DBPhotos.autorotAtImport,
+ )
+- if iii.exifdate=="":
++ if iii.exifdate == "":
+ # exif is not present, and photocmd can't reach
+ # to recreate minimal exif tags (because it's readonly ?)
+ # we can't continue to import this photo
+- raise Exception("Exif couldn't be set in this picture (readonly?)")
++ raise Exception("Exif couldn't be set " +
++ "in this picture (readonly?)")
+ except:
+ # getback the stack trace exception
+ import traceback
+- err=traceback.format_exc()
++ err = traceback.format_exc()
+
+ # remove the bad node
+ nodeDir.remove(newNode)
+
+ # and raise exception
+- raise Exception(err+"\nPhoto has incorrect exif/iptc tags, can't be imported :\n"+str([file,]))
++ raise Exception(err + """
++ Photo has incorrect exif/iptc tags, can't be imported :
++ """ + str([file, ]))
+ return None
+ else:
+- importedTags=node.updateInfo( iii )
+- for i in importedTags: tags[i]=i # feed the dict of tags
++ importedTags = node.updateInfo(iii)
++ for i in importedTags:
++ tags[i] = i # feed the dict of tags
+
+ return node
+
+ def getRootFolder(self):
+- if len(self.root)>0:
++ if len(self.root) > 0:
+ return FolderNode(self.root[0])
+
+ def redoIPTC(self):
+ """ refresh IPTC in file and db """
+ ln = self.root.xpath(u"""//photo[t]""")
+ for i in ln:
+- p=PhotoNode(i)
++ p = PhotoNode(i)
+ print p.name
+ pc = PhotoCmd(p.file)
+ pc._write() # rewrite iptc in file
+- p.updateInfo( pc ) # rewrite iptc in db.xml
+-
++ p.updateInfo(pc) # rewrite iptc in db.xml
+
+ def getMinMaxDates(self):
+ """ return a tuple of the (min,max) of photo dates
+@@ -229,42 +232,40 @@ class DBPhotos:
+ ma = 11111111111111
+ mi = 99999999999999
+ for i in ln:
+- a=int( i.attrib["date"] )
+- ma = max(a,ma)
+- mi = min(a,mi)
+- return cd2d(str(mi)),cd2d(str(ma))
++ a = int(i.attrib["date"])
++ ma = max(a, ma)
++ mi = min(a, mi)
++ return cd2d(str(mi)), cd2d(str(ma))
+
+-
+- def select(self,xpath,fromNode=None):
+- ln=self.root.xpath(xpath)
++ def select(self, xpath, fromNode=None):
++ ln = self.root.xpath(xpath)
+ if ln:
+ return [PhotoNode(i) for i in ln]
+ else:
+ return []
+
+-
+ def toXml(self):
+ """ for tests only """
+ from StringIO import StringIO
+- fid=StringIO()
++ fid = StringIO()
+ fid.write("""<?xml version="1.0" encoding="UTF-8"?>""")
+- ElementTree(self.root).write(fid,encoding="utf-8")
++ ElementTree(self.root).write(fid, encoding="utf-8")
+ return fid.getvalue()
+
+ def save(self):
+ """ save the db, and a basket.txt file """
+- fid = open(self.file,"w")
++ fid = open(self.file, "w")
+ fid.write("""<?xml version="1.0" encoding="UTF-8"?>""")
+- ElementTree(self.root).write(fid,encoding="utf-8")
++ ElementTree(self.root).write(fid, encoding="utf-8")
+ fid.close()
+
+ # save a "simple txt file" of basket'files near db.xml
+ # (could be used in another prog ?)
+- file = os.path.join( os.path.dirname(self.file),"basket.txt")
++ file = os.path.join(os.path.dirname(self.file), "basket.txt")
+ if self.isBasket():
+- list =[i.file for i in self.getBasket()]
++ list = [i.file for i in self.getBasket()]
+
+- fid = open(file,"w")
++ fid = open(file, "w")
+ if fid:
+ fid.write((u"\n".join(list)).encode("utf_8"))
+ fid.close()
+@@ -273,40 +274,44 @@ class DBPhotos:
+ os.unlink(file)
+ except:
+ pass
+- #--------------------------------------------------------------------------------
++
++ #-------------------------------------------------------------------------
+ # basket methods
+- #--------------------------------------------------------------------------------
++ #-------------------------------------------------------------------------
+ def isBasket(self):
+- return len(self.root.xpath("//photo[@basket='1']"))>0
++ return len(self.root.xpath("//photo[@basket='1']")) > 0
+
+ def clearBasket(self):
+- ln=self.getBasket()
++ ln = self.getBasket()
+ for i in ln:
+ i.removeFromBasket()
+
+- def getBasket(self,nodeFrom=None):
++ def getBasket(self, nodeFrom=None):
+ if nodeFrom is not None:
+- return [PhotoNode(i) for i in nodeFrom.xpath("//photo[@basket='1']")]
++ return [PhotoNode(i) for i in
++ nodeFrom.xpath("//photo[@basket='1']")]
+ else:
+- return [PhotoNode(i) for i in self.root.xpath("//photo[@basket='1']")]
+-
++ return [PhotoNode(i) for i in
++ self.root.xpath("//photo[@basket='1']")]
+
+
+ class FolderNode(object):
+ """ A folder node containing photo nodes"""
+- commentFile="album.txt"
++ commentFile = "album.txt"
+
+- def __init__(self,n):
+- assert n.tag in ["folder","db"]
++ def __init__(self, n):
++ assert n.tag in ["folder", "db"]
+ self.__node = n
+
+- def __getName(self): return os.path.basename(self.__node.attrib["name"])
++ def __getName(self):
++ return os.path.basename(self.__node.attrib["name"])
+ name = property(__getName)
+
+ #~ def __getIsReadOnly(self): return not os.access( self.file, os.W_OK)
+ #~ isReadOnly = property(__getIsReadOnly)
+
+- def __getFile(self): return self.__node.attrib["name"]
++ def __getFile(self):
++ return self.__node.attrib["name"]
+ file = property(__getFile)
+
+ def __getComment(self):
+@@ -319,20 +324,20 @@ class FolderNode(object):
+
+ def __getExpand(self):
+ if "expand" in self.__node.attrib:
+- return (self.__node.attrib["expand"]!="0")
++ return (self.__node.attrib["expand"] != "0")
+ else:
+ return True
+ expand = property(__getExpand)
+
+- def _getNode(self): # special
++ def _getNode(self): # special
+ return self.__node
+
+ def getParent(self):
+- return FolderNode( self.__node.getparent() )
++ return FolderNode(self.__node.getparent())
+
+ def getFolders(self):
+- ln=[FolderNode(i) for i in self.__node.xpath("folder")]
+- ln.sort(cmp=lambda x,y: cmp(x.name.lower(),y.name.lower()))
++ ln = [FolderNode(i) for i in self.__node.xpath("folder")]
++ ln.sort(cmp=lambda x, y: cmp(x.name.lower(), y.name.lower()))
+ return ln
+
+ def getPhotos(self):
+@@ -341,22 +346,22 @@ class FolderNode(object):
+ def getAllPhotos(self):
+ return self._select("descendant::photo")
+
+- def _select(self,xpath):
++ def _select(self, xpath):
+ """ 'xpath' should only target photo node """
+ class PhotoNodes(list):
+- def __init__(self,l,xpath):
+- list.__init__(self,l)
+- self.xpath=xpath
+-
+- ln=self.__node.xpath(xpath)
+- ll= [PhotoNode(i) for i in ln]
+- return PhotoNodes(ll,"//folder[@name='%s']/%s"%(self.file,xpath))
+-
+- def setComment(self,t):
+- assert type(t)==unicode
+- file = os.path.join(self.file,FolderNode.commentFile)
+- if t=="": # if is the "kill comment"
+- if os.path.isfile(file): # if files exists, kill it
++ def __init__(self, l, xpath):
++ list.__init__(self, l)
++ self.xpath = xpath
++
++ ln = self.__node.xpath(xpath)
++ ll = [PhotoNode(i) for i in ln]
++ return PhotoNodes(ll, "//folder[@name='%s']/%s" % (self.file, xpath))
++
++ def setComment(self, t):
++ assert type(t) == unicode
++ file = os.path.join(self.file, FolderNode.commentFile)
++ if t == "": # if is the "kill comment"
++ if os.path.isfile(file): # if files exists, kill it
+ try:
+ os.unlink(file)
+ return True
+@@ -365,9 +370,9 @@ class FolderNode(object):
+
+ return True
+ else:
+- fid=open( file ,"w" )
++ fid = open(file, "w")
+ if fid:
+- fid.write( t.encode("utf_8") )
++ fid.write(t.encode("utf_8"))
+ fid.close()
+ self._updateInfo()
+ return True
+@@ -376,45 +381,44 @@ class FolderNode(object):
+
+ def _updateInfo(self):
+ ln = self.__node.xpath("c")
+- assert len(ln) in [0,1]
++ assert len(ln) in [0, 1]
+ if ln:
+- nodeComment =ln[0]
++ nodeComment = ln[0]
+ else:
+- nodeComment =None
++ nodeComment = None
+
+ comment = None
+- file = os.path.join(self.file,FolderNode.commentFile)
++ file = os.path.join(self.file, FolderNode.commentFile)
+ if os.path.isfile(file):
+- fid=open( file ,"r" )
++ fid = open(file, "r")
+ if fid:
+ comment = fid.read().decode("utf_8")
+ fid.close()
+
+ if comment:
+- if nodeComment == None:
++ if nodeComment == None:
+ nodeComment = Element("c")
+ nodeComment.text = comment
+ self.__node.append(nodeComment)
+ else:
+ nodeComment.text = comment
+ else:
+- if nodeComment != None:
++ if nodeComment != None:
+ self.__node.remove(nodeComment)
+
+-
+- def setExpand(self,bool):
++ def setExpand(self, bool):
+ if bool:
+ self.__node.attrib["expand"] = "1"
+ else:
+ self.__node.attrib["expand"] = "0"
+
+- def rename(self,newname):
+- assert type(newname)==unicode
++ def rename(self, newname):
++ assert type(newname) == unicode
+ oldname = self.file
+- newname = os.path.join( os.path.dirname(oldname), newname )
++ newname = os.path.join(os.path.dirname(oldname), newname)
+ if not (os.path.isdir(newname) or os.path.isfile(newname)):
+ try:
+- shutil.move( oldname, newname )
++ shutil.move(oldname, newname)
+ moved = True
+ except os.error, detail:
+ raise Exception(detail)
+@@ -425,16 +429,17 @@ class FolderNode(object):
+
+ ln = self.__node.xpath("descendant::folder")
+ for i in ln:
+- i.attrib["name"] = newname + i.attrib["name"][len(oldname):]
++ i.attrib["name"] = newname + \
++ i.attrib["name"][len(oldname):]
+ return True
+
+ return False
+
+- def createNewFolder(self,newname):
+- assert type(newname)==unicode
+- newname = os.path.join( self.file, newname )
+- ll=[i for i in self.getFolders() if i.file==newname]
+- if len(ll)==1:
++ def createNewFolder(self, newname):
++ assert type(newname) == unicode
++ newname = os.path.join(self.file, newname)
++ ll = [i for i in self.getFolders() if i.file == newname]
++ if len(ll) == 1:
+ # folder is already mapped in the db/xml
+ # so no creation
+ return False
+@@ -449,16 +454,16 @@ class FolderNode(object):
+ # this is a real new folder
+ # let's create it in the FS
+ try:
+- os.mkdir( newname )
+- created = True
++ os.mkdir(newname)
++ created = True
+ except os.error, detail:
+- raise Exception(detail)
+- created = False
++ raise Exception(detail)
++ created = False
+
+ if created:
+ #so map the folder to a db node
+ nodeDir = Element("folder", name=newname)
+- self.__node.append( nodeDir )
++ self.__node.append(nodeDir)
+ return FolderNode(nodeDir)
+ return False
+
+@@ -470,13 +475,13 @@ class FolderNode(object):
+ """ delete real folder and node """
+ if os.path.isdir(self.file):
+ try:
+- shutil.rmtree( self.file )
+- deleted = True
++ shutil.rmtree(self.file)
++ deleted = True
+ except os.error, detail:
+- raise Exception(detail)
+- deleted = False
++ raise Exception(detail)
++ deleted = False
+ else:
+- deleted=True
++ deleted = True
+
+ if deleted:
+ self.remove()
+@@ -484,13 +489,13 @@ class FolderNode(object):
+
+ return False
+
+- def moveToFolder(self,nodeFolder):
++ def moveToFolder(self, nodeFolder):
+ assert nodeFolder.__class__ == FolderNode
+ oldname = self.file
+- newname = os.path.join(nodeFolder.file,self.name)
++ newname = os.path.join(nodeFolder.file, self.name)
+ if not (os.path.isdir(newname) or os.path.isfile(newname)):
+ try:
+- shutil.move( oldname, newname )
++ shutil.move(oldname, newname)
+ moved = True
+ except os.error, detail:
+ raise Exception(detail)
+@@ -503,11 +508,11 @@ class FolderNode(object):
+
+ ln = self.__node.xpath("descendant::folder")
+ for i in ln:
+- i.attrib["name"] = newname + i.attrib["name"][len(oldname):]
++ i.attrib["name"] = newname + \
++ i.attrib["name"][len(oldname):]
+ return self
+ return False
+
+-
+ #~ def pixbuf_from_data(data):
+ #~ loader = gtk.gdk.PixbufLoader ('jpeg')
+ #~ loader.write (data, len (data))
+@@ -524,9 +529,7 @@ class FolderNode(object):
+ #~ finally:
+ #~ gtk.threads_leave()
+ #~ gobject.idle_add(idle_func)
+-
+-
+-
++#
+ #~ class PhotoFile:
+ #~ @staticmethod
+ #~ def generate(path):
+@@ -555,22 +558,24 @@ class PhotoNode(object):
+ Class PhotoNode
+ to manipulate a node photo in the dom of album.xml.
+ """
+- def __init__(self,node):
++ def __init__(self, node):
+ assert node.tag == "photo"
+ self.__node = node
+
+- def __getName(self): return self.__node.attrib["name"]
++ def __getName(self):
++ return self.__node.attrib["name"]
+ name = property(__getName)
+
+- def __getfolderName(self): return os.path.basename(self.folder)
++ def __getfolderName(self):
++ return os.path.basename(self.folder)
+ folderName = property(__getfolderName)
+
+- def __getIsReadOnly(self): return not os.access( self.file, os.W_OK)
++ def __getIsReadOnly(self):
++ return not os.access(self.file, os.W_OK)
+ isReadOnly = property(__getIsReadOnly)
+
+-
+ def __getTags(self):
+- l=[dec(i.text) for i in self.__node.xpath("t")]
++ l = [dec(i.text) for i in self.__node.xpath("t")]
+ l.sort()
+ return l
+ tags = property(__getTags)
+@@ -584,47 +589,54 @@ class PhotoNode(object):
+ comment = property(__getComment)
+
+ def __getRating(self): # 0x4746 18246 IFD0 Exif.Image.Rating Short
+- ln = self.__node.xpath("r") # saved decimal like <r>5</r>
+- if ln:
+- return int(ln[0].text)
+- else:
+- return 0
++ ln = self.__node.xpath("r") # saved decimal like <r>5</r>
++ if ln:
++ return int(ln[0].text)
++ else:
++ return 0
+ rating = property(__getRating)
+
+- def __getDate(self): return self.__node.attrib["date"] # if exif -> exifdate else filedate
++ def __getDate(self):
++ # if exif -> exifdate else filedate
++ return self.__node.attrib["date"]
+ date = property(__getDate)
+
+- def __getResolution(self): return self.__node.attrib["resolution"]
++ def __getResolution(self):
++ return self.__node.attrib["resolution"]
+ resolution = property(__getResolution)
+
+- def __getReal(self): return self.__node.attrib["real"] # if exifdate -> true else false
++ def __getReal(self):
++ # if exifdate -> true else false
++ return self.__node.attrib["real"]
+ real = property(__getReal)
+
+ def __getFolder(self):
+ try:
+- na=dec(self.__node.getparent().attrib["name"])
++ na = dec(self.__node.getparent().attrib["name"])
+ except Exception as exc:
+- print >>sys.stderr, "Catching exception e:\n%s" % exc
+- print >>sys.stderr, "self.__node = %s" % \
++ print >> sys.stderr, "Catching exception e:\n%s" % exc
++ print >> sys.stderr, "self.__node = %s" % \
+ et.tostring(self.__node, encoding="utf-8")
+- print >>sys.stderr, "self.__node.getparent() = %s" % \
++ print >> sys.stderr, "self.__node.getparent() = %s" % \
+ et.tostring(self.__node.getparent(), encoding="utf-8")
+- assert type(na)==unicode
++ assert type(na) == unicode
+ return na
+ folder = property(__getFolder)
+
+- def __getFile(self): return dec(os.path.join(self.__getFolder(),self.__getName()))
++ def __getFile(self):
++ return dec(os.path.join(self.__getFolder(), self.__getName()))
+ file = property(__getFile)
+
+ def getParent(self):
+- return FolderNode( self.__node.getparent() )
++ return FolderNode(self.__node.getparent())
+
+- def __getIsInBasket(self): return (self.__node.get("basket")=="1")
++ def __getIsInBasket(self):
++ return (self.__node.get("basket") == "1")
+ isInBasket = property(__getIsInBasket)
+
+
+ def addToBasket(self):
+- self.__node.set("basket","1")
++ self.__node.set("basket", "1")
+
+ def removeFromBasket(self):
+ if self.isInBasket:
+@@ -638,58 +650,58 @@ class PhotoNode(object):
+ def getThumb(self):
+ """ Get thumb from exif data"""
+ if self.real == "yes": # real photo (exifdate !)
+- backGroundColor=None
++ backGroundColor = None
+ pb_nothumb = Buffer.pixbufNT
+- pb_notfound =Buffer.pixbufNF
+- pb_error =Buffer.pixbufERR
+- else: # photo with hadn't got exif before (exif setted by jbrout)
+- backGroundColor=rgb(255,0,0)
++ pb_notfound = Buffer.pixbufNF
++ pb_error = Buffer.pixbufERR
++ else:
++ # photo with hadn't got exif before (exif setted by jbrout)
++ backGroundColor = rgb(255, 0, 0)
+ pb_nothumb = Buffer.pixbufNTNE
+- pb_notfound =Buffer.pixbufNFNE
+- pb_error =Buffer.pixbufERRNE
++ pb_notfound = Buffer.pixbufNFNE
++ pb_error = Buffer.pixbufERRNE
+
+ try:
+- i=Img(thumb=self.file)
+- pb= i.resizeC(160,backGroundColor).pixbuf
+- except IOError: # 404
+- pb= pb_notfound
+- except KeyError: # no exif
+- pb= pb_nothumb
++ i = Img(thumb=self.file)
++ pb = i.resizeC(160, backGroundColor).pixbuf
++ except IOError: # 404
++ pb = pb_notfound
++ except KeyError: # no exif
++ pb = pb_nothumb
+ except:
+- pb=pb_error
++ pb = pb_error
+ raise
+
+-
+ return pb
+
+ def getImage(self):
+ file = self.file
+ # XXX external call while pyexiv2 can't handle it
+- extension=file.split('.')[-1].lower()
++ extension = file.split('.')[-1].lower()
+ if extension == 'nef':
+- data=Popen(["exiftool","-b","-JpgFromRaw","%s"%file],stdout=PIPE).communicate()[0]
+- loader = gtk.gdk.PixbufLoader ('jpeg')
+- loader.write (data, len (data))
+- im = loader.get_pixbuf ()
+- loader.close ()
++ data = Popen(["exiftool", "-b", "-JpgFromRaw", "%s" % file],
++ stdout=PIPE).communicate()[0]
++ loader = gtk.gdk.PixbufLoader('jpeg')
++ loader.write(data, len(data))
++ im = loader.get_pixbuf()
++ loader.close()
+ return im
+ else:
+ return gtk.gdk.pixbuf_new_from_file(file)
+
+-
+- def moveToFolder(self,nodeFolder):
++ def moveToFolder(self, nodeFolder):
+ assert nodeFolder.__class__ == FolderNode
+
+ name = self.name
+- while os.path.isfile(os.path.join(nodeFolder.file,name) ):
+- name=PhotoCmd.giveMeANewName(name)
++ while os.path.isfile(os.path.join(nodeFolder.file, name)):
++ name = PhotoCmd.giveMeANewName(name)
+
+ try:
+- shutil.move( self.file, os.path.join(nodeFolder.file,name) )
+- moved=True
++ shutil.move(self.file, os.path.join(nodeFolder.file, name))
++ moved = True
+ except os.error, detail:
+ raise Exception(detail)
+- moved=False
++ moved = False
+
+ if moved:
+ self.__node.attrib["name"] = name
+@@ -698,50 +710,52 @@ class PhotoNode(object):
+ nf.append(self.__node)
+ return True
+
+- def rotate(self,sens):
+- assert sens in ["R","L"]
++ def rotate(self, sens):
++ assert sens in ["R", "L"]
+
+ pc = PhotoCmd(self.file)
+ pc.rotate(sens)
+ self.updateInfo(pc)
+
+- def transform(self,sens):
+- assert sens in ["auto","rotate90","rotate180","rotate270","flipHorizontal","flipVertical","transpose","transverse"]
++ def transform(self, sens):
++ assert sens in ["auto", "rotate90", "rotate180",
++ "rotate270", "flipHorizontal", "flipVertical",
++ "transpose", "transverse"]
+
+ pc = PhotoCmd(self.file)
+ pc.transform(sens)
+ self.updateInfo(pc)
+
+- def setComment(self,txt):
+- assert type(txt)==unicode
++ def setComment(self, txt):
++ assert type(txt) == unicode
+
+ pc = PhotoCmd(self.file)
+ if pc.addComment(txt):
+ self.updateInfo(pc)
+
+- def setRating(self,val):
+- assert type(val)==int
++ def setRating(self, val):
++ assert type(val) == int
+
+ pc = PhotoCmd(self.file)
+- if pc.addRating(val): # always true
++ if pc.addRating(val): # always true
+ self.updateInfo(pc)
+
+- def addTag(self,tag):
+- assert type(tag)==unicode
++ def addTag(self, tag):
++ assert type(tag) == unicode
+
+ pc = PhotoCmd(self.file)
+ if pc.add(tag):
+ self.updateInfo(pc)
+
+- def addTags(self,tags):
+- assert type(tags)==list
++ def addTags(self, tags):
++ assert type(tags) == list
+
+ pc = PhotoCmd(self.file)
+ if pc.addTags(tags):
+ self.updateInfo(pc)
+
+- def delTag(self,tag):
+- assert type(tag)==unicode
++ def delTag(self, tag):
++ assert type(tag) == unicode
+
+ pc = PhotoCmd(self.file)
+ if pc.sub(tag):
+@@ -757,10 +771,12 @@ class PhotoNode(object):
+ pc.rebuildExifTB()
+ self.updateInfo(pc)
+
+- def copyTo(self,path,resize=None, keepInfo=True, delTags=False, delCom=False):
++ def copyTo(self, path, resize=None, keepInfo=True,
++ delTags=False, delCom=False):
+ """ copy self to the path "path", and return its newfilename or none
+- by default, it keeps IPTC/THUMB/EXIF, but it can be removed by setting
+- keepInfo at False. In all case, new file keep its filedate system
++ by default, it keeps IPTC/THUMB/EXIF, but it can be removed by
++ setting keepInfo at False. In all case, new file keep its filedate
++ system
+
+ image can be resized/recompressed (preserving ratio) if resize
+ (which is a tuple=(size,qual)) is provided:
+@@ -768,48 +784,48 @@ class PhotoNode(object):
+ if size is a int : it's the desired largest side
+ qual : is the percent for the quality
+ """
+- assert type(path)==unicode, "photonod.copyTo() : path is not unicode"
+- dest = os.path.join( path, self.name)
++ assert type(path) == unicode, "photonod.copyTo() : path is not unicode"
++ dest = os.path.join(path, self.name)
+
+ while os.path.isfile(dest):
+- dest = os.path.join( path, PhotoCmd.giveMeANewName(os.path.basename(dest)) )
++ dest = os.path.join(path,
++ PhotoCmd.giveMeANewName(os.path.basename(dest)))
+
+ if resize:
+- assert len(resize)==2
+- size,qual = resize
+- assert type(size) in [int,float]
+-
+- pb = self.getImage() # a gtk.PixBuf
+- (wx,wy) = pb.get_width(),pb.get_height()
++ assert len(resize) == 2
++ size, qual = resize
++ assert type(size) in [int, float]
+
++ pb = self.getImage() # a gtk.PixBuf
++ (wx, wy) = pb.get_width(), pb.get_height()
+
+ # compute the new size -> wx/wy
+- if type(size)==float:
++ if type(size) == float:
+ # size is a percent
+- size = int(size*100)
+- wx = int(wx*size / 100)
+- wy = int(wy*size / 100)
++ size = int(size * 100)
++ wx = int(wx * size / 100)
++ wy = int(wy * size / 100)
+
+ else:
+ # size is the largest side in pixels
+- if wx>wy:
++ if wx > wy:
+ # format landscape
+- wx, wy = size, (size * wy)/wx
++ wx, wy = size, (size * wy) / wx
+ else:
+ # format portrait
+- wx, wy = (size * wx)/wy, size
+-
++ wx, wy = (size * wx) / wy, size
+
+- pb = pb.scale_simple(wx,wy,3) # 3= best quality (gtk.gdk.INTERP_HYPER)
+- pb.save(dest, "jpeg", {"quality":str(int(qual))})
++ # 3= best quality (gtk.gdk.INTERP_HYPER)
++ pb = pb.scale_simple(wx, wy, 3)
++ pb.save(dest, "jpeg", {"quality": str(int(qual))})
+
+ if keepInfo:
+ pc = PhotoCmd(self.file)
+ pc.copyInfoTo(dest)
+ del(pb)
+- gc.collect() # so it cleans pixbufs
++ gc.collect() # so it cleans pixbufs
+ else:
+- shutil.copy2(self.file,dest)
++ shutil.copy2(self.file, dest)
+ if not keepInfo:
+ # we must destroy info
+ PhotoCmd(dest).destroyInfo()
+@@ -821,13 +837,13 @@ class PhotoNode(object):
+
+ return dest
+
+- def getInfoFrom(self,copy):
++ def getInfoFrom(self, copy):
+ """ rewrite info from a 'copy' to the file (exif, iptc, ...)
+ and rebuild thumb
+ (used to ensure everything is back after a run in another program
+ see plugin 'touch')
+ """
+- pc=PhotoCmd(copy)
++ pc = PhotoCmd(copy)
+ pc.copyInfoTo(self.file)
+
+ #and update infos
+@@ -839,12 +855,13 @@ class PhotoNode(object):
+ #~ def repair(self):
+ #~ pc = PhotoCmd(self.file)
+ #~ pc.repair() # kill exif tags ;-(
+- #~ pc.rebuildExifTB() # recreate "fake exif tags" with exifutils and thumbnails
++ #~ pc.rebuildExifTB() - recreate "fake exif tags" with exifutils &
++ # thumbnails
+ #~ self.updateInfo(pc)
+
+- def redate(self,w,d,h,m,s ):
++ def redate(self, w, d, h, m, s):
+ pc = PhotoCmd(self.file)
+- pc.redate(w,d,h,m,s)
++ pc.redate(w, d, h, m, s)
+ self.updateInfo(pc)
+ self.updateName()
+
+@@ -858,22 +875,22 @@ class PhotoNode(object):
+ #photo has been redated
+ #it should be renamed if in config ...
+ if DBPhotos.normalizeName:
+- pc = PhotoCmd(self.file,needAutoRename=True)
++ pc = PhotoCmd(self.file, needAutoRename=True)
+ self.updateInfo(pc)
+
+ return True
+
+- def updateInfo(self,pc):
++ def updateInfo(self, pc):
+ """ feel the node with REALS INFOS from "pc"(PhotoCmd)
+ return the tags
+ """
+- assert pc.__class__==PhotoCmd
++ assert pc.__class__ == PhotoCmd
+
+ wasInBasket = self.isInBasket
+
+ self.__node.clear()
+- self.__node.attrib["name"]=os.path.basename(pc.file)
+- self.__node.attrib["resolution"]=pc.resolution
++ self.__node.attrib["name"] = os.path.basename(pc.file)
++ self.__node.attrib["resolution"] = pc.resolution
+
+ # OLD PhotoCmd
+ #~ if pc.exifdate:
+@@ -884,11 +901,11 @@ class PhotoNode(object):
+ #~ self.__node.attrib["real"]="no"
+
+ # NEW PhotoCmd (always a exifdate)
+- self.__node.attrib["date"]=pc.exifdate
++ self.__node.attrib["date"] = pc.exifdate
+ if pc.isreal:
+- self.__node.attrib["real"]="yes"
++ self.__node.attrib["real"] = "yes"
+ else:
+- self.__node.attrib["real"]="no"
++ self.__node.attrib["real"] = "no"
+
+ if pc.tags:
+ for tag in pc.tags:
+@@ -897,7 +914,7 @@ class PhotoNode(object):
+ self.__node.append(nodeTag)
+ if pc.comment:
+ nodeComment = Element("c")
+- nodeComment.text = pc.comment.replace(u'\x00',u' ')
++ nodeComment.text = pc.comment.replace(u'\x00', u' ')
+ self.__node.append(nodeComment)
+ if pc.rating:
+ nodeRating = Element("r")
+@@ -914,11 +931,11 @@ class PhotoNode(object):
+ get real infos from photocmd
+ """
+ pc = PhotoCmd(self.file)
+- info={}
++ info = {}
+ info["tags"] = pc.tags
+ info["comment"] = pc.comment
+ info["exifdate"] = pc.exifdate
+- info["rating"] = pc.rating # huh, did i use that?
++ info["rating"] = pc.rating # huh, did i use that?
+ info["filedate"] = pc.filedate
+ info["resolution"] = pc.resolution
+ info["readonly"] = pc.readonly
+@@ -929,19 +946,18 @@ class PhotoNode(object):
+ def getThumbSize(self):
+ """Get the size (width,height) of the thumbnail"""
+ try:
+- thumbnail=Img(thumb=self.file)
+- return (thumbnail.width,thumbnail.height)
+- except IOError: # 404
+- return (-1,-1)
+-
++ thumbnail = Img(thumb=self.file)
++ return (thumbnail.width, thumbnail.height)
++ except IOError: # 404
++ return (-1, -1)
+
+ def delete(self):
+ try:
+- os.unlink( self.file )
+- deleted = True
++ os.unlink(self.file)
++ deleted = True
+ except os.error, detail:
+- raise Exception(detail)
+- deleted = False
++ raise Exception(detail)
++ deleted = False
+
+ if deleted:
+ self.__node.getparent().remove(self.__node)
+@@ -950,10 +966,10 @@ class PhotoNode(object):
+ return False
+
+
+-# ============================================================================================
++# ============================================================================
+ class DBTags:
+ """ Class to manage tags tree """
+- def __init__(self,file):
++ def __init__(self, file):
+ if os.path.isfile(file):
+ self.root = ElementTree(file=file).getroot()
+ else:
+@@ -962,14 +978,15 @@ class DBTags:
+
+ def getAllTags(self):
+ """ return list of tuples (tag, parent catg)"""
+- l=[(n.text,n.getparent().get("name")) for n in self.root.xpath("//tag")]
+- l.sort(cmp= lambda x,y: cmp(x[0].lower(),y[0].lower()))
++ l = [(n.text, n.getparent().get("name"))
++ for n in self.root.xpath("//tag")]
++ l.sort(cmp=lambda x, y: cmp(x[0].lower(), y[0].lower()))
+ return l
+
+ def save(self):
+- fid = open(self.file,"w")
++ fid = open(self.file, "w")
+ fid.write("""<?xml version="1.0" encoding="UTF-8"?>""")
+- ElementTree(self.root).write(fid,encoding="utf-8")
++ ElementTree(self.root).write(fid, encoding="utf-8")
+ fid.close()
+
+ #def getTagForKey(self,key):
+@@ -1003,14 +1020,14 @@ class DBTags:
+ def getRootTag(self):
+ return CatgNode(self.root)
+
+- def updateImportedTags( self, importedTags ):
+- assert type(importedTags)==list
++ def updateImportedTags(self, importedTags):
++ assert type(importedTags) == list
+
+ r = self.getRootTag()
+ existingTags = [i.name for i in r.getAllTags()]
+
+ # compare existing and imported tags -> newTags
+- newTags=[]
++ newTags = []
+ for tag in importedTags:
+ if tag not in existingTags:
+ newTags.append(tag)
+@@ -1019,43 +1036,48 @@ class DBTags:
+ # create a category imported
+ nom = u"Imported Tags"
+ while 1:
+- nc=r.addCatg(nom)
+- if nc!=None:
++ nc = r.addCatg(nom)
++ if nc != None:
+ break
+ else:
+- nom+=u"!"
++ nom += u"!"
+
+ for tag in newTags:
+- ret=nc.addTag(tag)
+- assert ret!=None,"tag '%s' couldn't be added"%tag
++ ret = nc.addTag(tag)
++ assert ret != None, "tag '%s' couldn't be added" % tag
+
+ return len(newTags)
+
++
+ class TagNode(object):
+ """ """
+- def __init__(self,n):
++ def __init__(self, n):
+ assert n.tag == "tag"
+ self.__node = n
+
+- def __getName(self): return dec(self.__node.text)
++ def __getName(self):
++ return dec(self.__node.text)
+ name = property(__getName)
+
+- def __getKey(self): return dec(self.__node.get("key"))
+- def __setKey(self,v): self.__node.set("key",v)
+- key = property(__getKey,__setKey)
++ def __getKey(self):
++ return dec(self.__node.get("key"))
++
++ def __setKey(self, v):
++ self.__node.set("key", v)
++ key = property(__getKey, __setKey)
+
+ def remove(self):
+ self.__node.getparent().remove(self.__node)
+
+- def moveToCatg(self,c):
+- assert type(c)==CatgNode
++ def moveToCatg(self, c):
++ assert type(c) == CatgNode
+ self.remove()
+ c._appendToCatg(self.__node)
+
+
+ class CatgNode(object):
+ """ """
+- def __init__(self,n):
++ def __init__(self, n):
+ assert n.tag == "tags"
+ self.__node = n
+
+@@ -1068,65 +1090,65 @@ class CatgNode(object):
+
+ def __getExpand(self):
+ if "expand" in self.__node.attrib:
+- return (self.__node.attrib["expand"]!="0")
++ return (self.__node.attrib["expand"] != "0")
+ else:
+ return True
+ expand = property(__getExpand)
+
+ def getTags(self):
+- l=[TagNode(i) for i in self.__node.xpath("tag")]
+- l.sort( cmp=lambda x,y: cmp(x.name,y.name) )
++ l = [TagNode(i) for i in self.__node.xpath("tag")]
++ l.sort(cmp=lambda x, y: cmp(x.name, y.name))
+ return l
++
+ def getCatgs(self):
+ return [CatgNode(i) for i in self.__node.xpath("tags")]
+
+ def getAllTags(self):
+- l= self.getTags()
++ l = self.getTags()
+ for i in self.getCatgs():
+- l.extend( i.getAllTags() )
+- l.sort(cmp=lambda x,y: cmp(x.name,y.name))
++ l.extend(i.getAllTags())
++ l.sort(cmp=lambda x, y: cmp(x.name, y.name))
+ return l
+
+- def addTag(self,t):
+- assert type(t)==unicode
+- if self.isUnique("tag",t):
++ def addTag(self, t):
++ assert type(t) == unicode
++ if self.isUnique("tag", t):
+ n = Element("tag")
+ n.text = t
+ self.__node.append(n)
+ return TagNode(n)
+
+- def rename(self,newName):
++ def rename(self, newName):
+ self.__node.attrib["name"] = newName
+
+-
+ def remove(self):
+ self.__node.getparent().remove(self.__node)
+
+- def moveToCatg(self,c):
++ def moveToCatg(self, c):
+ self.remove()
+ c._appendToCatg(self.__node)
+
+- def _appendToCatg(self,element):
++ def _appendToCatg(self, element):
+ self.__node.append(element)
+
+- def addCatg(self,t):
+- assert type(t)==unicode
+- if self.isUnique("tags",t):
+- n = Element("tags",name=t)
++ def addCatg(self, t):
++ assert type(t) == unicode
++ if self.isUnique("tags", t):
++ n = Element("tags", name=t)
+ self.__node.append(n)
+ return CatgNode(n)
+
+- def setExpand(self,bool):
++ def setExpand(self, bool):
+ if bool:
+ self.__node.attrib["expand"] = "1"
+ else:
+ self.__node.attrib["expand"] = "0"
+
+- def isUnique(self,type,name):
+- if type=="tag":
+- ln=[dec(i.text) for i in self.__node.xpath("//tag")]
++ def isUnique(self, type, name):
++ if type == "tag":
++ ln = [dec(i.text) for i in self.__node.xpath("//tag")]
+ else:
+- ln=[CatgNode(i).name for i in self.__node.xpath("//tags")]
++ ln = [CatgNode(i).name for i in self.__node.xpath("//tags")]
+ return name not in ln
+
+
+@@ -1158,4 +1180,3 @@ if __name__ == "__main__":
+ #~ for i in ln:
+ #~ print i.name, i.file
+ #~ print ln[0].getParent()
+-
+--- a/jbrout/jbrout/pyexiv.py
++++ b/jbrout/jbrout/pyexiv.py
+@@ -19,7 +19,7 @@
+ pyexiv2 wrapper
+ ===============
+
+-map old methods/objects from pyexiv2(<2), to be able to work with versions 1 & 2
++map old methods/objects from pyexiv2(<2), to work with versions 1 & 2
+
+ """
+ import re
+@@ -32,72 +32,82 @@ except:
+ sys.exit(-1)
+
+
+-
+-
+ ###############################################################################
+ class Exiv2Metadata(object):
+ ###############################################################################
+ """ pyexiv2 > 0.2 """
+- def __init__(self,md):
+- self._md=md
++ def __init__(self, md):
++ self._md = md
+
+ #============================================== V 0.1 api
+ def readMetadata(self):
+ return self._md.read()
++
+ def writeMetadata(self):
+- self._md["Iptc.Envelope.CharacterSet"] = ['\x1b%G',] # set Charset as UTF8
++ # set CharacterSet as UTF8
++ self._md["Iptc.Envelope.CharacterSet"] = ['\x1b%G', ]
+ return self._md.write()
+- def __getitem__(self,k):
+- v=self._md[k]
+- if hasattr(v,"value"):
++
++ def __getitem__(self, k):
++ v = self._md[k]
++ if hasattr(v, "value"):
+ return v.value
+- elif hasattr(v,"values"):
++ elif hasattr(v, "values"):
+ return tuple(v.values)
+ else:
+ raise
+- def __setitem__(self,k,v):
+- self._md[k]=v
+- def __delitem__(self,k):
++
++ def __setitem__(self, k, v):
++ self._md[k] = v
++
++ def __delitem__(self, k):
+ del self._md[k]
++
+ def getComment(self):
+ return self._md.comment
+- def setComment(self,v):
+- self._md.comment=v
++
++ def setComment(self, v):
++ self._md.comment = v
++
+ def clearComment(self):
+- self._md.comment=None
++ self._md.comment = None
+
+ def getThumbnailData(self):
+- l=[i.data for i in self._md.previews]
++ l = [i.data for i in self._md.previews]
+ if l:
+- return [None,l[0]]
++ return [None, l[0]]
+ else:
+ return []
+
+- def setThumbnailData(self,o):
+- if pyexiv2.version_info > (0,2,2):
++ def setThumbnailData(self, o):
++ if pyexiv2.version_info > (0, 2, 2):
+ self._md.exif_thumbnail.data = o
+ else:
+- print "***WARNING*** : not implemented : setThumbnailData (you need pyexiv2>0.2.2)"
++ print "***WARNING*** : not implemented : " + \
++ "setThumbnailData (you need pyexiv2>0.2.2)"
++
+ def deleteThumbnail(self):
+- if pyexiv2.version_info > (0,2,2):
++ if pyexiv2.version_info > (0, 2, 2):
+ self._md.exif_thumbnail.erase()
+ else:
+- print "***WARNING*** : not implemented : deleteThumbnail (you need pyexiv2>0.2.2)"
++ print "***WARNING*** : not implemented : " + \
++ "deleteThumbnail (you need pyexiv2>0.2.2)"
+
+ def exifKeys(self):
+ return self._md.exif_keys
++
+ def iptcKeys(self):
+ return self._md.iptc_keys
+
+- def tagDetails(self,k): # see viewexif plugin
+- md=self._md[k]
+- if hasattr(md,"label"):
+- lbl=getattr(md,"label")
+- elif hasattr(md,"title"):
+- lbl=getattr(md,"title")
+- return [lbl,md.description,]
++ def tagDetails(self, k): # see viewexif plugin
++ md = self._md[k]
++ if hasattr(md, "label"):
++ lbl = getattr(md, "label")
++ elif hasattr(md, "title"):
++ lbl = getattr(md, "title")
++ return [lbl, md.description, ]
+
+- def interpretedExifValue(self,k): # see viewexif plugin
++ def interpretedExifValue(self, k): # see viewexif plugin
+ return self._md[k].human_value
+ #==============================================
+
+@@ -105,20 +115,22 @@ class Exiv2Metadata(object):
+ def xmpKeys(self):
+ return self._md.xmp_keys
+
+-
+ def getTags(self):
+ """ return a list of merged tags (xmp+iptc) (list of str)"""
+ # Authoritative reference
+- # http://www.iptc.org/std/Iptc4xmpCore/1.0/documentation/Iptc4xmpCore_1.0-doc-CpanelsUserGuide_13.pdf
++ # http://www.iptc.org/std/Iptc4xmpCore/1.0/documentation\
++ # /Iptc4xmpCore_1.0-doc-CpanelsUserGuide_13.pdf
+ # however
+- # http://metadataworkinggroup.com/pdf/mwg_guidance.pdf says on page 35 that
++ # http://metadataworkinggroup.com/pdf/mwg_guidance.pdf page 35:
+ ## IPTC Keywords is mapped to XMP (dc:subject)
+ # It seems that the latter is true ... at least according to
+ # http://trac.yorba.org/wiki/PhotoTags
+
+- li=[]
++ li = []
+ if "Iptc.Application2.Keywords" in self._md.iptc_keys:
+- li=[str(i.strip("\x00")) for i in self._md["Iptc.Application2.Keywords"].value] #digikam patch
++ # digikam patch
++ li = [str(i.strip("\x00"))
++ for i in self._md["Iptc.Application2.Keywords"].value]
+ # assume UTF8
+ lk = []
+ if "Xmp.iptc.Keywords" in self._md.xmp_keys:
+@@ -130,17 +142,17 @@ class Exiv2Metadata(object):
+ for xel in self._md["Xmp.dc.subject"].value:
+ lx.extend([x.strip() for x in xel.encode("utf-8").split(",")])
+
+- ll=list(set(li+lx+lk))
++ ll = list(set(li + lx + lk))
+ ll.sort()
+ return ll
+
+-
+- def setTags(self,l):
++ def setTags(self, l):
+ for i in l:
+- assert type(i)==unicode
++ assert type(i) == unicode
+
+ if l:
+- self._md["Iptc.Application2.Keywords"] = [i.encode("utf_8") for i in l]
++ self._md["Iptc.Application2.Keywords"] = \
++ [i.encode("utf_8") for i in l]
+ self._md["Xmp.dc.subject"] = [",".join(l)]
+ else:
+ del self._md["Iptc.Application2.Keywords"]
+@@ -148,7 +160,6 @@ class Exiv2Metadata(object):
+ if 'Xmp.iptc.Keywords' in self._md.xmp_keys:
+ del self._md['Xmp.iptc.Keywords']
+
+-
+ def clearTags(self):
+ if "Iptc.Application2.Keywords" in self._md.iptc_keys:
+ del self._md["Iptc.Application2.Keywords"]
+@@ -157,8 +168,8 @@ class Exiv2Metadata(object):
+ if 'Xmp.iptc.Keywords' in self._md.xmp_keys:
+ del self._md['Xmp.iptc.Keywords']
+
+-
+- def copyToFile(self, destFilename, exif=True, iptc=True, xmp=True, comment=True):
++ def copyToFile(self, destFilename, exif=True, iptc=True, xmp=True,
++ comment=True):
+ dest = pyexiv2.ImageMetadata(destFilename)
+ dest.read()
+ self._md.copy(dest, exif, iptc, xmp, comment)
+@@ -166,65 +177,65 @@ class Exiv2Metadata(object):
+
+ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+-
+-
+-if not hasattr(pyexiv2,"Image"): # Only here to make the following code
++if not hasattr(pyexiv2, "Image"): # Only here to make the following code
+ class Fake(object): # compliant with old objects from 0.1
+- def __init__(self,f): # when using 0.2 version
++ def __init__(self, f): # when using 0.2 version
+ pass # else it can't compile ;-)
+- pyexiv2.Image=Fake
++ pyexiv2.Image = Fake
++
+
+ ###############################################################################
+ class Exiv1Metadata(pyexiv2.Image):
+ ###############################################################################
+ """ pyexiv2 < 0.2 """
+- def __init__(self,f):
+- pyexiv2.Image.__init__(self,f)
+-
++ def __init__(self, f):
++ pyexiv2.Image.__init__(self, f)
+
+ def writeMetadata(self):
+- self["Iptc.Envelope.CharacterSet"] = ['\x1b%G',] # set Charset as UTF8
++ # set CharacterSet as UTF8
++ self["Iptc.Envelope.CharacterSet"] = ['\x1b%G', ]
+ return pyexiv2.Image.writeMetadata(self)
+
+-
+ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- new apis
+ def xmpKeys(self):
+ return []
+
+ def getTags(self):
+ try:
+- l=self["Iptc.Application2.Keywords"]
++ l = self["Iptc.Application2.Keywords"]
+ if type(l) == tuple:
+- ll = [i.strip("\x00") for i in l] # strip("\x00") = digikam patch
++ # strip("\x00") = digikam patch
++ ll = [i.strip("\x00") for i in l]
+ ll.sort()
+ else:
+- ll = [l.strip("\x00"),]
++ ll = [l.strip("\x00"), ]
+ except KeyError:
+ ll = []
+ return ll # many case = list of utf8 strings
+
+- def setTags(self,l):
++ def setTags(self, l):
+ for i in l:
+- assert type(i)==unicode
++ assert type(i) == unicode
+
+ self["Iptc.Application2.Keywords"] = [i.encode("utf_8") for i in l]
+
+ def clearTags(self):
+ try:
+- prec = self["Iptc.Application2.Keywords"] #TODO: to bypass a bug in pyexiv2
++ # TODO: to bypass a bug in pyexiv2
++ prec = self["Iptc.Application2.Keywords"]
+ self["Iptc.Application2.Keywords"] = []
+ except:
+ pass
+
+-
+- def copyToFile(self, destFilename, exif=True, iptc=True, xmp=True, comment=True):
++ def copyToFile(self, destFilename, exif=True, iptc=True, xmp=True,
++ comment=True):
+ dest = pyexiv2.Image(destFilename)
+ dest.readMetadata()
+ # delete all tags :
+ for i in (dest.exifKeys() + dest.iptcKeys()):
+ try:
+ del dest[i]
+- except KeyError: # 'tag not set'
++ except KeyError: # 'tag not set'
+ # the tag seems not to be here, so
+ # we don't need to clear it, no ?
+ pass
+@@ -234,24 +245,31 @@ class Exiv1Metadata(pyexiv2.Image):
+
+ # copy all exif/iptc/xmp/comment info as directed
+ l = []
+- if exif: l= l+self.exifKeys()
+- if exif: l= l+self.iptcKeys()
++ if exif:
++ l = l + self.exifKeys()
++ if exif:
++ l = l + self.iptcKeys()
+ for i in l:
+- if i not in ["Exif.Photo.UserComment",]: # key "Exif.Photo.UserComment" bugs always ?!
+- if not i.startswith("Exif.Thumbnail"): # don't need exif.thumb things because it's copied after
+- if len(re.findall('0x0',i))==0: # Work around to fix error in pyev2 with most unknown makernoite tags
+- # TODO: fix nasty bodge to get around pyexiv2 issues with multi part exif fields
++ # key "Exif.Photo.UserComment" bugs always ?!
++ if i not in ["Exif.Photo.UserComment", ]:
++ # don't need exif.thumb things because it's copied after
++ if not i.startswith("Exif.Thumbnail"):
++ # Work around to fix error in pyev2 with most unknown
++ # makernoite tags
++ if len(re.findall('0x0', i)) == 0:
++ # TODO: fix nasty bodge to get around pyexiv2 issues
++ # with multi part exif fields
+ # known not to copy the following:
+ # - unknown maker not fields
+ # - lens data for canon
+ try:
+- dest[i] =self[i]
++ dest[i] = self[i]
+ except:
+- print "Problems copying %s keyword" %i
++ print "Problems copying %s keyword" % i
+
+ # copy comment
+ if comment:
+- dest.setComment( self.getComment() )
++ dest.setComment(self.getComment())
+
+ # copy exif thumbnail
+ if exif:
+@@ -260,9 +278,8 @@ class Exiv1Metadata(pyexiv2.Image):
+ #=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
+
+
+-
+ def Image(f):
+- if hasattr(pyexiv2,"ImageMetadata"):
++ if hasattr(pyexiv2, "ImageMetadata"):
+ # pyexiv2 >= 0.2
+ return Exiv2Metadata(pyexiv2.ImageMetadata(f))
+ else:
+@@ -270,21 +287,21 @@ def Image(f):
+ return Exiv1Metadata(f)
+
+ if __name__ == "__main__":
+- t=Image("/home/manatlan/Documents/python/tests_libs_python/TestJPG/p20030830_130202 (copie).jpg")
+- #~ t=Image("/home/manatlan/Documents/python/tests_libs_python/TestJPG/p20030830_130202.jpg")
++ t = Image("/home/manatlan/Documents/python/tests_libs_python" + \
++ "/TestJPG/p20030830_130202 (copie).jpg")
+ #~ t=Image("/home/manatlan/Desktop/fotaux/autorot/p20020115_173654(1).jpg")
+ t.readMetadata()
+
+ ##----
+ #aa=t._image["Xmp.dc.subject"].raw_value[0]
+- #import chardet; print chardet.detect(aa) # in fact, it's latin1 encoded as utf8
++ #import chardet; print chardet.detect(aa) # it's latin1 encoded as utf8
+ #print aa.decode("utf_8").encode("latin1")
+ ##----
+
+ #t.setThumbnailData("")
+
+- L=t.getTags()
+- print "===>",L
++ L = t.getTags()
++ print "===>", L
+
+ #t=Image("/home/manatlan/Desktop/fotaux/autorot/jpg/p20090319_061423.jpg")
+ #t.readMetadata()
+--- a/jbrout/jbrout/winshow.py
++++ b/jbrout/jbrout/winshow.py
+@@ -11,82 +11,90 @@
+ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ## GNU General Public License for more details.
+ ##
+-import gtk,gc,pango,gobject,os
+-from __main__ import Buffer,GladeApp,JBrout
++from __main__ import Buffer, GladeApp, JBrout
++from common import cd2rd, format_file_size_for_display
+ from commongtk import WinKeyTag
+-from common import cd2rd,format_file_size_for_display
+ from jbrout.externaltools import ExternalTools
++import gtk
++import gc
++import pango
++import gobject
++import os
+ #TODO: add ops : add/del from basket
+ #TODO: add ops : external tools
+
++
+ class TagList(gtk.VBox):
+- #TODO: this object need to display its parent Hscrollbar when needed (does'nt work ?!)
+- def __init__(self,callbackRemove):
++ # TODO: this object need to display its parent Hscrollbar
++ # when needed (does'nt work ?!)
++ def __init__(self, callbackRemove):
+ #self.b = gtk.Button()
+ #self.b.set_label("Test bouton")
+ gtk.VBox.__init__(self)
+ self.__callbackRemove = callbackRemove
+- self.__tags= dict(JBrout.tags.getAllTags())
++ self.__tags = dict(JBrout.tags.getAllTags())
+
+- def fill(self,ll):
+- ll.sort(lambda a,b: cmp(a.lower(),b.lower()))
++ def fill(self, ll):
++ ll.sort(lambda a, b: cmp(a.lower(), b.lower()))
+ self.__ll = ll
+ self.__refresh()
+
+ def __refresh(self):
+- l=self.get_children()
++ l = self.get_children()
+ for a in l:
+ a.destroy()
+ del a
+
+ for i in self.__ll:
+
+- hb=gtk.HBox()
+- lbl=gtk.Label()
+- lbl.set_label("%s (%s)" %(i,self.__tags[i]))
+- hb.pack_start(lbl,False,False)
+- btn=gtk.Button()
++ hb = gtk.HBox()
++ lbl = gtk.Label()
++ lbl.set_label("%s (%s)" % (i, self.__tags[i]))
++ hb.pack_start(lbl, False, False)
++ btn = gtk.Button()
+ btn.set_label("X")
+- btn.connect('button-press-event', self.__callbackRemove,i)
+- hb.pack_end(btn,False)
++ btn.connect('button-press-event', self.__callbackRemove, i)
++ hb.pack_end(btn, False)
+
+- self.pack_start(hb,False)
++ self.pack_start(hb, False)
+
+ self.resize_children()
+ self.show_all()
+
+
+-
+ class WinShow(GladeApp):
+ """ a window that displays an image in full screen
+ it may switch to next/previous image
+ WinShow receives a set of jbrout.db.PhotoNodes
+ """
+- glade=os.path.join(os.path.dirname(os.path.dirname(__file__)),'data','jbrout.glade')
+- window="WinShow"
+-
+- def init(self, ln,idx,showInfo=True,isModify=False,selected=[]):
+- self.ln=[]+ln
+- self.idx=idx
+- if len(selected)>1:
+- self.selected=selected # to be able to handle a new selection (reselect with space)
++ glade = os.path.join(os.path.dirname(os.path.dirname(__file__)),
++ 'data', 'jbrout.glade')
++ window = "WinShow"
++
++ def init(self, ln, idx, showInfo=True, isModify=False, selected=[]):
++ self.ln = [] + ln
++ self.idx = idx
++ if len(selected) > 1:
++ # to be able to handle a new selection (reselect with space)
++ self.selected = selected
+ else:
+- self.selected=[]
+- self.removed=[] # deleted items
+- self.invalidThumbs=[]
+-
+- self.zoom=False
+-
+- self.win_width=0
+- self.win_height=0
+- self.pointer_position = (0,0,0,0) #x, y, screen_width, screen_height
+-
+- self.isBasketUpdate=False
+- self.needInfo=showInfo
+- self.isModify=isModify
++ self.selected = []
++ self.removed = [] # deleted items
++ self.invalidThumbs = []
++
++ self.zoom = False
++
++ self.win_width = 0
++ self.win_height = 0
++ # x, y, screen_width, screen_height
++ self.pointer_position = (0, 0, 0, 0)
++
++ self.isBasketUpdate = False
++ self.needInfo = showInfo
++ self.isModify = isModify
+
+- PixbufCache._file=None
+- PixbufCache._cache=None
++ PixbufCache._file = None
++ PixbufCache._cache = None
+
+ self.taglist = TagList(self.on_remove_tag)
+ self.sc_tags.add_with_viewport(self.taglist)
+@@ -95,36 +103,38 @@ class WinShow(GladeApp):
+
+ self.hpShow.add2(self.viewer)
+
+- image=gtk.Image()
++ image = gtk.Image()
+ image.set_from_pixbuf(Buffer.pbBasket)
+ image.show()
+
+ self.basket.set_icon_widget(image)
+ self.toolbar1.set_style(gtk.TOOLBAR_ICONS)
+
+- #=======================================================================
++ #======================================================================
+ # put real plugins
+- #=======================================================================
++ #======================================================================
+ self.tooltips = gtk.Tooltips()
+ if isModify:
+- l=JBrout.plugins.request("PhotosProcess",isIcon=True)
++ l = JBrout.plugins.request("PhotosProcess", isIcon=True)
+ else:
+- l=JBrout.plugins.request("PhotosProcess",isIcon=True,isAlter=False)
++ l = JBrout.plugins.request("PhotosProcess", isIcon=True,
++ isAlter=False)
+
+- for instance,callback,props in l:
+- image=gtk.Image()
++ for instance, callback, props in l:
++ image = gtk.Image()
+ image.set_from_file(props["icon"])
+ image.show()
+
+ bb = gtk.ToolButton(image)
+ txt = props["label"]
+- if props["key"]: txt+=" (ctrl + %s)"%props["key"]
++ if props["key"]:
++ txt += " (ctrl + %s)" % props["key"]
+ bb.set_tooltip(self.tooltips, txt)
+- bb.connect("clicked", self.on_selecteur_menu_select_plugin,callback)
++ bb.connect("clicked", self.on_selecteur_menu_select_plugin,
++ callback)
+ self.toolbar1.insert(bb, 3)
+ bb.show()
+- #=======================================================================
+-
++ #====================================================================
+
+ self.main_widget.show_all()
+ self.main_widget.fullscreen()
+@@ -132,61 +142,65 @@ class WinShow(GladeApp):
+
+ self.draw()
+
+- def on_selecteur_menu_select_plugin(self,ib,callback):
++ def on_selecteur_menu_select_plugin(self, ib, callback):
+ currentNode = self.ln[self.idx]
+ if self.isModify and not currentNode.isReadOnly:
+
+- ret=callback([currentNode,]) #TODO: try/cath here
++ ret = callback([currentNode, ]) # TODO: try/cath here
+
+- if ret: # if change have be done ...
++ if ret: # if change have be done ...
+ if currentNode not in self.invalidThumbs:
+ self.invalidThumbs.append(currentNode)
+
+ self.draw(forceReload=True)
+
+- #TODO: if plugin "redate" is called, we'll need to redraw "time tab"
++ # TODO: if plugin "redate" is called, we'll need to
++ # redraw "time tab"
+
+- def on_eb_scroll_event(self,widget,b):
++ def on_eb_scroll_event(self, widget, b):
+ #print "eb scroll event !"
+- if int(b.direction)==1:
+- self.idx+=1
++ if int(b.direction) == 1:
++ self.idx += 1
+ else:
+- self.idx-=1
++ self.idx -= 1
+ self.draw()
+
+ def on_WinShow_key_press_event(self, widget, b):
+- key= gtk.gdk.keyval_name(b.keyval).lower()
++ key = gtk.gdk.keyval_name(b.keyval).lower()
+ isCtrl = b.state & gtk.gdk.CONTROL_MASK
+ if isCtrl:
+ currentNode = self.ln[self.idx]
+ if self.isModify and not currentNode.isReadOnly:
+- pluginsWithKey = JBrout.plugins.request("PhotosProcess",isKey=True)
++ pluginsWithKey = JBrout.plugins.request("PhotosProcess",
++ isKey=True)
+ else:
+- pluginsWithKey = JBrout.plugins.request("PhotosProcess",isKey=True,isAlter=False)
++ pluginsWithKey = JBrout.plugins.request("PhotosProcess",
++ isKey=True, isAlter=False)
+
+- for instance,callback,props in pluginsWithKey:
+- if props["key"]==key:
+- self.on_selecteur_menu_select_plugin("?!?",callback) #TODO: what's ib ? see "?!?"
++ for instance, callback, props in pluginsWithKey:
++ if props["key"] == key:
++ # TODO: what's ib ? see "?!?"
++ self.on_selecteur_menu_select_plugin("?!?", callback)
+ return 1
+ else:
+ if (key == "page_up") or (key == "up") or (key == "left"):
+- self.idx-=1
++ self.idx -= 1
+ self.draw()
+ elif (key == "page_down") or (key == "down") or (key == "right"):
+- self.idx+=1
++ self.idx += 1
+ self.draw()
+- elif key=="home":
+- self.idx=0
++ elif key == "home":
++ self.idx = 0
+ self.draw()
+- elif key=="end":
+- self.idx=len(self.ln) -1
++ elif key == "end":
++ self.idx = len(self.ln) - 1
+ self.draw()
+- elif key=="escape":
+- self.quit();
++ elif key == "escape":
++ self.quit()
+
+- elif key=="space":
++ elif key == "space":
+ # add/remove this photo to selection
+- node=self.ln[self.idx]
++ node = self.ln[self.idx]
+ if node in self.selected:
+ self.selected.remove(node)
+ else:
+@@ -194,36 +208,37 @@ class WinShow(GladeApp):
+ self.draw()
+ elif key == "f11":
+ self.on_zoom_toggled()
+- elif key=="backspace":
++ elif key == "backspace":
+ # clear selection
+- self.selected=[]
++ self.selected = []
+ self.draw()
+- elif key=="delete":
++ elif key == "delete":
+ # delete
+ self.on_delete_clicked(None) # and call draw
+- elif key=="insert" or key=="f9":
++ elif key == "insert" or key == "f9":
+ self.needInfo = not self.needInfo
+ self.draw()
+ else:
+ # print key
+ currentNode = self.ln[self.idx]
+ if self.isModify and not currentNode.isReadOnly:
+- if b.keyval<255 and b.string.strip()!="":
+- wk=WinKeyTag(_("Apply to this photo"),b.string,JBrout.tags.getAllTags())
+- ret=wk.loop()
++ if b.keyval < 255 and b.string.strip() != "":
++ wk = WinKeyTag(_("Apply to this photo"), b.string,
++ JBrout.tags.getAllTags())
++ ret = wk.loop()
+ self.main_widget.fullscreen()
+ if ret:
+ tag = ret[0]
+ currentNode.addTag(tag)
+ self.draw()
+- elif b.string>='0' and b.string<='5':
++ elif b.string >= '0' and b.string <= '5':
+ # capture keypad 0-5 for rating
+ currentNode.setRating(int(b.string))
+ self.draw()
+
+ return 0
+
+- def draw(self,forceReload=False):
++ def draw(self, forceReload=False):
+ """
+ Draws the currently selected photo in the full screen view
+
+@@ -231,11 +246,11 @@ class WinShow(GladeApp):
+ cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
+ self.main_widget.window.set_cursor(cursor)
+
+- gobject.idle_add( self._draw, forceReload )
++ gobject.idle_add(self._draw, forceReload)
+
+- def _draw(self,forceReload):
++ def _draw(self, forceReload):
+ if self.idx >= len(self.ln):
+- self.idx = len(self.ln)-1
++ self.idx = len(self.ln) - 1
+ if self.idx < 0:
+ self.idx = 0
+
+@@ -246,17 +261,17 @@ class WinShow(GladeApp):
+ return
+ try:
+ info = node.getInfo()
+- ltags=info["tags"]
+- folder=node.folderName
+- filename=os.path.basename(node.file)
+- resolution=info["resolution"]
++ ltags = info["tags"]
++ folder = node.folderName
++ filename = os.path.basename(node.file)
++ resolution = info["resolution"]
+
+- comment=info["comment"]
+- exifdate=cd2rd(info["exifdate"])
++ comment = info["comment"]
++ exifdate = cd2rd(info["exifdate"])
+ # filedate=cd2rd(info["filedate"])
+- filesize=format_file_size_for_display(info["filesize"])
++ filesize = format_file_size_for_display(info["filesize"])
+
+- rating=info["rating"]
++ rating = info["rating"]
+
+ msg = _("""
+ %(exifdate)s
+@@ -276,9 +291,9 @@ COMMENT :
+
+ TAGS :
+ """) % locals()
+- except Exception,m:
++ except Exception, m:
+ msg = ""
+- ltags=[]
++ ltags = []
+ print m
+
+ if self.isModify and not node.isReadOnly:
+@@ -288,9 +303,9 @@ TAGS :
+
+ self.taglist.fill(ltags)
+
+- d=Display()
++ d = Display()
+ d.node = None
+- self.viewer.display=d # prevent toggle event
++ self.viewer.display = d # prevent toggle event
+ self.basket.set_active(node.isInBasket)
+
+ if self.needInfo:
+@@ -298,48 +313,51 @@ TAGS :
+ else:
+ self.vb_info.hide()
+
+- d=Display()
++ d = Display()
+ d.node = node
+ if forceReload:
+- d.image = PixbufCache().get(node,forceReload)
++ d.image = PixbufCache().get(node, forceReload)
+ else:
+ d.image = PixbufCache().get(node)
+- d.title = "%d/%d"%(self.idx+1,len(self.ln))
++ d.title = "%d/%d" % (self.idx + 1, len(self.ln))
+ try:
+ self.lbl_info.set_text(msg)
+- except Exception,m:
++ except Exception, m:
+ self.lbl_info.set_text("")
+- print "*ERROR* bad characters in jpeg info : ",m
++ print "*ERROR* bad characters in jpeg info : ", m
+ d.isSelected = (node in self.selected)
+ d.nbSelected = len(self.selected)
+ d.rating = rating
+- self.viewer.show( d,self.zoom,self.pointer_position )
++ self.viewer.show(d, self.zoom, self.pointer_position)
+ gc.collect()
+
+ self.main_widget.window.set_cursor(None)
+
+- def on_WinShow_delete_event(self,*args):
++ def on_WinShow_delete_event(self, *args):
+ self.quit()
+
+ def on_WinShow_button_press_event(self, widget, data):
+ #print "winshow button press"
+- screen_width, screen_height=data.window.get_size()
++ screen_width, screen_height = data.window.get_size()
+ pointer_x, pointer_y = data.get_coords()
+- self.pointer_position=(pointer_x, pointer_y, screen_width,screen_height)
+- #print "Type %s, button %s, x = %s,y = %s" % (data.type, data.button, self.pointer_position[0], self.pointer_position[1])
+- if data.button == 1: #left click does zoom
++ self.pointer_position = (pointer_x, pointer_y, screen_width,
++ screen_height)
++ # print "Type %s, button %s, x = %s,y = %s" % \
++ # (data.type, data.button, self.pointer_position[0],
++ # self.pointer_position[1])
++ if data.button == 1: # left click does zoom
+ self.on_zoom_toggled()
+- elif data.button == 2 : #center click
++ elif data.button == 2: # center click
+ self.quit()
+- else: #button 3 closes
++ else: # button 3 closes
+ self.quit()
+
+- def on_remove_tag(self,widget,event,tag):
++ def on_remove_tag(self, widget, event, tag):
+ currentNode = self.viewer.display.node
+ currentNode.delTag(tag)
+ self.draw()
+
+- def on_delete_clicked(self,*args):
++ def on_delete_clicked(self, *args):
+ if self.isModify:
+ node = self.ln[self.idx]
+ #currentNode = self.viewer.display.node
+@@ -347,23 +365,24 @@ TAGS :
+ self.removed.append(node)
+ self.draw()
+
+- def on_basket_toggled(self,widget):
++ def on_basket_toggled(self, widget):
+ currentNode = self.viewer.display.node
+ if currentNode:
+ if widget.get_active():
+ currentNode.addToBasket()
+ else:
+ currentNode.removeFromBasket()
+- self.isBasketUpdate=True
++ self.isBasketUpdate = True
+
+ def on_zoom_toggled(self):
+- self.zoom= not self.zoom
++ self.zoom = not self.zoom
+ self.draw()
+
++
+ class ImageShow(gtk.DrawingArea):
+ def __init__(self):
+- self.zoom=False
+- self.pointer_position=(0,0,0,0) #x,y,window_width,window_height
++ self.zoom = False
++ self.pointer_position = (0, 0, 0, 0) # x,y,window_width,window_height
+ super(gtk.DrawingArea, self).__init__()
+ self.connect("expose_event", self.expose)
+
+@@ -375,7 +394,8 @@ class ImageShow(gtk.DrawingArea):
+ # set a clip region for the expose event
+ context.rectangle(event.area.x, event.area.y,
+ event.area.width, event.area.height)
+- #print "expose : x:%s y:%s witdth:%s height:%s" %(event.area.x, event.area.y,event.area.width,event.area.height)
++ # print "expose : x:%s y:%s witdth:%s height:%s" \
++ # %(event.area.x, event.area.y,event.area.width,event.area.height)
+ context.clip()
+
+ self.draw(context)
+@@ -383,49 +403,51 @@ class ImageShow(gtk.DrawingArea):
+ return False
+
+ def draw(self, context):
+- fond=(0,0,0,0.4)
++ fond = (0, 0, 0, 0.4)
+ rect = self.get_allocation()
+
+- context.set_source_rgb(0,0,0)
++ context.set_source_rgb(0, 0, 0)
+ context.paint()
+
+ if self.display:
+ if self.display.image:
+ context.save()
+ #print self.zoom
+- pb,x,y=render(self.display.image,rect.width,rect.height,self.zoom,self.pointer_position)
+- context.set_source_pixbuf(pb,x,y)
++ pb, x, y = render(self.display.image, rect.width, rect.height,
++ self.zoom, self.pointer_position)
++ context.set_source_pixbuf(pb, x, y)
+ context.paint()
+ context.restore()
+
+-
+ if self.display.title:
+ context.set_source_rgba(*fond)
+- context.rectangle(0,0,200,30)
++ context.rectangle(0, 0, 200, 30)
+ context.fill()
+
+ title = self.display.title
+ if self.display.isSelected:
+- context.set_source_rgb(1,1,0)
+- title+="*"
++ context.set_source_rgb(1, 1, 0)
++ title += "*"
+ else:
+- context.set_source_rgb(1,1,1)
++ context.set_source_rgb(1, 1, 1)
+
+- context.move_to(20,20)
++ context.move_to(20, 20)
+ context.set_font_size(20)
+ context.show_text(title)
+
+- if self.display.nbSelected>0:
+- context.set_source_rgb(1,1,0)
+- context.rel_move_to(5,0)
++ if self.display.nbSelected > 0:
++ context.set_source_rgb(1, 1, 0)
++ context.rel_move_to(5, 0)
+ context.set_font_size(12)
+- context.show_text(_("(%d selected)") % self.display.nbSelected)
++ context.show_text(_("(%d selected)") %
++ self.display.nbSelected)
+
+ if self.display.rating:
+- context.move_to(rect.width-35, 20)
+- context.set_source_rgb(1,1,1)
++ context.move_to(rect.width - 35, 20)
++ context.set_source_rgb(1, 1, 1)
+ context.set_font_size(12)
+- context.show_text((self.display.rating*"*")+((5-self.display.rating)*"-"))
++ context.show_text((self.display.rating * "*")
++ + ((5 - self.display.rating) * "-"))
+
+ #if self.display.info:
+ # wx=200
+@@ -439,96 +461,103 @@ class ImageShow(gtk.DrawingArea):
+ #
+ # layout=context.create_layout ()
+ # layout.set_text(self.display.info)
+- # layout.set_font_description(pango.FontDescription ("courier 8"))
++ # layout.set_font_description(pango.FontDescription("courie 8"))
+ # layout.set_width((wx-5)*1000)
+ # layout.set_wrap(1)
+ # context.show_layout(layout)
+
+-
+- def show(self,d,zoom=False,pointer_position=()):
++ def show(self, d, zoom=False, pointer_position=()):
+ # store instance display
+ self.display = d
+- self.zoom=zoom
+- self.pointer_position=pointer_position
++ self.zoom = zoom
++ self.pointer_position = pointer_position
+
+ # and trig expose event to redraw all
+ rect = self.get_allocation()
+- self.queue_draw_area(0,0,rect.width,rect.height)
++ self.queue_draw_area(0, 0, rect.width, rect.height)
+
+-def fit(orig_width, orig_height, dest_width, dest_height,zoom=False,pointer_position=(0,0,0,0)):
++
++def fit(orig_width, orig_height, dest_width, dest_height, zoom=False,
++ pointer_position=(0, 0, 0, 0)):
+ if orig_width == 0 or orig_height == 0:
+ return 0, 0
+- scale = min(dest_width/orig_width, dest_height/orig_height)
++ scale = min(dest_width / orig_width, dest_height / orig_height)
+ if scale > 1:
+ scale = 1
+- if zoom==True:
+- scale=1
++ if zoom == True:
++ scale = 1
+ #print "fit: zoom %s scale %s" % (zoom, scale)
+ fit_width = scale * orig_width
+ fit_height = scale * orig_height
+ return int(fit_width), int(fit_height)
+
+-def render(pb,maxw,maxh,zoom=1,pointer_position=(0,0,0,0)):
++
++def render(pb, maxw, maxh, zoom=1, pointer_position=(0, 0, 0, 0)):
+ """ resize pixbuf 'pb' to fit in box maxw*maxh
+ return the new pixbuf and x,y to center it
+ """
+- (wx,wy) = pb.get_width(),pb.get_height()
+- dwx,dwy = fit(wx,wy,float(maxw),float(maxh),zoom)
+- image_x, image_y = fit(wx,wy,float(maxw),float(maxh), False)
+- pb = pb.scale_simple(dwx,dwy,gtk.gdk.INTERP_NEAREST)
+- if pointer_position==(0,0,0,0) or zoom==False:
+- ratiox=ratioy=1.0/2
++ (wx, wy) = pb.get_width(), pb.get_height()
++ dwx, dwy = fit(wx, wy, float(maxw), float(maxh), zoom)
++ image_x, image_y = fit(wx, wy, float(maxw), float(maxh), False)
++ pb = pb.scale_simple(dwx, dwy, gtk.gdk.INTERP_NEAREST)
++ if pointer_position == (0, 0, 0, 0) or zoom == False:
++ ratiox = ratioy = 1.0 / 2
+ else:
+- (mouse_x,mouse_y,screen_width,screen_height)=pointer_position
++ (mouse_x, mouse_y, screen_width, screen_height) = pointer_position
+
+- mouse_x=max(mouse_x -(screen_width-maxw),0) #remove pane space
+- mouse_x=max(mouse_x-(maxw-image_x)/2.0, 0)
+- if mouse_x>image_x:
+- mouse_x=image_x
+- mouse_y=max(mouse_y -(screen_height-maxh),0) #remove eventual space
+- mouse_y=max(mouse_y-(maxh-image_y)/2.0, 0)
+- if mouse_y>dwy:
+- mouse_y=dwy
++ mouse_x = max(mouse_x - (screen_width - maxw), 0) # remove pane space
++ mouse_x = max(mouse_x - (maxw - image_x) / 2.0, 0)
++ if mouse_x > image_x:
++ mouse_x = image_x
++ mouse_y = max(mouse_y - (screen_height - maxh), 0) # remove all space
++ mouse_y = max(mouse_y - (maxh - image_y) / 2.0, 0)
++ if mouse_y > dwy:
++ mouse_y = dwy
+
+- ratiox=1.0*(mouse_x/image_x)
+- ratioy=1.0*(mouse_y/image_y)
++ ratiox = 1.0 * (mouse_x / image_x)
++ ratioy = 1.0 * (mouse_y / image_y)
+ if zoom:
+- x,y=maxw/2 - min(wx-maxw/2, max(maxw/2,dwx*ratiox)), maxh/2 - min(wy-maxh/2, max(maxh/2, dwy*ratioy))
++ x, y = maxw / 2 - min(wx - maxw / 2, max(maxw / 2, dwx * ratiox)), \
++ maxh / 2 - min(wy - maxh / 2, max(maxh / 2, dwy * ratioy))
+ else:
+- x,y=(maxw - dwx)*ratiox,(maxh - dwy)*ratioy
++ x, y = (maxw - dwx) * ratiox, (maxh - dwy) * ratioy
++
++ return pb, x, y
+
+- return pb,x,y
+
+ class Display(object):
+ """ container class to pass params """
+ pass
+- node=None
++ node = None
++
+
+ class PixbufCache(object):
+ """ class to cache pixbuf by filename"""
+- _cache=None
+- _file=None
+- def get(self,node,forceReload=False):
++ _cache = None
++ _file = None
++
++ def get(self, node, forceReload=False):
+ file = node.file
+- if file == PixbufCache._file :
++ if file == PixbufCache._file:
+ if forceReload:
+- PixbufCache._cache=node.getImage()
++ PixbufCache._cache = node.getImage()
+ else:
+ PixbufCache._file = file
+ if os.path.isfile(file):
+ try:
+- PixbufCache._cache=node.getImage()
+- except Exception,m:
+- print "*WARNING* can't load this file : ",(file,),m
+- PixbufCache._cache=None
++ PixbufCache._cache = node.getImage()
++ except Exception, m:
++ print "*WARNING* can't load this file : ", (file,), m
++ PixbufCache._cache = None
+ else:
+- PixbufCache._cache=None
++ PixbufCache._cache = None
+ return PixbufCache._cache
+
+
+ #class WinComment(GladeApp):
+ # """ Creates and handles the dialog for Editing photo comments """
+-# glade=os.path.join(os.path.dirname(os.path.dirname(__file__)),'data','jbrout.glade')
++# glade=os.path.join(os.path.dirname(os.path.dirname(__file__)),'data',
++# 'jbrout.glade')
+ # window="WinComment"
+ #
+ # def init(self,comment):
+@@ -544,7 +573,8 @@ class PixbufCache(object):
+ # """ Handles the rotate right button """
+ # start=self.tbufComment.get_start_iter()
+ # end =self.tbufComment.get_end_iter()
+-# self.quit(True,self.tbufComment.gset_mnemonic_modifieret_text(start,end,False))
++# self.quit(True,self.tbufComment.\
++# gset_mnemonic_modifieret_text(start,end,False))
+ #
+ # def on_WinGetComment_delete_event(self,*args):
+ # """ Handles window delete (close) events """
+@@ -554,4 +584,3 @@ class PixbufCache(object):
+ if __name__ == "__main__":
+ # self test
+ pass
+-
diff --git a/0002-Overkill-solution-for-illegal-XML-characters.patch b/0002-Overkill-solution-for-illegal-XML-characters.patch
new file mode 100644
index 0000000..ecf87f3
--- /dev/null
+++ b/0002-Overkill-solution-for-illegal-XML-characters.patch
@@ -0,0 +1,139 @@
+--- a/jbrout/jbrout/db.py
++++ b/jbrout/jbrout/db.py
+@@ -914,7 +914,13 @@ class PhotoNode(object):
+ self.__node.append(nodeTag)
+ if pc.comment:
+ nodeComment = Element("c")
+- nodeComment.text = pc.comment.replace(u'\x00', u' ')
++ try:
++ nodeComment.text = char_utils.make_xml_string_legal(pc.comment)
++ except ValueError, f:
++ print "exception = %s" % f
++ print "nodeComment = %s" % nodeComment
++ print "pc.comment = %s" % pc.comment
++ raise
+ self.__node.append(nodeComment)
+ if pc.rating:
+ nodeRating = Element("r")
+--- /dev/null
++++ b/jbrout/jbrout/char_utils.py
+@@ -0,0 +1,119 @@
++import re
++# Originally from http://boodebr.org/main/python/all-about-python-and-unicode#UNI_XML
++# http://coreapython.hosting.paran.com/boodebr\
++# /All%20About%20Python%20and%20Unicode%20%20boodebr_org.htm#UNI_XML
++
++def raw_illegal_xml_regex():
++ """
++ I want to define a regexp to match *illegal* characters.
++ That way, I can do "re.search()" to find a single character,
++ instead of "re.match()" to match the entire string. [Based on
++ my assumption that .search() would be faster in this case.]
++
++ Here is a verbose map of the XML character space (as defined
++ in section 2.2 of the XML specification):
++
++ u0000 - u0008 = Illegal
++ u0009 - u000A = Legal
++ u000B - u000C = Illegal
++ u000D = Legal
++ u000E - u001F = Illegal
++ u0020 - uD7FF = Legal
++ uD800 - uDFFF = Illegal (See note!)
++ uE000 - uFFFD = Legal
++ uFFFE - uFFFF = Illegal
++ U00010000 - U0010FFFF = Legal (See note!)
++
++ Note:
++
++ The range U00010000 - U0010FFFF is coded as 2-character sequences
++ using the codes (D800-DBFF),(DC00-DFFF), which are both illegal
++ when used as single chars, from above.
++
++ Python won't let you define \U character ranges, so you can't
++ just say '\U00010000-\U0010FFFF'. However, you can take advantage
++ of the fact that (D800-DBFF) and (DC00-DFFF) are illegal, unless
++ part of a 2-character sequence, to match for the \U characters.
++ """
++
++ # First, add a group for all the basic illegal areas above
++ re_xml_illegal = u'([\u0000-\u0008\u000b-\u000c\u000e-\u001f\ufffe-\uffff])'
++
++ re_xml_illegal += u"|"
++
++ # Next, we know that (uD800-uDBFF) must ALWAYS be followed by (uDC00-uDFFF),
++ # and (uDC00-uDFFF) must ALWAYS be preceded by (uD800-uDBFF), so this
++ # is how we check for the U00010000-U0010FFFF range. There are also special
++ # case checks for start & end of string cases.
++
++ # I've defined this oddly due to the bug mentioned at the top of this file
++ re_xml_illegal += u'([%s-%s][^%s-%s])|([^%s-%s][%s-%s])|([%s-%s]$)|(^[%s-%s])' % \
++ (unichr(0xd800), unichr(0xdbff), unichr(0xdc00), unichr(0xdfff),
++ unichr(0xd800), unichr(0xdbff), unichr(0xdc00), unichr(0xdfff),
++ unichr(0xd800), unichr(0xdbff), unichr(0xdc00), unichr(0xdfff))
++
++ return re_xml_illegal
++
++def make_illegal_xml_regex():
++ return re.compile(raw_illegal_xml_regex())
++
++c_re_xml_illegal = make_illegal_xml_regex()
++
++def is_legal_xml(uval):
++ """
++ Given a Unicode object, figure out if it is legal
++ to place it in an XML file.
++ """
++ return (c_re_xml_illegal.search(uval) == None)
++
++def make_xml_string_legal(instr):
++ return c_re_xml_illegal.sub('', instr)
++
++def is_legal_xml_char(uchar):
++ """
++ Check if a single unicode char is XML-legal.
++ (This is faster that running the full 'is_legal_xml()' regexp
++ when you need to go character-at-a-time. For string-at-a-time
++ of course you want to use is_legal_xml().)
++
++ USAGE NOTE:
++ If you want to use this in a 'for' loop,
++ make sure use usplit(), e.g.:
++
++ for c in usplit( uval ):
++ if is_legal_xml_char(c):
++ ...
++
++ Otherwise, the first char of a legal 2-character
++ sequence will be incorrectly tagged as illegal, on
++ Pythons where \U is stored as 2-chars.
++ """
++
++ # due to inconsistencies in how \U is handled (based on
++ # how Python was compiled) it is shorter to test for
++ # illegal chars than legal ones, and invert the result.
++ #
++ # (as one example: (u'\ud900' > u'\U00100000') can be True,
++ # depending on how Python was compiled. Testing for illegal chars
++ # lets us stick with the single char sequences (all 2-char
++ # sequences are legal for XML).
++
++ if len(uchar) == 1:
++ return not \
++ (
++ (uchar >= u'\u0000' and uchar <= u'\u0008') or \
++ (uchar >= u'\u000b' and uchar <= u'\u000c') or \
++ (uchar >= u'\u000e' and uchar <= u'\u001f') or \
++ # always illegal as single chars
++ (uchar >= unichr(0xd800) and uchar <= unichr(0xdfff)) or \
++ (uchar >= u'\ufffe' and uchar <= u'\uffff')
++ )
++ elif len(uchar) == 2:
++ # all 2-char codings are legal in XML
++ # (this looks weird, but remember that even after calling
++ # usplit(), \U00010000 is STILL len() of 2, usplit() just
++ # made it a single listitem
++ return True
++
++ else:
++ raise Exception("Must pass a single character to is_legal_xml_char")
diff --git a/0003-IPTC-charset-backtrace.patch b/0003-IPTC-charset-backtrace.patch
new file mode 100644
index 0000000..7bae7d2
--- /dev/null
+++ b/0003-IPTC-charset-backtrace.patch
@@ -0,0 +1,35 @@
+--- a/jbrout/jbrout/pyexiv.py
++++ b/jbrout/jbrout/pyexiv.py
+@@ -31,6 +31,9 @@ except:
+ print "You should install pyexiv2 (>=0.1.2)"
+ sys.exit(-1)
+
++import logging
++logging.basicConfig(format='%(levelname)s:%(funcName)s:%(message)s',
++ level=logging.DEBUG)
+
+ ###############################################################################
+ class Exiv2Metadata(object):
+@@ -45,7 +48,21 @@ class Exiv2Metadata(object):
+
+ def writeMetadata(self):
+ # set CharacterSet as UTF8
+- self._md["Iptc.Envelope.CharacterSet"] = ['\x1b%G', ]
++ logging.debug("self._md.iptc_keys = %s" % self._md.iptc_keys)
++ logging.debug("self._md.iptc_charset = %s" % hasattr(self._md, "iptc_charset"))
++ # For compatibility with pyexiv2 >= 0.3.2
++ if hasattr(self._md, "iptc_charset"):
++ # remove Iptc.Envelope.CharacterSet tag
++ # it doesn't work with pyexiv2 O.3.2 which wants to do everything
++ # on its own.
++ if "Iptc.Envelope.CharacterSet" in self._md.iptc_keys:
++ del self._md["Iptc.Envelope.CharacterSet"]
++
++ # Currently pyexiv2.IptcTag("Iptc.Envelope.CharacterSet", ['\x1b%G',])
++ # fails with Invalidvalue error. FIXME
++ #self._md.iptc_charset = "utf-8"
++ else:
++ self._md["Iptc.Envelope.CharacterSet"] = ['\x1b%G', ] # set Charset as UTF8
+ return self._md.write()
+
+ def __getitem__(self, k):
diff --git a/0004-Gtk-Tooltips-depreceated.patch b/0004-Gtk-Tooltips-depreceated.patch
new file mode 100644
index 0000000..30d08ac
--- /dev/null
+++ b/0004-Gtk-Tooltips-depreceated.patch
@@ -0,0 +1,39 @@
+--- a/jbrout/jbrout.py
++++ b/jbrout/jbrout.py
+@@ -947,8 +947,6 @@ class Window(GladeApp):
+
+
+ # build the "plugins buttons"
+- self.tooltips = gtk.Tooltips()
+-
+ if JBrout.modify:
+ l=JBrout.plugins.request("PhotosProcess",isIcon=True)
+ else:
+@@ -962,7 +960,7 @@ class Window(GladeApp):
+ bb = gtk.ToolButton(image)
+ txt = props["label"]
+ if props["key"]: txt+=" (ctrl + %s)"%props["key"]
+- bb.set_tooltip(self.tooltips, txt)
++ bb.set_tooltip_text(txt)
+ bb.connect("clicked", self.on_selecteur_menu_select_plugin,table,instance.id,callback)
+ self.toolbar.insert(bb, 3)
+ bb.show()
+--- a/jbrout/jbrout/winshow.py
++++ b/jbrout/jbrout/winshow.py
+@@ -113,7 +113,6 @@ class WinShow(GladeApp):
+ #======================================================================
+ # put real plugins
+ #======================================================================
+- self.tooltips = gtk.Tooltips()
+ if isModify:
+ l = JBrout.plugins.request("PhotosProcess", isIcon=True)
+ else:
+@@ -129,7 +128,7 @@ class WinShow(GladeApp):
+ txt = props["label"]
+ if props["key"]:
+ txt += " (ctrl + %s)" % props["key"]
+- bb.set_tooltip(self.tooltips, txt)
++ bb.set_tooltip_text(txt)
+ bb.connect("clicked", self.on_selecteur_menu_select_plugin,
+ callback)
+ self.toolbar1.insert(bb, 3)
diff --git a/jbrout-no-pyexiv2-warning.patch b/jbrout-no-pyexiv2-warning.patch
index 0d740d1..09ddf7c 100644
--- a/jbrout-no-pyexiv2-warning.patch
+++ b/jbrout-no-pyexiv2-warning.patch
@@ -1,21 +1,6 @@
-Index: jbrout/jbrout/jbrout.py
-===================================================================
---- jbrout.orig/jbrout/jbrout.py
-+++ jbrout/jbrout/jbrout.py
-@@ -3117,9 +3117,6 @@ if __name__ == "__main__":
- psyco.full()
- except:
- print "The psyco module does not seem to be installed. It is not necessary, however it can speed up performance."
-- # Print pyexiv2-0.2+ warning if necessary
-- from jbrout.pyexiv import Check
-- Check()
-
- try:
- parser = optparse.OptionParser(usage=USAGE, version=("JBrout "+__version__))
-Index: jbrout/jbrout/jbrout/pyexiv.py
-===================================================================
---- jbrout.orig/jbrout/jbrout/pyexiv.py
-+++ jbrout/jbrout/jbrout/pyexiv.py
+diff -up jbrout/jbrout/jbrout/pyexiv.py.noPyexiv2Warn jbrout/jbrout/jbrout/pyexiv.py
+--- jbrout/jbrout/jbrout/pyexiv.py.noPyexiv2Warn 2011-07-07 10:34:19.000000000 +0200
++++ jbrout/jbrout/jbrout/pyexiv.py 2012-01-14 22:13:06.227033871 +0100
@@ -269,11 +269,6 @@ def Image(f):
# pyexiv2 < 0.2
return Exiv1Metadata(f)
@@ -28,3 +13,16 @@ Index: jbrout/jbrout/jbrout/pyexiv.py
if __name__ == "__main__":
t=Image("/home/manatlan/Documents/python/tests_libs_python/TestJPG/p20030830_130202 (copie).jpg")
#~ t=Image("/home/manatlan/Documents/python/tests_libs_python/TestJPG/p20030830_130202.jpg")
+diff -up jbrout/jbrout/jbrout.py.noPyexiv2Warn jbrout/jbrout/jbrout.py
+--- jbrout/jbrout/jbrout.py.noPyexiv2Warn 2011-07-07 10:34:19.000000000 +0200
++++ jbrout/jbrout/jbrout.py 2012-01-14 22:13:06.227033871 +0100
+@@ -3117,9 +3117,6 @@ if __name__ == "__main__":
+ psyco.full()
+ except:
+ print "The psyco module does not seem to be installed. It is not necessary, however it can speed up performance."
+- # Print pyexiv2-0.2+ warning if necessary
+- from jbrout.pyexiv import Check
+- Check()
+
+ try:
+ parser = optparse.OptionParser(usage=USAGE, version=("JBrout "+__version__))
diff --git a/jbrout-purge-no-attribute-attrib.patch b/jbrout-purge-no-attribute-attrib.patch
index 074a08e..aa6abb1 100644
--- a/jbrout-purge-no-attribute-attrib.patch
+++ b/jbrout-purge-no-attribute-attrib.patch
@@ -1,7 +1,6 @@
-Index: jbrout/jbrout/jbrout/db.py
-===================================================================
---- jbrout.orig/jbrout/jbrout/db.py
-+++ jbrout/jbrout/jbrout/db.py
+diff -up jbrout/jbrout/jbrout/db.py.noAttributeAttrib jbrout/jbrout/jbrout/db.py
+--- jbrout/jbrout/jbrout/db.py.noAttributeAttrib 2011-07-07 10:34:19.000000000 +0200
++++ jbrout/jbrout/jbrout/db.py 2012-01-14 22:12:13.400916607 +0100
@@ -14,6 +14,7 @@
##
diff --git a/jbrout.spec b/jbrout.spec
index d522467..55373f8 100644
--- a/jbrout.spec
+++ b/jbrout.spec
@@ -4,7 +4,7 @@
Name: jbrout
Version: 0.3.%{revno}
%if 0%{?svn_checkout}
-Release: 0.4.svn%{revno}%{?dist}
+Release: 0.5.svn%{revno}.MC.1%{?dist}
%else
Release: 1%{?dist}
%endif
@@ -30,6 +30,15 @@ Patch0: jbrout-purge-no-attribute-attrib.patch
# Fedora users have no choice about what pyexiv2 to use.
# Besides pyexiv2 0.3.* is now officially stable.
Patch1: jbrout-no-pyexiv2-warning.patch
+# Reformat some files to make Eclipse happy
+Patch2: 0001-Reformatting-to-make-code-PEP8-compatible.patch
+# Finally get rid of bad XML characters!
+Patch3: 0002-Overkill-solution-for-illegal-XML-characters.patch
+# Problems with Iptc.Envelope.CharacterSet
+Patch4: 0003-IPTC-charset-backtrace.patch
+# Gtk.Tooltips has been depreceated a long time ago
+Patch5: 0004-Gtk-Tooltips-depreceated.patch
+
BuildArch: noarch
BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
Requires: python >= 2.4, python-lxml, pygtk2 >= 2.6
@@ -62,6 +71,11 @@ jBrout is able to :
%setup -q -n %{name}
%patch0 -p1 -b .noAttributeAttrib
%patch1 -p1 -b .noPyexiv2Warn
+%patch2 -p1 -b .EclipseReformat
+%patch3 -p1 -b .illegalXMLchar
+%patch4 -p1 -b .charSet
+%patch5 -p1 -b .GtkTooltip
+
sh %{SOURCE5}
install -p %{SOURCE1} jbrout/Makefile
install -p -m a+rx,u+w %{SOURCE4} jbrout/install-script
@@ -99,6 +113,9 @@ rm -rf $RPM_BUILD_ROOT
%{_datadir}/applications/jbrout.desktop
%changelog
+* Sat Jan 14 2012 'Matej Cepl <mcepl at redhat.com>' - 0.3.338-0.5.svn338.MC.1
+- EXPERIMENTAL support for pyexiv2 0.3.2 ... produces invalid IPTC tags!!!
+
* Thu Oct 27 2011 Matěj Cepl <mcepl at redhat.com> - 0.3.338-0.4.svn338
- fix find cleaning .exe and .dll (closes #749425)
More information about the scm-commits
mailing list