def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): m = index.model() col = m.column_map[index.column()] # If shifted, bring up the tag editor instead of the line editor. if check_key_modifier(Qt.ShiftModifier) and col != 'authors': key = col if m.is_custom_column(col) else None d = TagEditor(parent, self.db, m.id(index.row()), key=key) if d.exec_() == TagEditor.Accepted: m.setData(index, self.sep.join(d.tags), Qt.EditRole) return None editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator( tweaks['authors_completer_append_separator']) if not m.is_custom_column(col): all_items = getattr(self.db, self.items_func_name)() else: all_items = list( self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) editor.update_items_cache(all_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): col = self.col if col is None: # We have not specified an explicit column, so we need # to lookup a column name. The calibre one will rely on stuff # on the model, we will rely on a callback function instead col = self.col_fn(index.column()) editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator(tweaks['authors_completer_append_separator']) if col.startswith('#'): all_items = list(self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) else: all_items = getattr(self.db, self.items_func_name)() editor.update_items_cache(all_items) for item in sorted(all_items, key=sort_key): editor.addItem(item) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): col = self.col if col is None: # We have not specified an explicit column, so we need # to lookup a column name. The calibre one will rely on stuff # on the model, we will rely on a callback function instead col = self.col_fn(index.column()) editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator( tweaks['authors_completer_append_separator']) if col.startswith('#'): all_items = list( self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) else: all_items = getattr(self.db, self.items_func_name)() editor.update_items_cache(all_items) for item in sorted(all_items, key=sort_key): editor.addItem(item) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): m = index.model() col = m.column_map[index.column()] # If shifted, bring up the tag editor instead of the line editor. if check_key_modifier(Qt.ShiftModifier) and col != 'authors': key = col if m.is_custom_column(col) else None d = TagEditor(parent, self.db, m.id(index.row()), key=key) if d.exec_() == TagEditor.Accepted: m.setData(index, self.sep.join(d.tags), Qt.EditRole) return None editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator(tweaks['authors_completer_append_separator']) if not m.is_custom_column(col): all_items = getattr(self.db, self.items_func_name)() else: all_items = list(self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) editor.update_items_cache(all_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.completion_data: editor = EditWithComplete(parent) editor.set_separator(None) editor.update_items_cache(self.completion_data) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] editor = EditWithComplete(parent) editor.set_separator(None) complete_items = sorted(list(m.db.all_custom(label=m.db.field_metadata.key_to_label(col))), key=sort_key) editor.update_items_cache(complete_items) return editor
def createEditor(self, parent, option, index): if self.auto_complete_function: editor = EditWithComplete(parent) editor.set_separator(None) complete_items = [i[1] for i in self.auto_complete_function()] editor.update_items_cache(complete_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.auto_complete_function: editor = EditWithComplete(parent) editor.set_separator(None) complete_items = [i[1] for i in self.auto_complete_function()] editor.update_items_cache(complete_items) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] key = m.db.field_metadata.key_to_label(col) if m.db.field_metadata[col]['datatype'] != 'comments': editor = EditWithComplete(parent) editor.set_separator(None) complete_items = sorted(list(m.db.all_custom(label=key)), key=sort_key) editor.update_items_cache(complete_items) else: editor = QStyledItemDelegate.createEditor(self, parent, option, index) return editor
def createEditor(self, parent, option, index): if index.column() == 0: if self.completion_data: from calibre.gui2.complete2 import EditWithComplete editor = EditWithComplete(parent) editor.set_separator(None) editor.update_items_cache(self.completion_data) else: from calibre.gui2.widgets import EnLineEdit editor = EnLineEdit(parent) return editor return QItemDelegate.createEditor(self, parent, option, index)
def createEditor(self, parent, option, index): if self.auto_complete_function: if self.use_title_sort: editor = EditWithComplete(parent, sort_func=title_sort) else: editor = EditWithComplete(parent) editor.set_separator(None) editor.set_clear_button_enabled(False) complete_items = [i[1] for i in self.auto_complete_function()] editor.update_items_cache(complete_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): self.editing_started.emit(index.row()) if index.column() == 0: self.item = self.table.itemFromIndex(index) if self.item.is_deleted: return None if self.completion_data: editor = EditWithComplete(parent) editor.set_separator(None) editor.update_items_cache(self.completion_data) else: editor = EnLineEdit(parent) return editor return None
def setup_ui(self, parent): w = EditWithComplete(parent) w.set_separator(None) w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon) w.setMinimumContentsLength(25) self.name_widget = w self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w] self.widgets.append(QLabel('&'+self.col_metadata['name']+_(' index:'), parent)) w = QDoubleSpinBox(parent) w.setRange(-100., float(100000000)) w.setDecimals(2) w.setSingleStep(1) self.idx_widget=w self.widgets.append(w)
class MultipleWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) layout = QHBoxLayout() layout.setSpacing(5) layout.setContentsMargins(0, 0, 0, 0) self.tags_box = EditWithComplete(parent) layout.addWidget(self.tags_box, stretch=1000) self.editor_button = QToolButton(self) self.editor_button.setToolTip(_('Open Item Editor')) self.editor_button.setIcon(QIcon(I('chapters.png'))) layout.addWidget(self.editor_button) self.setLayout(layout) def get_editor_button(self): return self.editor_button def update_items_cache(self, values): self.tags_box.update_items_cache(values) def clear(self): self.tags_box.clear() def setEditText(self): self.tags_box.setEditText() def addItem(self, itm): self.tags_box.addItem(itm) def set_separator(self, sep): self.tags_box.set_separator(sep) def set_add_separator(self, sep): self.tags_box.set_add_separator(sep) def set_space_before_sep(self, v): self.tags_box.set_space_before_sep(v) def setSizePolicy(self, v1, v2): self.tags_box.setSizePolicy(v1, v2) def setText(self, v): self.tags_box.setText(v) def text(self): return self.tags_box.text()
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): col = index.model().column_map[index.column()] editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == "&": editor.set_add_separator(tweaks["authors_completer_append_separator"]) if not index.model().is_custom_column(col): all_items = getattr(self.db, self.items_func_name)() else: all_items = list(self.db.all_custom(label=self.db.field_metadata.key_to_label(col))) editor.update_items_cache(all_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] key = m.db.field_metadata.key_to_label(col) if m.db.field_metadata[col]['datatype'] != 'comments': editor = EditWithComplete(parent) editor.set_separator(None) complete_items = sorted(list(m.db.all_custom(label=key)), key=sort_key) editor.update_items_cache(complete_items) else: editor = QLineEdit(parent) text = index.data(Qt.ItemDataRole.DisplayRole) if text: editor.setText(text) editor.selectAll() return editor
def createEditor(self, parent, option, index): m = index.model() col = m.column_map[index.column()] key = m.db.field_metadata.key_to_label(col) if m.db.field_metadata[col]['datatype'] != 'comments': editor = EditWithComplete(parent) editor.set_separator(None) complete_items = sorted(list(m.db.all_custom(label=key)), key=sort_key) editor.update_items_cache(complete_items) else: editor = QLineEdit(parent) text = index.data(Qt.DisplayRole) if text: editor.setText(text) editor.selectAll() return editor
def setup_ui(self, parent): w = EditWithComplete(parent) w.set_separator(None) w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon) w.setMinimumContentsLength(25) self.name_widget = w self.widgets = [QLabel("&" + self.col_metadata["name"] + ":", parent), w] w.editTextChanged.connect(self.series_changed) self.widgets.append(QLabel("&" + self.col_metadata["name"] + _(" index:"), parent)) w = QDoubleSpinBox(parent) w.setRange(-10000.0, float(100000000)) w.setDecimals(2) w.setSingleStep(1) self.idx_widget = w self.widgets.append(w)
def setup_ui(self, parent): w = EditWithComplete(parent) w.set_separator(None) w.setSizeAdjustPolicy(w.AdjustToMinimumContentsLengthWithIcon) w.setMinimumContentsLength(25) self.name_widget = w self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), w] w.editTextChanged.connect(self.series_changed) self.widgets.append(QLabel('&'+self.col_metadata['name']+_(' index:'), parent)) w = QDoubleSpinBox(parent) w.setRange(-10000., float(100000000)) w.setDecimals(2) w.setSingleStep(1) self.idx_widget=w self.widgets.append(w)
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): col = index.model().column_map[index.column()] editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator(tweaks['authors_completer_append_separator']) if not index.model().is_custom_column(col): all_items = getattr(self.db, self.items_func_name)() else: all_items = list(self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) editor.update_items_cache(all_items) else: editor = EnLineEdit(parent) return editor
def createEditor(self, parent, option, index): if self.db and hasattr(self.db, self.items_func_name): editor = EditWithComplete(parent) editor.set_separator(self.sep) editor.set_space_before_sep(self.space_before_sep) if self.sep == '&': editor.set_add_separator( tweaks['authors_completer_append_separator']) if self.col.startswith('#'): all_items = list( self.db.all_custom( label=self.db.field_metadata.key_to_label(self.col))) else: all_items = getattr(self.db, self.items_func_name)() editor.update_items_cache(all_items) for item in sorted(all_items, key=sort_key): editor.addItem(item) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: editor = EnLineEdit(parent) return editor
class SeriesDialog(SizePersistedDialog): def __init__(self, parent, books, all_series, series_columns): SizePersistedDialog.__init__(self, parent, 'Manage Series plugin:series dialog') self.db = self.parent().library_view.model().db self.books = books self.all_series = all_series self.series_columns = series_columns self.block_events = True self.initialize_controls() # Books will have been sorted by the Calibre series column # Choose the appropriate series column to be editing initial_series_column = 'Series' self.series_column_combo.select_text(initial_series_column) if len(series_columns) == 0: # Will not have fired the series_column_changed event self.series_column_changed() # Renumber the books using the assigned series name/index in combos/spinbox self.renumber_series(display_in_table=False) # Display the books in the table self.block_events = False self.series_table.populate_table(books) if len(unicode(self.series_combo.text()).strip()) > 0: self.series_table.setFocus() else: self.series_combo.setFocus() self.update_series_headers(initial_series_column) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() def initialize_controls(self): self.setWindowTitle('Manage Series') layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'images/manage_series.png', 'Create or Modify Series') layout.addLayout(title_layout) # Series name and start index layout series_name_layout = QHBoxLayout() layout.addLayout(series_name_layout) series_column_label = QLabel('Series &Column:', self) series_name_layout.addWidget(series_column_label) self.series_column_combo = SeriesColumnComboBox( self, self.series_columns) self.series_column_combo.currentIndexChanged[int].connect( self.series_column_changed) series_name_layout.addWidget(self.series_column_combo) series_column_label.setBuddy(self.series_column_combo) series_name_layout.addSpacing(20) series_label = QLabel('Series &Name:', self) series_name_layout.addWidget(series_label) self.series_combo = EditWithComplete(self) self.series_combo.setEditable(True) self.series_combo.setInsertPolicy(QtGui.QComboBox.InsertAlphabetically) self.series_combo.setSizeAdjustPolicy( QtGui.QComboBox.AdjustToMinimumContentsLengthWithIcon) self.series_combo.setMinimumContentsLength(25) self.series_combo.currentIndexChanged[int].connect(self.series_changed) self.series_combo.editTextChanged.connect(self.series_changed) self.series_combo.set_separator(None) series_label.setBuddy(self.series_combo) series_name_layout.addWidget(self.series_combo) series_name_layout.addSpacing(20) series_start_label = QLabel('&Start At:', self) series_name_layout.addWidget(series_start_label) self.series_start_number = QtGui.QSpinBox(self) self.series_start_number.setRange(0, 99000000) self.series_start_number.valueChanged[int].connect( self.series_start_changed) series_name_layout.addWidget(self.series_start_number) series_start_label.setBuddy(self.series_start_number) series_name_layout.insertStretch(-1) # Main series table layout table_layout = QHBoxLayout() layout.addLayout(table_layout) self.series_table = SeriesTableWidget(self) self.series_table.itemSelectionChanged.connect( self.item_selection_changed) self.series_table.cellChanged[int, int].connect(self.cell_changed) table_layout.addWidget(self.series_table) table_button_layout = QVBoxLayout() table_layout.addLayout(table_button_layout) move_up_button = QtGui.QToolButton(self) move_up_button.setToolTip('Move book up in series (Alt+Up)') move_up_button.setIcon(get_icon('arrow-up.png')) move_up_button.setShortcut(_('Alt+Up')) move_up_button.clicked.connect(self.move_rows_up) table_button_layout.addWidget(move_up_button) move_down_button = QtGui.QToolButton(self) move_down_button.setToolTip('Move book down in series (Alt+Down)') move_down_button.setIcon(get_icon('arrow-down.png')) move_down_button.setShortcut(_('Alt+Down')) move_down_button.clicked.connect(self.move_rows_down) table_button_layout.addWidget(move_down_button) spacerItem1 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) table_button_layout.addItem(spacerItem1) assign_index_button = QtGui.QToolButton(self) assign_index_button.setToolTip('Lock to index value...') assign_index_button.setIcon(get_icon('images/lock.png')) assign_index_button.clicked.connect(self.assign_index) table_button_layout.addWidget(assign_index_button) clear_index_button = QtGui.QToolButton(self) clear_index_button.setToolTip('Unlock series index') clear_index_button.setIcon(get_icon('images/lock_delete.png')) clear_index_button.clicked.connect(self.clear_index) table_button_layout.addWidget(clear_index_button) spacerItem2 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) table_button_layout.addItem(spacerItem2) add_empty_button = QtGui.QToolButton(self) add_empty_button.setToolTip('Add empty book to the series list') add_empty_button.setIcon(get_icon('add_book.png')) add_empty_button.setShortcut(_('Ctrl+Shift+E')) add_empty_button.clicked.connect(self.add_empty_book) table_button_layout.addWidget(add_empty_button) delete_button = QtGui.QToolButton(self) delete_button.setToolTip('Remove book from the series list') delete_button.setIcon(get_icon('trash.png')) delete_button.clicked.connect(self.remove_book) table_button_layout.addWidget(delete_button) spacerItem3 = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) table_button_layout.addItem(spacerItem3) move_left_button = QtGui.QToolButton(self) move_left_button.setToolTip( 'Move series index to left of decimal point (Alt+Left)') move_left_button.setIcon(get_icon('back.png')) move_left_button.setShortcut(_('Alt+Left')) move_left_button.clicked.connect(partial(self.series_indent_change, -1)) table_button_layout.addWidget(move_left_button) move_right_button = QtGui.QToolButton(self) move_right_button.setToolTip( 'Move series index to right of decimal point (Alt+Right)') move_right_button.setIcon(get_icon('forward.png')) move_right_button.setShortcut(_('Alt+Right')) move_right_button.clicked.connect(partial(self.series_indent_change, 1)) table_button_layout.addWidget(move_right_button) # Dialog buttons button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) layout.addWidget(button_box) keep_button = button_box.addButton(' &Restore Original Series ', QDialogButtonBox.ResetRole) keep_button.clicked.connect(self.restore_original_series) def series_column_changed(self): series_column = self.series_column_combo.selected_value() SeriesBook.series_column = series_column # Choose a series name and series index from the first book in the list initial_series_name = '' initial_series_index = 1 if len(self.books) > 0: first_book = self.books[0] initial_series_name = first_book.series_name() if initial_series_name: initial_series_index = int(first_book.series_index()) # Populate the series name combo as appropriate for that column self.initialize_series_name_combo(series_column, initial_series_name) # Populate the series index spinbox with the initial value self.series_start_number.setProperty('value', initial_series_index) self.update_series_headers(series_column) if self.block_events: return self.renumber_series() def update_series_headers(self, series_column): if series_column == 'Series': self.series_table.set_series_column_headers(series_column) else: header_text = self.series_columns[series_column]['name'] self.series_table.set_series_column_headers(header_text) def initialize_series_name_combo(self, series_column, series_name): self.series_combo.clear() if series_name is None: series_name = '' values = self.all_series if series_column == 'Series': self.series_combo.update_items_cache([x[1] for x in values]) for i in values: _id, name = i self.series_combo.addItem(name) else: label = self.db.field_metadata.key_to_label(series_column) values = list(self.db.all_custom(label=label)) values.sort(key=sort_key) self.series_combo.update_items_cache(values) for name in values: self.series_combo.addItem(name) self.series_combo.setEditText(series_name) def series_changed(self): if self.block_events: return self.renumber_series() def series_start_changed(self): if self.block_events: return self.renumber_series() def restore_original_series(self): # Go through the books and overwrite the indexes with the originals, fixing in place for book in self.books: if book.orig_series_index(): book.set_assigned_index(book.orig_series_index()) #book.set_series_name(book.orig_series_name()) book.set_series_index(book.orig_series_index()) # Now renumber the whole series so that anything in between gets changed self.renumber_series() def renumber_series(self, display_in_table=True): if len(self.books) == 0: return series_name = unicode(self.series_combo.currentText()).strip() series_index = float(unicode(self.series_start_number.value())) last_series_indent = 0 for row, book in enumerate(self.books): book.set_series_name(series_name) series_indent = book.series_indent() if book.assigned_index() is not None: series_index = book.assigned_index() else: if series_indent >= last_series_indent: if series_indent == 0: if row > 0: series_index += 1. elif series_indent == 1: series_index += 0.1 else: series_index += 0.01 else: # When series indent decreases, need to round to next if series_indent == 1: series_index = round(series_index + 0.05, 1) else: # series_indent == 0: series_index = round(series_index + 0.5, 0) book.set_series_index(series_index) last_series_indent = series_indent # Now determine whether books have a valid index or not self.books[0].set_is_valid(True) for row in range(len(self.books) - 1, 0, -1): book = self.books[row] previous_book = self.books[row - 1] if book.series_index() <= previous_book.series_index(): book.set_is_valid(False) else: book.set_is_valid(True) if display_in_table: for row, book in enumerate(self.books): self.series_table.populate_table_row(row, book) def assign_original_index(self): if len(self.books) == 0: return for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] book.set_assigned_index(book.orig_series_index()) self.renumber_series() self.item_selection_changed() def assign_index(self): if len(self.books) == 0: return auto_assign_value = None for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] if auto_assign_value is not None: book.set_assigned_index(auto_assign_value) continue d = LockSeriesDialog(self, book.title(), book.series_index()) d.exec_() if d.result() != d.Accepted: break if d.assign_same_value(): auto_assign_value = d.get_value() book.set_assigned_index(auto_assign_value) else: book.set_assigned_index(d.get_value()) self.renumber_series() self.item_selection_changed() def clear_index(self, all_rows=False): if len(self.books) == 0: return if all_rows: for book in self.books: book.set_assigned_index(None) else: for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] book.set_assigned_index(None) self.renumber_series() def add_empty_book(self): def create_empty_book(authors): mi = Metadata(_('Unknown'), dlg.selected_authors) for key in self.series_columns.keys(): meta = self.db.metadata_for_field(key) mi.set_user_metadata(key, meta) mi.set(key, val=None, extra=None) return SeriesBook(mi, self.series_columns) idx = self.series_table.currentRow() if idx == -1: author = None else: author = self.books[idx].authors()[0] dlg = AddEmptyBookDialog(self, self.db, author) if dlg.exec_() != dlg.Accepted: return num = dlg.qty_to_add for _x in range(num): idx += 1 book = create_empty_book(dlg.selected_authors) self.books.insert(idx, book) self.series_table.setRowCount(len(self.books)) self.renumber_series() def remove_book(self): if not question_dialog( self, _('Are you sure?'), '<p>' + 'Remove the selected book(s) from the series list?', show_copy_button=False): return rows = self.series_table.selectionModel().selectedRows() if len(rows) == 0: return selrows = [] for row in rows: selrows.append(row.row()) selrows.sort() first_sel_row = self.series_table.currentRow() for row in reversed(selrows): self.books.pop(row) self.series_table.removeRow(row) if first_sel_row < self.series_table.rowCount(): self.series_table.select_and_scroll_to_row(first_sel_row) elif self.series_table.rowCount() > 0: self.series_table.select_and_scroll_to_row(first_sel_row - 1) self.renumber_series() def move_rows_up(self): self.series_table.setFocus() rows = self.series_table.selectionModel().selectedRows() if len(rows) == 0: return first_sel_row = rows[0].row() if first_sel_row <= 0: return # Workaround for strange selection bug in Qt which "alters" the selection # in certain circumstances which meant move down only worked properly "once" selrows = [] for row in rows: selrows.append(row.row()) selrows.sort() for selrow in selrows: self.series_table.swap_row_widgets(selrow - 1, selrow + 1) self.books[selrow - 1], self.books[selrow] = self.books[selrow], self.books[ selrow - 1] scroll_to_row = first_sel_row - 1 if scroll_to_row > 0: scroll_to_row = scroll_to_row - 1 self.series_table.scrollToItem(self.series_table.item( scroll_to_row, 0)) self.renumber_series() def move_rows_down(self): self.series_table.setFocus() rows = self.series_table.selectionModel().selectedRows() if len(rows) == 0: return last_sel_row = rows[-1].row() if last_sel_row == self.series_table.rowCount() - 1: return # Workaround for strange selection bug in Qt which "alters" the selection # in certain circumstances which meant move down only worked properly "once" selrows = [] for row in rows: selrows.append(row.row()) selrows.sort() for selrow in reversed(selrows): self.series_table.swap_row_widgets(selrow + 2, selrow) self.books[selrow + 1], self.books[selrow] = self.books[selrow], self.books[ selrow + 1] scroll_to_row = last_sel_row + 1 if scroll_to_row < self.series_table.rowCount() - 1: scroll_to_row = scroll_to_row + 1 self.series_table.scrollToItem(self.series_table.item( scroll_to_row, 0)) self.renumber_series() def series_indent_change(self, delta): for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] series_indent = book.series_indent() if delta > 0: if series_indent < 2: book.set_series_indent(series_indent + 1) else: if series_indent > 0: book.set_series_indent(series_indent - 1) book.set_assigned_index(None) self.renumber_series() def sort_by(self, name): if name == 'PubDate': self.books = sorted(self.books, key=lambda k: k.sort_key(sort_by_pubdate=True)) elif name == 'Original Series Name': self.books = sorted(self.books, key=lambda k: k.sort_key(sort_by_name=True)) else: self.books = sorted(self.books, key=lambda k: k.sort_key()) self.renumber_series() def search_web(self, name): URLS = { 'FantasticFiction': 'http://www.fantasticfiction.co.uk/search/?searchfor=author&keywords={author}', 'Goodreads': 'http://www.goodreads.com/search/search?q={author}&search_type=books', 'Google': 'http://www.google.com/#sclient=psy&q=%22{author}%22+%22{title}%22', 'Wikipedia': 'http://en.wikipedia.org/w/index.php?title=Special%3ASearch&search={author}' } for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] safe_title = self.convert_to_search_text(book.title()) safe_author = self.convert_author_to_search_text(book.authors()[0]) url = URLS[name].replace('{title}', safe_title).replace( '{author}', safe_author) open_url(QUrl.fromEncoded(url)) def convert_to_search_text(self, text, encoding='utf-8'): # First we strip characters we will definitely not want to pass through. # Periods from author initials etc do not need to be supplied text = text.replace('.', '') # Now encode the text using Python function with chosen encoding text = quote_plus(text.encode(encoding, 'ignore')) # If we ended up with double spaces as plus signs (++) replace them text = text.replace('++', '+') return text def convert_author_to_search_text(self, author, encoding='utf-8'): # We want to convert the author name to FN LN format if it is stored LN, FN # We do this because some websites (Kobo) have crappy search engines that # will not match Adams+Douglas but will match Douglas+Adams # Not really sure of the best way of determining if the user is using LN, FN # Approach will be to check the tweak and see if a comma is in the name # Comma separated author will be pipe delimited in Calibre database fn_ln_author = author if author.find(',') > -1: # This might be because of a FN LN,Jr - check the tweak sort_copy_method = tweaks['author_sort_copy_method'] if sort_copy_method == 'invert': # Calibre default. Hence "probably" using FN LN format. fn_ln_author = author else: # We will assume that we need to switch the names from LN,FN to FN LN parts = author.split(',') surname = parts.pop(0) parts.append(surname) fn_ln_author = ' '.join(parts).strip() return self.convert_to_search_text(fn_ln_author, encoding) def cell_changed(self, row, column): book = self.books[row] if column == 0: book.set_title( unicode(self.series_table.item(row, column).text()).strip()) elif column == 2: qtdate = convert_qvariant( self.series_table.item(row, column).data(Qt.DisplayRole)) book.set_pubdate(qt_to_dt(qtdate, as_utc=False)) def item_selection_changed(self): row = self.series_table.currentRow() if row == -1: return has_assigned_index = False for row in self.series_table.selectionModel().selectedRows(): book = self.books[row.row()] if book.assigned_index(): has_assigned_index = True self.series_table.clear_index_action.setEnabled(has_assigned_index) if not has_assigned_index: for book in self.books: if book.assigned_index(): has_assigned_index = True self.series_table.clear_all_index_action.setEnabled(has_assigned_index)
class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author, series=None): QDialog.__init__(self, parent) self.db = db self.setWindowTitle(_('How many empty books?')) self._layout = QGridLayout(self) self.setLayout(self._layout) self.qty_label = QLabel(_('How many empty books should be added?')) self._layout.addWidget(self.qty_label, 0, 0, 1, 2) self.qty_spinbox = QSpinBox(self) self.qty_spinbox.setRange(1, 10000) self.qty_spinbox.setValue(1) self._layout.addWidget(self.qty_spinbox, 1, 0, 1, 2) self.author_label = QLabel(_('Set the author of the new books to:')) self._layout.addWidget(self.author_label, 2, 0, 1, 2) self.authors_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.authors_combo.setEditable(True) self._layout.addWidget(self.authors_combo, 3, 0, 1, 1) self.initialize_authors(db, author) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon(I('trash.png'))) self.clear_button.setToolTip(_('Reset author to Unknown')) self.clear_button.clicked.connect(self.reset_author) self._layout.addWidget(self.clear_button, 3, 1, 1, 1) self.series_label = QLabel(_('Set the series of the new books to:')) self._layout.addWidget(self.series_label, 4, 0, 1, 2) self.series_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.series_combo.setEditable(True) self._layout.addWidget(self.series_combo, 5, 0, 1, 1) self.initialize_series(db, series) self.sclear_button = QToolButton(self) self.sclear_button.setIcon(QIcon(I('trash.png'))) self.sclear_button.setToolTip(_('Reset series')) self.sclear_button.clicked.connect(self.reset_series) self._layout.addWidget(self.sclear_button, 5, 1, 1, 1) self.create_epub = c = QCheckBox(_('Create an empty EPUB file as well')) c.setChecked(gprefs.get('create_empty_epub_file', False)) c.setToolTip(_('Also create an empty EPUB file that you can subsequently edit')) self._layout.addWidget(c, 6, 0, 1, -1) button_box = self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self._layout.addWidget(button_box, 7, 0, 1, -1) self.resize(self.sizeHint()) def accept(self): oval = gprefs.get('create_empty_epub_file', False) if self.create_epub.isChecked() != oval: gprefs['create_empty_epub_file'] = self.create_epub.isChecked() return QDialog.accept(self) def reset_author(self, *args): self.authors_combo.setEditText(_('Unknown')) def reset_series(self): self.series_combo.setEditText('') def initialize_authors(self, db, author): au = author if not au: au = _('Unknown') self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) self.authors_combo.set_add_separator(tweaks['authors_completer_append_separator']) self.authors_combo.update_items_cache(db.all_author_names()) def initialize_series(self, db, series): self.series_combo.show_initial_value(series or '') self.series_combo.update_items_cache(db.all_series_names()) self.series_combo.set_separator(None) @property def qty_to_add(self): return self.qty_spinbox.value() @property def selected_authors(self): return string_to_authors(unicode(self.authors_combo.text())) @property def selected_series(self): return unicode(self.series_combo.text())
class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author, series=None, title=None): QDialog.__init__(self, parent) self.db = db self.setWindowTitle(_('How many empty books?')) self._layout = QGridLayout(self) self.setLayout(self._layout) self.qty_label = QLabel(_('How many empty books should be added?')) self._layout.addWidget(self.qty_label, 0, 0, 1, 2) self.qty_spinbox = QSpinBox(self) self.qty_spinbox.setRange(1, 10000) self.qty_spinbox.setValue(1) self._layout.addWidget(self.qty_spinbox, 1, 0, 1, 2) self.author_label = QLabel(_('Set the author of the new books to:')) self._layout.addWidget(self.author_label, 2, 0, 1, 2) self.authors_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.authors_combo.setEditable(True) self._layout.addWidget(self.authors_combo, 3, 0, 1, 1) self.initialize_authors(db, author) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon(I('trash.png'))) self.clear_button.setToolTip(_('Reset author to Unknown')) self.clear_button.clicked.connect(self.reset_author) self._layout.addWidget(self.clear_button, 3, 1, 1, 1) self.series_label = QLabel(_('Set the series of the new books to:')) self._layout.addWidget(self.series_label, 4, 0, 1, 2) self.series_combo = EditWithComplete(self) self.series_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.series_combo.setEditable(True) self._layout.addWidget(self.series_combo, 5, 0, 1, 1) self.initialize_series(db, series) self.sclear_button = QToolButton(self) self.sclear_button.setIcon(QIcon(I('trash.png'))) self.sclear_button.setToolTip(_('Reset series')) self.sclear_button.clicked.connect(self.reset_series) self._layout.addWidget(self.sclear_button, 5, 1, 1, 1) self.title_label = QLabel(_('Set the title of the new books to:')) self._layout.addWidget(self.title_label, 6, 0, 1, 2) self.title_edit = QLineEdit(self) self.title_edit.setText(title or '') self._layout.addWidget(self.title_edit, 7, 0, 1, 1) self.tclear_button = QToolButton(self) self.tclear_button.setIcon(QIcon(I('trash.png'))) self.tclear_button.setToolTip(_('Reset title')) self.tclear_button.clicked.connect(self.title_edit.clear) self._layout.addWidget(self.tclear_button, 7, 1, 1, 1) self.format_label = QLabel(_('Also create an empty ebook in format:')) self._layout.addWidget(self.format_label, 8, 0, 1, 2) c = self.format_value = QComboBox(self) from calibre.ebooks.oeb.polish.create import valid_empty_formats possible_formats = [''] + sorted(x.upper() for x in valid_empty_formats) c.addItems(possible_formats) c.setToolTip(_('Also create an empty book format file that you can subsequently edit')) if gprefs.get('create_empty_epub_file', False): # Migration of the check box gprefs.set('create_empty_format_file', 'epub') del gprefs['create_empty_epub_file'] use_format = gprefs.get('create_empty_format_file', '').upper() try: c.setCurrentIndex(possible_formats.index(use_format)) except Exception: pass self._layout.addWidget(c, 9, 0, 1, 1) button_box = self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self._layout.addWidget(button_box, 10, 0, 1, -1) self.resize(self.sizeHint()) def accept(self): gprefs['create_empty_format_file'] = self.format_value.currentText().lower() return QDialog.accept(self) def reset_author(self, *args): self.authors_combo.setEditText(_('Unknown')) def reset_series(self): self.series_combo.setEditText('') def initialize_authors(self, db, author): au = author if not au: au = _('Unknown') self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) self.authors_combo.set_add_separator(tweaks['authors_completer_append_separator']) self.authors_combo.update_items_cache(db.all_author_names()) def initialize_series(self, db, series): self.series_combo.show_initial_value(series or '') self.series_combo.update_items_cache(db.all_series_names()) self.series_combo.set_separator(None) @property def qty_to_add(self): return self.qty_spinbox.value() @property def selected_authors(self): return string_to_authors(unicode(self.authors_combo.text())) @property def selected_series(self): return unicode(self.series_combo.text()) @property def selected_title(self): return self.title_edit.text().strip()
class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author): QDialog.__init__(self, parent) self.db = db self.setWindowTitle(_('How many empty books?')) self._layout = QGridLayout(self) self.setLayout(self._layout) self.qty_label = QLabel(_('How many empty books should be added?')) self._layout.addWidget(self.qty_label, 0, 0, 1, 2) self.qty_spinbox = QSpinBox(self) self.qty_spinbox.setRange(1, 10000) self.qty_spinbox.setValue(1) self._layout.addWidget(self.qty_spinbox, 1, 0, 1, 2) self.author_label = QLabel(_('Set the author of the new books to:')) self._layout.addWidget(self.author_label, 2, 0, 1, 2) self.authors_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.authors_combo.setEditable(True) self._layout.addWidget(self.authors_combo, 3, 0, 1, 1) self.initialize_authors(db, author) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon(I('trash.png'))) self.clear_button.setToolTip(_('Reset author to Unknown')) self.clear_button.clicked.connect(self.reset_author) self._layout.addWidget(self.clear_button, 3, 1, 1, 1) button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self._layout.addWidget(button_box) self.resize(self.sizeHint()) def reset_author(self, *args): self.authors_combo.setEditText(_('Unknown')) def initialize_authors(self, db, author): au = author if not au: au = _('Unknown') self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) self.authors_combo.set_add_separator(tweaks['authors_completer_append_separator']) self.authors_combo.update_items_cache(db.all_author_names()) @property def qty_to_add(self): return self.qty_spinbox.value() @property def selected_authors(self): return string_to_authors(unicode(self.authors_combo.text()))
class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author, series=None): QDialog.__init__(self, parent) self.db = db self.setWindowTitle(_('How many empty books?')) self._layout = QGridLayout(self) self.setLayout(self._layout) self.qty_label = QLabel(_('How many empty books should be added?')) self._layout.addWidget(self.qty_label, 0, 0, 1, 2) self.qty_spinbox = QSpinBox(self) self.qty_spinbox.setRange(1, 10000) self.qty_spinbox.setValue(1) self._layout.addWidget(self.qty_spinbox, 1, 0, 1, 2) self.author_label = QLabel(_('Set the author of the new books to:')) self._layout.addWidget(self.author_label, 2, 0, 1, 2) self.authors_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.authors_combo.setEditable(True) self._layout.addWidget(self.authors_combo, 3, 0, 1, 1) self.initialize_authors(db, author) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon(I('trash.png'))) self.clear_button.setToolTip(_('Reset author to Unknown')) self.clear_button.clicked.connect(self.reset_author) self._layout.addWidget(self.clear_button, 3, 1, 1, 1) self.series_label = QLabel(_('Set the series of the new books to:')) self._layout.addWidget(self.series_label, 4, 0, 1, 2) self.series_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.series_combo.setEditable(True) self._layout.addWidget(self.series_combo, 5, 0, 1, 1) self.initialize_series(db, series) self.sclear_button = QToolButton(self) self.sclear_button.setIcon(QIcon(I('trash.png'))) self.sclear_button.setToolTip(_('Reset series')) self.sclear_button.clicked.connect(self.reset_series) self._layout.addWidget(self.sclear_button, 5, 1, 1, 1) self.create_epub = c = QCheckBox( _('Create an empty EPUB file as well')) c.setChecked(gprefs.get('create_empty_epub_file', False)) c.setToolTip( _('Also create an empty EPUB file that you can subsequently edit')) self._layout.addWidget(c, 6, 0, 1, -1) button_box = self.bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self._layout.addWidget(button_box, 7, 0, 1, -1) self.resize(self.sizeHint()) def accept(self): oval = gprefs.get('create_empty_epub_file', False) if self.create_epub.isChecked() != oval: gprefs['create_empty_epub_file'] = self.create_epub.isChecked() return QDialog.accept(self) def reset_author(self, *args): self.authors_combo.setEditText(_('Unknown')) def reset_series(self): self.series_combo.setEditText('') def initialize_authors(self, db, author): au = author if not au: au = _('Unknown') self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) self.authors_combo.set_add_separator( tweaks['authors_completer_append_separator']) self.authors_combo.update_items_cache(db.all_author_names()) def initialize_series(self, db, series): self.series_combo.show_initial_value(series or '') self.series_combo.update_items_cache(db.all_series_names()) self.series_combo.set_separator(None) @property def qty_to_add(self): return self.qty_spinbox.value() @property def selected_authors(self): return string_to_authors(unicode(self.authors_combo.text())) @property def selected_series(self): return unicode(self.series_combo.text())
class AddEmptyBookDialog(QDialog): def __init__(self, parent, db, author, series=None, title=None, dup_title=None): QDialog.__init__(self, parent) self.db = db self.setWindowTitle(_('How many empty books?')) self._layout = QGridLayout(self) self.setLayout(self._layout) self.qty_label = QLabel(_('How many empty books should be added?')) self._layout.addWidget(self.qty_label, 0, 0, 1, 2) self.qty_spinbox = QSpinBox(self) self.qty_spinbox.setRange(1, 10000) self.qty_spinbox.setValue(1) self._layout.addWidget(self.qty_spinbox, 1, 0, 1, 2) self.author_label = QLabel(_('Set the author of the new books to:')) self._layout.addWidget(self.author_label, 2, 0, 1, 2) self.authors_combo = EditWithComplete(self) self.authors_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.authors_combo.setEditable(True) self._layout.addWidget(self.authors_combo, 3, 0, 1, 1) self.initialize_authors(db, author) self.clear_button = QToolButton(self) self.clear_button.setIcon(QIcon(I('trash.png'))) self.clear_button.setToolTip(_('Reset author to Unknown')) self.clear_button.clicked.connect(self.reset_author) self._layout.addWidget(self.clear_button, 3, 1, 1, 1) self.series_label = QLabel(_('Set the series of the new books to:')) self._layout.addWidget(self.series_label, 4, 0, 1, 2) self.series_combo = EditWithComplete(self) self.series_combo.setSizeAdjustPolicy( self.authors_combo.AdjustToMinimumContentsLengthWithIcon) self.series_combo.setEditable(True) self._layout.addWidget(self.series_combo, 5, 0, 1, 1) self.initialize_series(db, series) self.sclear_button = QToolButton(self) self.sclear_button.setIcon(QIcon(I('trash.png'))) self.sclear_button.setToolTip(_('Reset series')) self.sclear_button.clicked.connect(self.reset_series) self._layout.addWidget(self.sclear_button, 5, 1, 1, 1) self.title_label = QLabel(_('Set the title of the new books to:')) self._layout.addWidget(self.title_label, 6, 0, 1, 2) self.title_edit = QLineEdit(self) self.title_edit.setText(title or '') self._layout.addWidget(self.title_edit, 7, 0, 1, 1) self.tclear_button = QToolButton(self) self.tclear_button.setIcon(QIcon(I('trash.png'))) self.tclear_button.setToolTip(_('Reset title')) self.tclear_button.clicked.connect(self.title_edit.clear) self._layout.addWidget(self.tclear_button, 7, 1, 1, 1) self.format_label = QLabel(_('Also create an empty e-book in format:')) self._layout.addWidget(self.format_label, 8, 0, 1, 2) c = self.format_value = QComboBox(self) from calibre.ebooks.oeb.polish.create import valid_empty_formats possible_formats = [''] + sorted(x.upper() for x in valid_empty_formats) c.addItems(possible_formats) c.setToolTip(_('Also create an empty book format file that you can subsequently edit')) if gprefs.get('create_empty_epub_file', False): # Migration of the check box gprefs.set('create_empty_format_file', 'epub') del gprefs['create_empty_epub_file'] use_format = gprefs.get('create_empty_format_file', '').upper() try: c.setCurrentIndex(possible_formats.index(use_format)) except Exception: pass self._layout.addWidget(c, 9, 0, 1, 1) self.copy_formats = cf = QCheckBox(_('Also copy book &formats when duplicating a book'), self) cf.setToolTip(_( 'Also copy all e-book files into the newly created duplicate' ' books.')) cf.setChecked(gprefs.get('create_empty_copy_dup_formats', False)) self._layout.addWidget(cf, 10, 0, 1, -1) button_box = self.bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) button_box.accepted.connect(self.accept) button_box.rejected.connect(self.reject) self._layout.addWidget(button_box, 11, 0, 1, -1) if dup_title: self.dup_button = b = button_box.addButton(_('&Duplicate current book'), button_box.ActionRole) b.clicked.connect(self.do_duplicate_book) b.setIcon(QIcon(I('edit-copy.png'))) b.setToolTip(_( 'Make the new empty book records exact duplicates\n' 'of the current book "%s", with all metadata identical' ) % dup_title) self.resize(self.sizeHint()) self.duplicate_current_book = False def do_duplicate_book(self): self.duplicate_current_book = True self.accept() def accept(self): self.save_settings() return QDialog.accept(self) def save_settings(self): gprefs['create_empty_format_file'] = self.format_value.currentText().lower() gprefs['create_empty_copy_dup_formats'] = self.copy_formats.isChecked() def reject(self): self.save_settings() return QDialog.reject(self) def reset_author(self, *args): self.authors_combo.setEditText(_('Unknown')) def reset_series(self): self.series_combo.setEditText('') def initialize_authors(self, db, author): au = author if not au: au = _('Unknown') self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) self.authors_combo.set_add_separator(tweaks['authors_completer_append_separator']) self.authors_combo.update_items_cache(db.all_author_names()) def initialize_series(self, db, series): self.series_combo.show_initial_value(series or '') self.series_combo.update_items_cache(db.all_series_names()) self.series_combo.set_separator(None) @property def qty_to_add(self): return self.qty_spinbox.value() @property def selected_authors(self): return string_to_authors(unicode_type(self.authors_combo.text())) @property def selected_series(self): return unicode_type(self.series_combo.text()) @property def selected_title(self): return self.title_edit.text().strip()