%PDF- %PDF-
| Direktori : /lib/calibre/calibre/gui2/preferences/ |
| Current File : //lib/calibre/calibre/gui2/preferences/plugboard.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import copy
from collections import defaultdict
from qt.core import Qt, QComboBox, QListWidgetItem
from calibre.customize.ui import is_disabled
from calibre.gui2 import error_dialog, question_dialog, warning_dialog
from calibre.gui2.device import device_name_for_plugboards
from calibre.gui2.dialogs.template_line_editor import TemplateLineEditor
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
from calibre.gui2.preferences.plugboard_ui import Ui_Form
from calibre.customize.ui import metadata_writers, device_plugins, disabled_device_plugins
from calibre.library.save_to_disk import plugboard_any_format_value, \
plugboard_any_device_value, plugboard_save_to_disk_value, \
find_plugboard
from calibre.srv.content import plugboard_content_server_value, plugboard_content_server_formats
from calibre.gui2.email import plugboard_email_value, plugboard_email_formats
from calibre.utils.formatter import validation_formatter
from polyglot.builtins import native_string_type
class ConfigWidget(ConfigWidgetBase, Ui_Form):
def genesis(self, gui):
self.gui = gui
self.db = gui.library_view.model().db
def initialize(self):
ConfigWidgetBase.initialize(self)
self.current_plugboards = copy.deepcopy(self.db.prefs.get('plugboards',{}))
self.current_device = None
self.current_format = None
if self.gui.device_manager.connected_device is not None:
self.device_label.setText(_('Device currently connected: ') +
self.gui.device_manager.connected_device.__class__.__name__)
else:
self.device_label.setText(_('Device currently connected: None'))
self.devices = ['', 'APPLE', 'FOLDER_DEVICE']
self.disabled_devices = []
self.device_to_formats_map = {}
for device in device_plugins():
n = device_name_for_plugboards(device)
self.device_to_formats_map[n] = set(device.settings().format_map)
if getattr(device, 'CAN_DO_DEVICE_DB_PLUGBOARD', False):
self.device_to_formats_map[n].add('device_db')
if n not in self.devices:
self.devices.append(n)
for device in disabled_device_plugins():
n = device_name_for_plugboards(device)
if n not in self.disabled_devices:
self.disabled_devices.append(n)
self.devices.sort(key=lambda x: x.lower())
self.devices.insert(1, plugboard_save_to_disk_value)
self.devices.insert(1, plugboard_content_server_value)
self.device_to_formats_map[plugboard_content_server_value] = \
plugboard_content_server_formats
self.devices.insert(1, plugboard_email_value)
self.device_to_formats_map[plugboard_email_value] = \
plugboard_email_formats
self.devices.insert(1, plugboard_any_device_value)
self.new_device.addItems(self.devices)
self.formats = ['']
self.format_to_writers_map = defaultdict(list)
for w in metadata_writers():
for f in w.file_types:
if f not in self.formats:
self.formats.append(f)
self.format_to_writers_map[f].append(w)
self.formats.append('device_db')
self.formats.sort()
self.formats.insert(1, plugboard_any_format_value)
self.new_format.addItems(self.formats)
self.dest_fields = ['',
'authors', 'author_sort', 'language', 'publisher',
'series', 'tags', 'title', 'title_sort', 'comments']
self.source_widgets = []
self.dest_widgets = []
for i in range(0, len(self.dest_fields)-1):
w = TemplateLineEditor(self)
self.source_widgets.append(w)
self.fields_layout.addWidget(w, 5+i, 0, 1, 1)
w = QComboBox(self)
self.dest_widgets.append(w)
self.fields_layout.addWidget(w, 5+i, 1, 1, 1)
self.edit_device.currentIndexChanged[native_string_type].connect(self.edit_device_changed)
self.edit_format.currentIndexChanged[native_string_type].connect(self.edit_format_changed)
self.new_device.currentIndexChanged[native_string_type].connect(self.new_device_changed)
self.new_format.currentIndexChanged[native_string_type].connect(self.new_format_changed)
self.existing_plugboards.itemClicked.connect(self.existing_pb_clicked)
self.ok_button.clicked.connect(self.ok_clicked)
self.del_button.clicked.connect(self.del_clicked)
self.refilling = False
self.refill_all_boxes()
def clear_fields(self, edit_boxes=False, new_boxes=False):
self.ok_button.setEnabled(False)
self.del_button.setEnabled(False)
for w in self.source_widgets:
w.clear()
for w in self.dest_widgets:
w.clear()
if edit_boxes:
self.edit_device.setCurrentIndex(0)
self.edit_format.setCurrentIndex(0)
if new_boxes:
self.new_device.setCurrentIndex(0)
self.new_format.setCurrentIndex(0)
def set_fields(self):
self.ok_button.setEnabled(True)
self.del_button.setEnabled(True)
for w in self.source_widgets:
w.clear()
for w in self.dest_widgets:
w.addItems(self.dest_fields)
def set_field(self, i, src, dst):
self.source_widgets[i].setText(src)
idx = self.dest_fields.index(dst)
self.dest_widgets[i].setCurrentIndex(idx)
def edit_device_changed(self, txt):
self.current_device = None
if txt == '':
self.clear_fields(new_boxes=False)
return
self.clear_fields(new_boxes=True)
self.current_device = str(txt)
fpb = self.current_plugboards.get(self.current_format, None)
if fpb is None:
print('edit_device_changed: none format!')
return
dpb = fpb.get(self.current_device, None)
if dpb is None:
print('edit_device_changed: none device!')
return
self.set_fields()
for i,op in enumerate(dpb):
self.set_field(i, op[0], op[1])
self.ok_button.setEnabled(True)
self.del_button.setEnabled(True)
def edit_format_changed(self, txt):
self.edit_device.setCurrentIndex(0)
self.current_device = None
self.current_format = None
if txt == '':
self.clear_fields(new_boxes=False)
return
self.clear_fields(new_boxes=True)
txt = str(txt)
fpb = self.current_plugboards.get(txt, None)
if fpb is None:
print('edit_format_changed: none editable format!')
return
self.current_format = txt
self.check_if_writer_disabled(txt)
devices = ['']
for d in fpb:
devices.append(d)
self.edit_device.clear()
self.edit_device.addItems(devices)
def check_if_writer_disabled(self, format_name):
if format_name in ['device_db', plugboard_any_format_value]:
return
show_message = True
for writer in self.format_to_writers_map[format_name]:
if not is_disabled(writer):
show_message = False
if show_message:
warning_dialog(self, '',
_('That format has no metadata writers enabled. A plugboard '
'will probably have no effect.'),
show=True)
def new_device_changed(self, txt):
self.current_device = None
if txt == '':
self.clear_fields(edit_boxes=False)
return
self.clear_fields(edit_boxes=True)
self.current_device = str(txt)
if self.current_format in self.current_plugboards and \
self.current_device in self.current_plugboards[self.current_format]:
error_dialog(self, '',
_('That format and device already has a plugboard.'),
show=True)
self.new_device.setCurrentIndex(0)
return
# If we have a specific format/device combination, check if a more
# general combination matches.
if self.current_format != plugboard_any_format_value and \
self.current_device != plugboard_any_device_value:
if find_plugboard(self.current_device, self.current_format,
self.current_plugboards):
if not question_dialog(self.gui,
_('Possibly override plugboard?'),
_('A more general plugboard already exists for '
'that format and device. '
'Are you sure you want to add the new plugboard?')):
self.new_device.setCurrentIndex(0)
return
# If we have a specific format, check if we are adding a possibly-
# covered plugboard
if self.current_format != plugboard_any_format_value:
if self.current_format in self.current_plugboards:
if self.current_device == plugboard_any_device_value:
if not question_dialog(self.gui,
_('Add possibly overridden plugboard?'),
_('More specific device plugboards exist for '
'that format. '
'Are you sure you want to add the new plugboard?')):
self.new_device.setCurrentIndex(0)
return
# We are adding an 'any format' entry. Check if we are adding a specific
# device and if so, does some other plugboard match that device.
elif self.current_device != plugboard_any_device_value:
for fmt in self.current_plugboards:
if find_plugboard(self.current_device, fmt, self.current_plugboards):
if not question_dialog(self.gui,
_('Really add plugboard?'),
_('A different plugboard matches that format and '
'device combination. '
'Are you sure you want to add the new plugboard?')):
self.new_device.setCurrentIndex(0)
return
# We are adding an any format/any device entry, which will be overridden
# by any other entry. Ask if such entries exist.
elif len(self.current_plugboards):
if not question_dialog(self.gui,
_('Add possibly overridden plugboard?'),
_('More specific format and device plugboards '
'already exist. '
'Are you sure you want to add the new plugboard?')):
self.new_device.setCurrentIndex(0)
return
if self.current_format != plugboard_any_format_value and \
self.current_device in self.device_to_formats_map:
allowable_formats = self.device_to_formats_map[self.current_device]
if self.current_format not in allowable_formats:
error_dialog(self, '',
_('The {0} device does not support the {1} format.').
format(self.current_device, self.current_format), show=True)
self.new_device.setCurrentIndex(0)
return
if self.current_format == plugboard_any_format_value and \
self.current_device == plugboard_content_server_value:
warning_dialog(self, '',
_('The {0} device supports only the {1} format(s).').
format(plugboard_content_server_value,
', '.join(plugboard_content_server_formats)), show=True)
self.set_fields()
def new_format_changed(self, txt):
self.current_format = None
self.current_device = None
self.new_device.setCurrentIndex(0)
if txt:
self.clear_fields(edit_boxes=True)
self.current_format = str(txt)
self.check_if_writer_disabled(self.current_format)
else:
self.clear_fields(edit_boxes=False)
def ok_clicked(self):
pb = []
comments_in_dests = False
for i in range(0, len(self.source_widgets)):
s = str(self.source_widgets[i].text())
if s:
d = self.dest_widgets[i].currentIndex()
if d != 0:
try:
validation_formatter.validate(s)
except Exception as err:
error_dialog(self, _('Invalid template'),
'<p>'+_('The template %s is invalid:')%s +
'<br>'+str(err), show=True)
return
pb.append((s, self.dest_fields[d]))
comments_in_dests = comments_in_dests or self.dest_fields[d] == 'comments'
else:
error_dialog(self, _('Invalid destination'),
'<p>'+_('The destination field cannot be blank'),
show=True)
return
if len(pb) == 0:
if self.current_format in self.current_plugboards:
fpb = self.current_plugboards[self.current_format]
if self.current_device in fpb:
del fpb[self.current_device]
if len(fpb) == 0:
del self.current_plugboards[self.current_format]
else:
if comments_in_dests and not question_dialog(self.gui, _('Plugboard modifies comments'),
_('This plugboard modifies the comments metadata. '
'If the comments are set to invalid HTML, it could cause problems on the device. '
'Are you sure you wish to save this plugboard?'
),
skip_dialog_name='plugboard_comments_in_dests'
):
return
if self.current_format not in self.current_plugboards:
self.current_plugboards[self.current_format] = {}
fpb = self.current_plugboards[self.current_format]
fpb[self.current_device] = pb
self.changed_signal.emit()
self.refill_all_boxes()
def del_clicked(self):
if self.current_format in self.current_plugboards:
fpb = self.current_plugboards[self.current_format]
if self.current_device in fpb:
del fpb[self.current_device]
if len(fpb) == 0:
del self.current_plugboards[self.current_format]
self.changed_signal.emit()
self.refill_all_boxes()
def existing_pb_clicked(self, qitem):
item = qitem.data(Qt.ItemDataRole.UserRole)
if (qitem.flags() & Qt.ItemFlag.ItemIsEnabled):
self.edit_format.setCurrentIndex(self.edit_format.findText(item[0]))
self.edit_device.setCurrentIndex(self.edit_device.findText(item[1]))
else:
warning_dialog(self, '',
_('The {0} device plugin is disabled.').format(item[1]),
show=True)
def refill_all_boxes(self):
if self.refilling:
return
self.refilling = True
self.current_device = None
self.current_format = None
self.clear_fields(new_boxes=True)
self.edit_format.clear()
self.edit_format.addItem('')
for format_ in self.current_plugboards:
self.edit_format.addItem(format_)
self.edit_format.setCurrentIndex(0)
self.edit_device.clear()
self.ok_button.setEnabled(False)
self.del_button.setEnabled(False)
self.existing_plugboards.clear()
for f in self.formats:
if f not in self.current_plugboards:
continue
for d in sorted(self.devices + self.disabled_devices, key=lambda x:x.lower()):
if d not in self.current_plugboards[f]:
continue
ops = []
for op in self.current_plugboards[f][d]:
ops.append('([' + op[0] + '] -> ' + op[1] + ')')
txt = '%s:%s = %s\n'%(f, d, ', '.join(ops))
item = QListWidgetItem(txt)
item.setData(Qt.ItemDataRole.UserRole, (f, d))
if d in self.disabled_devices:
item.setFlags(item.flags() & ~Qt.ItemFlag.ItemIsEnabled)
self.existing_plugboards.addItem(item)
self.refilling = False
def restore_defaults(self):
ConfigWidgetBase.restore_defaults(self)
self.current_plugboards = {}
self.refill_all_boxes()
self.changed_signal.emit()
def commit(self):
self.db.new_api.set_pref('plugboards', self.current_plugboards)
return ConfigWidgetBase.commit(self)
def refresh_gui(self, gui):
pass
if __name__ == '__main__':
from qt.core import QApplication
app = QApplication([])
test_widget('Import/Export', 'Plugboard')