mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Fix reference cycles due to lambda/partial slots in various dialogs
This commit is contained in:
parent
feec3e3024
commit
859917cce9
@ -1,6 +1,6 @@
|
||||
[flake8]
|
||||
max-line-length = 160
|
||||
builtins = _,dynamic_property,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext
|
||||
builtins = _,dynamic_property,__,P,I,lopen,icu_lower,icu_upper,icu_title,ngettext,connect_lambda
|
||||
ignore = E12,E203,E22,E231,E241,E401,E402,E731,W391,E722,E741,W504
|
||||
|
||||
[yapf]
|
||||
|
@ -2,8 +2,6 @@
|
||||
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.Qt import (
|
||||
QBrush, QCheckBox, QCoreApplication, QDialog, QGridLayout, QHBoxLayout, QIcon,
|
||||
QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton,
|
||||
@ -40,14 +38,14 @@ class Configure(Dialog):
|
||||
h.addWidget(fdo)
|
||||
v = QVBoxLayout()
|
||||
self.mub = b = QToolButton(self)
|
||||
b.clicked.connect(partial(move_field_up, fdo, self.model))
|
||||
connect_lambda(b.clicked, self, lambda self: move_field_up(fdo, self.model))
|
||||
b.setIcon(QIcon(I('arrow-up.png')))
|
||||
b.setToolTip(_('Move the selected field up'))
|
||||
v.addWidget(b), v.addStretch(10)
|
||||
self.mud = b = QToolButton(self)
|
||||
b.setIcon(QIcon(I('arrow-down.png')))
|
||||
b.setToolTip(_('Move the selected field down'))
|
||||
b.clicked.connect(partial(move_field_down, fdo, self.model))
|
||||
connect_lambda(b.clicked, self, lambda self: move_field_down(fdo, self.model))
|
||||
v.addWidget(b)
|
||||
h.addLayout(v)
|
||||
|
||||
|
@ -4,8 +4,6 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' \
|
||||
'2010, John Schember <john@nachtimwald.com>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from functools import partial
|
||||
|
||||
from calibre.gui2.dialogs.confirm_delete_location_ui import Ui_Dialog
|
||||
from PyQt5.Qt import QDialog, Qt, QPixmap, QIcon
|
||||
|
||||
@ -20,9 +18,9 @@ class Dialog(QDialog, Ui_Dialog):
|
||||
self.msg.setText(msg)
|
||||
self.name = name
|
||||
self.buttonBox.setFocus(Qt.OtherFocusReason)
|
||||
self.button_lib.clicked.connect(partial(self.set_loc, 'lib'))
|
||||
self.button_device.clicked.connect(partial(self.set_loc, 'dev'))
|
||||
self.button_both.clicked.connect(partial(self.set_loc, 'both'))
|
||||
connect_lambda(self.button_lib.clicked, self, lambda self: self.set_loc('lib'))
|
||||
connect_lambda(self.button_device.clicked, self, lambda self: self.set_loc('dev'))
|
||||
connect_lambda(self.button_both.clicked, self, lambda self: self.set_loc('both'))
|
||||
|
||||
def set_loc(self, loc):
|
||||
self.loc = loc
|
||||
|
@ -6,7 +6,6 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from functools import partial
|
||||
from PyQt5.Qt import (
|
||||
QVBoxLayout, QSplitter, QWidget, QLabel, QCheckBox, QTextBrowser, Qt,
|
||||
)
|
||||
@ -116,7 +115,7 @@ class ChooseMerge(Dialog):
|
||||
l.addWidget(ans)
|
||||
prefs_key = ans.prefs_key = 'choose-merge-cb-' + name
|
||||
ans.setChecked(gprefs.get(prefs_key, True))
|
||||
ans.stateChanged.connect(partial(self.state_changed, ans), type=Qt.QueuedConnection)
|
||||
connect_lambda(ans.stateChanged, self, lambda self, state: self.state_changed(ans, state), type=Qt.QueuedConnection)
|
||||
if tt:
|
||||
ans.setToolTip(tt)
|
||||
setattr(self, name, ans)
|
||||
|
@ -561,7 +561,7 @@ class CustomRecipes(Dialog):
|
||||
d.l = QVBoxLayout()
|
||||
d.setLayout(d.l)
|
||||
d.list = QListWidget(d)
|
||||
d.list.doubleClicked.connect(lambda x: d.accept())
|
||||
connect_lambda(d.list.doubleClicked, d, lambda d: d.accept())
|
||||
d.l.addWidget(d.list)
|
||||
d.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
|
||||
Qt.Horizontal, d)
|
||||
|
@ -177,10 +177,10 @@ class EximDialog(Dialog):
|
||||
l.addWidget(la)
|
||||
l.addSpacing(20)
|
||||
self.exp_button = b = QPushButton(_('&Export all your calibre data'))
|
||||
b.clicked.connect(partial(self.show_panel, 'export'))
|
||||
connect_lambda(b.clicked, self, lambda self: self.show_panel('export'))
|
||||
l.addWidget(b), l.addSpacing(20)
|
||||
self.imp_button = b = QPushButton(_('&Import previously exported data'))
|
||||
b.clicked.connect(partial(self.show_panel, 'import'))
|
||||
connect_lambda(b.clicked, self, lambda self: self.show_panel('import'))
|
||||
l.addWidget(b), l.addStretch(20)
|
||||
|
||||
self.setup_export_panel()
|
||||
|
@ -494,7 +494,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
self.initialize_combos()
|
||||
|
||||
self.series.currentIndexChanged[int].connect(self.series_changed)
|
||||
self.rating.currentIndexChanged.connect(lambda:self.apply_rating.setChecked(True))
|
||||
connect_lambda(self.rating.currentIndexChanged, self, lambda self:self.apply_rating.setChecked(True))
|
||||
self.series.editTextChanged.connect(self.series_changed)
|
||||
self.tag_editor_button.clicked.connect(self.tag_editor)
|
||||
self.autonumber_series.stateChanged[int].connect(self.auto_number_changed)
|
||||
@ -525,7 +525,9 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
||||
idx = max(0, self.casing_map.index(prevca))
|
||||
self.casing_algorithm.setCurrentIndex(idx)
|
||||
self.casing_algorithm.setEnabled(False)
|
||||
self.change_title_to_title_case.toggled.connect(lambda : self.casing_algorithm.setEnabled(self.change_title_to_title_case.isChecked()))
|
||||
connect_lambda(
|
||||
self.change_title_to_title_case.toggled, self,
|
||||
lambda self: self.casing_algorithm.setEnabled(self.change_title_to_title_case.isChecked()))
|
||||
|
||||
if len(self.db.custom_field_keys(include_composites=False)) == 0:
|
||||
self.central_widget.removeTab(1)
|
||||
|
@ -212,11 +212,11 @@ def create_date_tab(self, db):
|
||||
self.date_human = dh = a(QComboBox(w))
|
||||
for val, text in [('today', _('Today')), ('yesterday', _('Yesterday')), ('thismonth', _('This month'))]:
|
||||
dh.addItem(text, val)
|
||||
self.date_year.valueChanged.connect(lambda : self.sel_date.setChecked(True))
|
||||
self.date_month.currentIndexChanged.connect(lambda : self.sel_date.setChecked(True))
|
||||
self.date_day.valueChanged.connect(lambda : self.sel_date.setChecked(True))
|
||||
self.date_daysago.valueChanged.connect(lambda : self.sel_daysago.setChecked(True))
|
||||
self.date_human.currentIndexChanged.connect(lambda : self.sel_human.setChecked(True))
|
||||
connect_lambda(self.date_year.valueChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||
connect_lambda(self.date_month.currentIndexChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||
connect_lambda(self.date_day.valueChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||
connect_lambda(self.date_daysago.valueChanged, self, lambda self: self.sel_daysago.setChecked(True))
|
||||
connect_lambda(self.date_human.currentIndexChanged, self, lambda self: self.sel_human.setChecked(True))
|
||||
self.sel_date.setChecked(True)
|
||||
h.addStretch(10)
|
||||
|
||||
|
@ -1,8 +1,6 @@
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from functools import partial
|
||||
|
||||
from PyQt5.Qt import Qt, QDialog, QAbstractItemView
|
||||
|
||||
from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor
|
||||
@ -67,19 +65,18 @@ class TagEditor(QDialog, Ui_TagEditor):
|
||||
if tag not in q:
|
||||
self.available_tags.addItem(tag)
|
||||
|
||||
self.apply_button.clicked.connect(lambda: self.apply_tags())
|
||||
self.unapply_button.clicked.connect(lambda: self.unapply_tags())
|
||||
connect_lambda(self.apply_button.clicked, self, lambda self: self.apply_tags())
|
||||
connect_lambda(self.unapply_button.clicked, self, lambda self: self.unapply_tags())
|
||||
self.add_tag_button.clicked.connect(self.add_tag)
|
||||
self.delete_button.clicked.connect(lambda: self.delete_tags())
|
||||
connect_lambda(self.delete_button.clicked, self, lambda self: self.delete_tags())
|
||||
self.add_tag_input.returnPressed[()].connect(self.add_tag)
|
||||
# add the handlers for the filter input fields
|
||||
self.available_filter_input.textChanged.connect(self.filter_tags)
|
||||
self.applied_filter_input.textChanged.connect(partial(self.filter_tags, which='applied_tags'))
|
||||
connect_lambda(self.available_filter_input.textChanged, self, lambda self, text: self.filter_tags(text))
|
||||
connect_lambda(self.applied_filter_input.textChanged, self, lambda self, text: self.filter_tags(text, which='applied_tags'))
|
||||
|
||||
# Restore the focus to the last input box used (typed into)
|
||||
self.add_tag_input.textChanged.connect(partial(self.edit_box_changed, which="add_tag_input"))
|
||||
self.available_filter_input.textChanged.connect(partial(self.edit_box_changed, which="available_filter_input"))
|
||||
self.applied_filter_input.textChanged.connect(partial(self.edit_box_changed, which="applied_filter_input"))
|
||||
for x in ('add_tag_input', 'available_filter_input', 'applied_filter_input'):
|
||||
connect_lambda(getattr(self, x).textChanged, self, lambda self: self.edit_box_changed(x))
|
||||
getattr(self, gprefs.get('tag_editor_last_filter', 'add_tag_input')).setFocus()
|
||||
|
||||
if islinux:
|
||||
|
@ -153,6 +153,24 @@ if not _run_once:
|
||||
__builtin__.__dict__['icu_upper'] = icu_upper
|
||||
__builtin__.__dict__['icu_title'] = title_case
|
||||
|
||||
def connect_lambda(bound_signal, self, func, **kw):
|
||||
import weakref
|
||||
r = weakref.ref(self)
|
||||
del self
|
||||
num_args = func.__code__.co_argcount - 1
|
||||
if num_args < 0:
|
||||
raise TypeError('lambda must take at least one argument')
|
||||
|
||||
def slot(*args):
|
||||
ctx = r()
|
||||
if ctx is not None:
|
||||
if len(args) != num_args:
|
||||
args = args[:num_args]
|
||||
func(ctx, *args)
|
||||
|
||||
bound_signal.connect(slot, **kw)
|
||||
__builtin__.__dict__['connect_lambda'] = connect_lambda
|
||||
|
||||
if islinux:
|
||||
# Name all threads at the OS level created using the threading module, see
|
||||
# http://bugs.python.org/issue15500
|
||||
|
Loading…
x
Reference in New Issue
Block a user