From ebd6f978ac06e740b285ea3d5838732e82f7b0f2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 23 Dec 2013 15:48:00 +0530 Subject: [PATCH] Edit book: Allow import of multiple files at once, via File->Import files into book --- src/calibre/gui2/tweak_book/boss.py | 33 ++++++++- .../gui2/tweak_book/editor/insert_resource.py | 68 ++++++++++++++++++- src/calibre/gui2/tweak_book/ui.py | 2 + 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index dc6da3ae92..caa319703b 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -34,7 +34,7 @@ from calibre.gui2.tweak_book.save import SaveManager, save_container from calibre.gui2.tweak_book.preview import parse_worker, font_cache from calibre.gui2.tweak_book.toc import TOCEditor from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime -from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, NewBook +from calibre.gui2.tweak_book.editor.insert_resource import get_resource_data, NewBook, ChooseFolder from calibre.gui2.tweak_book.preferences import Preferences def get_container(*args, **kwargs): @@ -320,6 +320,37 @@ class Boss(QObject): else: self.edit_file(d.file_name, syntax) + def add_files(self): + if current_container() is None: + return error_dialog(self.gui, _('No open book'), _( + 'You must first open a book to tweak, before trying to create new files' + ' in it.'), show=True) + + files = choose_files(self.gui, 'tweak-book-bulk-import-files', _('Choose files')) + if files: + d = ChooseFolder(parent=self.gui) + if d.exec_() == d.Accepted: + base = d.chosen_folder + files = {x:'/'.join((base, os.path.basename(x))) for x in files} + self.commit_dirty_opf() + self.add_savepoint(_('Add files')) + c = current_container() + for path, name in files.iteritems(): + i = 0 + while c.exists(name): + i += 1 + name, ext = name.rpartition('.')[0::2] + name = '%s_%d.%s' % (name, i, ext) + try: + with open(path, 'rb') as f: + c.add_file(name, f.read()) + except: + self.rewind_savepoint() + raise + self.gui.file_list.build(c) + if c.opf_name in editors: + editors[c.opf_name].replace_data(c.raw_data(c.opf_name)) + def edit_toc(self): self.commit_all_editors_to_container() self.add_savepoint(_('Edit Table of Contents')) diff --git a/src/calibre/gui2/tweak_book/editor/insert_resource.py b/src/calibre/gui2/tweak_book/editor/insert_resource.py index 1949c739d1..c73f5fa211 100644 --- a/src/calibre/gui2/tweak_book/editor/insert_resource.py +++ b/src/calibre/gui2/tweak_book/editor/insert_resource.py @@ -13,7 +13,8 @@ from PyQt4.Qt import ( QDialog, QGridLayout, QDialogButtonBox, QSize, QListView, QStyledItemDelegate, QLabel, QPixmap, QApplication, QSizePolicy, QAbstractListModel, QVariant, Qt, QRect, QPainter, QModelIndex, QSortFilterProxyModel, QLineEdit, - QToolButton, QIcon, QFormLayout, pyqtSignal) + QToolButton, QIcon, QFormLayout, pyqtSignal, QTreeWidget, QTreeWidgetItem, + QVBoxLayout) from calibre import fit_image from calibre.constants import plugins @@ -308,6 +309,67 @@ def get_resource_data(rtype, parent): if d.exec_() == d.Accepted: return d.chosen_image, d.chosen_image_is_external +def create_folder_tree(container): + root = {} + + all_folders = {tuple(x.split('/')[:-1]) for x in container.name_path_map} + all_folders.discard(()) + + for folder_path in all_folders: + current = root + for x in folder_path: + current[x] = current = current.get(x, {}) + return root + +class ChooseFolder(Dialog): # {{{ + + def __init__(self, msg=None, parent=None): + self.msg = msg + Dialog.__init__(self, _('Choose folder'), 'choose-folder', parent=parent) + + def setup_ui(self): + self.l = l = QVBoxLayout(self) + self.setLayout(l) + + self.msg = m = QLabel(self.msg or _( + 'Choose the folder into which the files will be placed')) + l.addWidget(m) + m.setWordWrap(True) + + self.folders = f = QTreeWidget(self) + f.setHeaderHidden(True) + f.itemDoubleClicked.connect(self.accept) + l.addWidget(f) + self.root = QTreeWidgetItem(f, ('/',)) + self.root.setExpanded(True) + + def process(node, parent): + for child in sorted(node, key=sort_key): + c = QTreeWidgetItem(parent, (child,)) + process(node[child], c) + if parent.childCount() == 1: + parent.child(0).setExpanded(True) + process(create_folder_tree(current_container()), self.root) + self.root.setSelected(True) + + l.addWidget(self.bb) + + def folder_path(self, item): + ans = [] + while item is not self.root: + ans.append(unicode(item.text(0))) + item = item.parent() + return tuple(reversed(ans)) + + @property + def chosen_folder(self): + try: + return '/'.join(self.folder_path(self.folders.selectedItems()[0])) + except IndexError: + return '' +# }}} + + class NewBook(Dialog): # {{{ def __init__(self, parent=None): @@ -362,7 +424,7 @@ if __name__ == '__main__': from calibre.gui2.tweak_book.boss import get_container set_current_container(get_container(sys.argv[-1])) - d = InsertImage() + d = ChooseFolder() if d.exec_() == d.Accepted: - print (d.chosen_image, d.chosen_image_is_external) + print (repr(d.chosen_folder)) diff --git a/src/calibre/gui2/tweak_book/ui.py b/src/calibre/gui2/tweak_book/ui.py index 3bc1ef6e5e..8282c9eae7 100644 --- a/src/calibre/gui2/tweak_book/ui.py +++ b/src/calibre/gui2/tweak_book/ui.py @@ -276,6 +276,7 @@ class Main(MainWindow): self.action_new_file = reg('document-new.png', _('&New file (images/fonts/HTML/etc.)'), self.boss.add_file, 'new-file', (), _('Create a new file in the current book')) + self.action_import_files = reg(None, _('&Import files into book'), self.boss.add_files, 'new-files', (), _('Import files into book')) self.action_open_book = reg('document_open.png', _('Open &book'), self.boss.open_book, 'open-book', 'Ctrl+O', _('Open a new book')) self.action_global_undo = reg('back.png', _('&Revert to before'), self.boss.do_global_undo, 'global-undo', 'Ctrl+Left', _('Revert book to before the last action (Undo)')) @@ -400,6 +401,7 @@ class Main(MainWindow): f = b.addMenu(_('&File')) f.addAction(self.action_new_file) + f.addAction(self.action_import_files) f.addAction(self.action_open_book) f.addAction(self.action_new_book) self.recent_books_menu = f.addMenu(_('&Recently opened books'))