mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add ToC Editor to Tweak Book
This commit is contained in:
parent
89c33c3713
commit
5231d7958c
@ -25,6 +25,7 @@ from calibre.gui2.tweak_book import set_current_container, current_container, tp
|
||||
from calibre.gui2.tweak_book.undo import GlobalUndoHistory
|
||||
from calibre.gui2.tweak_book.save import SaveManager
|
||||
from calibre.gui2.tweak_book.preview import parse_worker
|
||||
from calibre.gui2.tweak_book.toc import TOCEditor
|
||||
from calibre.gui2.tweak_book.editor import editor_from_syntax, syntax_from_mime
|
||||
|
||||
def get_container(*args, **kwargs):
|
||||
@ -86,7 +87,7 @@ class Boss(QObject):
|
||||
' Convert your book to one of these formats first.') % _(' and ').join(sorted(SUPPORTED)),
|
||||
show=True)
|
||||
|
||||
for name in editors:
|
||||
for name in tuple(editors):
|
||||
self.close_editor(name)
|
||||
self.gui.preview.clear()
|
||||
self.container_count = -1
|
||||
@ -110,12 +111,20 @@ class Boss(QObject):
|
||||
self.gui.action_save.setEnabled(False)
|
||||
self.update_global_history_actions()
|
||||
|
||||
def update_editors_from_container(self, container=None):
|
||||
c = container or current_container()
|
||||
for name, ed in tuple(editors.iteritems()):
|
||||
if c.has_name(name):
|
||||
ed.replace_data(c.raw_data(name))
|
||||
else:
|
||||
self.close_editor(name)
|
||||
|
||||
def apply_container_update_to_gui(self):
|
||||
container = current_container()
|
||||
self.gui.file_list.build(container)
|
||||
self.update_global_history_actions()
|
||||
self.gui.action_save.setEnabled(True)
|
||||
# TODO: Apply to other GUI elements
|
||||
self.update_editors_from_container()
|
||||
|
||||
def delete_requested(self, spine_items, other_items):
|
||||
if not self.check_dirtied():
|
||||
@ -130,7 +139,8 @@ class Boss(QObject):
|
||||
for name in list(spine_items) + list(other_items):
|
||||
if name in editors:
|
||||
self.close_editor(name)
|
||||
# TODO: Update other GUI elements
|
||||
if not editors:
|
||||
self.gui.preview.clear()
|
||||
|
||||
def reorder_spine(self, items):
|
||||
# TODO: If content.opf is dirty in an editor, abort, calling
|
||||
@ -142,6 +152,16 @@ class Boss(QObject):
|
||||
self.gui.file_list.build(current_container()) # needed as the linear flag may have changed on some items
|
||||
# TODO: If content.opf is open in an editor, reload it
|
||||
|
||||
def edit_toc(self):
|
||||
if not self.check_dirtied():
|
||||
return
|
||||
self.add_savepoint(_('Edit Table of Contents'))
|
||||
d = TOCEditor(parent=self.gui)
|
||||
if d.exec_() != d.Accepted:
|
||||
self.rewind_savepoint()
|
||||
return
|
||||
self.update_editors_from_container()
|
||||
|
||||
# Renaming {{{
|
||||
def rename_requested(self, oldname, newname):
|
||||
if not self.check_dirtied():
|
||||
@ -176,7 +196,8 @@ class Boss(QObject):
|
||||
det_msg=job.traceback, show=True)
|
||||
self.gui.file_list.build(current_container())
|
||||
self.gui.action_save.setEnabled(True)
|
||||
# TODO: Update the rest of the GUI
|
||||
# TODO: Update the rest of the GUI. This means renaming open editors and
|
||||
# then calling update_editors_from_container()
|
||||
# }}}
|
||||
|
||||
# Global history {{{
|
||||
@ -335,6 +356,8 @@ class Boss(QObject):
|
||||
editor = editors.pop(name)
|
||||
self.gui.central.close_editor(editor)
|
||||
editor.break_cycles()
|
||||
if not editors:
|
||||
self.gui.preview.clear()
|
||||
|
||||
def do_editor_save(self):
|
||||
ed = self.gui.central.current_editor
|
||||
|
@ -114,6 +114,18 @@ class TextEdit(QPlainTextEdit):
|
||||
self.highlighter.setDocument(self.document())
|
||||
self.setPlainText(text)
|
||||
|
||||
def replace_text(self, text):
|
||||
c = self.textCursor()
|
||||
pos = c.position()
|
||||
c.beginEditBlock()
|
||||
c.clearSelection()
|
||||
c.select(c.Document)
|
||||
c.insertText(text)
|
||||
c.endEditBlock()
|
||||
c.setPosition(pos)
|
||||
self.setTextCursor(c)
|
||||
self.ensureCursorVisible()
|
||||
|
||||
# Line numbers and cursor line {{{
|
||||
def highlight_cursor_line(self):
|
||||
sel = QTextEdit.ExtraSelection()
|
||||
|
@ -9,6 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
from PyQt4.Qt import QMainWindow, Qt, QApplication, pyqtSignal
|
||||
|
||||
from calibre import xml_replace_entities
|
||||
from calibre.gui2 import error_dialog
|
||||
from calibre.gui2.tweak_book import actions
|
||||
from calibre.gui2.tweak_book.editor.text import TextEdit
|
||||
|
||||
@ -50,6 +51,13 @@ class Editor(QMainWindow):
|
||||
def get_raw_data(self):
|
||||
return unicode(self.editor.toPlainText())
|
||||
|
||||
def replace_data(self, raw, only_if_different=True):
|
||||
if isinstance(raw, bytes):
|
||||
raw = raw.decode('utf-8')
|
||||
current = self.get_raw_data() if only_if_different else False
|
||||
if current != raw:
|
||||
self.editor.replace_text(raw)
|
||||
|
||||
def undo(self):
|
||||
self.editor.undo()
|
||||
|
||||
@ -107,6 +115,9 @@ class Editor(QMainWindow):
|
||||
self.editor.copy()
|
||||
|
||||
def paste(self):
|
||||
if not self.editor.canPaste():
|
||||
return error_dialog(self, _('No text'), _(
|
||||
'There is no suitable text in the clipboard to paste.'), show=True)
|
||||
self.editor.paste()
|
||||
|
||||
|
||||
|
96
src/calibre/gui2/tweak_book/toc.py
Normal file
96
src/calibre/gui2/tweak_book/toc.py
Normal file
@ -0,0 +1,96 @@
|
||||
#!/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>'
|
||||
|
||||
from PyQt4.Qt import (QDialog, pyqtSignal, QIcon, QVBoxLayout, QDialogButtonBox, QStackedWidget)
|
||||
|
||||
from calibre.ebooks.oeb.polish.toc import commit_toc
|
||||
from calibre.gui2 import gprefs, error_dialog
|
||||
from calibre.gui2.toc.main import TOCView, ItemEdit
|
||||
from calibre.gui2.tweak_book import current_container
|
||||
|
||||
class TOCEditor(QDialog):
|
||||
|
||||
explode_done = pyqtSignal(object)
|
||||
writing_done = pyqtSignal(object)
|
||||
|
||||
def __init__(self, title=None, parent=None):
|
||||
QDialog.__init__(self, parent)
|
||||
|
||||
t = title or current_container().mi.title
|
||||
self.book_title = t
|
||||
self.setWindowTitle(_('Edit the ToC in %s')%t)
|
||||
self.setWindowIcon(QIcon(I('toc.png')))
|
||||
|
||||
l = self.l = QVBoxLayout()
|
||||
self.setLayout(l)
|
||||
|
||||
self.stacks = s = QStackedWidget(self)
|
||||
l.addWidget(s)
|
||||
self.toc_view = TOCView(self)
|
||||
self.toc_view.add_new_item.connect(self.add_new_item)
|
||||
s.addWidget(self.toc_view)
|
||||
self.item_edit = ItemEdit(self)
|
||||
s.addWidget(self.item_edit)
|
||||
|
||||
bb = self.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel)
|
||||
l.addWidget(bb)
|
||||
bb.accepted.connect(self.accept)
|
||||
bb.rejected.connect(self.reject)
|
||||
|
||||
self.read_toc()
|
||||
|
||||
self.resize(950, 630)
|
||||
geom = gprefs.get('toc_editor_window_geom', None)
|
||||
if geom is not None:
|
||||
self.restoreGeometry(bytes(geom))
|
||||
|
||||
def add_new_item(self, item, where):
|
||||
self.item_edit(item, where)
|
||||
self.stacks.setCurrentIndex(1)
|
||||
|
||||
def accept(self):
|
||||
if self.stacks.currentIndex() == 1:
|
||||
self.toc_view.update_item(*self.item_edit.result)
|
||||
gprefs['toc_edit_splitter_state'] = bytearray(self.item_edit.splitter.saveState())
|
||||
self.stacks.setCurrentIndex(0)
|
||||
elif self.stacks.currentIndex() == 0:
|
||||
self.write_toc()
|
||||
super(TOCEditor, self).accept()
|
||||
|
||||
def really_accept(self, tb):
|
||||
gprefs['toc_editor_window_geom'] = bytearray(self.saveGeometry())
|
||||
if tb:
|
||||
error_dialog(self, _('Failed to write book'),
|
||||
_('Could not write %s. Click "Show details" for'
|
||||
' more information.')%self.book_title, det_msg=tb, show=True)
|
||||
gprefs['toc_editor_window_geom'] = bytearray(self.saveGeometry())
|
||||
super(TOCEditor, self).reject()
|
||||
return
|
||||
|
||||
super(TOCEditor, self).accept()
|
||||
|
||||
def reject(self):
|
||||
if not self.bb.isEnabled():
|
||||
return
|
||||
if self.stacks.currentIndex() == 1:
|
||||
gprefs['toc_edit_splitter_state'] = bytearray(self.item_edit.splitter.saveState())
|
||||
self.stacks.setCurrentIndex(0)
|
||||
else:
|
||||
gprefs['toc_editor_window_geom'] = bytearray(self.saveGeometry())
|
||||
super(TOCEditor, self).reject()
|
||||
|
||||
def read_toc(self):
|
||||
self.toc_view(current_container())
|
||||
self.item_edit.load(current_container())
|
||||
self.stacks.setCurrentIndex(0)
|
||||
|
||||
def write_toc(self):
|
||||
toc = self.toc_view.create_toc()
|
||||
commit_toc(current_container(), toc, lang=self.toc_view.toc_lang,
|
||||
uid=self.toc_view.toc_uid)
|
||||
|
@ -164,17 +164,21 @@ class Main(MainWindow):
|
||||
_('Redo typing'))
|
||||
self.action_editor_save = reg('save.png', _('&Save'), self.boss.do_editor_save, 'editor-save', 'Ctrl+S',
|
||||
_('Save changes to the current file'))
|
||||
self.action_editor_cut = reg('edit-cut.png', _('C&ut text'), self.boss.do_editor_cut, 'editor-cut', 'Ctrl+X',
|
||||
self.action_editor_cut = reg('edit-cut.png', _('C&ut text'), self.boss.do_editor_cut, 'editor-cut', ('Ctrl+X', 'Shift+Delete', ),
|
||||
_('Cut text'))
|
||||
self.action_editor_copy = reg('edit-copy.png', _('&Copy text'), self.boss.do_editor_copy, 'editor-copy', 'Ctrl+C',
|
||||
self.action_editor_copy = reg('edit-copy.png', _('&Copy text'), self.boss.do_editor_copy, 'editor-copy', ('Ctrl+C', 'Ctrl+Insert'),
|
||||
_('Copy text'))
|
||||
self.action_editor_paste = reg('edit-paste.png', _('&Paste text'), self.boss.do_editor_paste, 'editor-paste', 'Ctrl+V',
|
||||
self.action_editor_paste = reg('edit-paste.png', _('&Paste text'), self.boss.do_editor_paste, 'editor-paste', ('Ctrl+V', 'Shift+Insert', ),
|
||||
_('Paste text'))
|
||||
self.action_editor_cut.setEnabled(False)
|
||||
self.action_editor_copy.setEnabled(False)
|
||||
self.action_editor_undo.setEnabled(False)
|
||||
self.action_editor_redo.setEnabled(False)
|
||||
|
||||
# Tool actions
|
||||
group = _('Tools')
|
||||
self.action_toc = reg('toc.png', _('&Edit ToC'), self.boss.edit_toc, 'edit-toc', (), _('Edit Table of Contents'))
|
||||
|
||||
def create_menubar(self):
|
||||
b = self.menuBar()
|
||||
|
||||
@ -194,13 +198,17 @@ class Main(MainWindow):
|
||||
e.addAction(self.action_editor_copy)
|
||||
e.addAction(self.action_editor_paste)
|
||||
|
||||
e = b.addMenu(_('&Tools'))
|
||||
e.addAction(self.action_toc)
|
||||
|
||||
def create_toolbar(self):
|
||||
self.global_bar = b = self.addToolBar(_('Global tool bar'))
|
||||
self.global_bar = b = self.addToolBar(_('Book tool bar'))
|
||||
b.setObjectName('global_bar') # Needed for saveState
|
||||
b.addAction(self.action_open_book)
|
||||
b.addAction(self.action_global_undo)
|
||||
b.addAction(self.action_global_redo)
|
||||
b.addAction(self.action_save)
|
||||
b.addAction(self.action_toc)
|
||||
|
||||
def create_docks(self):
|
||||
self.file_list_dock = d = QDockWidget(_('&Files Browser'), self)
|
||||
|
Loading…
x
Reference in New Issue
Block a user