mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Edit metadata dialog: Elide the names of custom columns that are longer than a fixed width, instead of using multiple lines. Configurable via Preferences->Tweaks->Edit metadata custom column label length
Merge branch 'master' of https://github.com/cbhaley/calibre into master
This commit is contained in:
commit
d8e502507b
@ -404,6 +404,13 @@ metadata_single_use_2_cols_for_custom_fields = True
|
||||
# metadata_edit_custom_column_order = ['#genre', '#mytags', '#etc']
|
||||
metadata_edit_custom_column_order = []
|
||||
|
||||
#: Edit metadata custom column label length
|
||||
# Set the length of custom column labels shown in the edit metadata dialogs.
|
||||
# Labels longer than this length will be elided. The length is computed by
|
||||
# multiplying the average width of characters in the font by the number below.
|
||||
metadata_edit_bulk_cc_label_length = 25
|
||||
metadata_edit_single_cc_label_length = 12
|
||||
|
||||
#: The number of seconds to wait before sending emails
|
||||
# The number of seconds to wait before sending emails when using a
|
||||
# public email server like GMX/Hotmail/Gmail. Default is: 5 minutes
|
||||
|
@ -7,6 +7,7 @@ __copyright__ = '2014, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from collections import defaultdict
|
||||
from functools import partial
|
||||
from operator import itemgetter
|
||||
|
||||
from css_parser.css import CSSRule, CSSStyleDeclaration
|
||||
from css_selectors import parse, SelectorSyntaxError
|
||||
@ -74,6 +75,37 @@ def merge_identical_selectors(sheet):
|
||||
return len(remove)
|
||||
|
||||
|
||||
def merge_identical_properties(sheet):
|
||||
' Merge rules having identical properties '
|
||||
properties_map = defaultdict(list)
|
||||
|
||||
def declaration_key(declaration):
|
||||
items = []
|
||||
for prop in declaration.getProperties():
|
||||
val = prop.propertyValue.value
|
||||
name = prop.name
|
||||
items.append((name, val))
|
||||
items.sort(key=itemgetter(0))
|
||||
return tuple(items)
|
||||
|
||||
for rule in sheet.cssRules.rulesOfType(CSSRule.STYLE_RULE):
|
||||
properties_map[declaration_key(rule.style)].append(rule)
|
||||
|
||||
for rule_group in properties_map.values():
|
||||
if len(rule_group) < 2:
|
||||
continue
|
||||
selectors = rule_group[0].selectorList
|
||||
seen = {s.selectorText for s in selectors}
|
||||
rules = iter(rule_group)
|
||||
next(rules)
|
||||
for rule in rules:
|
||||
for s in rule.selectorList:
|
||||
q = s.selectorText
|
||||
if q not in seen:
|
||||
seen.add(q)
|
||||
selectors.append(s)
|
||||
|
||||
|
||||
def remove_unused_css(container, report=None, remove_unused_classes=False, merge_rules=False):
|
||||
'''
|
||||
Remove all unused CSS rules from the book. An unused CSS rule is one that does not match any actual content.
|
||||
|
@ -9,15 +9,15 @@ __docformat__ = 'restructuredtext en'
|
||||
import os
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.Qt import (QComboBox, QLabel, QSpinBox, QDoubleSpinBox,
|
||||
from PyQt5.Qt import (Qt, QComboBox, QLabel, QSpinBox, QDoubleSpinBox,
|
||||
QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, QGridLayout, QUrl,
|
||||
QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, QLineEdit,
|
||||
QPushButton, QMessageBox, QToolButton, QPlainTextEdit)
|
||||
QMessageBox, QToolButton, QPlainTextEdit)
|
||||
|
||||
from calibre.utils.date import qt_to_dt, now, as_local_time, as_utc, internal_iso_format_string
|
||||
from calibre.gui2.complete2 import EditWithComplete
|
||||
from calibre.gui2.comments_editor import Editor as CommentsEditor
|
||||
from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog
|
||||
from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog, elided_text
|
||||
from calibre.gui2.dialogs.tag_editor import TagEditor
|
||||
from calibre.utils.config import tweaks
|
||||
from calibre.utils.icu import sort_key
|
||||
@ -161,32 +161,22 @@ class Bool(Base):
|
||||
self.combobox = QComboBox(parent)
|
||||
l.addWidget(self.combobox)
|
||||
|
||||
t = _('Yes')
|
||||
c = QPushButton(t, parent)
|
||||
width = c.fontMetrics().boundingRect(t).width() + 7
|
||||
c.setMaximumWidth(width)
|
||||
c = QToolButton(parent)
|
||||
c.setText(_('Yes'))
|
||||
l.addWidget(c)
|
||||
c.clicked.connect(self.set_to_yes)
|
||||
|
||||
t = _('No')
|
||||
c = QPushButton(t, parent)
|
||||
width = c.fontMetrics().boundingRect(t).width() + 7
|
||||
c.setMaximumWidth(width)
|
||||
c = QToolButton(parent)
|
||||
c.setText(_('No'))
|
||||
l.addWidget(c)
|
||||
c.clicked.connect(self.set_to_no)
|
||||
|
||||
if self.db.new_api.pref('bools_are_tristate'):
|
||||
t = _('Clear')
|
||||
c = QPushButton(t, parent)
|
||||
width = c.fontMetrics().boundingRect(t).width() + 7
|
||||
c.setMaximumWidth(width)
|
||||
c = QToolButton(parent)
|
||||
c.setText(_('Clear'))
|
||||
l.addWidget(c)
|
||||
c.clicked.connect(self.set_to_cleared)
|
||||
|
||||
c = QLabel('', parent)
|
||||
c.setMaximumWidth(1)
|
||||
l.addWidget(c, 1)
|
||||
|
||||
w = self.combobox
|
||||
items = [_('Yes'), _('No'), _('Undefined')]
|
||||
icons = [I('ok.png'), I('list_remove.png'), I('blank.png')]
|
||||
@ -326,15 +316,16 @@ class DateTime(Base):
|
||||
dte.setMinimumDateTime(UNDEFINED_QDATETIME)
|
||||
dte.setSpecialValueText(_('Undefined'))
|
||||
l.addWidget(dte)
|
||||
|
||||
self.today_button = QToolButton(parent)
|
||||
self.today_button.setText(_('Today'))
|
||||
self.today_button.clicked.connect(dte.set_to_today)
|
||||
l.addWidget(self.today_button)
|
||||
|
||||
self.clear_button = QToolButton(parent)
|
||||
self.clear_button.setIcon(QIcon(I('trash.png')))
|
||||
self.clear_button.clicked.connect(dte.set_to_clear)
|
||||
l.addWidget(self.clear_button)
|
||||
l.addStretch(1)
|
||||
|
||||
def setter(self, val):
|
||||
if val is None:
|
||||
@ -755,7 +746,7 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
|
||||
turnover_point = count + 1000
|
||||
ans = []
|
||||
column = row = base_row = max_row = 0
|
||||
minimum_label = 0
|
||||
label_width = 0
|
||||
for key in cols:
|
||||
if not fm[key]['is_editable']:
|
||||
continue # this almost never happens
|
||||
@ -780,6 +771,7 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
|
||||
comments_not_in_tweak = 0
|
||||
|
||||
l = QGridLayout()
|
||||
l.setHorizontalSpacing(0)
|
||||
if is_comments:
|
||||
layout.addLayout(l, row, column, layout_rows_for_comments, 1)
|
||||
layout.setColumnStretch(column, 100)
|
||||
@ -790,33 +782,28 @@ def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, pa
|
||||
row += 1
|
||||
for c in range(0, len(w.widgets), 2):
|
||||
if not is_comments:
|
||||
w.widgets[c].setWordWrap(True)
|
||||
'''
|
||||
It seems that there is something strange with wordwrapped labels
|
||||
with some fonts. Apparently one part of QT thinks it is showing
|
||||
a single line and sizes the line vertically accordingly. Another
|
||||
part thinks there isn't enough space and wraps the label. The
|
||||
result is two lines in a single line space, cutting off parts of
|
||||
the lines. It doesn't happen with every font, nor with every
|
||||
"long" label.
|
||||
|
||||
This change works around the problem by setting the maximum
|
||||
display width and telling QT to respect that width.
|
||||
|
||||
While here I implemented an arbitrary minimum label length so
|
||||
that there is a better chance that the field edit boxes line up.
|
||||
'''
|
||||
if minimum_label == 0:
|
||||
minimum_label = w.widgets[c].fontMetrics().boundingRect('smallLabel').width()
|
||||
label_width = w.widgets[c].fontMetrics().boundingRect(w.widgets[c].text()).width()
|
||||
if c == 0:
|
||||
w.widgets[0].setMaximumWidth(label_width)
|
||||
w.widgets[0].setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
|
||||
l.setColumnMinimumWidth(0, minimum_label)
|
||||
# Set the label column width to a fixed size. Elide labels that
|
||||
# don't fit
|
||||
wij = w.widgets[c]
|
||||
if label_width == 0:
|
||||
font_metrics = wij.fontMetrics()
|
||||
if bulk:
|
||||
label_width = (font_metrics.averageCharWidth() *
|
||||
tweaks['metadata_edit_bulk_cc_label_length'])
|
||||
else:
|
||||
w.widgets[0].setMaximumWidth(max(w.widgets[0].maximumWidth(), label_width))
|
||||
w.widgets[c].setBuddy(w.widgets[c+1])
|
||||
l.addWidget(w.widgets[c], c, 0)
|
||||
label_width = (font_metrics.averageCharWidth() *
|
||||
tweaks['metadata_edit_single_cc_label_length'])
|
||||
wij.setMaximumWidth(label_width)
|
||||
if c == 0:
|
||||
wij.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
|
||||
l.setColumnMinimumWidth(0, label_width)
|
||||
wij.setAlignment(Qt.AlignRight|Qt.AlignVCenter)
|
||||
t = unicode_type(wij.text())
|
||||
wij.setToolTip(t[1:-1] if t.startswith('&') else t[:-1])
|
||||
wij.setText(elided_text(t+' ', font=font_metrics,
|
||||
width=label_width, pos='right'))
|
||||
wij.setBuddy(w.widgets[c+1])
|
||||
l.addWidget(wij, c, 0)
|
||||
l.addWidget(w.widgets[c+1], c, 1)
|
||||
else:
|
||||
l.addWidget(w.widgets[0], 0, 0, 1, 2)
|
||||
@ -1306,7 +1293,7 @@ class BulkText(BulkBase):
|
||||
w = RemoveTags(parent, values)
|
||||
w.remove_tags_button.clicked.connect(self.edit_remove)
|
||||
self.widgets.append(QLabel(label_string(self.col_metadata['name'])+': ' +
|
||||
_('tags to remove'), parent))
|
||||
_('tags to remove') + ':', parent))
|
||||
self.widgets.append(w)
|
||||
self.removing_widget = w
|
||||
self.main_widget.set_separator(',')
|
||||
|
Loading…
x
Reference in New Issue
Block a user