Migrated Add Books action

This commit is contained in:
Kovid Goyal 2010-08-12 11:09:47 -06:00
parent 5d96982933
commit 82dc900a11
6 changed files with 98 additions and 68 deletions

View File

@ -5,8 +5,12 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from functools import partial
from PyQt4.Qt import QToolButton, QAction, QIcon
from calibre.customize import InterfaceActionBase
from calibre.gui2 import Dispatcher
class InterfaceAction(InterfaceActionBase):
@ -17,12 +21,31 @@ class InterfaceAction(InterfaceActionBase):
positions = frozenset([])
separators = frozenset([])
popup_type = QToolButton.MenuPopup
#: Of the form: (text, icon_path, tooltip, keyboard shortcut)
#: tooltip and keybard shortcut can be None
#: shortcut must be a translated string if not None
action_spec = ('text', 'icon', None, None)
def do_genesis(self, gui):
self.gui = gui
self.Dispatcher = partial(Dispatcher, parent=gui)
self.create_action()
self.genesis()
# Subclassable methods {{{
def genesis(self):
raise NotImplementedError()
# }}}
def create_action(self):
text, icon, tooltip, shortcut = self.action_spec
action = QAction(QIcon(I(icon)), text, self)
text = tooltip if tooltip else text
action.setToolTip(text)
action.setStatusTip(text)
action.setWhatsThis(text)
action.setAutoRepeat(False)
if shortcut:
action.setShortcut(shortcut)
self.qaction = action
def genesis(self):
pass

View File

