diff --git a/src/calibre/gui2/catalog/catalog_epub_mobi.py b/src/calibre/gui2/catalog/catalog_epub_mobi.py index 70531b888f..aa517c1af6 100644 --- a/src/calibre/gui2/catalog/catalog_epub_mobi.py +++ b/src/calibre/gui2/catalog/catalog_epub_mobi.py @@ -27,7 +27,7 @@ class PluginWidget(QWidget,Ui_Form): TITLE = _('E-book options') HELP = _('Options specific to')+' AZW3/EPUB/MOBI '+_('output') - DEBUG = True + DEBUG = False # Output synced to the connected device? sync_enabled = True @@ -39,6 +39,7 @@ class PluginWidget(QWidget,Ui_Form): QWidget.__init__(self, parent) self.setupUi(self) self._initControlArrays() + self.blocking_all_signals = None def _initControlArrays(self): # Default values for controls @@ -112,6 +113,16 @@ class PluginWidget(QWidget,Ui_Form): self.OPTION_FIELDS = option_fields + def block_all_signals(self, bool): + if self.DEBUG: + print("block_all_signals: %s" % bool) + self.blocking_all_signals = bool + for opt in self.OPTION_FIELDS: + c_name, c_def, c_type = opt + if c_name in ['exclusion_rules_tw', 'prefix_rules_tw']: + continue + getattr(self, c_name).blockSignals(bool) + def construct_tw_opts_object(self, c_name, opt_value, opts_dict): ''' Build an opts object from the UI settings to pass to the catalog builder @@ -320,6 +331,9 @@ class PluginWidget(QWidget,Ui_Form): self.populate_combo_boxes() # Update dialog fields from stored options, validating options for combo boxes + # Hook all change events to self.settings_changed + + self.blocking_all_signals = True exclusion_rules = [] prefix_rules = [] for opt in self.OPTION_FIELDS: @@ -327,6 +341,7 @@ class PluginWidget(QWidget,Ui_Form): opt_value = gprefs.get(self.name + '_' + c_name, c_def) if c_type in ['check_box']: getattr(self, c_name).setChecked(eval(str(opt_value))) + getattr(self, c_name).clicked.connect(partial(self.settings_changed, c_name)) elif c_type in ['combo_box']: if opt_value is None: index = 0 @@ -340,12 +355,17 @@ class PluginWidget(QWidget,Ui_Form): elif c_name == 'genre_source_field': index = self.genre_source_field.findText(_('Tags')) getattr(self,c_name).setCurrentIndex(index) + if c_name != 'preset_field': + getattr(self, c_name).currentIndexChanged.connect(partial(self.settings_changed, c_name)) elif c_type in ['line_edit']: getattr(self, c_name).setText(opt_value if opt_value else '') + getattr(self, c_name).editingFinished.connect(partial(self.settings_changed, c_name)) elif c_type in ['radio_button'] and opt_value is not None: getattr(self, c_name).setChecked(opt_value) + getattr(self, c_name).clicked.connect(partial(self.settings_changed, c_name)) elif c_type in ['spin_box']: getattr(self, c_name).setValue(float(opt_value)) + getattr(self, c_name).valueChanged.connect(partial(self.settings_changed, c_name)) if c_type == 'table_widget': if c_name == 'exclusion_rules_tw': if opt_value not in exclusion_rules: @@ -391,12 +411,12 @@ class PluginWidget(QWidget,Ui_Form): self.generate_genres_changed(self.generate_genres.isChecked()) # Initialize exclusion rules - self.exclusion_rules_table = ExclusionRules(self.exclusion_rules_gb, - "exclusion_rules_tw", exclusion_rules, self.eligible_custom_fields, self.db) + self.exclusion_rules_table = ExclusionRules(self, self.exclusion_rules_gb, + "exclusion_rules_tw", exclusion_rules) # Initialize prefix rules - self.prefix_rules_table = PrefixRules(self.prefix_rules_gb, - "prefix_rules_tw", prefix_rules, self.eligible_custom_fields, self.db) + self.prefix_rules_table = PrefixRules(self, self.prefix_rules_gb, + "prefix_rules_tw", prefix_rules) # Initialize excluded genres preview self.exclude_genre_changed() @@ -406,6 +426,8 @@ class PluginWidget(QWidget,Ui_Form): self.preset_save_pb.clicked.connect(self.preset_save) self.preset_field.currentIndexChanged[str].connect(self.preset_change) + self.blocking_all_signals = False + def merge_source_field_changed(self,new_index): ''' Process changes in the merge_source_field combo box @@ -579,7 +601,6 @@ class PluginWidget(QWidget,Ui_Form): ''' Update catalog options from current preset ''' - print("preset_change: %s" % item_name) if not item_name: return @@ -588,6 +609,8 @@ class PluginWidget(QWidget,Ui_Form): exclusion_rules = [] prefix_rules = [] + + self.block_all_signals(True) for opt in self.OPTION_FIELDS: c_name, c_def, c_type = opt if c_name == 'preset_field': @@ -630,13 +653,13 @@ class PluginWidget(QWidget,Ui_Form): # Reset exclusion rules self.exclusion_rules_table.clearLayout() - self.exclusion_rules_table = ExclusionRules(self.exclusion_rules_gb, - "exclusion_rules_tw", exclusion_rules, self.eligible_custom_fields, self.db) + self.exclusion_rules_table = ExclusionRules(self, self.exclusion_rules_gb, + "exclusion_rules_tw", exclusion_rules) # Reset prefix rules self.prefix_rules_table.clearLayout() - self.prefix_rules_table = PrefixRules(self.prefix_rules_gb, - "prefix_rules_tw", prefix_rules, self.eligible_custom_fields, self.db) + self.prefix_rules_table = PrefixRules(self, self.prefix_rules_gb, + "prefix_rules_tw", prefix_rules) # Reset excluded genres preview self.exclude_genre_changed() @@ -649,6 +672,8 @@ class PluginWidget(QWidget,Ui_Form): # Reset Descriptions-related enable/disable switches self.generate_descriptions_changed(self.generate_descriptions.isChecked()) + self.block_all_signals(False) + def preset_remove(self): if self.preset_field.currentIndex() == 0: return @@ -779,6 +804,14 @@ class PluginWidget(QWidget,Ui_Form): elif child.objectName() == 'title': child.setText(title) + def settings_changed(self, source): + ''' + When anything changes, clear Preset combobox + ''' + if self.DEBUG: + print("settings_changed: %s" % source) + self.preset_field.setCurrentIndex(0) + def show_help(self): ''' Display help file @@ -843,10 +876,11 @@ class GenericRulesTable(QTableWidget): MAXIMUM_TABLE_HEIGHT = 113 NAME_FIELD_WIDTH = 225 - def __init__(self, parent_gb, object_name, rules, eligible_custom_fields, db): + def __init__(self, parent, parent_gb, object_name, rules): + self.parent = parent self.rules = rules - self.eligible_custom_fields = eligible_custom_fields - self.db = db + self.eligible_custom_fields = parent.eligible_custom_fields + self.db = parent.db QTableWidget.__init__(self) self.setObjectName(object_name) self.layout = parent_gb.layout() @@ -961,6 +995,7 @@ class GenericRulesTable(QTableWidget): def enabled_state_changed(self, row, col): if col in [self.COLUMNS['ENABLED']['ordinal']]: self.select_and_scroll_to_row(row) + self.settings_changed("enabled_state_changed") if self.DEBUG: print("%s:enabled_state_changed(): row %d col %d" % (self.objectName(), row, col)) @@ -1063,6 +1098,7 @@ class GenericRulesTable(QTableWidget): current_row = self.currentRow() self.cellWidget(current_row,1).home(False) self.select_and_scroll_to_row(current_row) + self.settings_changed("rule_name_edited") def select_and_scroll_to_row(self, row): self.setFocus() @@ -1071,6 +1107,10 @@ class GenericRulesTable(QTableWidget): self.last_row_selected = self.currentRow() self.last_rows_selected = self.selectionModel().selectedRows() + def settings_changed(self, source): + if not self.parent.blocking_all_signals: + self.parent.settings_changed(source) + def _source_index_changed(self, combo): # Figure out which row we're in for row in range(self.rowCount()): @@ -1108,12 +1148,14 @@ class GenericRulesTable(QTableWidget): values_combo.currentIndexChanged.connect(partial(self.values_index_changed, values_combo)) self.setCellWidget(row, self.COLUMNS['PATTERN']['ordinal'], values_combo) self.select_and_scroll_to_row(row) + self.settings_changed("source_index_changed") def values_index_changed(self, combo): # After edit, select row for row in range(self.rowCount()): if self.cellWidget(row, self.COLUMNS['PATTERN']['ordinal']) is combo: self.select_and_scroll_to_row(row) + self.settings_changed("values_index_changed") break if self.DEBUG: @@ -1127,8 +1169,8 @@ class ExclusionRules(GenericRulesTable): 'FIELD': {'ordinal': 2, 'name': _('Field')}, 'PATTERN': {'ordinal': 3, 'name': _('Value')},} - def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db): - super(ExclusionRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db) + def __init__(self, parent, parent_gb_hl, object_name, rules): + super(ExclusionRules, self).__init__(parent, parent_gb_hl, object_name, rules) self.setObjectName("exclusion_rules_table") self._init_table_widget() self._initialize() @@ -1219,8 +1261,8 @@ class PrefixRules(GenericRulesTable): 'FIELD': {'ordinal': 3, 'name': _('Field')}, 'PATTERN':{'ordinal': 4, 'name': _('Value')},} - def __init__(self, parent_gb_hl, object_name, rules, eligible_custom_fields, db): - super(PrefixRules, self).__init__(parent_gb_hl, object_name, rules, eligible_custom_fields, db) + def __init__(self, parent, parent_gb_hl, object_name, rules): + super(PrefixRules, self).__init__(parent, parent_gb_hl, object_name, rules) self.setObjectName("prefix_rules_table") self._init_table_widget() self._initialize() @@ -1412,6 +1454,7 @@ class PrefixRules(GenericRulesTable): def set_prefix_field_in_row(row, col, field=''): prefix_combo = ComboBox(self, self.prefix_list, field) + prefix_combo.currentIndexChanged.connect(partial(self.settings_changed, 'set_prefix_field_in_row')) self.setCellWidget(row, col, prefix_combo) def set_rule_name_in_row(row, col, name=''): diff --git a/src/calibre/gui2/dialogs/catalog.py b/src/calibre/gui2/dialogs/catalog.py index 6ec5dd6d13..3700237d5e 100644 --- a/src/calibre/gui2/dialogs/catalog.py +++ b/src/calibre/gui2/dialogs/catalog.py @@ -98,16 +98,20 @@ class Catalog(ResizableDialog, Ui_Dialog): if fmt[1]: self.sync_enabled_formats.append(fmt[0]) - # Callback when format changes + # Callbacks when format, title changes self.format.currentIndexChanged.connect(self.format_changed) + self.format.currentIndexChanged.connect(self.settings_changed) + self.title.editingFinished.connect(self.settings_changed) # Add the installed catalog format list to the format QComboBox + self.format.blockSignals(True) self.format.addItems(fmts) pref = dynamic.get('catalog_preferred_format', 'CSV') idx = self.format.findText(pref) if idx > -1: self.format.setCurrentIndex(idx) + self.format.blockSignals(False) if self.sync.isEnabled(): self.sync.setChecked(dynamic.get('catalog_sync_to_device', True)) @@ -142,6 +146,14 @@ class Catalog(ResizableDialog, Ui_Dialog): self.sync.setDisabled(True) self.sync.setChecked(False) + def settings_changed(self): + ''' + When title/format change, invalidate Preset in E-book options tab + ''' + cf = unicode(self.format.currentText()).lower() + if cf in ['azw3', 'epub', 'mobi'] and hasattr(self.tabs.widget(1), 'settings_changed'): + self.tabs.widget(1).settings_changed("title/format") + @property def fmt_options(self): ans = {}