diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 5f62aede09..a7fcf4a7f9 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -70,6 +70,21 @@ class Base(object): except: pass + def finish_ui_setup(self, parent, edit_widget): + self.was_none = False + w = QWidget(parent) + self.widgets.append(w) + l = QHBoxLayout() + l.setContentsMargins(0, 0, 0, 0) + w.setLayout(l) + self.editor = editor = edit_widget(parent) + l.addWidget(editor) + self.clear_button = QToolButton(parent) + self.clear_button.setIcon(QIcon(I('trash.png'))) + self.clear_button.clicked.connect(self.set_to_undefined) + self.clear_button.setToolTip(_('Clear {0}').format(self.col_metadata['name'])) + l.addWidget(self.clear_button) + def initialize(self, book_id): val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) val = self.normalize_db_val(val) @@ -114,18 +129,20 @@ class Base(object): class SimpleText(Base): def setup_ui(self, parent): + self.editor = QLineEdit(parent) self.widgets = [QLabel(label_string(self.col_metadata['name']), parent), - QLineEdit(parent)] + self.editor] + self.editor.setClearButtonEnabled(True) def setter(self, val): - self.widgets[1].setText(unicode_type(val or '')) + self.editor.setText(unicode_type(val or '')) def getter(self): - return self.widgets[1].text().strip() + return self.editor.text().strip() def connect_data_changed(self, slot): - self.widgets[1].textChanged.connect(slot) - self.signals_to_disconnect.append(self.widgets[1].textChanged) + self.editor.textChanged.connect(slot) + self.signals_to_disconnect.append(self.editor.textChanged) class LongText(Base): @@ -179,7 +196,7 @@ class Bool(Base): if self.db.new_api.pref('bools_are_tristate'): c = QToolButton(parent) - c.setText(_('Clear')) + c.setIcon(QIcon(I('trash.png'))) c.setToolTip(_('Clear {}').format(name)) l.addWidget(c) c.clicked.connect(self.set_to_cleared) @@ -225,23 +242,10 @@ class Int(Base): self.editor.setRange(-1000000, 100000000) def finish_ui_setup(self, parent, edit_widget): - self.was_none = False - w = QWidget(parent) - self.widgets.append(w) - l = QHBoxLayout() - l.setContentsMargins(0, 0, 0, 0) - w.setLayout(l) - self.editor = editor = edit_widget(parent) - editor.setRange(-1000000, 100000000) - editor.setSpecialValueText(_('Undefined')) - editor.setSingleStep(1) - editor.valueChanged.connect(self.valueChanged) - l.addWidget(editor) - self.clear_button = QToolButton(parent) - self.clear_button.setIcon(QIcon(I('trash.png'))) - self.clear_button.clicked.connect(self.set_to_undefined) - self.clear_button.setToolTip(_('Clear {0}').format(self.col_metadata['name'])) - l.addWidget(self.clear_button) + Base.finish_ui_setup(self, parent, edit_widget) + self.editor.setSpecialValueText(_('Undefined')) + self.editor.setSingleStep(1) + self.editor.valueChanged.connect(self.valueChanged) def setter(self, val): if val is None: @@ -276,24 +280,26 @@ class Float(Int): self.editor.setRange(-1000000., float(100000000)) self.editor.setDecimals(2) - class Rating(Base): def setup_ui(self, parent): allow_half_stars = self.col_metadata['display'].get('allow_half_stars', False) - self.widgets = [QLabel(label_string(self.col_metadata['name']), parent), - RatingEditor(parent=parent, is_half_star=allow_half_stars)] + self.widgets = [QLabel(label_string(self.col_metadata['name']), parent)] + self.finish_ui_setup(parent, partial(RatingEditor, is_half_star=allow_half_stars)) + + def set_to_undefined(self): + self.editor.setCurrentIndex(0) def setter(self, val): val = max(0, min(int(val or 0), 10)) - self.widgets[1].rating_value = val + self.editor.rating_value = val def getter(self): - return self.widgets[1].rating_value or None + return self.editor.rating_value or None def connect_data_changed(self, slot): - self.widgets[1].currentTextChanged.connect(slot) - self.signals_to_disconnect.append(self.widgets[1].currentTextChanged) + self.editor.currentTextChanged.connect(slot) + self.signals_to_disconnect.append(self.editor.currentTextChanged) class DateTimeEdit(DateTimeEditBase): @@ -493,19 +499,22 @@ class Text(Base): w.set_add_separator(tweaks['authors_completer_append_separator']) w.get_editor_button().clicked.connect(self.edit) w.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Preferred) + self.set_to_undefined = w.clear else: w = EditWithComplete(parent) w.set_separator(None) w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon) w.setMinimumContentsLength(25) - self.widgets = [QLabel(label_string(self.col_metadata['name']), parent), w] + self.set_to_undefined = w.clearEditText + self.widgets = [QLabel(label_string(self.col_metadata['name']), parent)] + self.finish_ui_setup(parent, lambda parent: w) def initialize(self, book_id): values = list(self.db.all_custom(num=self.col_id)) values.sort(key=sort_key) self.book_id = book_id - self.widgets[1].clear() - self.widgets[1].update_items_cache(values) + self.editor.clear() + self.editor.update_items_cache(values) val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) if isinstance(val, list): if not self.col_metadata.get('display', {}).get('is_names', False): @@ -515,23 +524,23 @@ class Text(Base): if self.col_metadata['is_multiple']: self.setter(val) else: - self.widgets[1].setText(val) + self.editor.setText(val) self.initial_val = self.current_val def setter(self, val): if self.col_metadata['is_multiple']: if not val: val = [] - self.widgets[1].setText(self.sep['list_to_ui'].join(val)) + self.editor.setText(self.sep['list_to_ui'].join(val)) def getter(self): if self.col_metadata['is_multiple']: - val = unicode_type(self.widgets[1].text()).strip() + val = unicode_type(self.editor.text()).strip() ans = [x.strip() for x in val.split(self.sep['ui_to_list']) if x.strip()] if not ans: ans = None return ans - val = unicode_type(self.widgets[1].currentText()).strip() + val = unicode_type(self.editor.currentText()).strip() if not val: val = None return val @@ -556,9 +565,9 @@ class Text(Base): def connect_data_changed(self, slot): if self.col_metadata['is_multiple']: - s = self.widgets[1].tags_box.currentTextChanged + s = self.editor.tags_box.currentTextChanged else: - s = self.widgets[1].currentTextChanged + s = self.editor.currentTextChanged s.connect(slot) self.signals_to_disconnect.append(s) @@ -571,7 +580,8 @@ class Series(Base): w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon) w.setMinimumContentsLength(25) self.name_widget = w - self.widgets = [QLabel(label_string(self.col_metadata['name']), parent), w] + self.widgets = [QLabel(label_string(self.col_metadata['name']), parent)] + self.finish_ui_setup(parent, lambda parent: w) w.editTextChanged.connect(self.series_changed) w = QLabel(label_string(self.col_metadata['name'])+_(' index'), parent) @@ -585,6 +595,10 @@ class Series(Base): w.setToolTip(get_tooltip(self.col_metadata, add_index=True)) self.widgets.append(w) + def set_to_undefined(self): + self.name_widget.clearEditText() + self.idx_widget.setValue(1.0) + def initialize(self, book_id): values = list(self.db.all_custom(num=self.col_id)) values.sort(key=sort_key) @@ -639,7 +653,7 @@ class Series(Base): mi.set('#' + self.col_metadata['label'], val, extra=s_index) def connect_data_changed(self, slot): - for s in self.widgets[1].editTextChanged, self.widgets[3].valueChanged: + for s in self.name_widget.editTextChanged, self.idx_widget.valueChanged: s.connect(slot) self.signals_to_disconnect.append(s) @@ -648,18 +662,17 @@ class Enumeration(Base): def setup_ui(self, parent): self.parent = parent - self.widgets = [QLabel(label_string(self.col_metadata['name']), parent), - QComboBox(parent)] - w = self.widgets[1] + self.widgets = [QLabel(label_string(self.col_metadata['name']), parent)] + self.finish_ui_setup(parent, QComboBox) vals = self.col_metadata['display']['enum_values'] - w.addItem('') + self.editor.addItem('') for v in vals: - w.addItem(v) + self.editor.addItem(v) def initialize(self, book_id): val = self.db.get_custom(book_id, num=self.col_id, index_is_id=True) val = self.normalize_db_val(val) - idx = self.widgets[1].findText(val) + idx = self.editor.findText(val) if idx < 0: error_dialog(self.parent, '', _('The enumeration "{0}" contains an invalid value ' @@ -668,14 +681,14 @@ class Enumeration(Base): show=True, show_copy_button=False) idx = 0 - self.widgets[1].setCurrentIndex(idx) + self.editor.setCurrentIndex(idx) self.initial_val = self.current_val def setter(self, val): - self.widgets[1].setCurrentIndex(self.widgets[1].findText(val)) + self.editor.setCurrentIndex(self.editor.findText(val)) def getter(self): - return unicode_type(self.widgets[1].currentText()) + return unicode_type(self.editor.currentText()) def normalize_db_val(self, val): if val is None: @@ -687,9 +700,12 @@ class Enumeration(Base): val = None return val + def set_to_undefined(self): + self.editor.setCurrentIndex(0) + def connect_data_changed(self, slot): - self.widgets[1].currentIndexChanged.connect(slot) - self.signals_to_disconnect.append(self.widgets[1].currentIndexChanged) + self.editor.currentIndexChanged.connect(slot) + self.signals_to_disconnect.append(self.editor.currentIndexChanged) def comments_factory(db, key, parent): @@ -879,6 +895,16 @@ class BulkBase(Base): ans = list(ans) return ans + def finish_ui_setup(self, parent): + self.was_none = False + l = self.widgets[1].layout() + self.clear_button = QToolButton(parent) + self.clear_button.setIcon(QIcon(I('trash.png'))) + self.clear_button.setToolTip(_('Clear {0}').format(self.col_metadata['name'])) + l.insertWidget(1, self.clear_button) + l.insertStretch(2) + self.clear_button.clicked.connect(self.set_to_undefined) + def initialize(self, book_ids): self.initial_val = val = self.get_initial_value(book_ids) val = self.normalize_db_val(val) @@ -948,7 +974,8 @@ class BulkBool(BulkBase, Bool): def setup_ui(self, parent): self.make_widgets(parent, QComboBox) items = [_('Yes'), _('No')] - if not self.db.new_api.pref('bools_are_tristate'): + self.bools_are_tristate = self.db.new_api.pref('bools_are_tristate') + if not self.bools_are_tristate: items.append('') else: items.append(_('Undefined')) @@ -957,10 +984,17 @@ class BulkBool(BulkBase, Bool): for icon, text in zip(icons, items): self.main_widget.addItem(QIcon(icon), text) self.main_widget.blockSignals(False) + if self.bools_are_tristate: + # Add clear if bools are tristate + self.finish_ui_setup(parent) + + def set_to_undefined(self): + # Only called if bools are tristate + self.main_widget.setCurrentIndex(2) def getter(self): val = self.main_widget.currentIndex() - if not self.db.new_api.pref('bools_are_tristate'): + if not self.bools_are_tristate: return {2: False, 1: False, 0: True}[val] else: return {2: None, 1: False, 0: True}[val] @@ -975,14 +1009,13 @@ class BulkBool(BulkBase, Bool): return val = self.gui_val val = self.normalize_ui_val(val) - if not self.db.new_api.pref('bools_are_tristate') and val is None: + if not self.bools_are_tristate and val is None: val = False self.db.set_custom_bulk(book_ids, val, num=self.col_id, notify=notify) def a_c_checkbox_changed(self): if not self.ignore_change_signals: - if not self.db.new_api.pref('bools_are_tristate') and \ - self.main_widget.currentIndex() == 2: + if not self.bools_are_tristate and self.main_widget.currentIndex() == 2: self.a_c_checkbox.setChecked(False) else: self.a_c_checkbox.setChecked(True) @@ -996,17 +1029,10 @@ class BulkInt(BulkBase): self.finish_ui_setup(parent) def finish_ui_setup(self, parent): - self.was_none = False + BulkBase.finish_ui_setup(self, parent) self.main_widget.setSpecialValueText(_('Undefined')) self.main_widget.setSingleStep(1) self.main_widget.valueChanged.connect(self.valueChanged) - l = self.widgets[1].layout() - self.clear_button = QToolButton(parent) - self.clear_button.setIcon(QIcon(I('trash.png'))) - self.clear_button.setToolTip(_('Clear {0}').format(self.col_metadata['name'])) - l.insertWidget(1, self.clear_button) - l.insertStretch(2) - self.clear_button.clicked.connect(self.set_to_undefined) def setter(self, val): if val is None: @@ -1029,7 +1055,6 @@ class BulkInt(BulkBase): def set_to_undefined(self): self.main_widget.setValue(-1000000) - class BulkFloat(BulkInt): def setup_ui(self, parent): @@ -1047,6 +1072,10 @@ class BulkRating(BulkBase): def setup_ui(self, parent): allow_half_stars = self.col_metadata['display'].get('allow_half_stars', False) self.make_widgets(parent, partial(RatingEditor, is_half_star=allow_half_stars)) + self.finish_ui_setup(parent) + + def set_to_undefined(self): + self.main_widget.setCurrentIndex(0) def setter(self, val): val = max(0, min(int(val or 0), 10)) @@ -1274,12 +1303,16 @@ class BulkEnumeration(BulkBase, Enumeration): def setup_ui(self, parent): self.parent = parent self.make_widgets(parent, QComboBox) + self.finish_ui_setup(parent) vals = self.col_metadata['display']['enum_values'] self.main_widget.blockSignals(True) self.main_widget.addItem('') self.main_widget.addItems(vals) self.main_widget.blockSignals(False) + def set_to_undefined(self): + self.main_widget.setCurrentIndex(0) + def getter(self): return unicode_type(self.main_widget.currentText()) @@ -1359,6 +1392,10 @@ class BulkText(BulkBase): self.main_widget.setMinimumContentsLength(25) self.ignore_change_signals = False self.parent = parent + self.finish_ui_setup(parent) + + def set_to_undefined(self): + self.main_widget.clearEditText() def initialize(self, book_ids): self.main_widget.update_items_cache(self.all_values)