def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Shape.NoFrame if gprefs['tag_browser_old_look'] else QFrame.Shape.StyledPanel) self._parent = parent self._layout = QVBoxLayout(self) self._layout.setContentsMargins(0,0,0,0) # Set up the find box & button self.tb_bar = tbb = TagBrowserBar(self) tbb.clear_find.connect(self.reset_find) self.alter_tb, self.item_search, self.search_button = tbb.alter_tb, tbb.item_search, tbb.search_button self.toggle_search_button = tbb.toggle_search_button self._layout.addWidget(tbb) self.current_find_position = None self.search_button.clicked.connect(self.find) self.item_search.lineEdit().textEdited.connect(self.find_text_changed) self.item_search.activated[str].connect(self.do_find) # The tags view parent.tags_view = TagsView(parent) self.tags_view = parent.tags_view self._layout.insertWidget(0, parent.tags_view) # Now the floating 'not found' box l = QLabel(self.tags_view) self.not_found_label = l l.setFrameStyle(QFrame.Shape.StyledPanel) l.setAutoFillBackground(True) l.setText('<p><b>'+_('No more matches.</b><p> Click Find again to go to first match')) l.setAlignment(Qt.AlignmentFlag.AlignVCenter) l.setWordWrap(True) l.resize(l.sizeHint()) l.move(10,20) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect(self.not_found_label_timer_event, type=Qt.ConnectionType.QueuedConnection) self.collapse_all_action = ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser collapse all', _('Collapse all'), default_keys=(), action=ac, group=_('Tag browser')) connect_lambda(ac.triggered, self, lambda self: self.tags_view.collapseAll()) # The Configure Tag Browser button l = self.alter_tb ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser alter', _('Configure Tag browser'), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(l.showMenu) l.m.aboutToShow.connect(self.about_to_show_configure_menu) l.m.show_counts_action = ac = l.m.addAction('counts') ac.triggered.connect(self.toggle_counts) l.m.show_avg_rating_action = ac = l.m.addAction('avg rating') ac.triggered.connect(self.toggle_avg_rating) sb = l.m.addAction(_('Sort by')) sb.m = l.sort_menu = QMenu(l.m) sb.setMenu(sb.m) sb.bg = QActionGroup(sb) # Must be in the same order as db2.CATEGORY_SORTS for i, x in enumerate((_('Name'), _('Number of books'), _('Average rating'))): a = sb.m.addAction(x) sb.bg.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) sb.setToolTip( _('Set the sort order for entries in the Tag browser')) sb.setStatusTip(sb.toolTip()) ma = l.m.addAction(_('Search type when selecting multiple items')) ma.m = l.match_menu = QMenu(l.m) ma.setMenu(ma.m) ma.ag = QActionGroup(ma) # Must be in the same order as db2.MATCH_TYPE for i, x in enumerate((_('Match any of the items'), _('Match all of the items'))): a = ma.m.addAction(x) ma.ag.addAction(a) a.setCheckable(True) if i == 0: a.setChecked(True) ma.setToolTip( _('When selecting multiple entries in the Tag browser ' 'match any or all of them')) ma.setStatusTip(ma.toolTip()) mt = l.m.addAction(_('Manage authors, tags, etc.')) mt.setToolTip(_('All of these category_managers are available by right-clicking ' 'on items in the Tag browser above')) mt.m = l.manage_menu = QMenu(l.m) mt.setMenu(mt.m) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser toggle item', _("'Click' found item"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.toggle_item) ac = QAction(parent) parent.addAction(ac) parent.keyboard.register_shortcut('tag browser set focus', _("Give the Tag browser keyboard focus"), default_keys=(), action=ac, group=_('Tag browser')) ac.triggered.connect(self.give_tb_focus)
class UnpackBook(QDialog): def __init__(self, parent, book_id, fmts, db): QDialog.__init__(self, parent) self.setWindowIcon(QIcon(I('unpack-book.png'))) self.book_id, self.fmts, self.db_ref = book_id, fmts, weakref.ref(db) self._exploded = None self._cleanup_dirs = [] self._cleanup_files = [] self.setup_ui() self.setWindowTitle(_('Unpack book') + ' - ' + db.title(book_id, index_is_id=True)) button = self.fmt_choice_buttons[0] button_map = {str(x.text()):x for x in self.fmt_choice_buttons} of = prefs['output_format'].upper() df = tweaks.get('default_tweak_format', None) lf = gprefs.get('last_tweak_format', None) if df and df.lower() == 'remember' and lf in button_map: button = button_map[lf] elif df and df.upper() in button_map: button = button_map[df.upper()] elif of in button_map: button = button_map[of] button.setChecked(True) self.init_state() for button in self.fmt_choice_buttons: button.toggled.connect(self.init_state) def init_state(self, *args): self._exploded = None self.preview_button.setEnabled(False) self.rebuild_button.setEnabled(False) self.explode_button.setEnabled(True) def setup_ui(self): # {{{ self._g = g = QHBoxLayout(self) self.setLayout(g) self._l = l = QVBoxLayout() g.addLayout(l) fmts = sorted(x.upper() for x in self.fmts) self.fmt_choice_box = QGroupBox(_('Choose the format to unpack:'), self) self._fl = fl = QHBoxLayout() self.fmt_choice_box.setLayout(self._fl) self.fmt_choice_buttons = [QRadioButton(y, self) for y in fmts] for x in self.fmt_choice_buttons: fl.addWidget(x, stretch=10 if x is self.fmt_choice_buttons[-1] else 0) l.addWidget(self.fmt_choice_box) self.fmt_choice_box.setVisible(len(fmts) > 1) self.help_label = QLabel(_('''\ <h2>About Unpack book</h2> <p>Unpack book allows you to fine tune the appearance of an e-book by making small changes to its internals. In order to use Unpack book, you need to know a little bit about HTML and CSS, technologies that are used in e-books. Follow the steps:</p> <br> <ol> <li>Click "Explode book": This will "explode" the book into its individual internal components.<br></li> <li>Right click on any individual file and select "Open with..." to edit it in your favorite text editor.<br></li> <li>When you are done: <b>close the file browser window and the editor windows you used to make your tweaks</b>. Then click the "Rebuild book" button, to update the book in your calibre library.</li> </ol>''')) self.help_label.setWordWrap(True) self._fr = QFrame() self._fr.setFrameShape(QFrame.Shape.VLine) g.addWidget(self._fr) g.addWidget(self.help_label) self._b = b = QGridLayout() left, top, right, bottom = b.getContentsMargins() top += top b.setContentsMargins(left, top, right, bottom) l.addLayout(b, stretch=10) self.explode_button = QPushButton(QIcon(I('wizard.png')), _('&Explode book')) self.preview_button = QPushButton(QIcon(I('view.png')), _('&Preview book')) self.cancel_button = QPushButton(QIcon(I('window-close.png')), _('&Cancel')) self.rebuild_button = QPushButton(QIcon(I('exec.png')), _('&Rebuild book')) self.explode_button.setToolTip( _('Explode the book to edit its components')) self.preview_button.setToolTip( _('Preview the result of your changes')) self.cancel_button.setToolTip( _('Abort without saving any changes')) self.rebuild_button.setToolTip( _('Save your changes and update the book in the calibre library')) a = b.addWidget a(self.explode_button, 0, 0, 1, 1) a(self.preview_button, 0, 1, 1, 1) a(self.cancel_button, 1, 0, 1, 1) a(self.rebuild_button, 1, 1, 1, 1) for x in ('explode', 'preview', 'cancel', 'rebuild'): getattr(self, x+'_button').clicked.connect(getattr(self, x)) self.msg = QLabel('dummy', self) self.msg.setVisible(False) self.msg.setStyleSheet(''' QLabel { text-align: center; background-color: white; color: black; border-width: 1px; border-style: solid; border-radius: 20px; font-size: x-large; font-weight: bold; } ''') self.resize(self.sizeHint() + QSize(40, 10)) # }}} def show_msg(self, msg): self.msg.setText(msg) self.msg.resize(self.size() - QSize(50, 25)) self.msg.move((self.width() - self.msg.width())//2, (self.height() - self.msg.height())//2) self.msg.setVisible(True) def hide_msg(self): self.msg.setVisible(False) def explode(self): self.show_msg(_('Exploding, please wait...')) if len(self.fmt_choice_buttons) > 1: gprefs.set('last_tweak_format', self.current_format.upper()) QTimer.singleShot(5, self.do_explode) def ask_question(self, msg): return question_dialog(self, _('Are you sure?'), msg) def do_explode(self): from calibre.ebooks.tweak import get_tools, Error, WorkerError tdir = PersistentTemporaryDirectory('_tweak_explode') self._cleanup_dirs.append(tdir) det_msg = None try: src = self.db.format(self.book_id, self.current_format, index_is_id=True, as_path=True) self._cleanup_files.append(src) exploder = get_tools(self.current_format)[0] opf = exploder(src, tdir, question=self.ask_question) except WorkerError as e: det_msg = e.orig_tb except Error as e: return error_dialog(self, _('Failed to unpack'), (_('Could not explode the %s file.')%self.current_format) + ' ' + as_unicode(e), show=True) except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: return error_dialog(self, _('Failed to unpack'), _('Could not explode the %s file. Click "Show details" for ' 'more information.')%self.current_format, det_msg=det_msg, show=True) if opf is None: # The question was answered with No return self._exploded = tdir self.explode_button.setEnabled(False) self.preview_button.setEnabled(True) self.rebuild_button.setEnabled(True) open_local_file(tdir) def rebuild_it(self): from calibre.ebooks.tweak import get_tools, WorkerError src_dir = self._exploded det_msg = None of = PersistentTemporaryFile('_tweak_rebuild.'+self.current_format.lower()) of.close() of = of.name self._cleanup_files.append(of) try: rebuilder = get_tools(self.current_format)[1] rebuilder(src_dir, of) except WorkerError as e: det_msg = e.orig_tb except: import traceback det_msg = traceback.format_exc() finally: self.hide_msg() if det_msg is not None: error_dialog(self, _('Failed to rebuild file'), _('Failed to rebuild %s. For more information, click ' '"Show details".')%self.current_format, det_msg=det_msg, show=True) return None return of def preview(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_preview) def do_preview(self): rebuilt = self.rebuild_it() if rebuilt is not None: self.parent().iactions['View']._view_file(rebuilt) def rebuild(self): self.show_msg(_('Rebuilding, please wait...')) QTimer.singleShot(5, self.do_rebuild) def do_rebuild(self): rebuilt = self.rebuild_it() if rebuilt is not None: fmt = os.path.splitext(rebuilt)[1][1:].upper() with open(rebuilt, 'rb') as f: self.db.add_format(self.book_id, fmt, f, index_is_id=True) self.accept() def cancel(self): self.reject() def cleanup(self): if ismacos and self._exploded: try: import appscript self.finder = appscript.app('Finder') self.finder.Finder_windows[os.path.basename(self._exploded)].close() except: pass for f in self._cleanup_files: try: os.remove(f) except: pass for d in self._cleanup_dirs: try: shutil.rmtree(d) except: pass @property def db(self): return self.db_ref() @property def current_format(self): for b in self.fmt_choice_buttons: if b.isChecked(): return str(b.text())
class Restrictions(QWidget): restrictions_changed = pyqtSignal() def __init__(self, parent): self.restrict_to_book_ids = frozenset() QWidget.__init__(self, parent) v = QVBoxLayout(self) v.setContentsMargins(0, 0, 0, 0) h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) v.addLayout(h) self.rla = QLabel(_('Restrict to') + ': ') h.addWidget(self.rla) la = QLabel(_('Type:')) h.addWidget(la) self.types_box = tb = QComboBox(self) tb.la = la tb.currentIndexChanged.connect(self.restrictions_changed) connect_lambda( tb.currentIndexChanged, tb, lambda tb: gprefs.set( 'browse_annots_restrict_to_type', tb.currentData())) la.setBuddy(tb) tb.setToolTip(_('Show only annotations of the specified type')) h.addWidget(tb) la = QLabel(_('User:'******'browse_annots_restrict_to_user', ub.currentData())) la.setBuddy(ub) ub.setToolTip(_('Show only annotations created by the specified user')) h.addWidget(ub) h.addStretch(10) h = QHBoxLayout() self.restrict_to_books_cb = cb = QCheckBox('') self.update_book_restrictions_text() cb.setToolTip( _('Only show annotations from books that have been selected in the calibre library' )) cb.setChecked( bool(gprefs.get('show_annots_from_selected_books_only', False))) cb.stateChanged.connect(self.show_only_selected_changed) h.addWidget(cb) v.addLayout(h) def update_book_restrictions_text(self): if not self.restrict_to_book_ids: t = _('&Show results from only selected books') else: t = ngettext('&Show results from only the selected book', '&Show results from only the {} selected books', len(self.restrict_to_book_ids)).format( len(self.restrict_to_book_ids)) self.restrict_to_books_cb.setText(t) def show_only_selected_changed(self): self.restrictions_changed.emit() gprefs['show_annots_from_selected_books_only'] = bool( self.restrict_to_books_cb.isChecked()) def selection_changed(self, restrict_to_book_ids): self.restrict_to_book_ids = frozenset(restrict_to_book_ids or set()) self.update_book_restrictions_text() if self.restrict_to_books_cb.isChecked(): self.restrictions_changed.emit() @property def effective_restrict_to_book_ids(self): return (self.restrict_to_book_ids or None) if self.restrict_to_books_cb.isChecked() else None def re_initialize(self, db, restrict_to_book_ids=None): self.restrict_to_book_ids = frozenset(restrict_to_book_ids or set()) self.update_book_restrictions_text() tb = self.types_box before = tb.currentData() if not before: before = gprefs['browse_annots_restrict_to_type'] tb.blockSignals(True) tb.clear() tb.addItem(' ', ' ') for atype in db.all_annotation_types(): tb.addItem(annotation_title(atype), atype) if before: row = tb.findData(before) if row > -1: tb.setCurrentIndex(row) tb.blockSignals(False) tb_is_visible = tb.count() > 2 tb.setVisible(tb_is_visible), tb.la.setVisible(tb_is_visible) tb = self.user_box before = tb.currentData() if not before: before = gprefs['browse_annots_restrict_to_user'] tb.blockSignals(True) tb.clear() tb.addItem(' ', ' ') for user_type, user in db.all_annotation_users(): display_name = friendly_username(user_type, user) tb.addItem(display_name, f'{user_type}:{user}') if before: row = tb.findData(before) if row > -1: tb.setCurrentIndex(row) tb.blockSignals(False) ub_is_visible = tb.count() > 2 tb.setVisible(ub_is_visible), tb.la.setVisible(ub_is_visible) self.rla.setVisible(tb_is_visible or ub_is_visible) self.setVisible(True)
def __init__(self, window, cat_name, tag_to_match, get_book_ids, sorter, ttm_is_first_letter=False, category=None, fm=None): QDialog.__init__(self, window) Ui_TagListEditor.__init__(self) self.setupUi(self) self.verticalLayout_2.setAlignment(Qt.AlignmentFlag.AlignCenter) self.search_box.setMinimumContentsLength(25) # Put the category name into the title bar t = self.windowTitle() self.category_name = cat_name self.category = category self.setWindowTitle(t + ' (' + cat_name + ')') # Remove help icon on title bar icon = self.windowIcon() self.setWindowFlags(self.windowFlags() & (~Qt.WindowType.WindowContextHelpButtonHint)) self.setWindowIcon(icon) # Get saved geometry info try: self.table_column_widths = \ gprefs.get('tag_list_editor_table_widths', None) except: pass # initialization self.to_rename = {} self.to_delete = set() self.all_tags = {} self.original_names = {} self.ordered_tags = [] self.sorter = sorter self.get_book_ids = get_book_ids self.text_before_editing = '' # Capture clicks on the horizontal header to sort the table columns hh = self.table.horizontalHeader() hh.sectionResized.connect(self.table_column_resized) hh.setSectionsClickable(True) hh.sectionClicked.connect(self.do_sort) hh.setSortIndicatorShown(True) self.last_sorted_by = 'name' self.name_order = 0 self.count_order = 1 self.was_order = 1 self.edit_delegate = EditColumnDelegate(self.table) self.edit_delegate.editing_finished.connect(self.stop_editing) self.edit_delegate.editing_started.connect(self.start_editing) self.table.setItemDelegateForColumn(0, self.edit_delegate) if prefs['case_sensitive']: self.string_contains = contains else: self.string_contains = self.case_insensitive_compare self.delete_button.clicked.connect(self.delete_tags) self.table.delete_pressed.connect(self.delete_pressed) self.rename_button.clicked.connect(self.rename_tag) self.undo_button.clicked.connect(self.undo_edit) self.table.itemDoubleClicked.connect(self._rename_tag) self.table.itemChanged.connect(self.finish_editing) self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( _('&OK')) self.buttonBox.button(QDialogButtonBox.StandardButton.Cancel).setText( _('&Cancel')) self.buttonBox.accepted.connect(self.accepted) self.search_box.initialize('tag_list_search_box_' + cat_name) le = self.search_box.lineEdit() ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION) if ac is not None: ac.triggered.connect(self.clear_search) self.search_box.textChanged.connect(self.search_text_changed) self.search_button.clicked.connect(self.do_search) self.search_button.setDefault(True) l = QLabel(self.table) self.not_found_label = l l.setFrameStyle(QFrame.Shape.StyledPanel) l.setAutoFillBackground(True) l.setText(_('No matches found')) l.setAlignment(Qt.AlignmentFlag.AlignVCenter) l.resize(l.sizeHint()) l.move(10, 0) l.setVisible(False) self.not_found_label_timer = QTimer() self.not_found_label_timer.setSingleShot(True) self.not_found_label_timer.timeout.connect( self.not_found_label_timer_event, type=Qt.ConnectionType.QueuedConnection) self.filter_box.initialize('tag_list_filter_box_' + cat_name) le = self.filter_box.lineEdit() ac = le.findChild(QAction, QT_HIDDEN_CLEAR_ACTION) if ac is not None: ac.triggered.connect(self.clear_filter) le.returnPressed.connect(self.do_filter) self.filter_button.clicked.connect(self.do_filter) self.apply_vl_checkbox.clicked.connect(self.vl_box_changed) self.table.setEditTriggers( QAbstractItemView.EditTrigger.EditKeyPressed) try: geom = gprefs.get('tag_list_editor_dialog_geometry', None) if geom is not None: QApplication.instance().safe_restore_geometry( self, QByteArray(geom)) else: self.resize(self.sizeHint() + QSize(150, 100)) except: pass self.is_enumerated = False if fm: if fm['datatype'] == 'enumeration': self.is_enumerated = True self.enum_permitted_values = fm.get('display', {}).get( 'enum_values', None) # Add the data self.search_item_row = -1 self.fill_in_table(None, tag_to_match, ttm_is_first_letter) self.table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.table.customContextMenuRequested.connect(self.show_context_menu)
class XPathEdit(QWidget): def __init__(self, parent=None, object_name='', show_msg=True): QWidget.__init__(self, parent) self.h = h = QHBoxLayout(self) h.setContentsMargins(0, 0, 0, 0) self.l = l = QVBoxLayout() h.addLayout(l) self.button = b = QToolButton(self) b.setIcon(QIcon(I('wizard.png'))) b.setToolTip(_('Use a wizard to generate the XPath expression')) b.clicked.connect(self.wizard) h.addWidget(b) self.edit = e = HistoryLineEdit(self) e.setMinimumWidth(350) e.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToMinimumContentsLengthWithIcon) e.setMinimumContentsLength(30) self.msg = QLabel('') l.addWidget(self.msg) l.addWidget(self.edit) if object_name: self.setObjectName(object_name) if show_msg: b.setIconSize(QSize(40, 40)) self.msg.setBuddy(self.edit) else: self.msg.setVisible(False) l.setContentsMargins(0, 0, 0, 0) def setPlaceholderText(self, val): self.edit.setPlaceholderText(val) def wizard(self): wiz = Wizard(self) if wiz.exec() == QDialog.DialogCode.Accepted: self.edit.setText(wiz.xpath) def setObjectName(self, *args): QWidget.setObjectName(self, *args) if hasattr(self, 'edit'): self.edit.initialize('xpath_edit_'+str(self.objectName())) def set_msg(self, msg): self.msg.setText(msg) @property def text(self): return str(self.edit.text()) @text.setter def text(self, val): self.edit.setText(str(val)) value = text @property def xpath(self): return self.text def check(self): from calibre.ebooks.oeb.base import XPath try: if self.text.strip(): XPath(self.text) except: import traceback traceback.print_exc() return False return True
class MainTab(QWidget): # {{{ changed_signal = pyqtSignal() start_server = pyqtSignal() stop_server = pyqtSignal() test_server = pyqtSignal() show_logs = pyqtSignal() def __init__(self, parent=None): QWidget.__init__(self, parent) self.l = l = QVBoxLayout(self) self.la = la = QLabel( _( 'calibre contains an internet server that allows you to' ' access your book collection using a browser from anywhere' ' in the world. Any changes to the settings will only take' ' effect after a server restart.' ) ) la.setWordWrap(True) l.addWidget(la) l.addSpacing(10) self.fl = fl = QFormLayout() l.addLayout(fl) self.opt_port = sb = QSpinBox(self) if options['port'].longdoc: sb.setToolTip(options['port'].longdoc) sb.setRange(1, 65535) sb.valueChanged.connect(self.changed_signal.emit) fl.addRow(options['port'].shortdoc + ':', sb) l.addSpacing(25) self.opt_auth = cb = QCheckBox( _('Require &username and password to access the Content server') ) l.addWidget(cb) self.auth_desc = la = QLabel(self) la.setStyleSheet('QLabel { font-size: small; font-style: italic }') la.setWordWrap(True) l.addWidget(la) l.addSpacing(25) self.opt_autolaunch_server = al = QCheckBox( _('Run server &automatically when calibre starts') ) l.addWidget(al) l.addSpacing(25) self.h = h = QHBoxLayout() l.addLayout(h) for text, name in [(_('&Start server'), 'start_server'), (_('St&op server'), 'stop_server'), (_('&Test server'), 'test_server'), (_('Show server &logs'), 'show_logs')]: b = QPushButton(text) b.clicked.connect(getattr(self, name).emit) setattr(self, name + '_button', b) if name == 'show_logs': h.addStretch(10) h.addWidget(b) self.ip_info = QLabel(self) self.update_ip_info() from calibre.gui2.ui import get_gui gui = get_gui() if gui is not None: gui.iactions['Connect Share'].share_conn_menu.server_state_changed_signal.connect(self.update_ip_info) l.addSpacing(10) l.addWidget(self.ip_info) if set_run_at_startup is not None: self.run_at_start_button = b = QPushButton('', self) self.set_run_at_start_text() b.clicked.connect(self.toggle_run_at_startup) l.addSpacing(10) l.addWidget(b) l.addSpacing(10) l.addStretch(10) def set_run_at_start_text(self): is_autostarted = is_set_to_run_at_startup() self.run_at_start_button.setText( _('Do not start calibre automatically when computer is started') if is_autostarted else _('Start calibre when the computer is started') ) self.run_at_start_button.setToolTip('<p>' + ( _('''Currently calibre is set to run automatically when the computer starts. Use this button to disable that.''') if is_autostarted else _('''Start calibre in the system tray automatically when the computer starts'''))) def toggle_run_at_startup(self): set_run_at_startup(not is_set_to_run_at_startup()) self.set_run_at_start_text() def update_ip_info(self): from calibre.gui2.ui import get_gui gui = get_gui() if gui is not None: t = get_gui().iactions['Connect Share'].share_conn_menu.ip_text t = t.strip().strip('[]') self.ip_info.setText(_('Content server listening at: %s') % t) def genesis(self): opts = server_config() self.opt_auth.setChecked(opts.auth) self.opt_auth.stateChanged.connect(self.auth_changed) self.opt_port.setValue(opts.port) self.change_auth_desc() self.update_button_state() def change_auth_desc(self): self.auth_desc.setText( _('Remember to create at least one user account in the "User accounts" tab') if self.opt_auth.isChecked() else _( 'Requiring a username/password prevents unauthorized people from' ' accessing your calibre library. It is also needed for some features' ' such as making any changes to the library as well as' ' last read position/annotation syncing.' ) ) def auth_changed(self): self.changed_signal.emit() self.change_auth_desc() def restore_defaults(self): self.opt_auth.setChecked(options['auth'].default) self.opt_port.setValue(options['port'].default) def update_button_state(self): from calibre.gui2.ui import get_gui gui = get_gui() if gui is not None: is_running = gui.content_server is not None and gui.content_server.is_running self.ip_info.setVisible(is_running) self.update_ip_info() self.start_server_button.setEnabled(not is_running) self.stop_server_button.setEnabled(is_running) self.test_server_button.setEnabled(is_running) @property def settings(self): return {'auth': self.opt_auth.isChecked(), 'port': self.opt_port.value()}