mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 10:14:46 -04:00
Edit Book: Live CSS: Allow copying of CSS rules by right clicking on the Live CSS panel. Fixes #1485237 [[Enhancement] Make info in Live CSS window copiable](https://bugs.launchpad.net/calibre/+bug/1485237)
This commit is contained in:
parent
f945643acc
commit
cecc7efb8a
@ -11,7 +11,7 @@ import json
|
|||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QWidget, QTimer, QStackedLayout, QLabel, QScrollArea, QVBoxLayout,
|
QWidget, QTimer, QStackedLayout, QLabel, QScrollArea, QVBoxLayout,
|
||||||
QPainter, Qt, QPalette, QRect, QSize, QSizePolicy, pyqtSignal,
|
QPainter, Qt, QPalette, QRect, QSize, QSizePolicy, pyqtSignal,
|
||||||
QColor)
|
QColor, QMenu, QApplication, QIcon)
|
||||||
|
|
||||||
from calibre.constants import iswindows
|
from calibre.constants import iswindows
|
||||||
from calibre.gui2.tweak_book import editors, actions, current_container, tprefs
|
from calibre.gui2.tweak_book import editors, actions, current_container, tprefs
|
||||||
@ -22,6 +22,7 @@ from css_selectors import parse, SelectorError
|
|||||||
class Heading(QWidget): # {{{
|
class Heading(QWidget): # {{{
|
||||||
|
|
||||||
toggled = pyqtSignal(object)
|
toggled = pyqtSignal(object)
|
||||||
|
context_menu_requested = pyqtSignal(object, object)
|
||||||
|
|
||||||
def __init__(self, text, expanded=True, parent=None):
|
def __init__(self, text, expanded=True, parent=None):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
@ -32,6 +33,10 @@ class Heading(QWidget): # {{{
|
|||||||
self.hovering = False
|
self.hovering = False
|
||||||
self.do_layout()
|
self.do_layout()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lines_for_copy(self):
|
||||||
|
return [self.text]
|
||||||
|
|
||||||
def do_layout(self):
|
def do_layout(self):
|
||||||
try:
|
try:
|
||||||
f = self.parent().font()
|
f = self.parent().font()
|
||||||
@ -79,6 +84,9 @@ class Heading(QWidget): # {{{
|
|||||||
self.hovering = False
|
self.hovering = False
|
||||||
self.update()
|
self.update()
|
||||||
return QWidget.leaveEvent(self, ev)
|
return QWidget.leaveEvent(self, ev)
|
||||||
|
|
||||||
|
def contextMenuEvent(self, ev):
|
||||||
|
self.context_menu_requested.emit(self, ev)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
class Cell(object): # {{{
|
class Cell(object): # {{{
|
||||||
@ -117,6 +125,7 @@ class Cell(object): # {{{
|
|||||||
class Declaration(QWidget):
|
class Declaration(QWidget):
|
||||||
|
|
||||||
hyperlink_activated = pyqtSignal(object)
|
hyperlink_activated = pyqtSignal(object)
|
||||||
|
context_menu_requested = pyqtSignal(object, object)
|
||||||
|
|
||||||
def __init__(self, html_name, data, is_first=False, parent=None):
|
def __init__(self, html_name, data, is_first=False, parent=None):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
@ -124,6 +133,7 @@ class Declaration(QWidget):
|
|||||||
self.data = data
|
self.data = data
|
||||||
self.is_first = is_first
|
self.is_first = is_first
|
||||||
self.html_name = html_name
|
self.html_name = html_name
|
||||||
|
self.lines_for_copy = []
|
||||||
self.do_layout()
|
self.do_layout()
|
||||||
self.setMouseTracking(True)
|
self.setMouseTracking(True)
|
||||||
|
|
||||||
@ -149,6 +159,7 @@ class Declaration(QWidget):
|
|||||||
Cell(sel, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), right_align=True)
|
Cell(sel, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), right_align=True)
|
||||||
])
|
])
|
||||||
ypos += max(br1.height(), br2.height()) + 2 * line_spacing
|
ypos += max(br1.height(), br2.height()) + 2 * line_spacing
|
||||||
|
self.lines_for_copy.append(name + ' ' + sel)
|
||||||
|
|
||||||
for prop in self.data['properties']:
|
for prop in self.data['properties']:
|
||||||
text = prop.name + ':\xa0'
|
text = prop.name + ':\xa0'
|
||||||
@ -159,6 +170,7 @@ class Declaration(QWidget):
|
|||||||
Cell(text, QRect(side_margin, ypos, br1.width(), br1.height()), color_role=QPalette.LinkVisited, is_overriden=prop.is_overriden),
|
Cell(text, QRect(side_margin, ypos, br1.width(), br1.height()), color_role=QPalette.LinkVisited, is_overriden=prop.is_overriden),
|
||||||
Cell(vtext, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), swatch=prop.color, is_overriden=prop.is_overriden)
|
Cell(vtext, QRect(br1.right() + side_margin, ypos, br2.width(), br2.height()), swatch=prop.color, is_overriden=prop.is_overriden)
|
||||||
])
|
])
|
||||||
|
self.lines_for_copy.append(text + vtext)
|
||||||
ypos += max(br1.height(), br2.height()) + line_spacing
|
ypos += max(br1.height(), br2.height()) + line_spacing
|
||||||
|
|
||||||
self.height_hint = ypos + line_spacing
|
self.height_hint = ypos + line_spacing
|
||||||
@ -204,7 +216,7 @@ class Declaration(QWidget):
|
|||||||
return QWidget.mouseMoveEvent(self, ev)
|
return QWidget.mouseMoveEvent(self, ev)
|
||||||
|
|
||||||
def mousePressEvent(self, ev):
|
def mousePressEvent(self, ev):
|
||||||
if hasattr(self, 'hyperlink_rect'):
|
if hasattr(self, 'hyperlink_rect') and ev.button() == Qt.LeftButton:
|
||||||
pos = ev.pos()
|
pos = ev.pos()
|
||||||
if self.hyperlink_rect.contains(pos):
|
if self.hyperlink_rect.contains(pos):
|
||||||
self.emit_hyperlink_activated()
|
self.emit_hyperlink_activated()
|
||||||
@ -236,6 +248,9 @@ class Declaration(QWidget):
|
|||||||
cell.override_color = QColor(Qt.red) if hovering else None
|
cell.override_color = QColor(Qt.red) if hovering else None
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def contextMenuEvent(self, ev):
|
||||||
|
self.context_menu_requested.emit(self, ev)
|
||||||
|
|
||||||
class Box(QWidget):
|
class Box(QWidget):
|
||||||
|
|
||||||
hyperlink_activated = pyqtSignal(object)
|
hyperlink_activated = pyqtSignal(object)
|
||||||
@ -250,7 +265,7 @@ class Box(QWidget):
|
|||||||
def show_data(self, data):
|
def show_data(self, data):
|
||||||
for w in self.widgets:
|
for w in self.widgets:
|
||||||
self.layout().removeWidget(w)
|
self.layout().removeWidget(w)
|
||||||
for x in ('toggled', 'hyperlink_activated'):
|
for x in ('toggled', 'hyperlink_activated', 'context_menu_requested'):
|
||||||
if hasattr(w, x):
|
if hasattr(w, x):
|
||||||
try:
|
try:
|
||||||
getattr(w, x).disconnect()
|
getattr(w, x).disconnect()
|
||||||
@ -279,6 +294,8 @@ class Box(QWidget):
|
|||||||
declaration = {'properties':[Property([k, ccss[k][0], '', ccss[k][1]]) for k in sorted(ccss)]}
|
declaration = {'properties':[Property([k, ccss[k][0], '', ccss[k][1]]) for k in sorted(ccss)]}
|
||||||
d = Declaration(None, declaration, is_first=True, parent=self)
|
d = Declaration(None, declaration, is_first=True, parent=self)
|
||||||
self.widgets.append(d), self.layout().addWidget(d)
|
self.widgets.append(d), self.layout().addWidget(d)
|
||||||
|
for w in self.widgets:
|
||||||
|
w.context_menu_requested.connect(self.context_menu_requested)
|
||||||
|
|
||||||
def heading_toggled(self, heading):
|
def heading_toggled(self, heading):
|
||||||
for i, w in enumerate(self.widgets):
|
for i, w in enumerate(self.widgets):
|
||||||
@ -294,6 +311,49 @@ class Box(QWidget):
|
|||||||
w.do_layout()
|
w.do_layout()
|
||||||
w.updateGeometry()
|
w.updateGeometry()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lines_for_copy(self):
|
||||||
|
ans = []
|
||||||
|
for w in self.widgets:
|
||||||
|
ans += w.lines_for_copy
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def context_menu_requested(self, widget, ev):
|
||||||
|
if isinstance(widget, Heading):
|
||||||
|
start = widget
|
||||||
|
else:
|
||||||
|
found = False
|
||||||
|
for w in reversed(self.widgets):
|
||||||
|
if w is widget:
|
||||||
|
found = True
|
||||||
|
elif found and isinstance(w, Heading):
|
||||||
|
start = w
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
found = False
|
||||||
|
lines = []
|
||||||
|
for w in self.widgets:
|
||||||
|
if found and isinstance(w, Heading):
|
||||||
|
break
|
||||||
|
if w is start:
|
||||||
|
found = True
|
||||||
|
if found:
|
||||||
|
lines += w.lines_for_copy
|
||||||
|
if not lines:
|
||||||
|
return
|
||||||
|
block = '\n'.join(lines).replace('\xa0', ' ')
|
||||||
|
heading = lines[0]
|
||||||
|
m = QMenu(self)
|
||||||
|
m.addAction(QIcon(I('edit-copy.png')), _('Copy') + ' ' + heading.replace('\xa0', ' '), lambda : QApplication.instance().clipboard().setText(block))
|
||||||
|
all_lines = []
|
||||||
|
for w in self.widgets:
|
||||||
|
all_lines += w.lines_for_copy
|
||||||
|
all_text = '\n'.join(all_lines).replace('\xa0', ' ')
|
||||||
|
m.addAction(QIcon(I('edit-copy.png')), _('Copy everything'), lambda : QApplication.instance().clipboard().setText(all_text))
|
||||||
|
m.exec_(ev.globalPos())
|
||||||
|
|
||||||
|
|
||||||
class Property(object):
|
class Property(object):
|
||||||
|
|
||||||
__slots__ = 'name', 'value', 'important', 'color', 'specificity', 'is_overriden'
|
__slots__ = 'name', 'value', 'important', 'color', 'specificity', 'is_overriden'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user