mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Speed up deleting of large numbers of books and show progress while doing so
This commit is contained in:
parent
418b036d4f
commit
e50c6d98a4
@ -5,13 +5,65 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from PyQt4.Qt import QMenu
|
||||
from functools import partial
|
||||
|
||||
from PyQt4.Qt import QMenu, QObject, QTimer
|
||||
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog
|
||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
|
||||
single_shot = partial(QTimer.singleShot, 10)
|
||||
|
||||
class MultiDeleter(QObject):
|
||||
|
||||
def __init__(self, gui, rows, callback):
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
QObject.__init__(self, gui)
|
||||
self.model = gui.library_view.model()
|
||||
self.ids = list(map(self.model.id, rows))
|
||||
self.gui = gui
|
||||
self.failures = []
|
||||
self.deleted_ids = []
|
||||
self.callback = callback
|
||||
single_shot(self.delete_one)
|
||||
self.pd = ProgressDialog(_('Deleting...'), parent=gui,
|
||||
cancelable=False, min=0, max=len(self.ids))
|
||||
self.pd.setModal(True)
|
||||
self.pd.show()
|
||||
|
||||
def delete_one(self):
|
||||
if not self.ids:
|
||||
self.cleanup()
|
||||
return
|
||||
id_ = self.ids.pop()
|
||||
title = 'id%d'%id_
|
||||
try:
|
||||
title = self.model.db.title(id_, index_is_id=True)
|
||||
self.model.db.delete_book(id_, notify=False, commit=False)
|
||||
self.deleted_ids.append(id_)
|
||||
except:
|
||||
import traceback
|
||||
self.failures.append((id_, title, traceback.format_exc()))
|
||||
single_shot(self.delete_one)
|
||||
self.pd.value += 1
|
||||
self.pd.set_msg(_('Deleted') + ' ' + title)
|
||||
|
||||
def cleanup(self):
|
||||
self.pd.hide()
|
||||
self.pd = None
|
||||
self.model.db.commit()
|
||||
self.model.db.clean()
|
||||
self.model.books_deleted()
|
||||
self.gui.tags_view.recount()
|
||||
self.callback(self.deleted_ids)
|
||||
if self.failures:
|
||||
msg = ['==>'+x[1]+'\n'+x[2] for x in self.failures]
|
||||
error_dialog(self.gui, _('Failed to delete'),
|
||||
_('Failed to delete some books, click the Show Details button'
|
||||
' for details.'), det_msg='\n\n'.join(msg), show=True)
|
||||
|
||||
class DeleteAction(InterfaceAction):
|
||||
|
||||
name = 'Remove Books'
|
||||
@ -179,8 +231,13 @@ class DeleteAction(InterfaceAction):
|
||||
row = None
|
||||
if ci.isValid():
|
||||
row = ci.row()
|
||||
ids_deleted = view.model().delete_books(rows)
|
||||
self.library_ids_deleted(ids_deleted, row)
|
||||
if len(rows) < 5:
|
||||
ids_deleted = view.model().delete_books(rows)
|
||||
self.library_ids_deleted(ids_deleted, row)
|
||||
else:
|
||||
self.__md = MultiDeleter(self.gui, rows,
|
||||
partial(self.library_ids_deleted, current_row=row))
|
||||
|
||||
else:
|
||||
if not confirm('<p>'+_('The selected books will be '
|
||||
'<b>permanently deleted</b> '
|
||||
|
@ -223,21 +223,22 @@ class BooksModel(QAbstractTableModel): # {{{
|
||||
def by_author(self):
|
||||
return self.sorted_on[0] == 'authors'
|
||||
|
||||
def books_deleted(self):
|
||||
self.count_changed()
|
||||
self.clear_caches()
|
||||
self.reset()
|
||||
|
||||
def delete_books(self, indices):
|
||||
ids = map(self.id, indices)
|
||||
for id in ids:
|
||||
self.db.delete_book(id, notify=False)
|
||||
self.count_changed()
|
||||
self.clear_caches()
|
||||
self.reset()
|
||||
self.books_deleted()
|
||||
return ids
|
||||
|
||||
def delete_books_by_id(self, ids):
|
||||
for id in ids:
|
||||
self.db.delete_book(id)
|
||||
self.count_changed()
|
||||
self.clear_caches()
|
||||
self.reset()
|
||||
self.books_deleted()
|
||||
|
||||
def books_added(self, num):
|
||||
if num > 0:
|
||||
|
@ -953,23 +953,24 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
self.notify('metadata', [id])
|
||||
return True
|
||||
|
||||
def delete_book(self, id, notify=True):
|
||||
def delete_book(self, id, notify=True, commit=True):
|
||||
'''
|
||||
Removes book from the result cache and the underlying database.
|
||||
If you set commit to False, you must call clean() manually afterwards
|
||||
'''
|
||||
try:
|
||||
path = os.path.join(self.library_path, self.path(id, index_is_id=True))
|
||||
except:
|
||||
path = None
|
||||
self.data.remove(id)
|
||||
if path and os.path.exists(path):
|
||||
self.rmtree(path)
|
||||
parent = os.path.dirname(path)
|
||||
if len(os.listdir(parent)) == 0:
|
||||
self.rmtree(parent)
|
||||
self.conn.execute('DELETE FROM books WHERE id=?', (id,))
|
||||
self.conn.commit()
|
||||
self.clean()
|
||||
if commit:
|
||||
self.conn.commit()
|
||||
self.clean()
|
||||
self.data.books_deleted([id])
|
||||
if notify:
|
||||
self.notify('delete', [id])
|
||||
|
Loading…
x
Reference in New Issue
Block a user