mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit ToC: Allow the size of the panels in the location view to be adjusted
This commit is contained in:
parent
cd1765b935
commit
4db56199ee
@ -11,14 +11,14 @@ from base64 import b64encode
|
|||||||
|
|
||||||
from PyQt4.Qt import (QWidget, QGridLayout, QListWidget, QSize, Qt, QUrl,
|
from PyQt4.Qt import (QWidget, QGridLayout, QListWidget, QSize, Qt, QUrl,
|
||||||
pyqtSlot, pyqtSignal, QVBoxLayout, QFrame, QLabel,
|
pyqtSlot, pyqtSignal, QVBoxLayout, QFrame, QLabel,
|
||||||
QLineEdit, QTimer, QPushButton, QIcon)
|
QLineEdit, QTimer, QPushButton, QIcon, QSplitter)
|
||||||
from PyQt4.QtWebKit import QWebView, QWebPage, QWebElement
|
from PyQt4.QtWebKit import QWebView, QWebPage, QWebElement
|
||||||
|
|
||||||
from calibre.ebooks.oeb.display.webview import load_html
|
from calibre.ebooks.oeb.display.webview import load_html
|
||||||
from calibre.gui2 import error_dialog, question_dialog
|
from calibre.gui2 import error_dialog, question_dialog, gprefs
|
||||||
from calibre.utils.logging import default_log
|
from calibre.utils.logging import default_log
|
||||||
|
|
||||||
class Page(QWebPage): # {{{
|
class Page(QWebPage): # {{{
|
||||||
|
|
||||||
elem_clicked = pyqtSignal(object, object, object, object)
|
elem_clicked = pyqtSignal(object, object, object, object)
|
||||||
|
|
||||||
@ -67,7 +67,7 @@ class Page(QWebPage): # {{{
|
|||||||
self.evaljs(self.js)
|
self.evaljs(self.js)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class WebView(QWebView): # {{{
|
class WebView(QWebView): # {{{
|
||||||
|
|
||||||
elem_clicked = pyqtSignal(object, object, object, object)
|
elem_clicked = pyqtSignal(object, object, object, object)
|
||||||
|
|
||||||
@ -106,38 +106,46 @@ class ItemEdit(QWidget):
|
|||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
self.l = l = QGridLayout()
|
self.setLayout(QVBoxLayout())
|
||||||
self.setLayout(l)
|
|
||||||
|
|
||||||
self.la = la = QLabel('<b>'+_(
|
self.la = la = QLabel('<b>'+_(
|
||||||
'Select a destination for the Table of Contents entry'))
|
'Select a destination for the Table of Contents entry'))
|
||||||
l.addWidget(la, 0, 0, 1, 3)
|
self.layout().addWidget(la)
|
||||||
|
self.splitter = sp = QSplitter(self)
|
||||||
|
self.layout().addWidget(sp)
|
||||||
|
self.layout().setStretch(1, 10)
|
||||||
|
sp.setOpaqueResize(False)
|
||||||
|
sp.setChildrenCollapsible(False)
|
||||||
|
|
||||||
self.dest_list = dl = QListWidget(self)
|
self.dest_list = dl = QListWidget(self)
|
||||||
dl.setMinimumWidth(250)
|
dl.setMinimumWidth(250)
|
||||||
dl.currentItemChanged.connect(self.current_changed)
|
dl.currentItemChanged.connect(self.current_changed)
|
||||||
l.addWidget(dl, 1, 0, 2, 1)
|
sp.addWidget(dl)
|
||||||
|
|
||||||
|
w = self.w = QWidget(self)
|
||||||
|
l = w.l = QGridLayout()
|
||||||
|
w.setLayout(l)
|
||||||
self.view = WebView(self)
|
self.view = WebView(self)
|
||||||
self.view.elem_clicked.connect(self.elem_clicked)
|
self.view.elem_clicked.connect(self.elem_clicked)
|
||||||
l.addWidget(self.view, 1, 1, 1, 3)
|
l.addWidget(self.view, 0, 0, 1, 3)
|
||||||
|
sp.addWidget(w)
|
||||||
|
|
||||||
|
self.search_text = s = QLineEdit(self)
|
||||||
|
s.setPlaceholderText(_('Search for text...'))
|
||||||
|
l.addWidget(s, 1, 0)
|
||||||
|
self.ns_button = b = QPushButton(QIcon(I('arrow-down.png')), _('Find &next'), self)
|
||||||
|
b.clicked.connect(self.find_next)
|
||||||
|
l.addWidget(b, 1, 1)
|
||||||
|
self.ps_button = b = QPushButton(QIcon(I('arrow-up.png')), _('Find &previous'), self)
|
||||||
|
l.addWidget(b, 1, 2)
|
||||||
|
b.clicked.connect(self.find_previous)
|
||||||
|
|
||||||
self.f = f = QFrame()
|
self.f = f = QFrame()
|
||||||
f.setFrameShape(f.StyledPanel)
|
f.setFrameShape(f.StyledPanel)
|
||||||
f.setMinimumWidth(250)
|
f.setMinimumWidth(250)
|
||||||
l.addWidget(f, 1, 4, 2, 1)
|
|
||||||
self.search_text = s = QLineEdit(self)
|
|
||||||
s.setPlaceholderText(_('Search for text...'))
|
|
||||||
l.addWidget(s, 2, 1, 1, 1)
|
|
||||||
self.ns_button = b = QPushButton(QIcon(I('arrow-down.png')), _('Find &next'), self)
|
|
||||||
b.clicked.connect(self.find_next)
|
|
||||||
l.addWidget(b, 2, 2, 1, 1)
|
|
||||||
self.ps_button = b = QPushButton(QIcon(I('arrow-up.png')), _('Find &previous'), self)
|
|
||||||
l.addWidget(b, 2, 3, 1, 1)
|
|
||||||
b.clicked.connect(self.find_previous)
|
|
||||||
l.setRowStretch(1, 10)
|
|
||||||
l = f.l = QVBoxLayout()
|
l = f.l = QVBoxLayout()
|
||||||
f.setLayout(l)
|
f.setLayout(l)
|
||||||
|
sp.addWidget(f)
|
||||||
|
|
||||||
f.la = la = QLabel('<p>'+_(
|
f.la = la = QLabel('<p>'+_(
|
||||||
'Here you can choose a destination for the Table of Contents\' entry'
|
'Here you can choose a destination for the Table of Contents\' entry'
|
||||||
@ -167,6 +175,10 @@ class ItemEdit(QWidget):
|
|||||||
|
|
||||||
l.addStretch()
|
l.addStretch()
|
||||||
|
|
||||||
|
state = gprefs.get('toc_edit_splitter_state', None)
|
||||||
|
if state is not None:
|
||||||
|
sp.restoreState(state)
|
||||||
|
|
||||||
def keyPressEvent(self, ev):
|
def keyPressEvent(self, ev):
|
||||||
if ev.key() in (Qt.Key_Return, Qt.Key_Enter) and self.search_text.hasFocus():
|
if ev.key() in (Qt.Key_Return, Qt.Key_Enter) and self.search_text.hasFocus():
|
||||||
# Prevent pressing enter in the search box from triggering the dialog's accept() method
|
# Prevent pressing enter in the search box from triggering the dialog's accept() method
|
||||||
@ -236,6 +248,7 @@ class ItemEdit(QWidget):
|
|||||||
if item is not None:
|
if item is not None:
|
||||||
if where is None:
|
if where is None:
|
||||||
self.name.setText(item.data(0, Qt.DisplayRole).toString())
|
self.name.setText(item.data(0, Qt.DisplayRole).toString())
|
||||||
|
self.name.setCursorPosition(0)
|
||||||
toc = item.data(0, Qt.UserRole).toPyObject()
|
toc = item.data(0, Qt.UserRole).toPyObject()
|
||||||
if toc.dest:
|
if toc.dest:
|
||||||
for i in xrange(self.dest_list.count()):
|
for i in xrange(self.dest_list.count()):
|
||||||
@ -272,7 +285,6 @@ class ItemEdit(QWidget):
|
|||||||
loctext = _('Approximately %d%% from the top')%frac
|
loctext = _('Approximately %d%% from the top')%frac
|
||||||
return loctext
|
return loctext
|
||||||
|
|
||||||
|
|
||||||
def elem_clicked(self, tag, frac, elem_id, loc):
|
def elem_clicked(self, tag, frac, elem_id, loc):
|
||||||
self.current_frag = elem_id or loc
|
self.current_frag = elem_id or loc
|
||||||
base = _('Location: A <%s> tag inside the file')%tag
|
base = _('Location: A <%s> tag inside the file')%tag
|
||||||
|
@ -14,7 +14,7 @@ from functools import partial
|
|||||||
from PyQt4.Qt import (QPushButton, QFrame, QVariant, QMenu, QInputDialog,
|
from PyQt4.Qt import (QPushButton, QFrame, QVariant, QMenu, QInputDialog,
|
||||||
QDialog, QVBoxLayout, QDialogButtonBox, QSize, QStackedWidget, QWidget,
|
QDialog, QVBoxLayout, QDialogButtonBox, QSize, QStackedWidget, QWidget,
|
||||||
QLabel, Qt, pyqtSignal, QIcon, QTreeWidget, QGridLayout, QTreeWidgetItem,
|
QLabel, Qt, pyqtSignal, QIcon, QTreeWidget, QGridLayout, QTreeWidgetItem,
|
||||||
QToolButton, QItemSelectionModel, QCursor)
|
QToolButton, QItemSelectionModel, QCursor, QKeySequence)
|
||||||
|
|
||||||
from calibre.ebooks.oeb.polish.container import get_container, AZW3Container
|
from calibre.ebooks.oeb.polish.container import get_container, AZW3Container
|
||||||
from calibre.ebooks.oeb.polish.toc import (
|
from calibre.ebooks.oeb.polish.toc import (
|
||||||
@ -27,7 +27,7 @@ from calibre.utils.logging import GUILog
|
|||||||
|
|
||||||
ICON_SIZE = 24
|
ICON_SIZE = 24
|
||||||
|
|
||||||
class XPathDialog(QDialog): # {{{
|
class XPathDialog(QDialog): # {{{
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QDialog.__init__(self, parent)
|
QDialog.__init__(self, parent)
|
||||||
@ -118,7 +118,7 @@ class XPathDialog(QDialog): # {{{
|
|||||||
return [w.xpath for w in self.widgets if w.xpath.strip()]
|
return [w.xpath for w in self.widgets if w.xpath.strip()]
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class ItemView(QFrame): # {{{
|
class ItemView(QFrame): # {{{
|
||||||
|
|
||||||
add_new_item = pyqtSignal(object, object)
|
add_new_item = pyqtSignal(object, object)
|
||||||
delete_item = pyqtSignal()
|
delete_item = pyqtSignal()
|
||||||
@ -207,7 +207,6 @@ class ItemView(QFrame): # {{{
|
|||||||
)))
|
)))
|
||||||
l.addWidget(b)
|
l.addWidget(b)
|
||||||
|
|
||||||
|
|
||||||
l.addStretch()
|
l.addStretch()
|
||||||
self.w1 = la = QLabel(_('<b>WARNING:</b> calibre only supports the '
|
self.w1 = la = QLabel(_('<b>WARNING:</b> calibre only supports the '
|
||||||
'creation of linear ToCs in AZW3 files. In a '
|
'creation of linear ToCs in AZW3 files. In a '
|
||||||
@ -349,7 +348,9 @@ class ItemView(QFrame): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class TreeWidget(QTreeWidget): # {{{
|
class TreeWidget(QTreeWidget): # {{{
|
||||||
|
|
||||||
|
edit_item = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent):
|
def __init__(self, parent):
|
||||||
QTreeWidget.__init__(self, parent)
|
QTreeWidget.__init__(self, parent)
|
||||||
@ -510,25 +511,30 @@ class TreeWidget(QTreeWidget): # {{{
|
|||||||
|
|
||||||
def show_context_menu(self, point):
|
def show_context_menu(self, point):
|
||||||
item = self.currentItem()
|
item = self.currentItem()
|
||||||
|
def key(k):
|
||||||
|
sc = unicode(QKeySequence(k | Qt.CTRL).toString(QKeySequence.NativeText))
|
||||||
|
return ' [%s]'%sc
|
||||||
|
|
||||||
if item is not None:
|
if item is not None:
|
||||||
m = QMenu()
|
m = QMenu()
|
||||||
ci = unicode(item.data(0, Qt.DisplayRole).toString())
|
ci = unicode(item.data(0, Qt.DisplayRole).toString())
|
||||||
p = item.parent() or self.invisibleRootItem()
|
p = item.parent() or self.invisibleRootItem()
|
||||||
idx = p.indexOfChild(item)
|
idx = p.indexOfChild(item)
|
||||||
if idx > 0:
|
if idx > 0:
|
||||||
m.addAction(QIcon(I('arrow-up.png')), _('Move "%s" up')%ci, self.move_up)
|
m.addAction(QIcon(I('arrow-up.png')), (_('Move "%s" up')%ci)+key(Qt.Key_Up), self.move_up)
|
||||||
if idx + 1 < p.childCount():
|
if idx + 1 < p.childCount():
|
||||||
m.addAction(QIcon(I('arrow-down.png')), _('Move "%s" down')%ci, self.move_down)
|
m.addAction(QIcon(I('arrow-down.png')), (_('Move "%s" down')%ci)+key(Qt.Key_Down), self.move_down)
|
||||||
m.addAction(QIcon(I('trash.png')), _('Remove all selected items'), self.del_items)
|
m.addAction(QIcon(I('trash.png')), _('Remove all selected items'), self.del_items)
|
||||||
if item.parent() is not None:
|
if item.parent() is not None:
|
||||||
m.addAction(QIcon(I('back.png')), _('Unindent "%s"')%ci, self.move_left)
|
m.addAction(QIcon(I('back.png')), (_('Unindent "%s"')%ci)+key(Qt.Key_Left), self.move_left)
|
||||||
if idx > 0:
|
if idx > 0:
|
||||||
m.addAction(QIcon(I('forward.png')), _('Indent "%s"')%ci, self.move_right)
|
m.addAction(QIcon(I('forward.png')), (_('Indent "%s"')%ci)+key(Qt.Key_Right), self.move_right)
|
||||||
|
m.addAction(QIcon(I('edit_input.png')), _('Change the location this entry points to'), self.edit_item)
|
||||||
m.addAction(_('Change all selected items to title case'), self.title_case)
|
m.addAction(_('Change all selected items to title case'), self.title_case)
|
||||||
m.exec_(QCursor.pos())
|
m.exec_(QCursor.pos())
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class TOCView(QWidget): # {{{
|
class TOCView(QWidget): # {{{
|
||||||
|
|
||||||
add_new_item = pyqtSignal(object, object)
|
add_new_item = pyqtSignal(object, object)
|
||||||
|
|
||||||
@ -537,6 +543,7 @@ class TOCView(QWidget): # {{{
|
|||||||
l = self.l = QGridLayout()
|
l = self.l = QGridLayout()
|
||||||
self.setLayout(l)
|
self.setLayout(l)
|
||||||
self.tocw = t = TreeWidget(self)
|
self.tocw = t = TreeWidget(self)
|
||||||
|
self.tocw.edit_item.connect(self.edit_item)
|
||||||
l.addWidget(t, 0, 0, 7, 3)
|
l.addWidget(t, 0, 0, 7, 3)
|
||||||
self.up_button = b = QToolButton(self)
|
self.up_button = b = QToolButton(self)
|
||||||
b.setIcon(QIcon(I('arrow-up.png')))
|
b.setIcon(QIcon(I('arrow-up.png')))
|
||||||
@ -595,6 +602,9 @@ class TOCView(QWidget): # {{{
|
|||||||
|
|
||||||
l.setColumnStretch(2, 10)
|
l.setColumnStretch(2, 10)
|
||||||
|
|
||||||
|
def edit_item(self):
|
||||||
|
self.item_view.edit_item()
|
||||||
|
|
||||||
def event(self, e):
|
def event(self, e):
|
||||||
if e.type() == e.StatusTip:
|
if e.type() == e.StatusTip:
|
||||||
txt = unicode(e.tip()) or self.default_msg
|
txt = unicode(e.tip()) or self.default_msg
|
||||||
@ -742,12 +752,12 @@ class TOCView(QWidget): # {{{
|
|||||||
else:
|
else:
|
||||||
parent = item.parent() or self.root
|
parent = item.parent() or self.root
|
||||||
idx = parent.indexOfChild(item)
|
idx = parent.indexOfChild(item)
|
||||||
if where == 'after': idx += 1
|
if where == 'after':
|
||||||
|
idx += 1
|
||||||
c = self.create_item(parent, child, idx=idx)
|
c = self.create_item(parent, child, idx=idx)
|
||||||
self.tocw.setCurrentItem(c, 0, QItemSelectionModel.ClearAndSelect)
|
self.tocw.setCurrentItem(c, 0, QItemSelectionModel.ClearAndSelect)
|
||||||
self.tocw.scrollToItem(c)
|
self.tocw.scrollToItem(c)
|
||||||
|
|
||||||
|
|
||||||
def create_toc(self):
|
def create_toc(self):
|
||||||
root = TOC()
|
root = TOC()
|
||||||
|
|
||||||
@ -799,7 +809,7 @@ class TOCView(QWidget): # {{{
|
|||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class TOCEditor(QDialog): # {{{
|
class TOCEditor(QDialog): # {{{
|
||||||
|
|
||||||
explode_done = pyqtSignal(object)
|
explode_done = pyqtSignal(object)
|
||||||
writing_done = pyqtSignal(object)
|
writing_done = pyqtSignal(object)
|
||||||
@ -857,6 +867,7 @@ class TOCEditor(QDialog): # {{{
|
|||||||
def accept(self):
|
def accept(self):
|
||||||
if self.stacks.currentIndex() == 2:
|
if self.stacks.currentIndex() == 2:
|
||||||
self.toc_view.update_item(*self.item_edit.result)
|
self.toc_view.update_item(*self.item_edit.result)
|
||||||
|
gprefs['toc_edit_splitter_state'] = bytearray(self.item_edit.splitter.saveState())
|
||||||
self.stacks.setCurrentIndex(1)
|
self.stacks.setCurrentIndex(1)
|
||||||
elif self.stacks.currentIndex() == 1:
|
elif self.stacks.currentIndex() == 1:
|
||||||
self.working = False
|
self.working = False
|
||||||
@ -883,6 +894,7 @@ class TOCEditor(QDialog): # {{{
|
|||||||
if not self.bb.isEnabled():
|
if not self.bb.isEnabled():
|
||||||
return
|
return
|
||||||
if self.stacks.currentIndex() == 2:
|
if self.stacks.currentIndex() == 2:
|
||||||
|
gprefs['toc_edit_splitter_state'] = bytearray(self.item_edit.splitter.saveState())
|
||||||
self.stacks.setCurrentIndex(1)
|
self.stacks.setCurrentIndex(1)
|
||||||
else:
|
else:
|
||||||
self.working = False
|
self.working = False
|
||||||
@ -938,5 +950,5 @@ if __name__ == '__main__':
|
|||||||
d = TOCEditor(sys.argv[-1])
|
d = TOCEditor(sys.argv[-1])
|
||||||
d.start()
|
d.start()
|
||||||
d.exec_()
|
d.exec_()
|
||||||
del d # Needed to prevent sigsegv in exit cleanup
|
del d # Needed to prevent sigsegv in exit cleanup
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user