| Trees | Indices | Help |
|
|---|
|
|
1 ### BITPIM
2 ###
3 ### Copyright (C) 2005 Joe Pham <djpham@netzero.net>
4 ###
5 ### This program is free software; you can redistribute it and/or modify
6 ### it under the terms of the BitPim license as detailed in the LICENSE file.
7 ###
8 ### $Id: playlist.py 4209 2007-05-02 23:06:05Z djpham $
9 """
10 Code to handle Playlist items.
11
12 The playlist data includes 2 components: the list of available songs, and
13 the playlist items.
14
15 The format of the Playlist items is standardized. It is a list of dict which
16 has the following standard fields:
17
18 name: string=the name of the play list
19 type: string=the type of this play list. Current supported types are mp3 and wma.
20 songs: [ 'song name', ... ]
21
22 To implement Playlist read/write for a phone module:
23 1. Add 2 entries into Profile._supportedsyncs:
24 ...
25 ('playlist', 'read', 'OVERWRITE'),
26 ('playlist', 'write', 'OVERWRITE'),
27 2. Implement the following 2 methods in your Phone class:
28 def getplaylist(self, result)
29 def saveplaylist(self, result, merge)
30
31 The result dict should have:
32 results[playlist.masterlist_key]=['song name 1', 'song name 2', ...]
33 results[playlist.playlist_key=[playlist.PlaylistEntry, playlist.PlaylistEntry, ..]
34
35 """
36
37 import wx
38 import wx.gizmos as gizmos
39
40 import database
41 import helpids
42 import guihelper
43 import widgets
44
45 # module constants--------------------------------------------------------------
46 playlist_key='playlist'
47 masterlist_key='masterlist'
48 playlists_list='playlists'
49 mp3_type='mp3'
50 wma_type='wma'
51 playlist_type=(mp3_type, wma_type)
52
53 #-------------------------------------------------------------------------------
55 _knownproperties=[]
56 _knownlistproperties=database.basedataobject._knownlistproperties.copy()
57 _knownlistproperties.update({ 'masterlist': ['name'] })
62 masterlistobjectfactory=database.dataobjectfactory(MasterListDataObject)
63
64 #-------------------------------------------------------------------------------
66 _knownproperties=[]
67 _knownlistproperties=database.basedataobject._knownlistproperties.copy()
68 _knownlistproperties.update( { 'playlist': ['name'] })
73 playlistobjectfactory=database.dataobjectfactory(PlaylistDataObject)
74
75 #-------------------------------------------------------------------------------
77 _knownproperties=['type']
78 _knownlistproperties=database.basedataobject._knownlistproperties.copy()
79 _knownlistproperties.update({ 'songs': ['name']})
81 if data is None or not isinstance(data, PlaylistEntry):
82 return
83 self.update(data.get_db_dict())
84 playlistentryobjectfactory=database.dataobjectfactory(PlaylistEntryDataObject)
85
86 #-------------------------------------------------------------------------------
90
92 return copy.deepcopy(self._data, {})
96
101 # name needs to set separately
102 self.pl_type=d.get('type', None)
103 self.songs=[x['name'] for x in d.get('songs', [])]
104
106 if v is None or v in v_list:
107 if self._data.has_key(key):
108 del self._data[key]
109 else:
110 self._data[key]=v
111
113 return self._data.get('name', '')
115 self._set_or_del('name', v, [''])
116 name=property(fget=_get_name, fset=_set_name)
117
119 return self._data.get('type', '')
121 self._set_or_del('type', v, [''])
122 pl_type=property(fget=_get_type, fset=_set_type)
123
125 return self._data.get('songs', [])
127 self._set_or_del('songs', v, [[]])
128 songs=property(fget=_get_songs, fset=_set_songs)
129
130 #-------------------------------------------------------------------------------
132
134 super(PlaylistWidget, self).__init__(parent, -1)
135 self._mw=mainwindow
136 self._data=[]
137 self._master=[]
138 self.ignoredirty=False
139 self.dirty=False
140 # main box sizer
141 vbs=wx.BoxSizer(wx.VERTICAL)
142 # horizontal sizer for the main contents
143 hbs=wx.BoxSizer(wx.HORIZONTAL)
144 # the list box
145 self._item_list=gizmos.EditableListBox(self, -1, 'Play Lists:',
146 style=gizmos.EL_ALLOW_NEW|\
147 gizmos.EL_ALLOW_EDIT|\
148 gizmos.EL_ALLOW_DELETE)
149 self._item_list.GetUpButton().Show(False)
150 self._item_list.GetDownButton().Show(False)
151 self._item_list_w=self._item_list.GetListCtrl()
152 hbs.Add(self._item_list, 1, wx.EXPAND|wx.ALL, border=5)
153 hbs.Add(wx.StaticLine(self, -1, style=wx.LI_VERTICAL), 0,
154 wx.EXPAND|wx.ALL, 5)
155 # the detailed panel
156 hbs1=wx.BoxSizer(wx.HORIZONTAL)
157 # the playlist
158 _vbs1=wx.BoxSizer(wx.VERTICAL)
159 self._pl_list=gizmos.EditableListBox(self, -1, "Play List Content:",
160 style=gizmos.EL_ALLOW_DELETE)
161 self._pl_list_w=self._pl_list.GetListCtrl()
162 _vbs1.Add(self._pl_list, 1, wx.EXPAND, 0)
163 self._count_lbl=wx.StaticText(self, -1, '')
164 _vbs1.Add(self._count_lbl, 0, wx.EXPAND|wx.TOP, 5)
165 hbs1.Add(_vbs1, 1, wx.EXPAND|wx.ALL, 5)
166 _add_btn=wx.Button(self, -1, '<-Add')
167 hbs1.Add(_add_btn, 0, wx.ALL, 5)
168 self._master_list=gizmos.EditableListBox(self, -1, 'Available Songs:', style=0)
169 self._master_list_w=self._master_list.GetListCtrl()
170 self._master_list.GetUpButton().Show(False)
171 self._master_list.GetDownButton().Show(False)
172 hbs1.Add(self._master_list, 1, wx.EXPAND|wx.ALL, 5)
173 hbs.Add(hbs1, 3, wx.EXPAND|wx.ALL, 5)
174 # the bottom buttons
175 hbs1=wx.BoxSizer(wx.HORIZONTAL)
176 self._save_btn=wx.Button(self, wx.ID_SAVE)
177 self._revert_btn=wx.Button(self, wx.ID_REVERT_TO_SAVED)
178 help_btn=wx.Button(self, wx.ID_HELP)
179 hbs1.Add(self._save_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
180 hbs1.Add(help_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
181 hbs1.Add(self._revert_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
182 # all done
183 vbs.Add(hbs, 1, wx.EXPAND|wx.ALL, 5)
184 vbs.Add(wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
185 vbs.Add(hbs1, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
186 self.SetSizer(vbs)
187 self.SetAutoLayout(True)
188 vbs.Fit(self)
189 # event handlers
190 wx.EVT_LIST_ITEM_SELECTED(self._item_list, self._item_list_w.GetId(),
191 self.OnPlaylistSelected)
192 wx.EVT_LIST_BEGIN_LABEL_EDIT(self._item_list, self._item_list_w.GetId(),
193 self.OnStartLabelChanged)
194 wx.EVT_LIST_END_LABEL_EDIT(self._item_list, self._item_list_w.GetId(),
195 self.OnLabelChanged)
196 wx.EVT_BUTTON(self, _add_btn.GetId(), self.OnAdd2Playlist)
197 wx.EVT_BUTTON(self, self._save_btn.GetId(), self.OnSave)
198 wx.EVT_BUTTON(self, self._revert_btn.GetId(), self.OnRevert)
199 wx.EVT_LIST_DELETE_ITEM(self._item_list, self._item_list_w.GetId(),
200 self.OnMakeDirty)
201 wx.EVT_LIST_DELETE_ITEM(self._pl_list, self._pl_list_w.GetId(),
202 self.OnMakeDirty)
203 wx.EVT_BUTTON(self, wx.ID_HELP,
204 lambda _: wx.GetApp().displayhelpid(helpids.ID_TAB_PLAYLIST))
205 wx.EVT_BUTTON(self._pl_list, self._pl_list.GetUpButton().GetId(),
206 self._OnUpDown)
207 wx.EVT_BUTTON(self._pl_list, self._pl_list.GetDownButton().GetId(),
208 self._OnUpDown)
209 # populate data
210 self._populate()
211 # turn on dirty flag
212 self.setdirty(False)
213
215 if self.ignoredirty:
216 return
217 self.dirty=val
218 self._item_list.Enable(not self.dirty)
219 self._save_btn.Enable(self.dirty)
220 self._revert_btn.Enable(self.dirty)
221
223 self._item_list_w.DeleteAllItems()
224 self._pl_list_w.DeleteAllItems()
225 if clear_master:
226 self._master_list_w.DeleteAllItems()
227
231 self._item_list_w.DeleteAllItems()
232 if self._data:
233 self._item_list.SetStrings([e.name for e in self._data])
234 else:
235 self._item_list.SetStrings([])
241 self._pl_list_w.DeleteAllItems()
242 self._count_lbl.SetLabel('')
243 if name is None:
244 return
245 self.ignoredirty=True
246 _list_idx=self._name2idx(name)
247 if _list_idx is not None:
248 self._pl_list.SetStrings(self._data[_list_idx].songs)
249 self._count_lbl.SetLabel('Playlist Size: %d'%len(self._data[_list_idx].songs))
250 self.ignoredirty=False
251 if not self.dirty:
252 self.setdirty(False)
253
257
259 self._data=dict.get(playlist_key, [])
260 self._master=dict.get(masterlist_key, [])
261 self._clear()
262 self._populate()
263
265 # first, save the master list of songs.
266 db_rr={ masterlist_key: MasterListDataObject(dict.get(masterlist_key, [])) }
267 database.ensurerecordtype(db_rr, masterlistobjectfactory)
268 self._mw.database.savemajordict(masterlist_key, db_rr)
269 # now, save the list of playlists
270 _pl_list=dict.get(playlist_key, [])
271 db_rr={ playlists_list: PlaylistDataObject([x.name for x in _pl_list]) }
272 database.ensurerecordtype(db_rr, playlistobjectfactory)
273 self._mw.database.savemajordict(playlists_list, db_rr)
274 # save the playlist entries
275 db_rr={ }
276 for e in _pl_list:
277 db_rr[e.name]=PlaylistEntryDataObject(e)
278 database.ensurerecordtype(db_rr, playlistentryobjectfactory)
279 self._mw.database.savemajordict(playlist_key, db_rr)
280
284
286 _master_dict=self._mw.database.getmajordictvalues(masterlist_key,
287 masterlistobjectfactory)
288 _master_dict=_master_dict.get(masterlist_key, {})
289 result.update( { masterlist_key: \
290 [x['name'] for x in _master_dict.get(masterlist_key, [])] })
291 _pl_list_dict=self._mw.database.getmajordictvalues(playlists_list,
292 playlistobjectfactory)
293 _pl_list_dict=_pl_list_dict.get(playlists_list, {})
294 _pl_entries_dict=self._mw.database.getmajordictvalues(playlist_key,
295 playlistentryobjectfactory)
296 _pl_list=[]
297 for e in _pl_list_dict.get(playlist_key, []):
298 _pl_entry=_pl_entries_dict.get(e['name'], None)
299 if _pl_entry:
300 _entry=PlaylistEntry()
301 _entry.name=e['name']
302 _entry.type=_pl_entry['type']
303 _entry.songs=[x['name'] for x in _pl_entry.get('songs', [])]
304 _pl_list.append(_entry)
305 result.update({playlist_key: _pl_list })
306 return result
307
308 # called from various widget update callbacks
313 """A public function you can call that will set the dirty flag"""
314 if self.dirty or self.ignoredirty:
315 # already dirty, no need to make it worse
316 return
317 self.setdirty(True)
318
323 self.setdirty(True)
324
333
337 _new_name=evt.GetLabel()
338 if _new_name:
339 self.setdirty(True)
340 if self._old_name:
341 self._change_playlist_name(_new_name)
342 else:
343 self._add_playlist_name(_new_name)
344 evt.Skip()
345
346 # kinda redundant given that the playlist does not support the add/delet controls
349
352
354 _pl_idx=self._item_list_w.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
355 _master_idx=self._master_list_w.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
356 if _pl_idx==-1 or _master_idx==-1:
357 # no selection
358 return
359 _entry_idx=self._name2idx(self._item_list_w.GetItemText(_pl_idx))
360 if _entry_idx is not None:
361 self.setdirty(True)
362 self._pl_list.SetStrings(self._pl_list.GetStrings()+\
363 [self._master_list_w.GetItemText(_master_idx)])
364
366 _pl_list=[]
367 for _name in self._item_list.GetStrings():
368 if _name:
369 _idx=self._name2idx(_name)
370 if _idx is not None:
371 _pl_list.append(self._data[_idx])
372 return _pl_list
373
375 # save the current playlist
376 _pl_idx=self._item_list_w.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
377 if _pl_idx!=-1:
378 _entry_idx=self._name2idx(self._item_list_w.GetItemText(_pl_idx))
379 if _entry_idx is not None:
380 self._data[_entry_idx].songs=self._pl_list.GetStrings()
381 # create data dicts & save them to db
382 self._save_to_db({ masterlist_key: self._master_list.GetStrings(),
383 playlist_key: self._build_playlist() })
384 self.setdirty(False)
385
387 self._item_list.Enable()
388 _pl_idx=self._item_list_w.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
389 # discard all changes
390 _res={}
391 self.getfromfs(_res)
392 self.populate(_res)
393 if _pl_idx!=wx.NOT_FOUND:
394 self._item_list_w.SetItemState(_pl_idx, wx.LIST_STATE_SELECTED,
395 wx.LIST_MASK_STATE)
396 self.setdirty(False)
397
399 dict[masterlist_key]=self._master_list.GetStrings()
400 dict[playlist_key]=self._build_playlist()
401 return dict
402
| Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sun Jan 24 16:22:16 2010 | http://epydoc.sourceforge.net |