# Copyright (c) 2004-5 Marek Hnilica. All rights reserved. # Provides unsaved changes textctrl, highlighting, etc. # Distributed under GPL version 2, or (at your option) later import wx import os,types,string,stat import AllTag,mboxFileUtils from utils import * class PendingList(wx.TextCtrl): def __init__(self,parent,tracklist): self.ForceOverwrite=0 self.Tracks=tracklist self.MainWindow=parent.GetParent().GetParent().GetParent().GetParent() wx.TextCtrl.__init__(self,parent,wx.NewId(),style=wx.SIMPLE_BORDER|wx.TE_MULTILINE|wx.TE_DONTWRAP|wx.TE_READONLY) self.AlreadyDoneDirs=[] self.AlreadyChmodedDirs=[] self.OperationList=[] self.ToolbarButtonsState=1 def DoRename(self): if self.OperationList: a=wx.MessageDialog(self.MainWindow,'All changes must be saved before creating directory structure.\nSave all changes?','Proceed?',wx.YES_NO) if a.ShowModal()==wx.ID_YES: self.DoIt() self.ContinueWithDir=1 a.Destroy() else: self.ContinueWithDir=1 if self.ContinueWithDir: Errors=[] for oper in self.RenWithDir: try: mboxFileUtils.renobj(SrcName=oper[1],DstName=oper[2]+'.mboxtempname',wxwindow=self.MainWindow) mboxFileUtils.renobj(SrcName=oper[2]+'.mboxtempname',DstName=oper[2],wxwindow=self.MainWindow) except: Errors.append('Failed to rename file %s to %s'%(oper[1],oper[2])) if Errors: GeneralError(None,label='Errors:',text=string.join(Errors,'\n')) self.Restart() self.MainWindow.Tracks.EvaluateTag(self.MainWindow.Tracks.CurrentDir,self.MainWindow.Tracks.TagType) self.MainWindow.ReloadDirTree('') return else: return def ShowOperation(self): self.Restart(delete=0) for OpPos in range(len(self.OperationList)): Op0=self.OperationList[OpPos][0] Op1=self.OperationList[OpPos][1] # for chmod-dir which has only one argument try: Op2=self.OperationList[OpPos][2] except IndexError: pass if Op0=='rename': InsPo=self.GetInsertionPoint() self.WriteText('Rename file %s to %s\n'%(os.path.basename(Op1),os.path.basename(Op2))) self.SetStyle(InsPo,len(self.GetValue()), wx.TextAttr((39,42,185),'WHITE')) elif Op0=='chmod': InsPo=self.GetInsertionPoint() self.WriteText('Change permission of %s\n'%os.path.basename(Op1)) self.SetStyle(InsPo,len(self.GetValue()), wx.TextAttr((255,27,27),'WHITE')) elif Op0=='tag': WillAddPicture=0 Sentence='Set tags in %s to these values: '%os.path.basename(Op1) for i in Op2.keys(): if not i=='APIC': Sentence+=i.capitalize()+': \''+Op2[i]+'\' ' else: WillAddPicture=1 if WillAddPicture: Sentence+=' and add picture.\n' else: Sentence+='\n' self.WriteText(Sentence) elif Op0=='chmod-dir': InsPo=self.GetInsertionPoint() self.WriteText('Change permission of directory %s\n'%Op1) self.SetStyle(InsPo,len(self.GetValue()), wx.TextAttr((255,27,27),'WHITE')) def AddOperation(self,Operation): if Operation[0]=='tag': TestName=Operation[1] reversed=self.OperationList[:] reversed.reverse() WillAddPicture=0 changed=0 for op in reversed: if op[0]=='rename' and op[2]==TestName: TestName=op[1] changed=1 if not os.access(TestName,os.W_OK+os.R_OK): if os.stat(TestName)[stat.ST_UID]!=os.getuid(): raise IOError else: if changed: toadd=op[1] else: toadd=Operation[1] self.AddOperation(['chmod',toadd,420]) # Modifies tag in main tracklist for TagPos in range(len(self.Tracks.Tag)): if self.Tracks.Tag[TagPos][0]==Operation[1]: NewList=list(self.Tracks.Tag[TagPos]) TagDict=Operation[2] if TagDict.has_key('ARTIST'): NewList[2]=TagDict['ARTIST'] if TagDict.has_key('ALBUM'): NewList[3]=TagDict['ALBUM'] if TagDict.has_key('GENRE'): NewList[4]=TagDict['GENRE'] if TagDict.has_key('YEAR'): NewList[6]=TagDict['YEAR'] if TagDict.has_key('COMMENT'): NewList[9]=TagDict['COMMENT'] if TagDict.has_key('TITLE'): NewList[1]=TagDict['TITLE'] if TagDict.has_key('TRACKNUMBER'): NewList[5]=TagDict['TRACKNUMBER'] if TagDict.has_key('APIC'): NewList[10]=TagDict['APIC'] self.Tracks.Tag[TagPos]=NewList elif Operation[0]=='rename': # This is ugly code, but it seems to work NewDirName=os.path.dirname(Operation[2]) # len(Operation)!=4 is needed not to create dir structure if os.path.exists(NewDirName) and len(Operation)!=4: # Check whether we can chmod if not os.access(NewDirName,os.W_OK): if os.stat(NewDirName)[stat.ST_UID]!=os.getuid(): raise IOError else: self.AddOperation(['chmod-dir',os.path.abspath(NewDirName)]) else: OldDirName=os.path.dirname(Operation[1]) # same as above if not os.access(OldDirName,os.W_OK): if os.stat(OldDirName)[stat.ST_UID]!=os.getuid(): raise IOError else: self.AddOperation(['chmod-dir',os.path.abspath(OldDirName)]) # we need to save all changes before attempting to create directory structure if len(Operation)==4: # creates list and eventually asks about saving if Operation[3]=='init': # list of operations to do self.RenWithDir=[Operation] return # renames all the files using mboxFIleUtils without DoIt() elif Operation[3]=='all': self.RenWithDir.append(Operation) self.ContinueWithDir=0 self.DoRename() else: self.RenWithDir.append(Operation) return # modifies tag in main tracklist for TagPos in range(len(self.Tracks.Tag)): if self.Tracks.Tag[TagPos][0]==Operation[1]: NewList=list(self.Tracks.Tag[TagPos]) NewList[0]=Operation[2] self.Tracks.Tag[TagPos]=NewList elif Operation[0]=='chmod-dir': if not Operation[1] in self.AlreadyChmodedDirs: self.AlreadyChmodedDirs.append(Operation[1]) self.OperationList.append(Operation) if not Operation[0]=='chmod-dir': self.OperationList.append(Operation) if len(Operation)==4: self.Restart() self.ToolbarButtonsState=0 def DoIt(self,ReallyDoIt=1): if not ReallyDoIt: self.ShowOperation() return ProgDiag=wx.ProgressDialog('Please wait','\t\t\t\t\t\t\t\t\t\t',len(self.OperationList),None,wx.PD_APP_MODAL|wx.PD_AUTO_HIDE) Pos=0 Errors=[] for Operation in self.OperationList: if Operation[0]=='tag': ProgDiag.Update(Pos,'writing to %s'%os.path.basename(Operation[1])) try: AllTag.WriteTag(Operation[1],Operation[2]) except: Errors.append('Failed to write tags to file %s'%Operation[1]) if Operation[0]=='chmod': ProgDiag.Update(Pos,'changing permission of %s'%os.path.basename(Operation[1])) try: os.chmod(Operation[1],Operation[2]) except: Errors.append('Failed to rename file %s'%Operation[1]) if Operation[0]=='chmod-dir': if not Operation[0] in self.AlreadyDoneDirs: ProgDiag.Update(Pos,'changing permission of %s'%os.path.basename(Operation[1])) os.system('chmod 755 %s'%Operation[1]) self.AlreadyDoneDirs.append(Operation[0]) if Operation[0]=='rename': self.ApplyToAllId=wx.NewId() ProgDiag.Update(Pos,'renaming %s'%os.path.basename(Operation[1])) # try: if os.path.exists(Operation[2]) and not os.path.samefile(Operation[1],Operation[2]): if not self.ForceOverwrite: val=OverDialog(self.MainWindow,Operation[1],Operation[2],self.ApplyToAllId) if val.ID==wx.ID_YES: mboxFileUtils.renobj(SrcName=Operation[1],DstName=Operation[2]+'.mboxtempname',wxwindow=self.MainWindow) mboxFileUtils.renobj(SrcName=Operation[2]+'.mboxtempname',DstName=Operation[2],wxwindow=self.MainWindow) if val.ID==wx.ID_NO: continue if val.ID==wx.ID_CANCEL: break if val.ID==self.ApplyToAllId: mboxFileUtils.renobj(SrcName=Operation[1],DstName=Operation[2]+'.mboxtempname',wxwindow=self.MainWindow) mboxFileUtils.renobj(SrcName=Operation[2]+'.mboxtempname',DstName=Operation[2],wxwindow=self.MainWindow) self.ForceOverwrite=1 else: mboxFileUtils.renobj(SrcName=Operation[1],DstName=Operation[2]+'.mboxtempname',wxwindow=self.MainWindow) mboxFileUtils.renobj(SrcName=Operation[2]+'.mboxtempname',DstName=Operation[2],wxwindow=self.MainWindow) else: mboxFileUtils.renobj(SrcName=Operation[1],DstName=Operation[2]+'.mboxtempname',wxwindow=self.MainWindow) mboxFileUtils.renobj(SrcName=Operation[2]+'.mboxtempname',DstName=Operation[2],wxwindow=self.MainWindow) # except: # Errors.append('Failed to rename file %s to %s'%(Operation[1],Operation[2])) # for multiple-times renamed files # for i in range(len(self.OperationList)): # if self.OperationList[i][1]==Operation[2]: # self.OperationList[i]=[self.OperationList[i][0],string.join(NewName,''),self.OperationList[i][2]] Pos+=1 if Errors: GeneralError(None,label='Errors:',text=string.join(Errors,'\n')) ProgDiag.Hide() ProgDiag.Destroy() self.Restart() self.MainWindow.Tracks.EvaluateTag(self.MainWindow.Tracks.CurrentDir,self.MainWindow.Tracks.TagType) def Restart(self,delete=1): if delete: self.OperationList=[] self.AlreadyChmodedDirs=[] self.Clear() self.AlreadyDoneDirs=[] self.ToolbarButtonsState=1 self.ForceOverwrite=0 def ShowUpdate(self,WillExit=0): if len(self.OperationList)>0: diag=wx.MessageDialog(self,'Do you want to save changes?','Unsaved changes',wx.YES|wx.NO|wx.CANCEL|wx.ICON_INFORMATION) RetVal=diag.ShowModal() if RetVal==wx.ID_YES: self.DoIt() elif RetVal==wx.ID_NO: self.Restart() if not WillExit: self.MainWindow.Tracks.EvaluateTag(self.MainWindow.Tracks.CurrentDir,self.MainWindow.Tracks.TagType) elif RetVal==wx.ID_CANCEL: return 'cancel' class OverDialog(wx.Dialog): def __init__(self,MainWindow,src,dst,ApplyToAllId): wx.Dialog.__init__(self,MainWindow,-1,title='Overwriting confirmation') ControlsSizer=wx.BoxSizer(wx.HORIZONTAL) ControlsSizer.AddMany([ (wx.Button(self,wx.ID_YES),0), (20,0), (wx.Button(self,wx.ID_NO),0), (20,0), (wx.Button(self,ApplyToAllId,'Yes to &all'),0), (20,0), (wx.Button(self,wx.ID_CANCEL),0), ]) MainSizer=wx.BoxSizer(wx.VERTICAL) MainSizer.AddMany([ (wx.StaticText(self,-1,'You\'re about to rename file %s to %s'%(os.path.basename(src),os.path.basename(dst)))), (wx.StaticText(self,-1,'Destination filename already exists. Overwrite?\n\n')), (ControlsSizer,0), ]) for i in [wx.ID_YES,wx.ID_NO,ApplyToAllId,wx.ID_CANCEL]: wx.EVT_BUTTON(self,i,self.Cancel) MainSizer.Fit(self) self.SetSizer(MainSizer) self.ShowModal() def Cancel(self,evt): self.ID=evt.GetId() self.Destroy()