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