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]
|
[flake8]
|
||||||
max-line-length = 160
|
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
|
ignore = E12,E203,E22,E231,E241,E401,E402,E731,W391,E722,E741,W504
|
||||||
|
|
||||||
[yapf]
|
[yapf]
|
||||||
|
@ -2,8 +2,6 @@
|
|||||||
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
|
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
|
||||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QBrush, QCheckBox, QCoreApplication, QDialog, QGridLayout, QHBoxLayout, QIcon,
|
QBrush, QCheckBox, QCoreApplication, QDialog, QGridLayout, QHBoxLayout, QIcon,
|
||||||
QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton,
|
QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton,
|
||||||
@ -40,14 +38,14 @@ class Configure(Dialog):
|
|||||||
h.addWidget(fdo)
|
h.addWidget(fdo)
|
||||||
v = QVBoxLayout()
|
v = QVBoxLayout()
|
||||||
self.mub = b = QToolButton(self)
|
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.setIcon(QIcon(I('arrow-up.png')))
|
||||||
b.setToolTip(_('Move the selected field up'))
|
b.setToolTip(_('Move the selected field up'))
|
||||||
v.addWidget(b), v.addStretch(10)
|
v.addWidget(b), v.addStretch(10)
|
||||||
self.mud = b = QToolButton(self)
|
self.mud = b = QToolButton(self)
|
||||||
b.setIcon(QIcon(I('arrow-down.png')))
|
b.setIcon(QIcon(I('arrow-down.png')))
|
||||||
b.setToolTip(_('Move the selected field down'))
|
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)
|
v.addWidget(b)
|
||||||
h.addLayout(v)
|
h.addLayout(v)
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' \
|
|||||||
'2010, John Schember <john@nachtimwald.com>'
|
'2010, John Schember <john@nachtimwald.com>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from calibre.gui2.dialogs.confirm_delete_location_ui import Ui_Dialog
|
from calibre.gui2.dialogs.confirm_delete_location_ui import Ui_Dialog
|
||||||
from PyQt5.Qt import QDialog, Qt, QPixmap, QIcon
|
from PyQt5.Qt import QDialog, Qt, QPixmap, QIcon
|
||||||
|
|
||||||
@ -20,9 +18,9 @@ class Dialog(QDialog, Ui_Dialog):
|
|||||||
self.msg.setText(msg)
|
self.msg.setText(msg)
|
||||||
self.name = name
|
self.name = name
|
||||||
self.buttonBox.setFocus(Qt.OtherFocusReason)
|
self.buttonBox.setFocus(Qt.OtherFocusReason)
|
||||||
self.button_lib.clicked.connect(partial(self.set_loc, 'lib'))
|
connect_lambda(self.button_lib.clicked, self, lambda self: self.set_loc('lib'))
|
||||||
self.button_device.clicked.connect(partial(self.set_loc, 'dev'))
|
connect_lambda(self.button_device.clicked, self, lambda self: self.set_loc('dev'))
|
||||||
self.button_both.clicked.connect(partial(self.set_loc, 'both'))
|
connect_lambda(self.button_both.clicked, self, lambda self: self.set_loc('both'))
|
||||||
|
|
||||||
def set_loc(self, loc):
|
def set_loc(self, loc):
|
||||||
self.loc = loc
|
self.loc = loc
|
||||||
|
@ -6,7 +6,6 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
from PyQt5.Qt import (
|
from PyQt5.Qt import (
|
||||||
QVBoxLayout, QSplitter, QWidget, QLabel, QCheckBox, QTextBrowser, Qt,
|
QVBoxLayout, QSplitter, QWidget, QLabel, QCheckBox, QTextBrowser, Qt,
|
||||||
)
|
)
|
||||||
@ -116,7 +115,7 @@ class ChooseMerge(Dialog):
|
|||||||
l.addWidget(ans)
|
l.addWidget(ans)
|
||||||
prefs_key = ans.prefs_key = 'choose-merge-cb-' + name
|
prefs_key = ans.prefs_key = 'choose-merge-cb-' + name
|
||||||
ans.setChecked(gprefs.get(prefs_key, True))
|
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:
|
if tt:
|
||||||
ans.setToolTip(tt)
|
ans.setToolTip(tt)
|
||||||
setattr(self, name, ans)
|
setattr(self, name, ans)
|
||||||
|
@ -561,7 +561,7 @@ class CustomRecipes(Dialog):
|
|||||||
d.l = QVBoxLayout()
|
d.l = QVBoxLayout()
|
||||||
d.setLayout(d.l)
|
d.setLayout(d.l)
|
||||||
d.list = QListWidget(d)
|
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.l.addWidget(d.list)
|
||||||
d.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
|
d.bb = QDialogButtonBox(QDialogButtonBox.Ok|QDialogButtonBox.Cancel,
|
||||||
Qt.Horizontal, d)
|
Qt.Horizontal, d)
|
||||||
|
@ -177,10 +177,10 @@ class EximDialog(Dialog):
|
|||||||
l.addWidget(la)
|
l.addWidget(la)
|
||||||
l.addSpacing(20)
|
l.addSpacing(20)
|
||||||
self.exp_button = b = QPushButton(_('&Export all your calibre data'))
|
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)
|
l.addWidget(b), l.addSpacing(20)
|
||||||
self.imp_button = b = QPushButton(_('&Import previously exported data'))
|
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)
|
l.addWidget(b), l.addStretch(20)
|
||||||
|
|
||||||
self.setup_export_panel()
|
self.setup_export_panel()
|
||||||
|
@ -494,7 +494,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog):
|
|||||||
self.initialize_combos()
|
self.initialize_combos()
|
||||||
|
|
||||||
self.series.currentIndexChanged[int].connect(self.series_changed)
|
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.series.editTextChanged.connect(self.series_changed)
|
||||||
self.tag_editor_button.clicked.connect(self.tag_editor)
|
self.tag_editor_button.clicked.connect(self.tag_editor)
|
||||||
self.autonumber_series.stateChanged[int].connect(self.auto_number_changed)
|
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))
|
idx = max(0, self.casing_map.index(prevca))
|
||||||
self.casing_algorithm.setCurrentIndex(idx)
|
self.casing_algorithm.setCurrentIndex(idx)
|
||||||
self.casing_algorithm.setEnabled(False)
|
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:
|
if len(self.db.custom_field_keys(include_composites=False)) == 0:
|
||||||
self.central_widget.removeTab(1)
|
self.central_widget.removeTab(1)
|
||||||
|
@ -212,11 +212,11 @@ def create_date_tab(self, db):
|
|||||||
self.date_human = dh = a(QComboBox(w))
|
self.date_human = dh = a(QComboBox(w))
|
||||||
for val, text in [('today', _('Today')), ('yesterday', _('Yesterday')), ('thismonth', _('This month'))]:
|
for val, text in [('today', _('Today')), ('yesterday', _('Yesterday')), ('thismonth', _('This month'))]:
|
||||||
dh.addItem(text, val)
|
dh.addItem(text, val)
|
||||||
self.date_year.valueChanged.connect(lambda : self.sel_date.setChecked(True))
|
connect_lambda(self.date_year.valueChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||||
self.date_month.currentIndexChanged.connect(lambda : self.sel_date.setChecked(True))
|
connect_lambda(self.date_month.currentIndexChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||||
self.date_day.valueChanged.connect(lambda : self.sel_date.setChecked(True))
|
connect_lambda(self.date_day.valueChanged, self, lambda self: self.sel_date.setChecked(True))
|
||||||
self.date_daysago.valueChanged.connect(lambda : self.sel_daysago.setChecked(True))
|
connect_lambda(self.date_daysago.valueChanged, self, lambda self: self.sel_daysago.setChecked(True))
|
||||||
self.date_human.currentIndexChanged.connect(lambda : self.sel_human.setChecked(True))
|
connect_lambda(self.date_human.currentIndexChanged, self, lambda self: self.sel_human.setChecked(True))
|
||||||
self.sel_date.setChecked(True)
|
self.sel_date.setChecked(True)
|
||||||
h.addStretch(10)
|
h.addStretch(10)
|
||||||
|
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
from PyQt5.Qt import Qt, QDialog, QAbstractItemView
|
from PyQt5.Qt import Qt, QDialog, QAbstractItemView
|
||||||
|
|
||||||
from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor
|
from calibre.gui2.dialogs.tag_editor_ui import Ui_TagEditor
|
||||||
@ -67,19 +65,18 @@ class TagEditor(QDialog, Ui_TagEditor):
|
|||||||
if tag not in q:
|
if tag not in q:
|
||||||
self.available_tags.addItem(tag)
|
self.available_tags.addItem(tag)
|
||||||
|
|
||||||
self.apply_button.clicked.connect(lambda: self.apply_tags())
|
connect_lambda(self.apply_button.clicked, self, lambda self: self.apply_tags())
|
||||||
self.unapply_button.clicked.connect(lambda: self.unapply_tags())
|
connect_lambda(self.unapply_button.clicked, self, lambda self: self.unapply_tags())
|
||||||
self.add_tag_button.clicked.connect(self.add_tag)
|
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)
|
self.add_tag_input.returnPressed[()].connect(self.add_tag)
|
||||||
# add the handlers for the filter input fields
|
# add the handlers for the filter input fields
|
||||||
self.available_filter_input.textChanged.connect(self.filter_tags)
|
connect_lambda(self.available_filter_input.textChanged, self, lambda self, text: self.filter_tags(text))
|
||||||
self.applied_filter_input.textChanged.connect(partial(self.filter_tags, which='applied_tags'))
|
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)
|
# 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"))
|
for x in ('add_tag_input', 'available_filter_input', 'applied_filter_input'):
|
||||||
self.available_filter_input.textChanged.connect(partial(self.edit_box_changed, which="available_filter_input"))
|
connect_lambda(getattr(self, x).textChanged, self, lambda self: self.edit_box_changed(x))
|
||||||
self.applied_filter_input.textChanged.connect(partial(self.edit_box_changed, which="applied_filter_input"))
|
|
||||||
getattr(self, gprefs.get('tag_editor_last_filter', 'add_tag_input')).setFocus()
|
getattr(self, gprefs.get('tag_editor_last_filter', 'add_tag_input')).setFocus()
|
||||||
|
|
||||||
if islinux:
|
if islinux:
|
||||||
|
@ -153,6 +153,24 @@ if not _run_once:
|
|||||||
__builtin__.__dict__['icu_upper'] = icu_upper
|
__builtin__.__dict__['icu_upper'] = icu_upper
|
||||||
__builtin__.__dict__['icu_title'] = title_case
|
__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:
|
if islinux:
|
||||||
# Name all threads at the OS level created using the threading module, see
|
# Name all threads at the OS level created using the threading module, see
|
||||||
# http://bugs.python.org/issue15500
|
# http://bugs.python.org/issue15500
|
||||||
|
Loading…
x
Reference in New Issue
Block a user