def __init__(self, parent=None): QTableView.__init__(self, parent) self.rt_delegate = RichTextDelegate(self) self.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) self.setAlternatingRowColors(True) self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) self.setIconSize(QSize(24, 24)) self.clicked.connect(self.show_details) self.doubleClicked.connect(self.select_index) self.setSortingEnabled(True)
def keyPressEvent(self, ev): if ev.key() in (Qt.Key.Key_Left, Qt.Key.Key_Right): ac = QAbstractItemView.CursorAction.MoveDown if ev.key() == Qt.Key.Key_Right else QAbstractItemView.CursorAction.MoveUp index = self.moveCursor(ac, ev.modifiers()) if index.isValid() and index != self.currentIndex(): m = self.selectionModel() m.select(index, QItemSelectionModel.SelectionFlag.Select|QItemSelectionModel.SelectionFlag.Current|QItemSelectionModel.SelectionFlag.Rows) self.setCurrentIndex(index) ev.accept() return return QTableView.keyPressEvent(self, ev)
def __init__(self, tts_client, initial_backend_settings=None, parent=None): QWidget.__init__(self, parent) self.l = l = QFormLayout(self) self.tts_client = tts_client with BusyCursor(): self.voice_data = self.tts_client.get_voice_data() self.default_system_rate = self.tts_client.default_system_rate self.all_sound_outputs = self.tts_client.get_sound_outputs() self.speed = s = QSlider(Qt.Orientation.Horizontal, self) s.setMinimumWidth(200) l.addRow(_('&Speed of speech (words per minute):'), s) s.setRange(self.tts_client.min_rate, self.tts_client.max_rate) s.setSingleStep(1) s.setPageStep(2) self.voices = v = QTableView(self) self.voices_model = VoicesModel(self.voice_data, parent=v) self.proxy_model = p = QSortFilterProxyModel(self) p.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) p.setSourceModel(self.voices_model) v.setModel(p) v.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) v.setSortingEnabled(True) v.horizontalHeader().resizeSection( 0, QFontMetrics(self.font()).averageCharWidth() * 25) v.horizontalHeader().resizeSection( 1, QFontMetrics(self.font()).averageCharWidth() * 30) v.verticalHeader().close() v.verticalHeader().close() v.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) v.sortByColumn(0, Qt.SortOrder.AscendingOrder) l.addRow(v) self.sound_outputs = so = QComboBox(self) so.addItem(_('System default'), '') for x in self.all_sound_outputs: so.addItem(x.get('description') or x['id'], x['id']) l.addRow(_('Sound output:'), so) self.backend_settings = initial_backend_settings or {}
def __init__(self, tts_client, initial_backend_settings=None, parent=None): QWidget.__init__(self, parent) self.l = l = QFormLayout(self) self.tts_client = tts_client self.speed = s = QSlider(Qt.Orientation.Horizontal, self) s.setTickPosition(QSlider.TickPosition.TicksAbove) s.setMinimumWidth(200) l.addRow(_('&Speed of speech:'), s) s.setRange(self.tts_client.min_rate, self.tts_client.max_rate) s.setSingleStep(10) s.setTickInterval((s.maximum() - s.minimum()) // 2) self.output_modules = om = QComboBox(self) with BusyCursor(): self.voice_data = self.tts_client.get_voice_data() self.system_default_output_module = self.tts_client.system_default_output_module om.addItem(_('System default'), self.system_default_output_module) for x in self.voice_data: om.addItem(x, x) l.addRow(_('Speech s&ynthesizer:'), om) self.voices = v = QTableView(self) self.voices_model = VoicesModel(self.voice_data, self.system_default_output_module, parent=v) self.proxy_model = p = QSortFilterProxyModel(self) p.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) p.setSourceModel(self.voices_model) v.setModel(p) v.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) v.setSortingEnabled(True) h = v.horizontalHeader() h.resizeSection(0, QFontMetrics(self.font()).averageCharWidth() * 30) v.verticalHeader().close() v.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) v.sortByColumn(0, Qt.SortOrder.AscendingOrder) om.currentIndexChanged.connect(self.output_module_changed) l.addRow(v) self.backend_settings = initial_backend_settings or {}
def __init__(self, tts_client, initial_backend_settings=None, parent=None): QWidget.__init__(self, parent) self.l = l = QFormLayout(self) self.tts_client = tts_client with BusyCursor(): self.voice_data = self.tts_client.get_voice_data() self.default_system_rate = self.tts_client.default_system_rate self.speed = s = QSlider(Qt.Orientation.Horizontal, self) s.setMinimumWidth(200) l.addRow(_('&Speed of speech (words per minute):'), s) s.setRange(self.tts_client.min_rate, self.tts_client.max_rate) s.setTickPosition(QSlider.TickPosition.TicksAbove) s.setTickInterval((s.maximum() - s.minimum()) // 2) s.setSingleStep(10) self.voices = v = QTableView(self) self.voices_model = VoicesModel(self.voice_data, parent=v) self.proxy_model = p = QSortFilterProxyModel(self) p.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) p.setSourceModel(self.voices_model) v.setModel(p) v.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) v.setSortingEnabled(True) v.horizontalHeader().resizeSection( 0, QFontMetrics(self.font()).averageCharWidth() * 20) v.horizontalHeader().resizeSection( 1, QFontMetrics(self.font()).averageCharWidth() * 30) v.verticalHeader().close() v.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) v.sortByColumn(0, Qt.SortOrder.AscendingOrder) l.addRow(v) self.backend_settings = initial_backend_settings or {}
def setup_ui(self): self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, False) self.l = l = QVBoxLayout(self) self.setLayout(l) self.bb.clear() self.bb.addButton(QDialogButtonBox.StandardButton.Close) self.splitter = s = QSplitter(self) self.h = h = QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) self.install_fonts_button = b = QPushButton(_('&Install fonts'), self) h.addWidget(b), b.setIcon(QIcon(I('plus.png'))) b.setToolTip(textwrap.fill(_('Install fonts from .ttf/.otf files to make them available for embedding'))) b.clicked.connect(self.install_fonts) l.addWidget(s), l.addLayout(h), h.addStretch(10), h.addWidget(self.bb) self.fonts_view = fv = QTableView(self) fv.doubleClicked.connect(self.show_embedding_data) self.model = m = AllFonts(fv) fv.horizontalHeader().setStretchLastSection(True) fv.setModel(m) fv.setSortingEnabled(True) fv.setShowGrid(False) fv.setAlternatingRowColors(True) fv.setSelectionMode(QAbstractItemView.SelectionMode.ExtendedSelection) fv.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows) fv.horizontalHeader().setSortIndicator(1, Qt.SortOrder.AscendingOrder) self.container = c = QWidget() l = c.l = QVBoxLayout(c) c.setLayout(l) s.addWidget(fv), s.addWidget(c) self.cb = b = QPushButton(_('&Change selected fonts')) b.setIcon(QIcon(I('wizard.png'))) b.clicked.connect(self.change_fonts) l.addWidget(b) self.rb = b = QPushButton(_('&Remove selected fonts')) b.clicked.connect(self.remove_fonts) b.setIcon(QIcon(I('trash.png'))) l.addWidget(b) self.eb = b = QPushButton(_('&Embed all fonts')) b.setIcon(QIcon(I('embed-fonts.png'))) b.clicked.connect(self.embed_fonts) l.addWidget(b) self.sb = b = QPushButton(_('&Subset all fonts')) b.setIcon(QIcon(I('subset-fonts.png'))) b.clicked.connect(self.subset_fonts) l.addWidget(b) self.refresh_button = b = self.bb.addButton(_('&Refresh'), QDialogButtonBox.ButtonRole.ActionRole) b.setToolTip(_('Rescan the book for fonts in case you have made changes')) b.setIcon(QIcon(I('view-refresh.png'))) b.clicked.connect(self.refresh) self.la = la = QLabel( '<p>' + _( ''' All the fonts declared in this book are shown to the left, along with whether they are embedded or not. You can remove or replace any selected font and also embed any declared fonts that are not already embedded.''') + '<p>' + _( ''' Double click any font family to see if the font is available for embedding on your computer. ''') ) la.setWordWrap(True) l.addWidget(la) l.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignHCenter)
def currentChanged(self, current, previous): ret = QTableView.currentChanged(self, current, previous) self.show_details(current) return ret
def _initialize_controls(self): self.setWindowTitle(_('User plugins')) self.setWindowIcon(QIcon(I('plugins/plugin_updater.png'))) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'plugins/plugin_updater.png', _('User plugins')) layout.addLayout(title_layout) header_layout = QHBoxLayout() layout.addLayout(header_layout) self.filter_combo = PluginFilterComboBox(self) self.filter_combo.setMinimumContentsLength(20) self.filter_combo.currentIndexChanged[int].connect( self._filter_combo_changed) la = QLabel(_('Filter list of &plugins') + ':', self) la.setBuddy(self.filter_combo) header_layout.addWidget(la) header_layout.addWidget(self.filter_combo) header_layout.addStretch(10) # filter plugins by name la = QLabel(_('Filter by &name') + ':', self) header_layout.addWidget(la) self.filter_by_name_lineedit = QLineEdit(self) la.setBuddy(self.filter_by_name_lineedit) self.filter_by_name_lineedit.setText("") self.filter_by_name_lineedit.textChanged.connect( self._filter_name_lineedit_changed) header_layout.addWidget(self.filter_by_name_lineedit) self.plugin_view = QTableView(self) self.plugin_view.horizontalHeader().setStretchLastSection(True) self.plugin_view.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.plugin_view.setSelectionMode( QAbstractItemView.SelectionMode.SingleSelection) self.plugin_view.setAlternatingRowColors(True) self.plugin_view.setSortingEnabled(True) self.plugin_view.setIconSize(QSize(28, 28)) layout.addWidget(self.plugin_view) details_layout = QHBoxLayout() layout.addLayout(details_layout) forum_label = self.forum_label = QLabel('') forum_label.setTextInteractionFlags( Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.LinksAccessibleByKeyboard) forum_label.linkActivated.connect(self._forum_label_activated) details_layout.addWidget(QLabel(_('Description') + ':', self), 0, Qt.AlignmentFlag.AlignLeft) details_layout.addWidget(forum_label, 1, Qt.AlignmentFlag.AlignRight) self.description = QLabel(self) self.description.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken) self.description.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft) self.description.setMinimumHeight(40) self.description.setWordWrap(True) layout.addWidget(self.description) self.button_box = QDialogButtonBox( QDialogButtonBox.StandardButton.Close) self.button_box.rejected.connect(self.reject) self.finished.connect(self._finished) self.install_button = self.button_box.addButton( _('&Install'), QDialogButtonBox.ButtonRole.AcceptRole) self.install_button.setToolTip(_('Install the selected plugin')) self.install_button.clicked.connect(self._install_clicked) self.install_button.setEnabled(False) self.configure_button = self.button_box.addButton( ' ' + _('&Customize plugin ') + ' ', QDialogButtonBox.ButtonRole.ResetRole) self.configure_button.setToolTip( _('Customize the options for this plugin')) self.configure_button.clicked.connect(self._configure_clicked) self.configure_button.setEnabled(False) layout.addWidget(self.button_box)
class PluginUpdaterDialog(SizePersistedDialog): initial_extra_size = QSize(350, 100) forum_label_text = _('Plugin homepage') def __init__(self, gui, initial_filter=FILTER_UPDATE_AVAILABLE): SizePersistedDialog.__init__( self, gui, 'Plugin Updater plugin:plugin updater dialog') self.gui = gui self.forum_link = None self.zip_url = None self.model = None self.do_restart = False self._initialize_controls() self._create_context_menu() try: display_plugins = read_available_plugins(raise_error=True) except Exception: display_plugins = [] import traceback error_dialog(self.gui, _('Update Check Failed'), _('Unable to reach the plugin index page.'), det_msg=traceback.format_exc(), show=True) if display_plugins: self.model = DisplayPluginModel(display_plugins) self.proxy_model = DisplayPluginSortFilterModel(self) self.proxy_model.setSourceModel(self.model) self.plugin_view.setModel(self.proxy_model) self.plugin_view.resizeColumnsToContents() self.plugin_view.selectionModel().currentRowChanged.connect( self._plugin_current_changed) self.plugin_view.doubleClicked.connect(self.install_button.click) self.filter_combo.setCurrentIndex(initial_filter) self._select_and_focus_view() else: self.filter_combo.setEnabled(False) # Cause our dialog size to be restored from prefs or created on first usage self.resize_dialog() def _initialize_controls(self): self.setWindowTitle(_('User plugins')) self.setWindowIcon(QIcon(I('plugins/plugin_updater.png'))) layout = QVBoxLayout(self) self.setLayout(layout) title_layout = ImageTitleLayout(self, 'plugins/plugin_updater.png', _('User plugins')) layout.addLayout(title_layout) header_layout = QHBoxLayout() layout.addLayout(header_layout) self.filter_combo = PluginFilterComboBox(self) self.filter_combo.setMinimumContentsLength(20) self.filter_combo.currentIndexChanged[int].connect( self._filter_combo_changed) la = QLabel(_('Filter list of &plugins') + ':', self) la.setBuddy(self.filter_combo) header_layout.addWidget(la) header_layout.addWidget(self.filter_combo) header_layout.addStretch(10) # filter plugins by name la = QLabel(_('Filter by &name') + ':', self) header_layout.addWidget(la) self.filter_by_name_lineedit = QLineEdit(self) la.setBuddy(self.filter_by_name_lineedit) self.filter_by_name_lineedit.setText("") self.filter_by_name_lineedit.textChanged.connect( self._filter_name_lineedit_changed) header_layout.addWidget(self.filter_by_name_lineedit) self.plugin_view = QTableView(self) self.plugin_view.horizontalHeader().setStretchLastSection(True) self.plugin_view.setSelectionBehavior( QAbstractItemView.SelectionBehavior.SelectRows) self.plugin_view.setSelectionMode( QAbstractItemView.SelectionMode.SingleSelection) self.plugin_view.setAlternatingRowColors(True) self.plugin_view.setSortingEnabled(True) self.plugin_view.setIconSize(QSize(28, 28)) layout.addWidget(self.plugin_view) details_layout = QHBoxLayout() layout.addLayout(details_layout) forum_label = self.forum_label = QLabel('') forum_label.setTextInteractionFlags( Qt.TextInteractionFlag.LinksAccessibleByMouse | Qt.TextInteractionFlag.LinksAccessibleByKeyboard) forum_label.linkActivated.connect(self._forum_label_activated) details_layout.addWidget(QLabel(_('Description') + ':', self), 0, Qt.AlignmentFlag.AlignLeft) details_layout.addWidget(forum_label, 1, Qt.AlignmentFlag.AlignRight) self.description = QLabel(self) self.description.setFrameStyle(QFrame.Shape.Panel | QFrame.Shadow.Sunken) self.description.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft) self.description.setMinimumHeight(40) self.description.setWordWrap(True) layout.addWidget(self.description) self.button_box = QDialogButtonBox( QDialogButtonBox.StandardButton.Close) self.button_box.rejected.connect(self.reject) self.finished.connect(self._finished) self.install_button = self.button_box.addButton( _('&Install'), QDialogButtonBox.ButtonRole.AcceptRole) self.install_button.setToolTip(_('Install the selected plugin')) self.install_button.clicked.connect(self._install_clicked) self.install_button.setEnabled(False) self.configure_button = self.button_box.addButton( ' ' + _('&Customize plugin ') + ' ', QDialogButtonBox.ButtonRole.ResetRole) self.configure_button.setToolTip( _('Customize the options for this plugin')) self.configure_button.clicked.connect(self._configure_clicked) self.configure_button.setEnabled(False) layout.addWidget(self.button_box) def update_forum_label(self): txt = '' if self.forum_link: txt = '<a href="%s">%s</a>' % (self.forum_link, self.forum_label_text) self.forum_label.setText(txt) def _create_context_menu(self): self.plugin_view.setContextMenuPolicy( Qt.ContextMenuPolicy.ActionsContextMenu) self.install_action = QAction( QIcon(I('plugins/plugin_upgrade_ok.png')), _('&Install'), self) self.install_action.setToolTip(_('Install the selected plugin')) self.install_action.triggered.connect(self._install_clicked) self.install_action.setEnabled(False) self.plugin_view.addAction(self.install_action) self.forum_action = QAction(QIcon(I('plugins/mobileread.png')), _('Plugin &forum thread'), self) self.forum_action.triggered.connect(self._forum_label_activated) self.forum_action.setEnabled(False) self.plugin_view.addAction(self.forum_action) sep1 = QAction(self) sep1.setSeparator(True) self.plugin_view.addAction(sep1) self.toggle_enabled_action = QAction(_('Enable/&disable plugin'), self) self.toggle_enabled_action.setToolTip( _('Enable or disable this plugin')) self.toggle_enabled_action.triggered.connect( self._toggle_enabled_clicked) self.toggle_enabled_action.setEnabled(False) self.plugin_view.addAction(self.toggle_enabled_action) self.uninstall_action = QAction(_('&Remove plugin'), self) self.uninstall_action.setToolTip(_('Uninstall the selected plugin')) self.uninstall_action.triggered.connect(self._uninstall_clicked) self.uninstall_action.setEnabled(False) self.plugin_view.addAction(self.uninstall_action) sep2 = QAction(self) sep2.setSeparator(True) self.plugin_view.addAction(sep2) self.donate_enabled_action = QAction(QIcon(I('donate.png')), _('Donate to developer'), self) self.donate_enabled_action.setToolTip( _('Donate to the developer of this plugin')) self.donate_enabled_action.triggered.connect(self._donate_clicked) self.donate_enabled_action.setEnabled(False) self.plugin_view.addAction(self.donate_enabled_action) sep3 = QAction(self) sep3.setSeparator(True) self.plugin_view.addAction(sep3) self.configure_action = QAction(QIcon(I('config.png')), _('&Customize plugin'), self) self.configure_action.setToolTip( _('Customize the options for this plugin')) self.configure_action.triggered.connect(self._configure_clicked) self.configure_action.setEnabled(False) self.plugin_view.addAction(self.configure_action) def _finished(self, *args): if self.model: update_plugins = list( filter(filter_upgradeable_plugins, self.model.display_plugins)) self.gui.recalc_update_label(len(update_plugins)) def _plugin_current_changed(self, current, previous): if current.isValid(): actual_idx = self.proxy_model.mapToSource(current) display_plugin = self.model.display_plugins[actual_idx.row()] self.description.setText(display_plugin.description) self.forum_link = display_plugin.forum_link self.zip_url = display_plugin.zip_url self.forum_action.setEnabled(bool(self.forum_link)) self.install_button.setEnabled( display_plugin.is_valid_to_install()) self.install_action.setEnabled(self.install_button.isEnabled()) self.uninstall_action.setEnabled(display_plugin.is_installed()) self.configure_button.setEnabled(display_plugin.is_installed()) self.configure_action.setEnabled(self.configure_button.isEnabled()) self.toggle_enabled_action.setEnabled( display_plugin.is_installed()) self.donate_enabled_action.setEnabled( bool(display_plugin.donation_link)) else: self.description.setText('') self.forum_link = None self.zip_url = None self.forum_action.setEnabled(False) self.install_button.setEnabled(False) self.install_action.setEnabled(False) self.uninstall_action.setEnabled(False) self.configure_button.setEnabled(False) self.configure_action.setEnabled(False) self.toggle_enabled_action.setEnabled(False) self.donate_enabled_action.setEnabled(False) self.update_forum_label() def _donate_clicked(self): plugin = self._selected_display_plugin() if plugin and plugin.donation_link: open_url(QUrl(plugin.donation_link)) def _select_and_focus_view(self, change_selection=True): if change_selection and self.plugin_view.model().rowCount() > 0: self.plugin_view.selectRow(0) else: idx = self.plugin_view.selectionModel().currentIndex() self._plugin_current_changed(idx, 0) self.plugin_view.setFocus() def _filter_combo_changed(self, idx): self.filter_by_name_lineedit.setText( "" ) # clear the name filter text when a different group was selected self.proxy_model.set_filter_criteria(idx) if idx == FILTER_NOT_INSTALLED: self.plugin_view.sortByColumn(5, Qt.SortOrder.DescendingOrder) else: self.plugin_view.sortByColumn(0, Qt.SortOrder.AscendingOrder) self._select_and_focus_view() def _filter_name_lineedit_changed(self, text): self.proxy_model.set_filter_text( text) # set the filter text for filterAcceptsRow def _forum_label_activated(self): if self.forum_link: open_url(QUrl(self.forum_link)) def _selected_display_plugin(self): idx = self.plugin_view.selectionModel().currentIndex() actual_idx = self.proxy_model.mapToSource(idx) return self.model.display_plugins[actual_idx.row()] def _uninstall_plugin(self, name_to_remove): if DEBUG: prints('Removing plugin: ', name_to_remove) remove_plugin(name_to_remove) # Make sure that any other plugins that required this plugin # to be uninstalled first have the requirement removed for display_plugin in self.model.display_plugins: # Make sure we update the status and display of the # plugin we just uninstalled if name_to_remove in display_plugin.uninstall_plugins: if DEBUG: prints('Removing uninstall dependency for: ', display_plugin.name) display_plugin.uninstall_plugins.remove(name_to_remove) if display_plugin.qname == name_to_remove: if DEBUG: prints('Resetting plugin to uninstalled status: ', display_plugin.name) display_plugin.installed_version = None display_plugin.plugin = None display_plugin.uninstall_plugins = [] if self.proxy_model.filter_criteria not in [ FILTER_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.refresh_plugin(display_plugin) def _uninstall_clicked(self): display_plugin = self._selected_display_plugin() if not question_dialog( self, _('Are you sure?'), '<p>' + _('Are you sure you want to uninstall the <b>%s</b> plugin?') % display_plugin.name, show_copy_button=False): return self._uninstall_plugin(display_plugin.qname) if self.proxy_model.filter_criteria in [ FILTER_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.beginResetModel(), self.model.endResetModel() self._select_and_focus_view() else: self._select_and_focus_view(change_selection=False) def _install_clicked(self): display_plugin = self._selected_display_plugin() if not question_dialog( self, _('Install %s') % display_plugin.name, '<p>' + _('Installing plugins is a <b>security risk</b>. ' 'Plugins can contain a virus/malware. ' 'Only install it if you got it from a trusted source.' ' Are you sure you want to proceed?'), show_copy_button=False): return if display_plugin.uninstall_plugins: uninstall_names = list(display_plugin.uninstall_plugins) if DEBUG: prints('Uninstalling plugin: ', ', '.join(uninstall_names)) for name_to_remove in uninstall_names: self._uninstall_plugin(name_to_remove) plugin_zip_url = display_plugin.zip_url if DEBUG: prints('Downloading plugin ZIP attachment: ', plugin_zip_url) self.gui.status_bar.showMessage( _('Downloading plugin ZIP attachment: %s') % plugin_zip_url) zip_path = self._download_zip(plugin_zip_url) if DEBUG: prints('Installing plugin: ', zip_path) self.gui.status_bar.showMessage(_('Installing plugin: %s') % zip_path) do_restart = False try: from calibre.customize.ui import config installed_plugins = frozenset(config['plugins']) try: plugin = add_plugin(zip_path) except NameConflict as e: return error_dialog(self.gui, _('Already exists'), unicode_type(e), show=True) # Check for any toolbars to add to. widget = ConfigWidget(self.gui) widget.gui = self.gui widget.check_for_add_to_toolbars(plugin, previously_installed=plugin.name in installed_plugins) self.gui.status_bar.showMessage( _('Plugin installed: %s') % display_plugin.name) d = info_dialog( self.gui, _('Success'), _('Plugin <b>{0}</b> successfully installed under <b>' '{1}</b>. You may have to restart calibre ' 'for the plugin to take effect.').format( plugin.name, plugin.type), show_copy_button=False) b = d.bb.addButton(_('&Restart calibre now'), QDialogButtonBox.ButtonRole.AcceptRole) b.setIcon(QIcon(I('lt.png'))) d.do_restart = False def rf(): d.do_restart = True b.clicked.connect(rf) d.set_details('') d.exec_() b.clicked.disconnect() do_restart = d.do_restart display_plugin.plugin = plugin # We cannot read the 'actual' version information as the plugin will not be loaded yet display_plugin.installed_version = display_plugin.available_version except: if DEBUG: prints('ERROR occurred while installing plugin: %s' % display_plugin.name) traceback.print_exc() error_dialog( self.gui, _('Install plugin failed'), _('A problem occurred while installing this plugin.' ' This plugin will now be uninstalled.' ' Please post the error message in details below into' ' the forum thread for this plugin and restart calibre.'), det_msg=traceback.format_exc(), show=True) if DEBUG: prints('Due to error now uninstalling plugin: %s' % display_plugin.name) remove_plugin(display_plugin.name) display_plugin.plugin = None display_plugin.uninstall_plugins = [] if self.proxy_model.filter_criteria in [ FILTER_NOT_INSTALLED, FILTER_UPDATE_AVAILABLE ]: self.model.beginResetModel(), self.model.endResetModel() self._select_and_focus_view() else: self.model.refresh_plugin(display_plugin) self._select_and_focus_view(change_selection=False) if do_restart: self.do_restart = True self.accept() def _configure_clicked(self): display_plugin = self._selected_display_plugin() plugin = display_plugin.plugin if not plugin.is_customizable(): return info_dialog(self, _('Plugin not customizable'), _('Plugin: %s does not need customization') % plugin.name, show=True) from calibre.customize import InterfaceActionBase if isinstance(plugin, InterfaceActionBase) and not getattr( plugin, 'actual_iaction_plugin_loaded', False): return error_dialog(self, _('Must restart'), _('You must restart calibre before you can' ' configure the <b>%s</b> plugin') % plugin.name, show=True) plugin.do_user_config(self.parent()) def _toggle_enabled_clicked(self): display_plugin = self._selected_display_plugin() plugin = display_plugin.plugin if not plugin.can_be_disabled: return error_dialog(self, _('Plugin cannot be disabled'), _('The plugin: %s cannot be disabled') % plugin.name, show=True) if is_disabled(plugin): enable_plugin(plugin) else: disable_plugin(plugin) self.model.refresh_plugin(display_plugin) def _download_zip(self, plugin_zip_url): from calibre.ptempfile import PersistentTemporaryFile raw = get_https_resource_securely( plugin_zip_url, headers={'User-Agent': '%s %s' % (__appname__, __version__)}) with PersistentTemporaryFile('.zip') as pt: pt.write(raw) return pt.name
def __init__(self, books_view, parent=None): QTableView.__init__(self, parent) self.books_view = books_view self.verticalHeader().close() self.splitter = None self.disable_save_state = False