@ -8,10 +8,10 @@ __docformat__ = 'restructuredtext en'
import os
from functools import partial
from PyQt4.Qt import QInputDialog, QPixmap
from PyQt4.Qt import QInputDialog, QPixmap, QMenu
from calibre.gui2 import error_dialog, Dispatcher, choose_files, \
from calibre.gui2 import error_dialog, choose_files, \
choose_dir, warning_dialog, info_dialog
from calibre.gui2.widgets import IMAGE_EXTENSIONS
from calibre.ebooks import BOOK_EXTENSIONS
@ -21,20 +21,41 @@ from calibre.gui2.actions import InterfaceAction
class AddAction(InterfaceAction):
name = 'Add Books'
action_spec = (_('Add books'), 'add_book.svg', None, _('A'))
positions = frozenset([
('toolbar', 'all', 0),
])
def genesis(self):
self._add_filesystem_book = Dispatcher(self.__add_filesystem_book,
parent=self.gui)
self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book)
self.add_menu = QMenu()
self.add_menu.addAction(_('Add books from a single directory'),
self.add_books)
self.add_menu.addAction(_('Add books from directories, including '
'sub-directories (One book per directory, assumes every ebook '
'file is the same book in a different format)'),
self.add_recursive_single)
self.add_menu.addAction(_('Add books from directories, including '
'sub directories (Multiple books per directory, assumes every '
'ebook file is a different book)'), self.add_recursive_multiple)
self.add_menu.addSeparator()
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
'formats)'), self.add_empty)
self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn)
self.qaction.setMenu(self.add_menu)
self.qaction.triggered.connect(self.add_books)
def add_recursive(self, single):
root = choose_dir(self, 'recursive book import root dir dialog',
root = choose_dir(self.gui, 'recursive book import root dir dialog',
'Select root folder')
if not root:
return
from calibre.gui2.add import Adder
self._adder = Adder(self,
self.library_view.model().db,
Dispatcher(self._files_added), spare_server=self.spare_server)
self._adder = Adder(self.gui,
self.gui.library_view.model().db,
self.Dispatcher(self._files_added), spare_server=self.gui.spare_server)
self._adder.add_recursive(root, single)
def add_recursive_single(self, *args):
@ -56,13 +77,13 @@ class AddAction(InterfaceAction):
Add an empty book item to the library. This does not import any formats
from a book file.
'''
num, ok = QInputDialog.getInt(self, _('How many empty books?'),
num, ok = QInputDialog.getInt(self.gui, _('How many empty books?'),
_('How many empty books should be added?'), 1, 1, 100)
if ok:
from calibre.ebooks.metadata import MetaInformation
for x in xrange(num):
self.library_view.model().db.import_book(MetaInformation(None), [])
self.library_view.model().books_added(num)
self.gui.library_view.model().db.import_book(MetaInformation(None), [])
self.gui.library_view.model().books_added(num)
def add_isbns(self, isbns):
from calibre.ebooks.metadata import MetaInformation
@ -70,21 +91,21 @@ class AddAction(InterfaceAction):
for x in isbns:
mi = MetaInformation(None)
mi.isbn = x
ids.add(self.library_view.model().db.import_book(mi, []))
self.library_view.model().books_added(len(isbns))
self.do_download_metadata(ids)
ids.add(self.gui.library_view.model().db.import_book(mi, []))
self.gui.library_view.model().books_added(len(isbns))
self.gui.do_download_metadata(ids)
def files_dropped(self, paths):
to_device = self.stack.currentIndex() != 0
to_device = self.gui.stack.currentIndex() != 0
self._add_books(paths, to_device)
def files_dropped_on_book(self, event, paths):
accept = False
if self.current_view() is not self.library_view:
if self.gui.current_view() is not self.gui.library_view:
return
db = self.library_view.model().db
current_idx = self.library_view.currentIndex()
db = self.gui.library_view.model().db
current_idx = self.gui.library_view.currentIndex()
if not current_idx.isValid(): return
cid = db.id(current_idx.row())
for path in paths:
@ -102,7 +123,7 @@ class AddAction(InterfaceAction):
accept = True
if accept:
event.accept()
self.library_view.model().current_changed(current_idx, current_idx)
self.gui.library_view.model().current_changed(current_idx, current_idx)
def __add_filesystem_book(self, paths, allow_device=True):
if isinstance(paths, basestring):
@ -111,10 +132,10 @@ class AddAction(InterfaceAction):
os.R_OK)]
if books:
to_device = allow_device and self.stack.currentIndex() != 0
to_device = allow_device and self.gui.stack.currentIndex() != 0
self._add_books(books, to_device)
if to_device:
self.status_bar.show_message(\
self.gui.status_bar.show_message(\
_('Uploading books to device.'), 2000)
@ -123,7 +144,7 @@ class AddAction(InterfaceAction):
def add_from_isbn(self, *args):
from calibre.gui2.dialogs.add_from_isbn import AddFromISBN
d = AddFromISBN(self)
d = AddFromISBN(self.gui)
if d.exec_() == d.Accepted:
self.add_isbns(d.isbns)
@ -144,11 +165,11 @@ class AddAction(InterfaceAction):
(_('Comics'), ['cbz', 'cbr', 'cbc']),
(_('Archives'), ['zip', 'rar']),
]
to_device = self.stack.currentIndex() != 0
to_device = self.gui.stack.currentIndex() != 0
if to_device:
filters = [(_('Supported books'), self.device_manager.device.FORMATS)]
filters = [(_('Supported books'), self.gui.device_manager.device.FORMATS)]
books = choose_files(self, 'add books dialog dir', 'Select books',
books = choose_files(self.gui, 'add books dialog dir', 'Select books',
filters=filters)
if not books:
return
@ -156,32 +177,33 @@ class AddAction(InterfaceAction):
def _add_books(self, paths, to_device, on_card=None):
if on_card is None:
on_card = 'carda' if self.stack.currentIndex() == 2 else 'cardb' if self.stack.currentIndex() == 3 else None
on_card = 'carda' if self.gui.stack.currentIndex() == 2 else \
'cardb' if self.gui.stack.currentIndex() == 3 else None
if not paths:
return
from calibre.gui2.add import Adder
self.__adder_func = partial(self._files_added, on_card=on_card)
self._adder = Adder(self,
None if to_device else self.library_view.model().db,
Dispatcher(self.__adder_func), spare_server=self.spare_server)
self._adder = Adder(self.gui,
None if to_device else self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(paths)
def _files_added(self, paths=[], names=[], infos=[], on_card=None):
if paths:
self.upload_books(paths,
self.gui.upload_books(paths,
list(map(ascii_filename, names)),
infos, on_card=on_card)
self.status_bar.show_message(
self.gui.status_bar.show_message(
_('Uploading books to device.'), 2000)
if getattr(self._adder, 'number_of_books_added', 0) > 0:
self.library_view.model().books_added(self._adder.number_of_books_added)
if hasattr(self, 'db_images'):
self.db_images.reset()
self.gui.library_view.model().books_added(self._adder.number_of_books_added)
if hasattr(self.gui, 'db_images'):
self.gui.db_images.reset()
if getattr(self._adder, 'merged_books', False):
books = u'\n'.join([x if isinstance(x, unicode) else
x.decode(preferred_encoding, 'replace') for x in
self._adder.merged_books])
info_dialog(self, _('Merged some books'),
info_dialog(self.gui, _('Merged some books'),
_('Some duplicates were found and merged into the '
'following existing books:'), det_msg=books, show=True)
if getattr(self._adder, 'critical', None):
@ -191,7 +213,7 @@ class AddAction(InterfaceAction):
name = name.decode(filesystem_encoding, 'replace')
det_msg.append(name+'\n'+log)
warning_dialog(self, _('Failed to read metadata'),
warning_dialog(self.gui, _('Failed to read metadata'),
_('Failed to read metadata from the following')+':',
det_msg='\n\n'.join(det_msg), show=True)
@ -205,17 +227,17 @@ class AddAction(InterfaceAction):
# set the in-library flags, and as a consequence send the library's
# metadata for this book to the device. This sets the uuid to the
# correct value.
self.set_books_in_library(booklists=[model.db], reset=True)
self.gui.set_books_in_library(booklists=[model.db], reset=True)
model.reset()
def add_books_from_device(self, view):
rows = view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self, _('Add to library'), _('No book selected'))
d = error_dialog(self.gui, _('Add to library'), _('No book selected'))
d.exec_()
return
paths = [p for p in view._model.paths(rows) if p is not None]
ve = self.device_manager.device.VIRTUAL_BOOK_EXTENSIONS
ve = self.gui.device_manager.device.VIRTUAL_BOOK_EXTENSIONS
def ext(x):
ans = os.path.splitext(x)[1]
ans = ans[1:] if len(ans) > 1 else ans
@ -223,21 +245,21 @@ class AddAction(InterfaceAction):
remove = set([p for p in paths if ext(p) in ve])
if remove:
paths = [p for p in paths if p not in remove]
info_dialog(self, _('Not Implemented'),
info_dialog(self.gui, _('Not Implemented'),
_('The following books are virtual and cannot be added'
' to the calibre library:'), '\n'.join(remove),
show=True)
if not paths:
return
if not paths or len(paths) == 0:
d = error_dialog(self, _('Add to library'), _('No book files found'))
d = error_dialog(self.gui, _('Add to library'), _('No book files found'))
d.exec_()
return
from calibre.gui2.add import Adder
self.__adder_func = partial(self._add_from_device_adder, on_card=None,
model=view._model)
self._adder = Adder(self, self.library_view.model().db,
Dispatcher(self.__adder_func), spare_server=self.spare_server)
self._adder = Adder(self.gui, self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(paths)

View File

@ -63,7 +63,8 @@ class LibraryViewMixin(object): # {{{
add_to_library = None,
edit_device_collections=None,
similar_menu=similar_menu)
add_to_library = (_('Add books to library'), self.add_books_from_device)
add_to_library = (_('Add books to library'),
self.iactions['Add Books'].add_books_from_device)
edit_device_collections = (_('Manage collections'),
partial(self.edit_device_collections, oncard=None))
@ -89,7 +90,7 @@ class LibraryViewMixin(object): # {{{
add_to_library=add_to_library,
edit_device_collections=edit_device_collections)
self.library_view.files_dropped.connect(self.files_dropped, type=Qt.QueuedConnection)
self.library_view.files_dropped.connect(self.iactions['Add Books'].files_dropped, type=Qt.QueuedConnection)
for func, args in [
('connect_to_search_box', (self.search,
self.search_done)),
@ -305,7 +306,7 @@ class LayoutMixin(object): # {{{
def finalize_layout(self):
self.status_bar.initialize(self.system_tray_icon)
self.book_details.show_book_info.connect(self.show_book_info)
self.book_details.files_dropped.connect(self.files_dropped_on_book)
self.book_details.files_dropped.connect(self.iactions['Add Books'].files_dropped_on_book)
self.book_details.open_containing_folder.connect(self.view_folder_for_id)
self.book_details.view_specific_format.connect(self.view_format_by_id)

View File

@ -528,22 +528,6 @@ class MainWindowMixin(object):
md.addSeparator()
md.addAction(self.action_merge)
self.add_menu = QMenu()
self.add_menu.addAction(_('Add books from a single directory'),
self.add_books)
self.add_menu.addAction(_('Add books from directories, including '
'sub-directories (One book per directory, assumes every ebook '
'file is the same book in a different format)'),
self.add_recursive_single)
self.add_menu.addAction(_('Add books from directories, including '
'sub directories (Multiple books per directory, assumes every '
'ebook file is a different book)'), self.add_recursive_multiple)
self.add_menu.addSeparator()
self.add_menu.addAction(_('Add Empty book. (Book entry with no '
'formats)'), self.add_empty)
self.add_menu.addAction(_('Add from ISBN'), self.add_from_isbn)
self.action_add.setMenu(self.add_menu)
self.action_add.triggered.connect(self.add_books)
self.action_del.triggered.connect(self.delete_books)
self.action_edit.triggered.connect(self.edit_metadata)
self.action_merge.triggered.connect(self.merge_books)

View File

@ -155,7 +155,7 @@ class GuiRunner(QObject):
main.initialize(self.library_path, self.db, self.listener, self.actions)
if DEBUG:
prints('Started up in', time.time() - self.startup_time)
add_filesystem_book = partial(main.add_filesystem_book, allow_device=False)
add_filesystem_book = partial(main.iactions['Add Books'].add_filesystem_book, allow_device=False)
sys.excepthook = main.unhandled_exception
if len(self.args) > 1:
p = os.path.abspath(self.args[1])

View File

@ -329,7 +329,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{
if len(argv) > 1:
path = os.path.abspath(argv[1])
if os.access(path, os.R_OK):
self.add_filesystem_book(path)
self.iactions['Add Books'].add_filesystem_book(path)
self.setWindowState(self.windowState() & \
~Qt.WindowMinimized|Qt.WindowActive)
self.show_windows()