1 from __future__
import with_statement
7 raise ImportError('You need gtk and glade')
11 raise ImportError('You need gobject')
13 from xml
.dom
.minidom
import parseString
, parse
15 raise ImportError('You need python-xml')
19 class XMLLoop(object):
20 """An abstraction layer for all the XML crap necessary for these loops."""
22 def __init__(self
, file=None):
23 if file and os
.path
.exists(file):
24 self
.doc
= parse(file)
26 self
.doc
= parseString(u
'<!DOCTYPE loopobj SYSTEM "loopobj.dtd"><loopobj />'.encode('UTF-8'))
28 self
.toxml
= self
.doc
.toxml
29 self
.toprettyxml
= self
.doc
.toprettyxml
31 def _get_filepath(self
):
32 return getCBTNText(self
.doc
, u
'filepath')
34 def _set_filepath(self
, filepath
):
35 if len(self
.doc
.getElementsByTagName(u
'filepath')) > 0:
36 getChildByTagName(self
.doc
, u
'filepath').firstChild
.data
= filepath
38 filepath_node
= self
.doc
.createElement(u
'filepath')
39 filepath_node
.appendChild(self
.doc
.createTextNode(filepath
))
40 self
.doc
.documentElement
.appendChild(filepath_node
)
42 filepath
= property(_get_filepath
, _set_filepath
)
44 def get_intervals(self
):
45 """Returns a list of intervals, where each interval is a list of four elements:
49 - whether this is the selected interval or not
51 For example, get_intervals might return the following:
52 [u'loop 1', 0, 150, False]"""
54 return [[getCBTNText(interval
, tag
)
55 for tag
in [u
'name', u
'start', u
'end']
57 for interval
in self
.doc
.getElementsByTagName(u
'interval')]
59 def add_interval(self
, interval
):
60 """Adds the requested interval, which must be of the same form get_intervals returns"""
62 interval_node
= self
.doc
.createElement(u
'interval')
64 name
= self
.doc
.createElement(u
'name')
65 name
.appendChild(self
.doc
.createTextNode(interval
[0]))
66 interval_node
.appendChild(name
)
68 start
= self
.doc
.createElement(u
'start')
69 start
.appendChild(self
.doc
.createTextNode(str(interval
[1])))
70 interval_node
.appendChild(start
)
72 end
= self
.doc
.createElement(u
'end')
73 end
.appendChild(self
.doc
.createTextNode(str(interval
[2])))
74 interval_node
.appendChild(end
)
76 loopobj
= self
.doc
.documentElement
77 loopobj
.appendChild(interval_node
)
79 # XXX These are convenience methods that do not make sure you aren't stupid.
80 # Perform this check yourself before using them.
81 def getChildByTagName(node
, tag
):
82 return node
.getElementsByTagName(tag
)[0]
84 return node
.firstChild
.data
85 def getCBTNText(node
, tag
):
86 return getText(getChildByTagName(node
, tag
))
88 class LooperTreeView(object):
89 def __init__(self
, wTree
, pylooper
=None):
90 self
.pylooper
= pylooper
92 self
.treeview
= wTree
.get_widget('treeview')
93 self
.liststore
= gtk
.ListStore(gobject
.TYPE_STRING
, gobject
.TYPE_INT64
, gobject
.TYPE_INT64
)
94 self
.treeview
.set_model(self
.liststore
)
96 cell0
= gtk
.CellRendererText()
97 cell1
= gtk
.CellRendererText()
98 cell2
= gtk
.CellRendererText()
99 self
.treeview
.append_column(gtk
.TreeViewColumn('Name', cell0
, text
=0, editable
=True))
100 self
.treeview
.append_column(gtk
.TreeViewColumn('Begin', cell1
))
101 self
.treeview
.append_column(gtk
.TreeViewColumn('End', cell2
))
103 cell0
.connect('edited', self
.name_edited
)
105 self
.treeview
.get_column(1).set_cell_data_func(cell1
, nsecs2str
, 1)
106 self
.treeview
.get_column(2).set_cell_data_func(cell2
, nsecs2str
, 2)
108 self
.treeview
.get_selection().set_mode(gtk
.SELECTION_SINGLE
)
109 self
.treeview
.get_selection().connect('changed', self
.changed
)
111 def add(self
, begin
, end
, name
='new_interval'):
112 iter = self
.liststore
.append([name
, long(begin
), long(end
)])
114 self
.treeview
.get_selection().select_iter(iter)
116 def changed(self
, treeselection
):
117 model
, iter = treeselection
.get_selected()
119 self
.pylooper
.update_interval(model
.get_value(iter, 1), model
.get_value(iter, 2))
124 def name_edited(self
, cellrenderertext
, path
, new_text
):
126 self
.liststore
.set(self
.liststore
.get_iter_from_string(path
), 0, new_text
)
131 def update_interval(self
, begin
, end
):
132 if self
.treeview
.get_selection().get_selected()[1]:
133 self
.liststore
.set(self
.treeview
.get_selection().get_selected()[1], 1, begin
, 2, end
)
139 self
.liststore
.clear()
141 def save(self
, filepath
):
143 xlp
.filepath
= self
.pylooper
.player
.status
.filepath
145 def callback_add(model
, path
, iter):
146 xlp
.add_interval([model
.get_value(iter, 0), model
.get_value(iter, 1), model
.get_value(iter, 2)])
149 self
.liststore
.foreach(callback_add
)
151 with
open(filepath
, 'w') as file:
152 file.write(xlp
.toxml())
155 def open(self
, filepath
):
157 xlp
= XMLLoop(filepath
)
161 oldpath
= self
.pylooper
.player
.status
.filepath
162 self
.pylooper
.player
.status
.filepath
= xlp
.filepath
164 # We need to do this, or when we call self.add, the changed event will
165 # fail with duration = 0
166 if not self
.pylooper
.player
.load():
167 self
.pylooper
.player
.status
.filepath
= oldpath
172 for interval
in xlp
.get_intervals():
173 self
.add(interval
[1], interval
[2], interval
[0])
175 def delete(self
, widget
):
176 treeselection
= self
.treeview
.get_selection()
177 model
, iter = treeselection
.get_selected()
178 if iter and model
.remove(iter):
179 treeselection
.select_iter(iter)
181 def nsecs2str(treeviewcolumn
, cellrenderer
, model
, iter, column
):
182 nsecs
= model
.get_value(iter, column
)
183 cellrenderer
.set_property('text', "%(m)02d:%(s)02d.%(ms)03d" % {
184 'm': nsecs
/ 60000000000,
185 's': (nsecs
/ 1000000000) % 60,
186 'ms': (nsecs
/ 1000000) % 1000})