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:
parent
d58e033689
commit
97dc36b8fb
@ -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):
|
||||
|
@ -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 ):
|
||||
|
@ -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>
|
||||
|
@ -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 ) )
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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">
|
||||
|
19
todo.txt
19
todo.txt
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user