mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Finish the implementation of delete files
This commit is contained in:
parent
ec9b69a299
commit
e5f5f28180
84
src/calibre/gui2/tweak_book/boss.py
Normal file
84
src/calibre/gui2/tweak_book/boss.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
import tempfile, shutil
|
||||||
|
|
||||||
|
from PyQt4.Qt import QObject
|
||||||
|
|
||||||
|
from calibre.gui2 import error_dialog
|
||||||
|
from calibre.ptempfile import PersistentTemporaryDirectory
|
||||||
|
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
||||||
|
from calibre.ebooks.oeb.polish.container import get_container, clone_container
|
||||||
|
from calibre.gui2.tweak_book import set_current_container, current_container
|
||||||
|
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
||||||
|
|
||||||
|
class Boss(QObject):
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
QObject.__init__(self, parent)
|
||||||
|
self.global_undo = GlobalUndoHistory()
|
||||||
|
self.container_count = 0
|
||||||
|
self.tdir = None
|
||||||
|
|
||||||
|
def __call__(self, gui):
|
||||||
|
self.gui = gui
|
||||||
|
gui.file_list.delete_requested.connect(self.delete_requested)
|
||||||
|
|
||||||
|
def mkdtemp(self):
|
||||||
|
self.container_count += 1
|
||||||
|
return tempfile.mkdtemp(prefix='%05d-' % self.container_count, dir=self.tdir)
|
||||||
|
|
||||||
|
def check_dirtied(self):
|
||||||
|
# TODO: Implement this
|
||||||
|
return True
|
||||||
|
|
||||||
|
def open_book(self, path):
|
||||||
|
ext = path.rpartition('.')[-1].upper()
|
||||||
|
if ext not in SUPPORTED:
|
||||||
|
return error_dialog(self.gui, _('Unsupported format'),
|
||||||
|
_('Tweaking is only supported for books in the %s formats.'
|
||||||
|
' Convert your book to one of these formats first.') % _(' and ').join(sorted(SUPPORTED)),
|
||||||
|
show=True)
|
||||||
|
|
||||||
|
if not self.check_dirtied():
|
||||||
|
return
|
||||||
|
|
||||||
|
self.container_count = -1
|
||||||
|
if self.tdir:
|
||||||
|
shutil.rmtree(self.tdir, ignore_errors=True)
|
||||||
|
self.tdir = PersistentTemporaryDirectory()
|
||||||
|
self.gui.blocking_job('open_book', _('Opening book, please wait...'), self.book_opened, get_container, path, tdir=self.mkdtemp())
|
||||||
|
|
||||||
|
def book_opened(self, job):
|
||||||
|
if job.traceback is not None:
|
||||||
|
return error_dialog(self.gui, _('Failed to open book'),
|
||||||
|
_('Failed to open book, click Show details for more information.'),
|
||||||
|
det_msg=job.traceback, show=True)
|
||||||
|
container = job.result
|
||||||
|
set_current_container(container)
|
||||||
|
self.current_metadata = self.gui.current_metadata = container.mi
|
||||||
|
self.global_undo.open_book(container)
|
||||||
|
self.gui.update_window_title()
|
||||||
|
self.gui.file_list.build(container)
|
||||||
|
|
||||||
|
def add_savepoint(self, msg):
|
||||||
|
nc = clone_container(current_container(), self.mkdtemp())
|
||||||
|
self.global_undo.add_savepoint(nc, msg)
|
||||||
|
set_current_container(nc)
|
||||||
|
|
||||||
|
def delete_requested(self, spine_items, other_items):
|
||||||
|
if not self.check_dirtied():
|
||||||
|
return
|
||||||
|
self.add_savepoint(_('Delete files'))
|
||||||
|
c = current_container()
|
||||||
|
c.remove_from_spine(spine_items)
|
||||||
|
for name in other_items:
|
||||||
|
c.remove_item(name)
|
||||||
|
self.gui.file_list.delete_done(spine_items, other_items)
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ class FileList(QTreeWidget):
|
|||||||
removals.append(child)
|
removals.append(child)
|
||||||
|
|
||||||
for c in removals:
|
for c in removals:
|
||||||
c.parent().removeChild(c.parent().indexOfChild(c))
|
c.parent().removeChild(c)
|
||||||
|
|
||||||
class FileListWidget(QWidget):
|
class FileListWidget(QWidget):
|
||||||
|
|
||||||
@ -274,6 +274,8 @@ class FileListWidget(QWidget):
|
|||||||
self.layout().setContentsMargins(0, 0, 0, 0)
|
self.layout().setContentsMargins(0, 0, 0, 0)
|
||||||
for x in ('delete_requested',):
|
for x in ('delete_requested',):
|
||||||
getattr(self.file_list, x).connect(getattr(self, x))
|
getattr(self.file_list, x).connect(getattr(self, x))
|
||||||
|
for x in ('delete_done',):
|
||||||
|
setattr(self, x, getattr(self.file_list, x))
|
||||||
|
|
||||||
def build(self, container):
|
def build(self, container):
|
||||||
self.file_list.build(container)
|
self.file_list.build(container)
|
||||||
|
@ -40,7 +40,7 @@ def main(args=sys.argv):
|
|||||||
sys.excepthook = main.unhandled_exception
|
sys.excepthook = main.unhandled_exception
|
||||||
main.show()
|
main.show()
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
main.open_book(args[1])
|
main.boss.open_book(args[1])
|
||||||
app.exec_()
|
app.exec_()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
@ -6,23 +6,13 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
import shutil, tempfile
|
|
||||||
|
|
||||||
from PyQt4.Qt import QDockWidget, Qt, QLabel, QIcon
|
from PyQt4.Qt import QDockWidget, Qt, QLabel, QIcon
|
||||||
|
|
||||||
from calibre.ebooks.oeb.polish.container import get_container
|
|
||||||
from calibre.ebooks.oeb.polish.main import SUPPORTED
|
|
||||||
from calibre.ptempfile import PersistentTemporaryDirectory
|
|
||||||
from calibre.gui2 import error_dialog
|
|
||||||
from calibre.gui2.main_window import MainWindow
|
from calibre.gui2.main_window import MainWindow
|
||||||
from calibre.gui2.tweak_book import set_current_container, current_container
|
from calibre.gui2.tweak_book import current_container
|
||||||
from calibre.gui2.tweak_book.file_list import FileListWidget
|
from calibre.gui2.tweak_book.file_list import FileListWidget
|
||||||
from calibre.gui2.tweak_book.job import BlockingJob
|
from calibre.gui2.tweak_book.job import BlockingJob
|
||||||
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
from calibre.gui2.tweak_book.boss import Boss
|
||||||
|
|
||||||
def load_book(path_to_ebook, base_tdir):
|
|
||||||
tdir = tempfile.mkdtemp(dir=base_tdir)
|
|
||||||
return get_container(path_to_ebook, tdir=tdir)
|
|
||||||
|
|
||||||
class Main(MainWindow):
|
class Main(MainWindow):
|
||||||
|
|
||||||
@ -30,13 +20,13 @@ class Main(MainWindow):
|
|||||||
|
|
||||||
def __init__(self, opts):
|
def __init__(self, opts):
|
||||||
MainWindow.__init__(self, opts, disable_automatic_gc=True)
|
MainWindow.__init__(self, opts, disable_automatic_gc=True)
|
||||||
|
self.boss = Boss(self)
|
||||||
self.setWindowTitle(self.APP_NAME)
|
self.setWindowTitle(self.APP_NAME)
|
||||||
self.setWindowIcon(QIcon(I('tweak.png')))
|
self.setWindowIcon(QIcon(I('tweak.png')))
|
||||||
self.opts = opts
|
self.opts = opts
|
||||||
self.tdir = None
|
|
||||||
self.path_to_ebook = None
|
self.path_to_ebook = None
|
||||||
self.container = None
|
self.container = None
|
||||||
self.global_undo = GlobalUndoHistory()
|
self.current_metadata = None
|
||||||
self.blocking_job = BlockingJob(self)
|
self.blocking_job = BlockingJob(self)
|
||||||
|
|
||||||
self.file_list_dock = d = QDockWidget(_('&Files Browser'), self)
|
self.file_list_dock = d = QDockWidget(_('&Files Browser'), self)
|
||||||
@ -49,37 +39,11 @@ class Main(MainWindow):
|
|||||||
self.l = QLabel('Placeholder')
|
self.l = QLabel('Placeholder')
|
||||||
|
|
||||||
self.setCentralWidget(self.l)
|
self.setCentralWidget(self.l)
|
||||||
|
self.boss(self)
|
||||||
|
|
||||||
def resizeEvent(self, ev):
|
def resizeEvent(self, ev):
|
||||||
self.blocking_job.resize(ev.size())
|
self.blocking_job.resize(ev.size())
|
||||||
return super(Main, self).resizeEvent(ev)
|
return super(Main, self).resizeEvent(ev)
|
||||||
|
|
||||||
def open_book(self, path):
|
|
||||||
ext = path.rpartition('.')[-1].upper()
|
|
||||||
if ext not in SUPPORTED:
|
|
||||||
return error_dialog(self, _('Unsupported format'),
|
|
||||||
_('Tweaking is only supported for books in the %s formats.'
|
|
||||||
' Convert your book to one of these formats first.') % _(' and ').join(sorted(SUPPORTED)),
|
|
||||||
show=True)
|
|
||||||
|
|
||||||
# TODO: Handle already open, dirtied book
|
|
||||||
|
|
||||||
if self.tdir:
|
|
||||||
shutil.rmtree(self.tdir, ignore_errors=True)
|
|
||||||
self.tdir = PersistentTemporaryDirectory()
|
|
||||||
self.blocking_job('open_book', _('Opening book, please wait...'), self.book_opened, load_book, path, self.tdir)
|
|
||||||
|
|
||||||
def book_opened(self, job):
|
|
||||||
if job.traceback is not None:
|
|
||||||
return error_dialog(self, _('Failed to open book'),
|
|
||||||
_('Failed to open book, click Show details for more information.'),
|
|
||||||
det_msg=job.traceback, show=True)
|
|
||||||
container = job.result
|
|
||||||
set_current_container(container)
|
|
||||||
self.current_metadata = container.mi
|
|
||||||
self.global_undo.open_book(container)
|
|
||||||
self.update_window_title()
|
|
||||||
self.file_list.build(container)
|
|
||||||
|
|
||||||
def update_window_title(self):
|
def update_window_title(self):
|
||||||
self.setWindowTitle(self.current_metadata.title + ' [%s] - %s' %(current_container().book_type.upper(), self.APP_NAME))
|
self.setWindowTitle(self.current_metadata.title + ' [%s] - %s' %(current_container().book_type.upper(), self.APP_NAME))
|
||||||
|
@ -6,18 +6,51 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
def cleanup(containers):
|
||||||
|
for container in containers:
|
||||||
|
try:
|
||||||
|
shutil.rmtree(container.root, ignore_errors=True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
class State(object):
|
class State(object):
|
||||||
|
|
||||||
def __init__(self, container):
|
def __init__(self, container):
|
||||||
self.container = container
|
self.container = container
|
||||||
self.operation = None
|
self.message = None
|
||||||
|
|
||||||
class GlobalUndoHistory(object):
|
class GlobalUndoHistory(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.states = []
|
self.states = []
|
||||||
|
self.pos = 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_container(self):
|
||||||
|
return self.states[self.pos].container
|
||||||
|
|
||||||
def open_book(self, container):
|
def open_book(self, container):
|
||||||
self.states = [State(container)]
|
self.states = [State(container)]
|
||||||
|
self.pos = 0
|
||||||
|
|
||||||
|
def add_savepoint(self, new_container, message):
|
||||||
|
self.states[self.pos].message = message
|
||||||
|
extra = self.states[self.pos+1:]
|
||||||
|
cleanup(extra)
|
||||||
|
self.states = self.states[:self.pos+1]
|
||||||
|
self.states.append(State(new_container))
|
||||||
|
self.pos += 1
|
||||||
|
|
||||||
|
def undo(self):
|
||||||
|
if self.pos > 0:
|
||||||
|
self.pos -= 1
|
||||||
|
return self.current_container
|
||||||
|
|
||||||
|
def redo(self):
|
||||||
|
if self.pos < len(self.states) - 1:
|
||||||
|
self.pos += 1
|
||||||
|
return self.current_container
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user