class DeviceListGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Show as on device")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.show_recommendations_checkbox = create_checkbox( _("Show recommendations"), _('Kobo shows recommendations on the device. In some cases these have ' 'files but in other cases they are just pointers to the web site to buy. ' 'Enable if you wish to see/delete them.'), device.get_pref('show_recommendations') ) self.show_archived_books_checkbox = create_checkbox( _("Show archived books"), _('Archived books are listed on the device but need to be downloaded to read.' ' Use this option to show these books and match them with books in the calibre library.'), device.get_pref('show_archived_books') ) self.show_previews_checkbox = create_checkbox( _('Show previews'), _('Kobo previews are included on the Touch and some other versions' ' by default they are no longer displayed as there is no good reason to ' 'see them. Enable if you wish to see/delete them.'), device.get_pref('show_previews') ) self.options_layout.addWidget(self.show_recommendations_checkbox, 0, 0, 1, 1) self.options_layout.addWidget(self.show_archived_books_checkbox, 1, 0, 1, 1) self.options_layout.addWidget(self.show_previews_checkbox, 2, 0, 1, 1) @property def show_recommendations(self): return self.show_recommendations_checkbox.isChecked() @property def show_archived_books(self): return self.show_archived_books_checkbox.isChecked() @property def show_previews(self): return self.show_previews_checkbox.isChecked()
class AdvancedGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super(AdvancedGroupBox, self).__init__(parent, device, _("Advanced options")) # self.setTitle(_("Advanced Options")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.support_newer_firmware_checkbox = create_checkbox( _("Attempt to support newer firmware"), _('Kobo routinely updates the firmware and the ' 'database version. With this option calibre will attempt ' 'to perform full read-write functionality - Here be Dragons!! ' 'Enable only if you are comfortable with restoring your kobo ' 'to factory defaults and testing software. ' 'This driver supports firmware V2.x.x and DBVersion up to ') + unicode_type(device.supported_dbversion), device.get_pref('support_newer_firmware')) self.debugging_title_checkbox = create_checkbox( _("Title to test when debugging"), _('Part of title of a book that can be used when doing some tests for debugging. ' 'The test is to see if the string is contained in the title of a book. ' 'The better the match, the less extraneous output.'), device.get_pref('debugging_title')) self.debugging_title_label = QLabel(_('Title to test when debugging:')) self.debugging_title_edit = QLineEdit(self) self.debugging_title_edit.setToolTip( _('Part of title of a book that can be used when doing some tests for debugging. ' 'The test is to see if the string is contained in the title of a book. ' 'The better the match, the less extraneous output.')) self.debugging_title_edit.setText(device.get_pref('debugging_title')) self.debugging_title_label.setBuddy(self.debugging_title_edit) self.options_layout.addWidget(self.support_newer_firmware_checkbox, 0, 0, 1, 2) self.options_layout.addWidget(self.debugging_title_label, 1, 0, 1, 1) self.options_layout.addWidget(self.debugging_title_edit, 1, 1, 1, 1) @property def support_newer_firmware(self): return self.support_newer_firmware_checkbox.isChecked() @property def debugging_title(self): return self.debugging_title_edit.text().strip()
class BookUploadsGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Uploading of books")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.modify_css_checkbox = create_checkbox( _("Modify CSS"), _('This allows addition of user CSS rules and removal of some CSS. ' 'When sending a book, the driver adds the contents of {0} to all stylesheets in the EPUB. ' 'This file is searched for in the root folder of the main memory of the device. ' 'As well as this, if the file contains settings for the "orphans" or "widows", ' 'these are removed for all styles in the original stylesheet.').format(device.KOBO_EXTRA_CSSFILE), device.get_pref('modify_css') ) self.override_kobo_replace_existing_checkbox = create_checkbox( _("Do not treat replacements as new books"), _('When a new book is side-loaded, the Kobo firmware imports details of the book into the internal database. ' 'Even if the book is a replacement for an existing book, the Kobo will remove the book from the database and then treat it as a new book. ' 'This means that the reading status, bookmarks and collections for the book will be lost. ' 'This option overrides firmware behavior and attempts to prevent a book that has been resent from being treated as a new book. ' 'If you prefer to have replacements treated as new books, turn this option off.' ), device.get_pref('override_kobo_replace_existing') ) self.options_layout.addWidget(self.modify_css_checkbox, 0, 0, 1, 2) self.options_layout.addWidget(self.override_kobo_replace_existing_checkbox, 1, 0, 1, 2) @property def modify_css(self): return self.modify_css_checkbox.isChecked() @property def override_kobo_replace_existing(self): return self.override_kobo_replace_existing_checkbox.isChecked()
class MetadataGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Update metadata on the device")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.setCheckable(True) self.setChecked(device.get_pref('update_device_metadata')) self.setToolTip(wrap_msg(_('Update the metadata on the device when it is connected. ' 'Be careful when doing this as it will take time and could make the initial connection take a long time.'))) self.update_series_checkbox = create_checkbox( _("Set series information"), _('The book lists on the Kobo devices can display series information. ' 'This is not read by the device from the sideloaded books. ' 'Series information can only be added to the device after the book has been processed by the device. ' 'Enable if you wish to set series information.'), device.get_pref('update_series') ) self.update_core_metadata_checkbox = create_checkbox( _("Update metadata on Book Details pages"), _('This will update the metadata in the device database when the device is connected. ' 'The metadata updated is displayed on the device in the library and the book details page. ' 'This is the title, authors, comments/synopsis, series name and number, publisher and published Date, ISBN and language. ' 'If a metadata plugboard exists for the device and book format, this will be used to set the metadata.' ), device.get_pref('update_core_metadata') ) self.update_purchased_kepubs_checkbox = create_checkbox( _("Update purchased books"), _('Update books purchased from Kobo and downloaded to the device.' ), device.get_pref('update_purchased_kepubs') ) self.update_subtitle_checkbox = create_checkbox( _("Subtitle"), _('Update the subtitle on the device using a template.'), device.get_pref('update_subtitle') ) self.subtitle_template_edit = TemplateConfig( device.get_pref('subtitle_template'), tooltip=_("Enter a template to use to set the subtitle. " "If the template is empty, the subtitle will be cleared." ) ) self.options_layout.addWidget(self.update_series_checkbox, 0, 0, 1, 2) self.options_layout.addWidget(self.update_core_metadata_checkbox, 1, 0, 1, 2) self.options_layout.addWidget(self.update_subtitle_checkbox, 2, 0, 1, 1) self.options_layout.addWidget(self.subtitle_template_edit, 2, 1, 1, 1) self.options_layout.addWidget(self.update_purchased_kepubs_checkbox, 3, 0, 1, 2) self.update_core_metadata_checkbox.clicked.connect(self.update_core_metadata_checkbox_clicked) self.update_subtitle_checkbox.clicked.connect(self.update_subtitle_checkbox_clicked) self.update_core_metadata_checkbox_clicked(device.get_pref('update_core_metadata')) self.update_subtitle_checkbox_clicked(device.get_pref('update_subtitle')) def update_core_metadata_checkbox_clicked(self, checked): self.update_series_checkbox.setEnabled(not checked) self.subtitle_template_edit.setEnabled(checked) self.update_subtitle_checkbox.setEnabled(checked) self.update_subtitle_checkbox_clicked(self.update_subtitle) self.update_purchased_kepubs_checkbox.setEnabled(checked) def update_subtitle_checkbox_clicked(self, checked): self.subtitle_template_edit.setEnabled(checked and self.update_core_metadata) def edit_template(self): t = TemplateDialog(self, self.template) t.setWindowTitle(_('Edit template')) if t.exec(): self.t.setText(t.rule[1]) def validate(self): if self.update_subtitle and not self.subtitle_template_edit.validate(): return False return True @property def update_series(self): return self.update_series_checkbox.isChecked() @property def update_core_metadata(self): return self.update_core_metadata_checkbox.isChecked() @property def update_purchased_kepubs(self): return self.update_purchased_kepubs_checkbox.isChecked() @property def update_device_metadata(self): return self.isChecked() @property def subtitle_template(self): return self.subtitle_template_edit.template @property def update_subtitle(self): return self.update_subtitle_checkbox.isChecked()
class CoversGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Upload covers")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.setCheckable(True) self.setChecked(device.get_pref('upload_covers')) self.setToolTip(wrap_msg(_('Upload cover images from the calibre library when sending books to the device.'))) self.upload_grayscale_checkbox = create_checkbox( _('Upload black and white covers'), _('Convert covers to grayscale when uploading.'), device.get_pref('upload_grayscale') ) self.dithered_covers_checkbox = create_checkbox( _('Upload dithered covers'), _('Dither cover images to the appropriate 16c grayscale palette for an eInk screen.' ' This usually ensures greater accuracy and avoids banding, making sleep covers look better.' ' On FW >= 4.11, Nickel itself may sometimes do a decent job of it.' ' Has no effect without "Upload black and white covers"!'), device.get_pref('dithered_covers') ) # Make it visually depend on B&W being enabled! # c.f., https://stackoverflow.com/q/36281103 self.dithered_covers_checkbox.setEnabled(device.get_pref('upload_grayscale')) self.upload_grayscale_checkbox.toggled.connect(self.dithered_covers_checkbox.setEnabled) self.upload_grayscale_checkbox.toggled.connect( lambda checked: not checked and self.dithered_covers_checkbox.setChecked(False)) self.keep_cover_aspect_checkbox = create_checkbox( _('Keep cover aspect ratio'), _('When uploading covers, do not change the aspect ratio when resizing for the device.' ' This is for firmware versions 2.3.1 and later.'), device.get_pref('keep_cover_aspect')) self.letterbox_fs_covers_checkbox = create_checkbox( _('Letterbox full-screen covers'), _('Do it on our end, instead of letting Nickel handle it.' ' Provides pixel-perfect results on devices where Nickel does not do extra processing.' ' Obviously has no effect without "Keep cover aspect ratio".' ' This is probably undesirable if you disable the "Show book covers full screen"' ' setting on your device.'), device.get_pref('letterbox_fs_covers')) self.letterbox_fs_covers_color_button = ColorButton(self.options_layout) self.letterbox_fs_covers_color_button.setToolTip(_('Choose the color to use when letterboxing the cover.' ' The default color is black (#000000)' ) ) self.letterbox_fs_covers_color_button.color = device.get_pref('letterbox_fs_covers_color') # Make it visually depend on AR being enabled! self.letterbox_fs_covers_checkbox.setEnabled(device.get_pref('keep_cover_aspect')) self.letterbox_fs_covers_color_button.setEnabled(device.get_pref('keep_cover_aspect') and device.get_pref('letterbox_fs_covers')) self.keep_cover_aspect_checkbox.toggled.connect(self.letterbox_fs_covers_checkbox.setEnabled) self.keep_cover_aspect_checkbox.toggled.connect( lambda checked: not checked and self.letterbox_fs_covers_checkbox.setChecked(False)) self.letterbox_fs_covers_checkbox.toggled.connect(self.letterbox_fs_covers_color_button.setEnabled) self.png_covers_checkbox = create_checkbox( _('Save covers as PNG'), _('Use the PNG image format instead of JPG.' ' Higher quality, especially with "Upload dithered covers" enabled,' ' which will also help generate potentially smaller files.' ' Behavior completely unknown on old (< 3.x) Kobo firmwares,' ' known to behave on FW >= 4.8.' ' Has no effect without "Upload black and white covers"!'), device.get_pref('png_covers')) # Make it visually depend on B&W being enabled, to avoid storing ridiculously large color PNGs. self.png_covers_checkbox.setEnabled(device.get_pref('upload_grayscale')) self.upload_grayscale_checkbox.toggled.connect(self.png_covers_checkbox.setEnabled) self.upload_grayscale_checkbox.toggled.connect( lambda checked: not checked and self.png_covers_checkbox.setChecked(False)) self.options_layout.addWidget(self.keep_cover_aspect_checkbox, 0, 0, 1, 1) self.options_layout.addWidget(self.letterbox_fs_covers_checkbox, 0, 1, 1, 2) self.options_layout.addWidget(self.letterbox_fs_covers_color_button, 1, 1, 1, 1) self.options_layout.addWidget(self.upload_grayscale_checkbox, 2, 0, 1, 1) self.options_layout.addWidget(self.dithered_covers_checkbox, 2, 1, 1, 2) self.options_layout.addWidget(self.png_covers_checkbox, 3, 1, 1, 2) self.options_layout.setColumnStretch(0, 0) self.options_layout.setColumnStretch(1, 0) self.options_layout.setColumnStretch(2, 1) @property def upload_covers(self): return self.isChecked() @property def upload_grayscale(self): return self.upload_grayscale_checkbox.isChecked() @property def dithered_covers(self): return self.dithered_covers_checkbox.isChecked() @property def keep_cover_aspect(self): return self.keep_cover_aspect_checkbox.isChecked() @property def letterbox_fs_covers(self): return self.letterbox_fs_covers_checkbox.isChecked() @property def letterbox_fs_covers_color(self): return self.letterbox_fs_covers_color_button.color @property def png_covers(self): return self.png_covers_checkbox.isChecked()
class CollectionsGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Collections")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.setCheckable(True) self.setChecked(device.get_pref('manage_collections')) self.setToolTip(wrap_msg(_('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'))) self.collections_columns_label = QLabel(_('Collections columns:')) self.collections_columns_edit = QLineEdit(self) self.collections_columns_edit.setToolTip(_('The Kobo from firmware V2.0.0 supports bookshelves.' ' These are created on the Kobo. ' 'Specify a tags type column for automatic management.')) self.collections_columns_edit.setText(device.get_pref('collections_columns')) self.create_collections_checkbox = create_checkbox( _("Create collections"), _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.'), device.get_pref('create_collections') ) self.delete_empty_collections_checkbox = create_checkbox( _('Delete empty bookshelves'), _('Delete any empty bookshelves from the Kobo when syncing is finished. This is only for firmware V2.0.0 or later.'), device.get_pref('delete_empty_collections') ) self.ignore_collections_names_label = QLabel(_('Ignore collections:')) self.ignore_collections_names_edit = QLineEdit(self) self.ignore_collections_names_edit.setToolTip(_('List the names of collections to be ignored by ' 'the collection management. The collections listed ' 'will not be changed. Names are separated by commas.')) self.ignore_collections_names_edit.setText(device.get_pref('ignore_collections_names')) self.options_layout.addWidget(self.collections_columns_label, 1, 0, 1, 1) self.options_layout.addWidget(self.collections_columns_edit, 1, 1, 1, 1) self.options_layout.addWidget(self.create_collections_checkbox, 2, 0, 1, 2) self.options_layout.addWidget(self.delete_empty_collections_checkbox, 3, 0, 1, 2) self.options_layout.addWidget(self.ignore_collections_names_label, 4, 0, 1, 1) self.options_layout.addWidget(self.ignore_collections_names_edit, 4, 1, 1, 1) @property def manage_collections(self): return self.isChecked() @property def collections_columns(self): return self.collections_columns_edit.text().strip() @property def create_collections(self): return self.create_collections_checkbox.isChecked() @property def delete_empty_collections(self): return self.delete_empty_collections_checkbox.isChecked() @property def ignore_collections_names(self): return self.ignore_collections_names_edit.text().strip()
class Config(QDialog): ''' Configuration dialog for single book conversion. If accepted, has the following important attributes output_format - Output format (without a leading .) input_format - Input format (without a leading .) opf_path - Path to OPF file with user specified metadata cover_path - Path to user specified cover (can be None) recommendations - A pickled list of 3 tuples in the same format as the recommendations member of the Input/Output plugins. ''' def __init__(self, parent, db, book_id, preferred_input_format=None, preferred_output_format=None): QDialog.__init__(self, parent) self.widgets = [] self.setupUi() self.opt_individual_saved_settings.setVisible(False) self.db, self.book_id = db, book_id self.setup_input_output_formats(self.db, self.book_id, preferred_input_format, preferred_output_format) self.setup_pipeline() self.input_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.output_formats.currentIndexChanged[native_string_type].connect( self.setup_pipeline) self.groups.setSpacing(5) self.groups.entered[(QModelIndex)].connect(self.show_group_help) rb = self.buttonBox.button( QDialogButtonBox.StandardButton.RestoreDefaults) rb.setText(_('Restore &defaults')) rb.setIcon(QIcon(I('clear_left.png'))) rb.clicked.connect(self.restore_defaults) self.groups.setMouseTracking(True) geom = gprefs.get('convert_single_dialog_geom', None) if geom: QApplication.instance().safe_restore_geometry(self, geom) else: self.resize(self.sizeHint()) def current_group_changed(self, cur, prev): self.show_pane(cur) def setupUi(self): self.setObjectName("Dialog") self.resize(1024, 700) self.setWindowIcon(QIcon(I('convert.png'))) self.gridLayout = QGridLayout(self) self.gridLayout.setObjectName("gridLayout") self.horizontalLayout = QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") self.input_label = QLabel(self) self.input_label.setObjectName("input_label") self.horizontalLayout.addWidget(self.input_label) self.input_formats = QComboBox(self) self.input_formats.setSizeAdjustPolicy( QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) self.input_formats.setMinimumContentsLength(5) self.input_formats.setObjectName("input_formats") self.horizontalLayout.addWidget(self.input_formats) self.opt_individual_saved_settings = QCheckBox(self) self.opt_individual_saved_settings.setObjectName( "opt_individual_saved_settings") self.horizontalLayout.addWidget(self.opt_individual_saved_settings) spacerItem = QSpacerItem(40, 20, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) self.horizontalLayout.addItem(spacerItem) self.label_2 = QLabel(self) self.label_2.setObjectName("label_2") self.horizontalLayout.addWidget(self.label_2) self.output_formats = QComboBox(self) self.output_formats.setSizeAdjustPolicy( QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) self.output_formats.setMinimumContentsLength(5) self.output_formats.setObjectName("output_formats") self.horizontalLayout.addWidget(self.output_formats) self.gridLayout.addLayout(self.horizontalLayout, 0, 0, 1, 2) self.groups = QListView(self) sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.groups.sizePolicy().hasHeightForWidth()) self.groups.setSizePolicy(sizePolicy) self.groups.setTabKeyNavigation(True) self.groups.setIconSize(QSize(48, 48)) self.groups.setWordWrap(True) self.groups.setObjectName("groups") self.gridLayout.addWidget(self.groups, 1, 0, 3, 1) self.scrollArea = QScrollArea(self) sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(4) sizePolicy.setVerticalStretch(10) sizePolicy.setHeightForWidth( self.scrollArea.sizePolicy().hasHeightForWidth()) self.scrollArea.setSizePolicy(sizePolicy) self.scrollArea.setFrameShape(QFrame.Shape.NoFrame) self.scrollArea.setLineWidth(0) self.scrollArea.setWidgetResizable(True) self.scrollArea.setObjectName("scrollArea") self.page = QWidget() self.page.setObjectName("page") self.gridLayout.addWidget(self.scrollArea, 1, 1, 1, 1) self.buttonBox = QDialogButtonBox(self) self.buttonBox.setOrientation(Qt.Orientation.Horizontal) self.buttonBox.setStandardButtons( QDialogButtonBox.StandardButton.Cancel | QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.RestoreDefaults) self.buttonBox.setObjectName("buttonBox") self.gridLayout.addWidget(self.buttonBox, 3, 1, 1, 1) self.help = QTextEdit(self) self.help.setReadOnly(True) sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.help.sizePolicy().hasHeightForWidth()) self.help.setSizePolicy(sizePolicy) self.help.setMaximumHeight(80) self.help.setObjectName("help") self.gridLayout.addWidget(self.help, 2, 1, 1, 1) self.input_label.setBuddy(self.input_formats) self.label_2.setBuddy(self.output_formats) self.input_label.setText(_("&Input format:")) self.opt_individual_saved_settings.setText( _("Use &saved conversion settings for individual books")) self.label_2.setText(_("&Output format:")) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) def sizeHint(self): geom = self.screen().availableSize() nh, nw = max(300, geom.height() - 100), max(400, geom.width() - 70) return QSize(nw, nh) def restore_defaults(self): delete_specifics(self.db, self.book_id) self.setup_pipeline() @property def input_format(self): return str(self.input_formats.currentText()).lower() @property def output_format(self): return str(self.output_formats.currentText()).lower() @property def manually_fine_tune_toc(self): for w in self.widgets: if hasattr(w, 'manually_fine_tune_toc'): return w.manually_fine_tune_toc.isChecked() def setup_pipeline(self, *args): oidx = self.groups.currentIndex().row() input_format = self.input_format output_format = self.output_format self.plumber = create_dummy_plumber(input_format, output_format) def widget_factory(cls): return cls(self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) self.mw = widget_factory(MetadataWidget) self.setWindowTitle(_('Convert') + ' ' + str(self.mw.title.text())) lf = widget_factory(LookAndFeelWidget) hw = widget_factory(HeuristicsWidget) sr = widget_factory(SearchAndReplaceWidget) ps = widget_factory(PageSetupWidget) sd = widget_factory(StructureDetectionWidget) toc = widget_factory(TOCWidget) from calibre.gui2.actions.toc_edit import SUPPORTED toc.manually_fine_tune_toc.setVisible( output_format.upper() in SUPPORTED) debug = widget_factory(DebugWidget) output_widget = self.plumber.output_plugin.gui_configuration_widget( self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) input_widget = self.plumber.input_plugin.gui_configuration_widget( self, self.plumber.get_option_by_name, self.plumber.get_option_help, self.db, self.book_id) self.break_cycles() self.widgets = widgets = [self.mw, lf, hw, ps, sd, toc, sr] if input_widget is not None: widgets.append(input_widget) if output_widget is not None: widgets.append(output_widget) widgets.append(debug) for w in widgets: w.set_help_signal.connect(self.help.setPlainText) w.setVisible(False) self._groups_model = GroupModel(widgets) self.groups.setModel(self._groups_model) idx = oidx if -1 < oidx < self._groups_model.rowCount() else 0 self.groups.setCurrentIndex(self._groups_model.index(idx)) self.show_pane(idx) self.groups.selectionModel().currentChanged.connect( self.current_group_changed) try: shutil.rmtree(self.plumber.archive_input_tdir, ignore_errors=True) except Exception: pass def setup_input_output_formats(self, db, book_id, preferred_input_format, preferred_output_format): if preferred_output_format: preferred_output_format = preferred_output_format.upper() output_formats = get_output_formats(preferred_output_format) input_format, input_formats = get_input_format_for_book( db, book_id, preferred_input_format) preferred_output_format = preferred_output_format if \ preferred_output_format in output_formats else \ sort_formats_by_preference(output_formats, [prefs['output_format']])[0] self.input_formats.addItems(str(x.upper()) for x in input_formats) self.output_formats.addItems(str(x.upper()) for x in output_formats) self.input_formats.setCurrentIndex(input_formats.index(input_format)) self.output_formats.setCurrentIndex( output_formats.index(preferred_output_format)) def show_pane(self, index): if hasattr(index, 'row'): index = index.row() ow = self.scrollArea.takeWidget() if ow: ow.setParent(self) for i, w in enumerate(self.widgets): if i == index: self.scrollArea.setWidget(w) w.show() else: w.setVisible(False) def accept(self): recs = GuiRecommendations() for w in self._groups_model.widgets: if not w.pre_commit_check(): return x = w.commit(save_defaults=False) recs.update(x) self.opf_file, self.cover_file = self.mw.opf_file, self.mw.cover_file self._recommendations = recs if self.db is not None: recs['gui_preferred_input_format'] = self.input_format save_specifics(self.db, self.book_id, recs) self.break_cycles() QDialog.accept(self) def reject(self): self.break_cycles() QDialog.reject(self) def done(self, r): if self.isVisible(): gprefs['convert_single_dialog_geom'] = \ bytearray(self.saveGeometry()) return QDialog.done(self, r) def break_cycles(self): for w in self.widgets: w.break_cycles() @property def recommendations(self): recs = [(k, v, OptionRecommendation.HIGH) for k, v in self._recommendations.items()] return recs def show_group_help(self, index): widget = self._groups_model.widgets[index.row()] self.help.setPlainText(widget.HELP)
class ExtraCustomization(DeviceConfigTab): # {{{ def __init__(self, extra_customization_message, extra_customization_choices, device_settings): super(ExtraCustomization, self).__init__() debug_print( "ExtraCustomization.__init__ - extra_customization_message=", extra_customization_message) debug_print( "ExtraCustomization.__init__ - extra_customization_choices=", extra_customization_choices) debug_print( "ExtraCustomization.__init__ - device_settings.extra_customization=", device_settings.extra_customization) debug_print("ExtraCustomization.__init__ - device_settings=", device_settings) self.extra_customization_message = extra_customization_message self.l = QVBoxLayout(self) self.setLayout(self.l) options_group = QGroupBox(_("Extra driver customization options"), self) self.l.addWidget(options_group) self.extra_layout = QGridLayout() self.extra_layout.setObjectName("extra_layout") options_group.setLayout(self.extra_layout) if extra_customization_message: extra_customization_choices = extra_customization_choices or {} def parse_msg(m): msg, _, tt = m.partition(':::') if m else ('', '', '') return msg.strip(), textwrap.fill(tt.strip(), 100) if isinstance(extra_customization_message, list): self.opt_extra_customization = [] if len(extra_customization_message) > 6: row_func = lambda x, y: ((x // 2) * 2) + y col_func = lambda x: x % 2 else: row_func = lambda x, y: x * 2 + y col_func = lambda x: 0 for i, m in enumerate(extra_customization_message): label_text, tt = parse_msg(m) if not label_text: self.opt_extra_customization.append(None) continue if isinstance(device_settings.extra_customization[i], bool): self.opt_extra_customization.append( QCheckBox(label_text)) self.opt_extra_customization[-1].setToolTip(tt) self.opt_extra_customization[i].setChecked( bool(device_settings.extra_customization[i])) elif i in extra_customization_choices: cb = QComboBox(self) self.opt_extra_customization.append(cb) l = QLabel(label_text) l.setToolTip(tt), cb.setToolTip(tt), l.setBuddy( cb), cb.setToolTip(tt) for li in sorted(extra_customization_choices[i]): self.opt_extra_customization[i].addItem(li) cb.setCurrentIndex( max( 0, cb.findText( device_settings.extra_customization[i]))) else: self.opt_extra_customization.append(QLineEdit(self)) l = QLabel(label_text) l.setToolTip(tt) self.opt_extra_customization[i].setToolTip(tt) l.setBuddy(self.opt_extra_customization[i]) l.setWordWrap(True) self.opt_extra_customization[i].setText( device_settings.extra_customization[i]) self.opt_extra_customization[i].setCursorPosition(0) self.extra_layout.addWidget(l, row_func(i + 2, 0), col_func(i)) self.extra_layout.addWidget( self.opt_extra_customization[i], row_func(i + 2, 1), col_func(i)) spacerItem1 = QSpacerItem(10, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding) self.extra_layout.addItem(spacerItem1, row_func(i + 2 + 2, 1), 0, 1, 2) self.extra_layout.setRowStretch(row_func(i + 2 + 2, 1), 2) else: self.opt_extra_customization = QLineEdit() label_text, tt = parse_msg(extra_customization_message) l = QLabel(label_text) l.setToolTip(tt) l.setBuddy(self.opt_extra_customization) l.setWordWrap(True) if device_settings.extra_customization: self.opt_extra_customization.setText( device_settings.extra_customization) self.opt_extra_customization.setCursorPosition(0) self.opt_extra_customization.setCursorPosition(0) self.extra_layout.addWidget(l, 0, 0) self.extra_layout.addWidget(self.opt_extra_customization, 1, 0) def extra_customization(self): ec = [] if self.extra_customization_message: if isinstance(self.extra_customization_message, list): for i in range(0, len(self.extra_customization_message)): if self.opt_extra_customization[i] is None: ec.append(None) continue if hasattr(self.opt_extra_customization[i], 'isChecked'): ec.append(self.opt_extra_customization[i].isChecked()) elif hasattr(self.opt_extra_customization[i], 'currentText'): ec.append( unicode_type(self.opt_extra_customization[i]. currentText()).strip()) else: ec.append( unicode_type(self.opt_extra_customization[i].text( )).strip()) else: ec = unicode_type(self.opt_extra_customization.text()).strip() if not ec: ec = None return ec @property def has_extra_customizations(self): debug_print( "ExtraCustomization::has_extra_customizations - self.extra_customization_message", self.extra_customization_message) return self.extra_customization_message and len( self.extra_customization_message) > 0
class CollectionsGroupBox(DeviceOptionsGroupBox): def __init__(self, parent, device): super().__init__(parent, device) self.setTitle(_("Collections")) self.options_layout = QGridLayout() self.options_layout.setObjectName("options_layout") self.setLayout(self.options_layout) self.setCheckable(True) self.setChecked(device.get_pref('manage_collections')) self.setToolTip( wrap_msg( _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.' ))) self.use_collections_columns_checkbox = create_checkbox( _("Collections columns:"), _('Use a column to generate collections.'), device.get_pref('use_collections_columns')) self.collections_columns_edit = QLineEdit(self) self.collections_columns_edit.setToolTip( _('The Kobo from firmware V2.0.0 supports bookshelves.' ' These are created on the Kobo. ' 'Specify a tags type column for automatic management.')) self.collections_columns_edit.setText( device.get_pref('collections_columns')) self.use_collections_template_checkbox = create_checkbox( _("Collections template:"), _('Use a template to generate collections.'), device.get_pref('use_collections_template')) self.collections_template_edit = TemplateConfig( device.get_pref('collections_template'), tooltip= _("Enter a template to generate collections." " The result of the template will be combined with the values from Collections column." " The template should return a list of collection names separated by ':@:' (without quotes)." )) self.create_collections_checkbox = create_checkbox( _("Create collections"), _('Create new bookshelves on the Kobo if they do not exist. This is only for firmware V2.0.0 or later.' ), device.get_pref('create_collections')) self.delete_empty_collections_checkbox = create_checkbox( _('Delete empty bookshelves'), _('Delete any empty bookshelves from the Kobo when syncing is finished. This is only for firmware V2.0.0 or later.' ), device.get_pref('delete_empty_collections')) self.ignore_collections_names_label = QLabel(_('Ignore collections:')) self.ignore_collections_names_edit = QLineEdit(self) self.ignore_collections_names_edit.setToolTip( _('List the names of collections to be ignored by ' 'the collection management. The collections listed ' 'will not be changed. Names are separated by commas.')) self.ignore_collections_names_edit.setText( device.get_pref('ignore_collections_names')) self.options_layout.addWidget(self.use_collections_columns_checkbox, 1, 0, 1, 1) self.options_layout.addWidget(self.collections_columns_edit, 1, 1, 1, 1) self.options_layout.addWidget(self.use_collections_template_checkbox, 2, 0, 1, 1) self.options_layout.addWidget(self.collections_template_edit, 2, 1, 1, 1) self.options_layout.addWidget(self.create_collections_checkbox, 3, 0, 1, 2) self.options_layout.addWidget(self.delete_empty_collections_checkbox, 4, 0, 1, 2) self.options_layout.addWidget(self.ignore_collections_names_label, 5, 0, 1, 1) self.options_layout.addWidget(self.ignore_collections_names_edit, 5, 1, 1, 1) self.use_collections_columns_checkbox.clicked.connect( self.use_collections_columns_checkbox_clicked) self.use_collections_template_checkbox.clicked.connect( self.use_collections_template_checkbox_clicked) self.use_collections_columns_checkbox_clicked( device.get_pref('use_collections_columns')) self.use_collections_template_checkbox_clicked( device.get_pref('use_collections_template')) def use_collections_columns_checkbox_clicked(self, checked): self.collections_columns_edit.setEnabled(checked) def use_collections_template_checkbox_clicked(self, checked): self.collections_template_edit.setEnabled(checked) @property def manage_collections(self): return self.isChecked() @property def use_collections_columns(self): return self.use_collections_columns_checkbox.isChecked() @property def collections_columns(self): return self.collections_columns_edit.text().strip() @property def use_collections_template(self): return self.use_collections_template_checkbox.isChecked() @property def collections_template(self): return self.collections_template_edit.template @property def create_collections(self): return self.create_collections_checkbox.isChecked() @property def delete_empty_collections(self): return self.delete_empty_collections_checkbox.isChecked() @property def ignore_collections_names(self): return self.ignore_collections_names_edit.text().strip()