diff --git a/src/calibre/ebooks/oeb/polish/create.py b/src/calibre/ebooks/oeb/polish/create.py index 52e4372745..e55ec97962 100644 --- a/src/calibre/ebooks/oeb/polish/create.py +++ b/src/calibre/ebooks/oeb/polish/create.py @@ -34,6 +34,8 @@ def create_toc(mi, opf, html_name, lang): def create_book(mi, path, fmt='epub', opf_name='metadata.opf', html_name='start.xhtml', toc_name='toc.ncx'): ''' Create an empty book in the specified format at the specified location. ''' + if fmt not in ['epub', 'azw3']: + return path = os.path.abspath(path) lang = 'und' opf = metadata_to_opf(mi, as_string=False) diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 89c4ee4a64..6524c8bbd2 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -14,7 +14,7 @@ from PyQt5.Qt import QPixmap, QTimer from calibre import as_unicode from calibre.gui2 import (error_dialog, choose_files, choose_dir, warning_dialog, info_dialog, gprefs) -from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog +from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog, valid_empty_formats from calibre.gui2.dialogs.confirm_delete import confirm from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.widgets import IMAGE_EXTENSIONS @@ -72,13 +72,17 @@ class AddAction(InterfaceAction): self.create_menu_action(arm, 'recursive-multiple-archive', _( 'Multiple books per directory in the archive')).triggered.connect(partial(self.add_archive, False)) self.add_menu.addSeparator() - self.add_menu.addSeparator() ma('add-empty', _('Add Empty book. (Book entry with no formats)'), shortcut='Shift+Ctrl+E').triggered.connect(self.add_empty) ma('add-isbn', _('Add from ISBN')).triggered.connect(self.add_from_isbn) self.add_menu.addSeparator() ma('add-formats', _('Add files to selected book records'), triggered=self.add_formats, shortcut='Shift+A') + arm = self.add_archive_menu = self.add_menu.addMenu(_('Add an empty file to selected book records')) + for fmt in valid_empty_formats: + self.create_menu_action(arm, 'add-empty-' + fmt, + _('Add empty {}').format(fmt)).triggered.connect( + partial(self.add_empty_format, fmt)) self.add_menu.addSeparator() ma('add-config', _('Control the adding of books'), triggered=self.add_config) @@ -143,6 +147,52 @@ class AddAction(InterfaceAction): if current_idx.isValid(): view.model().current_changed(current_idx, current_idx) + def add_empty_format(self, format_): + if self.gui.stack.currentIndex() != 0: + return + view = self.gui.library_view + rows = view.selectionModel().selectedRows() + if not rows: + return error_dialog(self.gui, _('No books selected'), + _('Cannot add files as no books are selected'), show=True) + + ids = [view.model().id(r) for r in rows] + + if len(ids) > 1 and not question_dialog( + self.gui, + _('Are you sure?'), + _('Are you sure you want to add the same' + ' empty file to all %d books? If the format' + ' already exists for a book, it will be replaced.')%len(ids)): + return + + db = self.gui.library_view.model().db + if len(ids) == 1: + formats = db.formats(ids[0], index_is_id=True) + if formats: + formats = {x.lower() for x in formats.split(',')} + if format_ in formats: + title = db.title(ids[0], index_is_id=True) + msg = _('The {0} format will be replaced in the book {1}. Are you sure?').format( + format_, title) + if not confirm(msg, 'confirm_format_override_on_add', title=_('Are you sure?'), + parent=self.gui): + return + + for id_ in ids: + from calibre.ebooks.oeb.polish.create import create_book + pt = PersistentTemporaryFile(suffix='.' + format_) + pt.close() + mi = db.new_api.get_metadata(id_, get_cover=False, + get_user_categories=False, cover_as_data=False) + create_book(mi, pt.name, fmt=format_) + db.add_format_with_hooks(id_, format_, pt.name, index_is_id=True, notify=True) + os.remove(pt.name) + + current_idx = self.gui.library_view.currentIndex() + if current_idx.isValid(): + view.model().current_changed(current_idx, current_idx) + def add_archive(self, single): paths = choose_files( self.gui, 'recursive-archive-add', _('Choose archive file'), @@ -209,12 +259,13 @@ class AddAction(InterfaceAction): mi.series = series mi.series_index = db.get_next_series_num_for(series) fmts = [] - if gprefs.get('create_empty_epub_file', False): + empty_format = gprefs.get('create_empty_format_file', '') + if empty_format: from calibre.ebooks.oeb.polish.create import create_book - pt = PersistentTemporaryFile(suffix='.epub') + pt = PersistentTemporaryFile(suffix='.' + empty_format) pt.close() temp_files.append(pt.name) - create_book(mi, pt.name) + create_book(mi, pt.name, fmt=empty_format) fmts = [pt.name] ids.append(db.import_book(mi, fmts)) self.gui.library_view.model().books_added(num) diff --git a/src/calibre/gui2/dialogs/add_empty_book.py b/src/calibre/gui2/dialogs/add_empty_book.py index 37ccb3d2da..faf87cd4c8 100644 --- a/src/calibre/gui2/dialogs/add_empty_book.py +++ b/src/calibre/gui2/dialogs/add_empty_book.py @@ -6,12 +6,14 @@ __license__ = 'GPL v3' from PyQt5.Qt import ( QDialog, QGridLayout, QLabel, QDialogButtonBox, QApplication, QSpinBox, - QToolButton, QIcon, QCheckBox, QLineEdit) + QToolButton, QIcon, QCheckBox, QLineEdit, QComboBox) from calibre.ebooks.metadata import string_to_authors from calibre.gui2.complete2 import EditWithComplete from calibre.utils.config import tweaks from calibre.gui2 import gprefs +valid_empty_formats = ['epub', 'txt', 'docx', 'azw3'] + class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author, series=None, title=None): @@ -76,21 +78,31 @@ class AddEmptyBookDialog(QDialog): self.tclear_button.clicked.connect(self.title_edit.clear) self._layout.addWidget(self.tclear_button, 7, 1, 1, 1) - self.create_epub = c = QCheckBox(_('Create an empty EPUB file as well')) - c.setChecked(gprefs.get('create_empty_epub_file', False)) - c.setToolTip(_('Also create an empty EPUB file that you can subsequently edit')) - self._layout.addWidget(c, 8, 0, 1, -1) + self.format_label = QLabel(_('Create an empty format as well:')) + self._layout.addWidget(self.format_label, 8, 0, 1, 2) + c = self.format_value = QComboBox(self) + possible_formats = [''] + valid_empty_formats + c.addItems(possible_formats) + c.setToolTip(_('Also create an empty book format file that you can subsequently edit')) + if gprefs.get('create_empty_epub_file', False): + # Migration of the check box + gprefs.set('create_empty_format_file', 'epub') + gprefs.set('create_empty_epub_file', False) + use_format = gprefs.get('create_empty_format_file', '') + try: + c.setCurrentIndex(possible_formats.index(use_format)) + except: + pass + self._layout.addWidget(c, 9, 0, 1, 1) button_box = self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) - self._layout.addWidget(button_box, 9, 0, 1, -1) + self._layout.addWidget(button_box, 10, 0, 1, -1) self.resize(self.sizeHint()) def accept(self): - oval = gprefs.get('create_empty_epub_file', False) - if self.create_epub.isChecked() != oval: - gprefs['create_empty_epub_file'] = self.create_epub.isChecked() + gprefs['create_empty_format_file'] = self.format_value.currentText() return QDialog.accept(self) def reset_author(self, *args):