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']})84 playlistentryobjectfactory=database.dataobjectfactory(PlaylistEntryDataObject) 85 86 #-------------------------------------------------------------------------------81 if data is None or not isinstance(data, PlaylistEntry): 82 return 83 self.update(data.get_db_dict())90129 130 #-------------------------------------------------------------------------------92 return copy.deepcopy(self._data, {})96101 # name needs to set separately 102 self.pl_type=d.get('type', None) 103 self.songs=[x['name'] for x in d.get('songs', [])]104106 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]=v111113 return self._data.get('name', '')115 self._set_or_del('name', v, [''])116 name=property(fget=_get_name, fset=_set_name) 117119 return self._data.get('type', '')121 self._set_or_del('type', v, [''])122 pl_type=property(fget=_get_type, fset=_set_type) 123125 return self._data.get('songs', [])127 self._set_or_del('songs', v, [[]])128 songs=property(fget=_get_songs, fset=_set_songs)132402134 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)213215 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)221223 self._item_list_w.DeleteAllItems() 224 self._pl_list_w.DeleteAllItems() 225 if clear_master: 226 self._master_list_w.DeleteAllItems()227231 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 257259 self._data=dict.get(playlist_key, []) 260 self._master=dict.get(masterlist_key, []) 261 self._clear() 262 self._populate()263265 # 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 284286 _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 result307 308 # called from various widget update callbacks313 """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)318323 self.setdirty(True)324 333337 _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 352354 _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)])364366 _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_list373375 # 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)385387 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)397399 dict[masterlist_key]=self._master_list.GetStrings() 400 dict[playlist_key]=self._build_playlist() 401 return dict
Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sun Jan 24 16:22:16 2010 | http://epydoc.sourceforge.net |