e4ecf1b9802bca9ceb99f55031f9df5d0f68a105
[minwii.git] / src / minwii / widgets / songfilebrowser.py
1 # -*- coding: utf-8 -*-
2 """
3 Boîte de dialogue pour sélection des chansons.
4
5 $Id$
6 $URL$
7 """
8
9 from pgu.gui import FileDialog
10 import os
11 import tempfile
12 from xml.etree import ElementTree
13 from minwii.musicxml import musicXml2Song
14
15 INDEX_TXT = 'index.txt'
16
17 class FileOpenDialog(FileDialog):
18
19
20
21 def __init__(self, path):
22 FileDialog.__init__(self,
23 title_txt="Ouvrir une chanson",
24 button_txt="Ouvrir",
25 path=path,
26 )
27
28 def _list_dir_(self):
29 self.input_dir.value = self.curdir
30 self.input_dir.pos = len(self.curdir)
31 self.input_dir.vpos = 0
32 dirs = []
33 files = []
34 try:
35 for i in os.listdir(self.curdir):
36 if i.startswith('.') : continue
37 if os.path.isdir(os.path.join(self.curdir, i)): dirs.append(i)
38 else: files.append(i)
39 except:
40 self.input_file.value = "Dossier innacessible !"
41
42 dirs.sort()
43 dirs.insert(0, '..')
44
45 files.sort()
46 for i in dirs:
47 self.list.add(i, image=self.dir_img, value=i)
48
49 xmlFiles = []
50 for i in files:
51 if not i.endswith('.xml') :
52 continue
53 filepath = os.path.join(self.curdir, i)
54 xmlFiles.append(filepath)
55 # self.list.add(FileOpenDialog.getSongTitle(filepath), value=i)
56
57 if xmlFiles :
58 printableLines = self.getPrintableLines(xmlFiles)
59 for l in printableLines :
60 self.list.add(l[0], value = l[1])
61
62 self.list.set_vertical_scroll(0)
63
64 def getPrintableLines(self, xmlFiles) :
65 index = self.getUpdatedIndex(xmlFiles)
66
67 printableLines = []
68 for l in index :
69 l = l.strip()
70 l = l.split('\t')
71 printableLines.append(('%s - %s / %s' % (l[2], l[3], l[4]), l[0]))
72
73 return printableLines
74
75
76 @staticmethod
77 def getSongTitle(file) :
78 it = ElementTree.iterparse(file, ['start', 'end'])
79 creditFound = False
80 title = os.path.basename(file)
81
82 for evt, el in it :
83 if el.tag == 'credit' :
84 creditFound = True
85 if el.tag == 'credit-words' and creditFound:
86 title = el.text
87 break
88 if el.tag == 'part-list' :
89 # au delà de ce tag : aucune chance de trouver un titre
90 break
91 return title
92
93 @staticmethod
94 def getSongMetadata(file) :
95 metadata = {}
96 metadata['title'] = FileOpenDialog.getSongTitle(file).encode('iso-8859-1')
97 metadata['mtime'] = str(os.stat(file).st_mtime)
98 metadata['file'] = os.path.basename(file)
99 song = musicXml2Song(file)
100 metadata['distinctNotes'] = len(song.distinctNotes)
101
102 histo = song.intervalsHistogram
103 coeffInter = reduce(lambda a, b : a + b,
104 [abs(k) * v for k, v in histo.items()])
105
106 totInter = reduce(lambda a, b: a+b, histo.values())
107 totInter = totInter - histo.get(0, 0)
108 difficulty = int(round(float(coeffInter) / totInter, 0))
109 metadata['difficulty'] = difficulty
110
111 return metadata
112
113 def getUpdatedIndex(self, xmlFiles) :
114 indexTxtPath = os.path.join(self.curdir, INDEX_TXT)
115 index = []
116
117 if not os.path.exists(indexTxtPath) :
118 musicXmlFound = False
119 tmp = tempfile.TemporaryFile(mode='r+')
120 for file in xmlFiles :
121 try :
122 metadata = FileOpenDialog.getSongMetadata(file)
123 musicXmlFound = True
124 except ValueError, e :
125 print e
126 if e.args and e.args[0] == 'not a musicxml file' :
127 continue
128
129 line = '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
130 index.append(line)
131 tmp.write(line)
132
133 if musicXmlFound :
134 tmp.seek(0)
135 indexFile = open(indexTxtPath, 'w')
136 indexFile.write(tmp.read())
137 indexFile.close()
138 tmp.close()
139 else :
140 indexedFiles = {}
141 indexTxt = open(indexTxtPath, 'r')
142
143 # check if index is up to date, and update entries if so.
144 for l in filter(None, indexTxt.readlines()) :
145 parts = l.split('\t')
146 fileBaseName, modificationTime = parts[0], parts[1]
147 filePath = os.path.join(self.curdir, fileBaseName)
148
149 if not os.path.exists(filePath) :
150 continue
151
152 indexedFiles[fileBaseName] = l
153 currentMtime = str(os.stat(filePath).st_mtime)
154
155 # check modification time missmatch
156 if currentMtime != modificationTime :
157 try :
158 metadata = FileOpenDialog.getSongMetadata(filePath)
159 musicXmlFound = True
160 except ValueError, e :
161 print e
162 if e.args and e.args[0] == 'not a musicxml file' :
163 continue
164
165 metadata = FileOpenDialog.getSongMetadata(filePath)
166 line = '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
167 indexedFiles[fileBaseName] = line
168
169 # check for new files.
170 for file in xmlFiles :
171 fileBaseName = os.path.basename(file)
172 if not indexedFiles.has_key(fileBaseName) :
173 try :
174 metadata = FileOpenDialog.getSongMetadata(filePath)
175 musicXmlFound = True
176 except ValueError, e :
177 print e
178 if e.args and e.args[0] == 'not a musicxml file' :
179 continue
180
181 metadata = FileOpenDialog.getSongMetadata(file)
182 line = '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
183 indexedFiles[fileBaseName] = line
184
185 # ok, the index is up to date !
186
187 index = indexedFiles.values()
188 index.sort()
189
190
191 return index
192