mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Bulk renaming of selected files
This commit is contained in:
parent
71aeed7cb5
commit
95ed2862a6
@ -88,6 +88,7 @@ class Boss(QObject):
|
||||
fl.delete_requested.connect(self.delete_requested)
|
||||
fl.reorder_spine.connect(self.reorder_spine)
|
||||
fl.rename_requested.connect(self.rename_requested)
|
||||
fl.bulk_rename_requested.connect(self.bulk_rename_requested)
|
||||
fl.edit_file.connect(self.edit_file_requested)
|
||||
fl.merge_requested.connect(self.merge_requested)
|
||||
fl.mark_requested.connect(self.mark_requested)
|
||||
@ -338,18 +339,26 @@ class Boss(QObject):
|
||||
'confirm-urlunsafe-change', parent=self.gui, title=_('Are you sure?'), config_set=tprefs):
|
||||
return
|
||||
self.add_savepoint(_('Rename %s') % oldname)
|
||||
name_map = {oldname:newname}
|
||||
self.gui.blocking_job(
|
||||
'rename_file', _('Renaming and updating links...'), partial(self.rename_done, oldname, newname),
|
||||
rename_files, current_container(), {oldname: newname})
|
||||
'rename_file', _('Renaming and updating links...'), partial(self.rename_done, name_map),
|
||||
rename_files, current_container(), name_map)
|
||||
|
||||
def rename_done(self, oldname, newname, job):
|
||||
def bulk_rename_requested(self, name_map):
|
||||
self.commit_all_editors_to_container()
|
||||
self.add_savepoint(_('Bulk rename'))
|
||||
self.gui.blocking_job(
|
||||
'bulk_rename_files', _('Renaming and updating links...'), partial(self.rename_done, name_map),
|
||||
rename_files, current_container(), name_map)
|
||||
|
||||
def rename_done(self, name_map, job):
|
||||
if job.traceback is not None:
|
||||
self.rewind_savepoint()
|
||||
return error_dialog(self.gui, _('Failed to rename files'),
|
||||
_('Failed to rename files, click Show details for more information.'),
|
||||
det_msg=job.traceback, show=True)
|
||||
self.gui.file_list.build(current_container())
|
||||
self.set_modified()
|
||||
for oldname, newname in name_map.iteritems():
|
||||
if oldname in editors:
|
||||
editors[newname] = editors.pop(oldname)
|
||||
self.gui.central.rename_editor(editors[newname], newname)
|
||||
|
@ -15,7 +15,8 @@ import sip
|
||||
from PyQt4.Qt import (
|
||||
QWidget, QTreeWidget, QGridLayout, QSize, Qt, QTreeWidgetItem, QIcon, QFont,
|
||||
QStyledItemDelegate, QStyle, QPixmap, QPainter, pyqtSignal, QMenu, QTimer,
|
||||
QDialogButtonBox, QDialog, QLabel, QLineEdit, QVBoxLayout, QScrollArea, QRadioButton)
|
||||
QDialogButtonBox, QDialog, QLabel, QLineEdit, QVBoxLayout, QScrollArea,
|
||||
QRadioButton, QFormLayout, QSpinBox)
|
||||
|
||||
from calibre import human_readable, sanitize_file_name_unicode
|
||||
from calibre.ebooks.oeb.base import OEB_STYLES, OEB_DOCS
|
||||
@ -97,6 +98,7 @@ class FileList(QTreeWidget):
|
||||
delete_requested = pyqtSignal(object, object)
|
||||
reorder_spine = pyqtSignal(object)
|
||||
rename_requested = pyqtSignal(object, object)
|
||||
bulk_rename_requested = pyqtSignal(object)
|
||||
edit_file = pyqtSignal(object, object, object)
|
||||
merge_requested = pyqtSignal(object, object, object)
|
||||
mark_requested = pyqtSignal(object, object)
|
||||
@ -350,7 +352,9 @@ class FileList(QTreeWidget):
|
||||
self.set_state(state)
|
||||
|
||||
if self.current_edited_name:
|
||||
self.mark_item_as_current(self.current_edited_name)
|
||||
item = self.item_from_name(self.current_edited_name)
|
||||
if item is not None:
|
||||
self.mark_item_as_current(item)
|
||||
|
||||
def show_context_menu(self, point):
|
||||
item = self.itemAt(point)
|
||||
@ -380,6 +384,8 @@ class FileList(QTreeWidget):
|
||||
|
||||
if num > 0:
|
||||
m.addSeparator()
|
||||
if num > 1:
|
||||
m.addAction(QIcon(I('modified.png')), _('&Bulk rename selected files'), self.request_bulk_rename)
|
||||
m.addAction(QIcon(I('trash.png')), _('&Delete selected files'), self.request_delete)
|
||||
m.addSeparator()
|
||||
|
||||
@ -435,6 +441,42 @@ class FileList(QTreeWidget):
|
||||
else:
|
||||
return QTreeWidget.keyPressEvent(self, ev)
|
||||
|
||||
def request_bulk_rename(self):
|
||||
names = {unicode(item.data(0, NAME_ROLE).toString()) for item in self.selectedItems()}
|
||||
bad = names & current_container().names_that_must_not_be_changed
|
||||
if bad:
|
||||
return error_dialog(self, _('Cannot rename'),
|
||||
_('The file(s) %s cannot be renamed.') % ('<b>%s</b>' % ', '.join(bad)), show=True)
|
||||
names = sorted(names, key=self.index_of_name)
|
||||
d = QDialog(self)
|
||||
d.l = l = QFormLayout(d)
|
||||
d.setLayout(l)
|
||||
d.prefix = p = QLineEdit(d)
|
||||
p.setText(_('Chapter-'))
|
||||
p.selectAll()
|
||||
d.la = la = QLabel(_(
|
||||
'All selected files will be renamed to the form prefix-number'))
|
||||
l.addRow(la)
|
||||
l.addRow(_('&Prefix:'), p)
|
||||
d.num = num = QSpinBox(d)
|
||||
num.setMinimum(0), num.setValue(1), num.setMaximum(1000)
|
||||
l.addRow(_('Starting &number:'), num)
|
||||
d.bb = bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
||||
bb.accepted.connect(d.accept), bb.rejected.connect(d.reject)
|
||||
l.addRow(bb)
|
||||
if d.exec_() == d.Accepted:
|
||||
prefix = sanitize_file_name_unicode(unicode(d.prefix.text()))
|
||||
num = d.num.value()
|
||||
largest = num + len(names) - 1
|
||||
fmt = '%0{0}d'.format(len(str(largest)))
|
||||
def change_name(name, num):
|
||||
parts = name.split('/')
|
||||
base, ext = parts[-1].rpartition('.')[0::2]
|
||||
parts[-1] = prefix + (fmt % num) + '.' + ext
|
||||
return '/'.join(parts)
|
||||
name_map = {n:change_name(n, num + i) for i, n in enumerate(names)}
|
||||
self.bulk_rename_requested.emit(name_map)
|
||||
|
||||
def request_delete(self):
|
||||
names = {unicode(item.data(0, NAME_ROLE).toString()) for item in self.selectedItems()}
|
||||
bad = names & current_container().names_that_must_not_be_removed
|
||||
@ -673,6 +715,7 @@ class FileListWidget(QWidget):
|
||||
delete_requested = pyqtSignal(object, object)
|
||||
reorder_spine = pyqtSignal(object)
|
||||
rename_requested = pyqtSignal(object, object)
|
||||
bulk_rename_requested = pyqtSignal(object)
|
||||
edit_file = pyqtSignal(object, object, object)
|
||||
merge_requested = pyqtSignal(object, object, object)
|
||||
mark_requested = pyqtSignal(object, object)
|
||||
@ -687,7 +730,7 @@ class FileListWidget(QWidget):
|
||||
self.layout().setContentsMargins(0, 0, 0, 0)
|
||||
for x in ('delete_requested', 'reorder_spine', 'rename_requested',
|
||||
'edit_file', 'merge_requested', 'mark_requested',
|
||||
'export_requested', 'replace_requested'):
|
||||
'export_requested', 'replace_requested', 'bulk_rename_requested'):
|
||||
getattr(self.file_list, x).connect(getattr(self, x))
|
||||
for x in ('delete_done', 'select_name', 'request_edit', 'mark_name_as_current', 'clear_currently_edited_name'):
|
||||
setattr(self, x, getattr(self.file_list, x))
|
||||
|
Loading…
x
Reference in New Issue
Block a user