1 # -*- coding: utf-8 -*-
3 Boîte de dialogue pour sélection des chansons.
9 from pgu
.gui
import FileDialog
10 import pgu
.gui
.basic
as basic
11 import pgu
.gui
.input as input
12 import pgu
.gui
.button
as button
13 import pgu
.gui
.pguglobals
as pguglobals
14 import pgu
.gui
.table
as table
15 import pgu
.gui
.area
as area
16 from pgu
.gui
.const
import *
17 from pgu
.gui
.dialog
import Dialog
21 from xml
.etree
import ElementTree
22 from minwii
.musicxml
import musicXml2Song
24 INDEX_TXT
= 'index.txt'
26 class FileOpenDialog(FileDialog
):
30 def __init__(self
, path
):
32 if not path
: self
.curdir
= os
.getcwd()
33 else: self
.curdir
= path
34 self
.dir_img
= basic
.Image(
35 pguglobals
.app
.theme
.get(cls1
+'.folder', '', 'image'))
36 td_style
= {'padding_left': 4,
40 self
.title
= basic
.Label("Ouvrir un chanson", cls
="dialog.title.label")
41 self
.body
= table
.Table()
42 self
.list = area
.List(width
=700, height
=250)
43 self
.input_dir
= input.Input()
44 self
.input_file
= input.Input()
45 self
._current
_sort
= 'alpha'
47 self
.button_ok
= button
.Button("Ouvrir")
48 self
.button_sort_alpha
= button
.Button("A-Z")
49 self
.button_sort_alpha
.connect(CLICK
, self
._set
_current
_sort
_, 'alpha')
50 self
.button_sort_num
= button
.Button("0-9")
51 self
.button_sort_num
.connect(CLICK
, self
._set
_current
_sort
_, 'num')
53 self
.body
.td(basic
.Label("Dossier"), style
=td_style
, align
=-1)
54 self
.body
.td(self
.input_dir
, style
=td_style
)
55 self
.body
.td(self
.button_sort_alpha
)
56 self
.body
.td(self
.button_sort_num
)
58 self
.body
.td(self
.list, colspan
=4, style
=td_style
)
59 self
.list.connect(CHANGE
, self
._item
_select
_changed
_, None)
60 self
.button_ok
.connect(CLICK
, self
._button
_okay
_clicked
_, None)
62 self
.body
.td(basic
.Label("Fichier"), style
=td_style
, align
=-1)
63 self
.body
.td(self
.input_file
, style
=td_style
)
64 self
.body
.td(self
.button_ok
, style
=td_style
, colspan
=2)
66 Dialog
.__init
__(self
, self
.title
, self
.body
)
68 # FileDialog.__init__(self,
69 # title_txt="Ouvrir une chanson",
70 # button_txt="Ouvrir",
73 # self.list.style.width = 700
74 # self.list.style.height = 250
77 self
.input_dir
.value
= self
.curdir
78 self
.input_dir
.pos
= len(self
.curdir
)
79 self
.input_dir
.vpos
= 0
83 for i
in os
.listdir(self
.curdir
):
84 if i
.startswith('.') : continue
85 if os
.path
.isdir(os
.path
.join(self
.curdir
, i
)): dirs
.append(i
)
88 self
.input_file
.value
= "Dossier innacessible !"
95 self
.list.add(i
, image
=self
.dir_img
, value
=i
)
99 if not i
.endswith('.xml') :
101 filepath
= os
.path
.join(self
.curdir
, i
)
102 xmlFiles
.append(filepath
)
103 # self.list.add(FileOpenDialog.getSongTitle(filepath), value=i)
106 printableLines
= self
.getPrintableLines(xmlFiles
)
107 for l
in printableLines
:
108 self
.list.add(l
[0], value
= l
[1])
110 self
.list.set_vertical_scroll(0)
112 def getPrintableLines(self
, xmlFiles
) :
113 index
= self
.getUpdatedIndex(xmlFiles
)
119 printableLines
.append(('%s - %s / %s' % (l
[2], l
[3], l
[4]), l
[0]))
121 return printableLines
125 def getSongTitle(file) :
126 it
= ElementTree
.iterparse(file, ['start', 'end'])
128 title
= os
.path
.basename(file)
131 if el
.tag
== 'credit' :
133 if el
.tag
== 'credit-words' and creditFound
:
136 if el
.tag
== 'part-list' :
137 # au delà de ce tag : aucune chance de trouver un titre
142 def getSongMetadata(file) :
144 metadata
['title'] = FileOpenDialog
.getSongTitle(file).encode('iso-8859-1')
145 metadata
['mtime'] = str(os
.stat(file).st_mtime
)
146 metadata
['file'] = os
.path
.basename(file)
147 song
= musicXml2Song(file)
148 metadata
['distinctNotes'] = len(song
.distinctNotes
)
150 histo
= song
.intervalsHistogram
151 coeffInter
= reduce(lambda a
, b
: a
+ b
,
152 [abs(k
) * v
for k
, v
in histo
.items()])
154 totInter
= reduce(lambda a
, b
: a
+b
, histo
.values())
155 totInter
= totInter
- histo
.get(0, 0)
156 difficulty
= int(round(float(coeffInter
) / totInter
, 0))
157 metadata
['difficulty'] = difficulty
161 def getUpdatedIndex(self
, xmlFiles
) :
162 indexTxtPath
= os
.path
.join(self
.curdir
, INDEX_TXT
)
165 if not os
.path
.exists(indexTxtPath
) :
166 musicXmlFound
= False
167 tmp
= tempfile
.TemporaryFile(mode
='r+')
168 for file in xmlFiles
:
170 metadata
= FileOpenDialog
.getSongMetadata(file)
172 except ValueError, e
:
174 if e
.args
and e
.args
[0] == 'not a musicxml file' :
177 line
= '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
183 indexFile
= open(indexTxtPath
, 'w')
184 indexFile
.write(tmp
.read())
189 indexTxt
= open(indexTxtPath
, 'r')
191 # check if index is up to date, and update entries if so.
192 for l
in filter(None, indexTxt
.readlines()) :
193 parts
= l
.split('\t')
194 fileBaseName
, modificationTime
= parts
[0], parts
[1]
195 filePath
= os
.path
.join(self
.curdir
, fileBaseName
)
197 if not os
.path
.exists(filePath
) :
200 indexedFiles
[fileBaseName
] = l
201 currentMtime
= str(os
.stat(filePath
).st_mtime
)
203 # check modification time missmatch
204 if currentMtime
!= modificationTime
:
206 metadata
= FileOpenDialog
.getSongMetadata(filePath
)
208 except ValueError, e
:
210 if e
.args
and e
.args
[0] == 'not a musicxml file' :
213 metadata
= FileOpenDialog
.getSongMetadata(filePath
)
214 line
= '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
215 indexedFiles
[fileBaseName
] = line
217 # check for new files.
218 for file in xmlFiles
:
219 fileBaseName
= os
.path
.basename(file)
220 if not indexedFiles
.has_key(fileBaseName
) :
222 metadata
= FileOpenDialog
.getSongMetadata(filePath
)
224 except ValueError, e
:
226 if e
.args
and e
.args
[0] == 'not a musicxml file' :
229 metadata
= FileOpenDialog
.getSongMetadata(file)
230 line
= '%(file)s\t%(mtime)s\t%(title)s\t%(distinctNotes)d\t%(difficulty)d\n' % metadata
231 indexedFiles
[fileBaseName
] = line
233 # ok, the index is up to date !
235 index
= indexedFiles
.values()
238 if self
._current
_sort
== 'alpha' :
240 da
= desacc(a
.split('\t')[2]).lower()
241 db
= desacc(b
.split('\t')[2]).lower()
244 elif self
._current
_sort
== 'num' :
246 da
= int(a
.split('\t')[3])
247 db
= int(b
.split('\t')[3])
255 def _set_current_sort_(self
, arg
) :
256 self
._current
_sort
= arg
261 from unicodedata
import decomposition
262 from string
import printable
263 _printable
= dict([(c
, True) for c
in printable
])
264 isPrintable
= _printable
.has_key
266 def _recurseDecomposition(uc
):
267 deco
= decomposition(uc
).split()
272 if code
.startswith('<') :
274 c
= unichr(int(code
, 16))
275 subDeco
= decomposition(c
).split()
284 fullDeco
= u
''.join(filter(lambda c
: isPrintable(c
), fullDeco
))
288 us
= s
.decode('utf-8', 'ignore')
291 ret
.append(_recurseDecomposition(uc
))