diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index d5e8824862..3084738b27 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -11,10 +11,10 @@ import textwrap, re, os from PyQt4.Qt import (Qt, QDateEdit, QDate, pyqtSignal, QMessageBox, QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication, - QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, - QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox) + QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu, + QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox, QAction) -from calibre.gui2.widgets import EnLineEdit, FormatList, ImageView +from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox from calibre.utils.icu import sort_key from calibre.utils.config import tweaks, prefs @@ -33,6 +33,7 @@ from calibre.gui2.comments_editor import Editor from calibre.library.comments import comments_to_html from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.utils.icu import strcmp +from calibre.ptempfile import PersistentTemporaryFile def save_dialog(parent, title, msg, det_msg=''): d = QMessageBox(parent) @@ -572,7 +573,9 @@ class BuddyLabel(QLabel): # {{{ self.setAlignment(Qt.AlignRight|Qt.AlignVCenter) # }}} -class Format(QListWidgetItem): # {{{ +# Formats {{{ + +class Format(QListWidgetItem): def __init__(self, parent, ext, size, path=None, timestamp=None): self.path = path @@ -588,13 +591,52 @@ class Format(QListWidgetItem): # {{{ self.setToolTip(text) self.setStatusTip(text) -# }}} +class OrigAction(QAction): -class FormatsManager(QWidget): # {{{ + restore_fmt = pyqtSignal(object) + + def __init__(self, fmt, parent): + self.fmt = fmt.replace('ORIGINAL_', '') + QAction.__init__(self, _('Restore %s from the original')%self.fmt, parent) + self.triggered.connect(self._triggered) + + def _triggered(self): + self.restore_fmt.emit(self.fmt) + +class FormatList(_FormatList): + + restore_fmt = pyqtSignal(object) def __init__(self, parent): + _FormatList.__init__(self, parent) + self.setContextMenuPolicy(Qt.DefaultContextMenu) + + def contextMenuEvent(self, event): + originals = [self.item(x).ext.upper() for x in range(self.count())] + originals = [x for x in originals if x.startswith('ORIGINAL_')] + if not originals: + return + self.cm = cm = QMenu(self) + for fmt in originals: + action = OrigAction(fmt, cm) + action.restore_fmt.connect(self.restore_fmt) + cm.addAction(action) + cm.popup(event.globalPos()) + event.accept() + + def remove_format(self, fmt): + for i in range(self.count()): + f = self.item(i) + if f.ext.upper() == fmt.upper(): + self.takeItem(i) + break + +class FormatsManager(QWidget): + + def __init__(self, parent, copy_fmt): QWidget.__init__(self, parent) self.dialog = parent + self.copy_fmt = copy_fmt self.changed = False self.l = l = QGridLayout() @@ -628,6 +670,7 @@ class FormatsManager(QWidget): # {{{ self.formats = FormatList(self) self.formats.setAcceptDrops(True) self.formats.formats_dropped.connect(self.formats_dropped) + self.formats.restore_fmt.connect(self.restore_fmt) self.formats.delete_format.connect(self.remove_format) self.formats.itemDoubleClicked.connect(self.show_format) self.formats.setDragDropMode(self.formats.DropOnly) @@ -640,7 +683,7 @@ class FormatsManager(QWidget): # {{{ l.addWidget(self.remove_format_button, 2, 2, 1, 1) l.addWidget(self.formats, 0, 1, 3, 1) - + self.temp_files = [] def initialize(self, db, id_): self.changed = False @@ -694,6 +737,16 @@ class FormatsManager(QWidget): # {{{ [(_('Books'), BOOK_EXTENSIONS)]) self._add_formats(files) + def restore_fmt(self, fmt): + pt = PersistentTemporaryFile(suffix='_restore_fmt.'+fmt.lower()) + ofmt = 'ORIGINAL_'+fmt + with pt: + self.copy_fmt(ofmt, pt) + self._add_formats((pt.name,)) + self.temp_files.append(pt.name) + self.changed = True + self.formats.remove_format(ofmt) + def _add_formats(self, paths): added = False if not paths: @@ -774,6 +827,13 @@ class FormatsManager(QWidget): # {{{ def break_cycles(self): self.dialog = None + self.copy_fmt = None + for name in self.temp_files: + try: + os.remove(name) + except: + pass + self.temp_files = [] # }}} class Cover(ImageView): # {{{ diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index 950d3722e5..998734511c 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -145,7 +145,7 @@ class MetadataSingleDialogBase(ResizableDialog): self.series_index = SeriesIndexEdit(self, self.series) self.basic_metadata_widgets.extend([self.series, self.series_index]) - self.formats_manager = FormatsManager(self) + self.formats_manager = FormatsManager(self, self.copy_fmt) self.basic_metadata_widgets.append(self.formats_manager) self.formats_manager.metadata_from_format_button.clicked.connect( self.metadata_from_format) @@ -240,6 +240,8 @@ class MetadataSingleDialogBase(ResizableDialog): else: self.view_format.emit(self.book_id, fmt) + def copy_fmt(self, fmt, f): + self.db.copy_format_to(self.book_id, fmt, f, index_is_id=True) def do_layout(self): raise NotImplementedError()