Implemented batch export to zip

more multi-file/batch enhancements

git-svn-id: http://comictagger.googlecode.com/svn/trunk@315 6c5673fe-1810-88d6-992b-cd32ca31540c
This commit is contained in:
beville 2013-01-20 08:36:21 +00:00
parent d58e033689
commit 97dc36b8fb
8 changed files with 209 additions and 45 deletions

View File

@ -477,11 +477,11 @@ class ComicArchive:
def isFolder( self ):
return self.archive_type == self.ArchiveType.Folder
def isWritable( self ):
def isWritable( self, check_rar_status=True ):
if self.archive_type == self.ArchiveType.Unknown :
return False
elif self.isRar() and self.archiver.rar_exe_path is None:
elif check_rar_status and self.isRar() and self.archiver.rar_exe_path is None:
return False
elif not os.access(self.path, os.W_OK):

View File

@ -1,6 +1,6 @@
# coding=utf-8
"""
A PyQt4 widget for managing list of files
A PyQt4 widget for managing list of comic archive files
"""
"""
@ -56,6 +56,15 @@ class FileSelectionList(QWidget):
selectionChanged = pyqtSignal(QVariant)
listCleared = pyqtSignal()
fileColNum = 0
CRFlagColNum = 1
CBLFlagColNum = 2
typeColNum = 3
readonlyColNum = 4
folderColNum = 5
dataColNum = fileColNum
def __init__(self, parent , settings ):
super(FileSelectionList, self).__init__(parent)
@ -164,14 +173,21 @@ class FileSelectionList(QWidget):
self.twList.setSortingEnabled(True)
#Maybe set a max size??
# Adjust column size
self.twList.resizeColumnsToContents()
self.twList.setColumnWidth(FileSelectionList.CRFlagColNum, 35)
self.twList.setColumnWidth(FileSelectionList.CBLFlagColNum, 35)
self.twList.setColumnWidth(FileSelectionList.readonlyColNum, 35)
self.twList.setColumnWidth(FileSelectionList.typeColNum, 45)
if self.twList.columnWidth(FileSelectionList.fileColNum) > 250:
self.twList.setColumnWidth(FileSelectionList.fileColNum, 250)
if self.twList.columnWidth(FileSelectionList.folderColNum ) > 200:
self.twList.setColumnWidth(FileSelectionList.folderColNum, 200)
def isListDupe( self, path ):
r = 0
while r < self.twList.rowCount():
fi = self.twList.item(r, 0).data( Qt.UserRole ).toPyObject()
fi = self.twList.item(r, FileSelectionList.dataColNum).data( Qt.UserRole ).toPyObject()
if fi.ca.path == path:
return True
r = r + 1
@ -180,6 +196,7 @@ class FileSelectionList(QWidget):
def addPathItem( self, path):
path = unicode( path )
path = os.path.abspath( path )
#print "processing", path
if self.isListDupe(path):
@ -200,33 +217,44 @@ class FileSelectionList(QWidget):
folder_item = QTableWidgetItem()
cix_item = FileTableWidgetItem()
cbi_item = FileTableWidgetItem()
readonly_item = FileTableWidgetItem()
type_item = QTableWidgetItem()
filename_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
filename_item.setData( Qt.UserRole , fi )
self.twList.setItem(row, 0, filename_item)
self.twList.setItem(row, FileSelectionList.fileColNum, filename_item)
folder_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
self.twList.setItem(row, 1, folder_item)
self.twList.setItem(row, FileSelectionList.folderColNum, folder_item)
type_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
self.twList.setItem(row, FileSelectionList.typeColNum, type_item)
cix_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
cix_item.setTextAlignment(Qt.AlignHCenter)
self.twList.setItem(row, 2, cix_item)
self.twList.setItem(row, FileSelectionList.CRFlagColNum, cix_item)
cbi_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
cbi_item.setTextAlignment(Qt.AlignHCenter)
self.twList.setItem(row, 3, cbi_item)
self.twList.setItem(row, FileSelectionList.CBLFlagColNum, cbi_item)
readonly_item.setFlags(Qt.ItemIsSelectable| Qt.ItemIsEnabled)
readonly_item.setTextAlignment(Qt.AlignHCenter)
self.twList.setItem(row, FileSelectionList.readonlyColNum, readonly_item)
self.updateRow( row )
return row
def updateRow( self, row ):
fi = self.twList.item( row, 0 ).data( Qt.UserRole ).toPyObject()
fi = self.twList.item( row, FileSelectionList.dataColNum ).data( Qt.UserRole ).toPyObject()
filename_item = self.twList.item( row, 0 )
folder_item = self.twList.item( row, 1 )
cix_item = self.twList.item( row, 2 )
cbi_item = self.twList.item( row, 3 )
filename_item = self.twList.item( row, FileSelectionList.fileColNum )
folder_item = self.twList.item( row, FileSelectionList.folderColNum )
cix_item = self.twList.item( row, FileSelectionList.CRFlagColNum )
cbi_item = self.twList.item( row, FileSelectionList.CBLFlagColNum )
type_item = self.twList.item( row, FileSelectionList.typeColNum )
readonly_item = self.twList.item( row, FileSelectionList.readonlyColNum )
item_text = os.path.split(fi.ca.path)[0]
folder_item.setText( item_text )
@ -236,6 +264,16 @@ class FileSelectionList(QWidget):
filename_item.setText( item_text )
filename_item.setData( Qt.ToolTipRole, item_text )
if fi.ca.isZip():
item_text = "ZIP"
elif fi.ca.isRar():
item_text = "RAR"
else:
item_text = ""
type_item.setText( item_text )
type_item.setData( Qt.ToolTipRole, item_text )
if fi.ca.hasCIX():
cix_item.setCheckState(Qt.Checked)
cix_item.setData(Qt.UserRole, True)
@ -249,6 +287,14 @@ class FileSelectionList(QWidget):
else:
cbi_item.setData(Qt.UserRole, False)
cbi_item.setCheckState(Qt.Unchecked)
if not fi.ca.isWritable():
readonly_item.setCheckState(Qt.Checked)
readonly_item.setData(Qt.UserRole, True)
else:
readonly_item.setData(Qt.UserRole, False)
readonly_item.setCheckState(Qt.Unchecked)
# Reading these will force them into the ComicArchive's cache
fi.ca.readCIX()
@ -257,7 +303,7 @@ class FileSelectionList(QWidget):
def getSelectedArchiveList( self ):
ca_list = []
for r in range( self.twList.rowCount() ):
item = self.twList.item(r, 0)
item = self.twList.item(r, FileSelectionList.dataColNum)
if self.twList.isItemSelected(item):
fi = item.data( Qt.UserRole ).toPyObject()
ca_list.append(fi.ca)
@ -270,7 +316,7 @@ class FileSelectionList(QWidget):
def updateSelectedRows( self ):
self.twList.setSortingEnabled(False)
for r in range( self.twList.rowCount() ):
item = self.twList.item(r, 0)
item = self.twList.item(r, FileSelectionList.dataColNum)
if self.twList.isItemSelected(item):
self.updateRow( r )
self.twList.setSortingEnabled(True)
@ -297,7 +343,7 @@ class FileSelectionList(QWidget):
QTimer.singleShot(1, self.revertSelection)
return
fi = self.twList.item( new_idx, 0 ).data( Qt.UserRole ).toPyObject()
fi = self.twList.item( new_idx, FileSelectionList.dataColNum ).data( Qt.UserRole ).toPyObject()
self.selectionChanged.emit( QVariant(fi))
def revertSelection( self ):

View File

@ -42,11 +42,6 @@
<string>File</string>
</property>
</column>
<column>
<property name="text">
<string>Path</string>
</property>
</column>
<column>
<property name="text">
<string>CR</string>
@ -66,6 +61,21 @@
<set>AlignHCenter|AlignVCenter|AlignCenter</set>
</property>
</column>
<column>
<property name="text">
<string>Type</string>
</property>
</column>
<column>
<property name="text">
<string>R/O</string>
</property>
</column>
<column>
<property name="text">
<string>Folder</string>
</property>
</column>
</widget>
</item>
</layout>

View File

@ -48,23 +48,55 @@ class RenameWindow(QtGui.QDialog):
self.renamer.setSmartCleanup( self.settings.rename_use_smart_string_cleanup )
def doPreview( self ):
preview = ""
self.rename_list = []
while self.twList.rowCount() > 0:
self.twList.removeRow(0)
self.twList.setSortingEnabled(False)
for ca in self.comic_archive_list:
md = ca.readMetadata(self.data_style)
if md.isEmpty:
md = ca.metadataFromFilename()
self.renamer.setMetadata( md )
new_name = self.renamer.determineName( ca.path )
preview += u"\"{0}\" ==> \"{1}\"\n".format( ca.path, new_name )
row = self.twList.rowCount()
self.twList.insertRow( row )
folder_item = QtGui.QTableWidgetItem()
old_name_item = QtGui.QTableWidgetItem()
new_name_item = QtGui.QTableWidgetItem()
item_text = os.path.split(ca.path)[0]
folder_item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 0, folder_item)
folder_item.setText( item_text )
folder_item.setData( QtCore.Qt.ToolTipRole, item_text )
item_text = os.path.split(ca.path)[1]
old_name_item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 1, old_name_item)
old_name_item.setText( item_text )
old_name_item.setData( QtCore.Qt.ToolTipRole, item_text )
new_name_item.setFlags(QtCore.Qt.ItemIsSelectable| QtCore.Qt.ItemIsEnabled)
self.twList.setItem(row, 2, new_name_item)
new_name_item.setText( new_name )
new_name_item.setData( QtCore.Qt.ToolTipRole, new_name )
dict_item = dict()
dict_item['archive'] = ca
dict_item['new_name'] = new_name
self.rename_list.append( dict_item)
self.textEdit.setPlainText( preview )
# Adjust column sizes
self.twList.setVisible( False )
self.twList.resizeColumnsToContents()
self.twList.setVisible( True )
if self.twList.columnWidth(0) > 200:
self.twList.setColumnWidth(0, 200)
self.twList.setSortingEnabled(True)
def modifySettings( self ):
settingswin = SettingsWindow( self, self.settings )
@ -94,7 +126,7 @@ class RenameWindow(QtGui.QDialog):
print item['new_name'] , "Filename is already good!"
continue
if not item['archive'].isWritable():
if not item['archive'].isWritable(check_rar_status=False):
continue
folder = os.path.dirname( os.path.abspath( item['archive'].path ) )

View File

@ -9,8 +9,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>813</width>
<height>261</height>
<width>801</width>
<height>360</height>
</rect>
</property>
<property name="windowTitle">
@ -30,10 +30,31 @@
</widget>
</item>
<item row="2" column="0">
<widget class="QTextEdit" name="textEdit">
<property name="readOnly">
<bool>true</bool>
<widget class="QTableWidget" name="twList">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="textElideMode">
<enum>Qt::ElideMiddle</enum>
</property>
<column>
<property name="text">
<string>Folder</string>
</property>
</column>
<column>
<property name="text">
<string>Old Name</string>
</property>
</column>
<column>
<property name="text">
<string>New Name</string>
</property>
</column>
</widget>
</item>
</layout>

View File

@ -167,6 +167,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.fileSelectionList.addAppAction( self.actionAutoSearch )
self.fileSelectionList.addAppAction( self.actionRename )
self.fileSelectionList.addAppAction( self.actionRemoveAuto )
self.fileSelectionList.addAppAction( self.actionRepackage )
if len(file_list) != 0:
self.fileSelectionList.addPathList( file_list )
@ -319,7 +320,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.toolBar.addAction( self.actionAutoSearch )
self.toolBar.addAction( self.actionClearEntryForm )
self.toolBar.addAction( self.actionPageBrowser )
"""
def repackageArchive( self ):
if self.comic_archive is not None:
if self.comic_archive.isZip():
@ -362,7 +363,57 @@ class TaggerWindow( QtGui.QMainWindow):
if not retcode:
QtGui.QMessageBox.information(self, self.tr("Export as Zip Archive"), self.tr("An error occure while exporting."))
"""
#ATB2
def repackageArchive( self ):
ca_list = self.fileSelectionList.getSelectedArchiveList()
rar_count = 0
for ca in ca_list:
if ca.isRar( ):
rar_count += 1
if rar_count == 0:
QtGui.QMessageBox.information(self, self.tr("Export as Zip Archive"), self.tr("No RAR archives selected!"))
return
if not self.dirtyFlagVerification( "Export as Zip Archive",
"If export archives as Zip now, unsaved data in the form may be lost. Are you sure?"):
return
if rar_count != 0:
reply = QtGui.QMessageBox.question(self,
self.tr("Export Archives"),
self.tr("Are you sure you wish to export {0} archive(s) to Zip format?".format(rar_count)),
QtGui.QMessageBox.Yes, QtGui.QMessageBox.No )
if reply == QtGui.QMessageBox.No:
return
progdialog = QtGui.QProgressDialog("", "Cancel", 0, rar_count, self)
progdialog.setWindowTitle( "Exporting as ZIP" )
progdialog.setWindowModality(QtCore.Qt.WindowModal)
prog_idx = 0
for ca in ca_list:
if ca.isRar():
QtCore.QCoreApplication.processEvents()
if progdialog.wasCanceled():
break
prog_idx += 1
progdialog.setValue(prog_idx)
export_name = os.path.splitext(ca.path)[0] + ".cbz"
export_name = utils.unique_file( export_name )
retcode = ca.exportAsZip( export_name )
if not retcode:
QtGui.QMessageBox.information(self, self.tr("Export as Zip Archive"),
self.tr("An error occure while exporting {0}. Batch operation aborted!".format(ca.path)))
break
progdialog.close()
# ATB maybe show a summary of files created here...?
def aboutApp( self ):
website = "http://code.google.com/p/comictagger"
@ -444,7 +495,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.actionRemoveCRTags.setEnabled( True )
self.actionRemoveCBLTags.setEnabled( True )
self.actionWrite_Tags.setEnabled( False )
self.actionRepackage.setEnabled(False)
#self.actionRepackage.setEnabled(False)
self.actionViewRawCBLTags.setEnabled( False )
self.actionViewRawCRTags.setEnabled( False )
self.actionParse_Filename.setEnabled( False )
@ -1420,6 +1471,7 @@ class TaggerWindow( QtGui.QMainWindow):
self.comic_archive = None
self.clearForm()
self.settings.last_opened_folder = os.path.abspath(os.path.split(comic_archive.path)[0])
self.comic_archive = comic_archive
self.metadata = self.comic_archive.readMetadata(self.load_data_style)
if self.metadata is None:

View File

@ -1389,7 +1389,7 @@
</action>
<action name="actionRemoveAuto">
<property name="text">
<string>Remove Selected Tag Style</string>
<string>Remove Current 'Modify' Tag Style</string>
</property>
</action>
<action name="actionRename">

View File

@ -14,23 +14,26 @@ Multi-file:
Batch Tag Copy
Verify overwrites
Export to CBZ:
start dialog with:
option to delete originals
option to add to list
option to stop current export if file already exists
maybe show a summary of files created at end
Rename
maybe make preview a table with checkboxes?
Export to CBZ?
check-box for rows?
Filelist:
Add archive type column
add read-only column
Better column sizing
Text display to cut out middle if too short?
-----------------------------------------------------
Bugs
-----------------------------------------------------
Ultimate Spider-Man files can't be read
---Maybe the foldername in the archive?
Last opened folder memory??
-----------------------------------------------------
Big Future Features