class QtAbout(QDialog): def __init__(self): super().__init__() self.layout = QVBoxLayout() # Description title_label = QLabel( "<b>napari: a multi-dimensional image viewer for python</b>") title_label.setTextInteractionFlags(Qt.TextSelectableByMouse) self.layout.addWidget(title_label) # Add information self.infoTextBox = QTextEdit() self.infoTextBox.setTextInteractionFlags(Qt.TextSelectableByMouse) self.infoTextBox.setLineWrapMode(QTextEdit.NoWrap) # Add text copy button self.infoCopyButton = QtCopyToClipboardButton(self.infoTextBox) self.info_layout = QHBoxLayout() self.info_layout.addWidget(self.infoTextBox, 1) self.info_layout.addWidget(self.infoCopyButton, 0, Qt.AlignTop) self.info_layout.setAlignment(Qt.AlignTop) self.layout.addLayout(self.info_layout) self.infoTextBox.setText(sys_info(as_html=True)) self.infoTextBox.setMinimumSize( self.infoTextBox.document().size().width() + 19, self.infoTextBox.document().size().height() + 10, ) self.layout.addWidget(QLabel('<b>citation information:</b>')) self.citationTextBox = QTextEdit(citation_text) self.citationTextBox.setFixedHeight(64) self.citationCopyButton = QtCopyToClipboardButton(self.citationTextBox) self.citation_layout = QHBoxLayout() self.citation_layout.addWidget(self.citationTextBox, 1) self.citation_layout.addWidget(self.citationCopyButton, 0, Qt.AlignTop) self.layout.addLayout(self.citation_layout) self.setLayout(self.layout) @staticmethod def showAbout(qt_viewer): d = QtAbout() d.setObjectName('QtAbout') d.setStyleSheet(qt_viewer.styleSheet()) d.setWindowTitle('About') d.setWindowModality(Qt.ApplicationModal) d.exec_()
class Console(FramelessWindow): message = Signal(dict) def __init__(self, parent=None): super(Console, self).__init__(parent) self.json_decode_warning = None self.widget = QWidget(self) self.console_layout = QVBoxLayout(self.widget) self.widget.setLayout(self.console_layout) self.output_label = QLabel(self.widget) self.output_label.setText("Output") self.output_edit = QTextEdit(self.widget) self.output_edit.setReadOnly(True) self.highlighter = Highlighter(self.output_edit.document()) self.output_edit.setStyleSheet("background-color: rgb(0, 0, 0);") self.output_edit.setTextColor(QColor(0, 255, 0)) self.output_edit.setFont(QFont(self.output_edit.currentFont().family(), 10)) self.input_label = QLabel(self.widget) self.input_label.setText("Command") self.input_edit = QLineEdit(self.widget) self.input_edit.setStyleSheet("background-color: rgb(0, 0, 0); color: rgb(0, 255, 0)") self.input_edit.setFont(QFont(self.output_edit.currentFont().family(), 10)) self.send_button = QPushButton(self.widget) self.send_button.setObjectName("send_button") self.send_button.setText("Send command") self.console_layout.addWidget(self.output_label) self.console_layout.addWidget(self.output_edit) self.console_layout.addWidget(self.input_label) self.console_layout.addWidget(self.input_edit) self.console_layout.addWidget(self.send_button) self.addContentWidget(self.widget) QMetaObject.connectSlotsByName(self) def on_send_button_clicked(self): mess = self.input_edit.text() try: mess = json.loads(mess) self.message.emit(mess) self.input_edit.clear() self.output_edit.append("$: {}".format(mess)) except json.JSONDecodeError as e: self.json_decode_warning = FramelessCriticalMessageBox(self) self.json_decode_warning.setText("Failed to convert string to JSON: {}".format(e)) self.json_decode_warning.setStandardButtons(QDialogButtonBox.Ok) self.json_decode_warning.button(QDialogButtonBox.Ok).clicked.connect(self.json_decode_warning.close) self.json_decode_warning.show() def write(self, resp: dict): if resp.get("event_type"): resp = "[{}]: {}".format(str(resp.get("event_type")).upper(), resp) else: resp = str(resp) self.output_edit.append(resp)
def show_tb(parent): tbdialog = QDialog(parent=parent.parent()) tbdialog.setModal(True) # this is about the minimum width to not get rewrap # and the minimum height to not have scrollbar tbdialog.resize(650, 270) tbdialog.setLayout(QVBoxLayout()) text = QTextEdit() theme = get_theme( get_settings().appearance.theme, as_dict=False ) _highlight = Pylighter( # noqa: F841 text.document(), "python", theme.syntax_style ) text.setText(notification.as_text()) text.setReadOnly(True) btn = QPushButton(trans._('Enter Debugger')) def _enter_debug_mode(): btn.setText( trans._( 'Now Debugging. Please quit debugger in console to continue' ) ) _debug_tb(notification.exception.__traceback__) btn.setText(trans._('Enter Debugger')) btn.clicked.connect(_enter_debug_mode) tbdialog.layout().addWidget(text) tbdialog.layout().addWidget(btn, 0, Qt.AlignRight) tbdialog.show()
class MainWindow(QMainWindow): def __init__(self): self.logger = logging.getLogger(APPLICATION_NAME + '.MainWindow') self.logger.info("MainWindow.__init__") super(MainWindow, self).__init__() self.init_ui() self.read_settings() def init_ui(self): # Define standard icon. standard_icon = self.style().standardIcon # Central widget. self.main_widget = SpectrumWidget() self.main_widget.setFocus() self.setCentralWidget(self.main_widget) # Project action new_project_action = QAction(QIcon(':/oi/svg/document.svg'), 'New project', self) new_project_action.setShortcut('Ctrl+N') new_project_action.setStatusTip('New project') new_project_action.triggered.connect(self.new_project) open_project_action = QAction(QIcon(':/oi/svg/envelope-open.svg'), 'Open project', self) open_project_action.setShortcut('Ctrl+O') open_project_action.setStatusTip('Open project') open_project_action.triggered.connect(self.open_project) close_project_action = QAction(QIcon(':/oi/svg/envelope-closed.svg'), 'Close project', self) close_project_action.setShortcut('Ctrl+C') close_project_action.setStatusTip('Close project') close_project_action.triggered.connect(self.close_project) save_project_action = QAction(QIcon(':/oi/svg/hard-drive.svg'), 'Save project', self) save_project_action.setShortcut('Ctrl+S') save_project_action.setStatusTip('Save project') save_project_action.triggered.connect(self.save_project) saveas_project_action = QAction(QIcon(':/oi/svg/hard-drive.svg'), 'Save project as ...', self) # saveas_project_action.setShortcut('Ctrl+S') saveas_project_action.setStatusTip('Save project as ...') saveas_project_action.triggered.connect(self.saveas_project) # Spectrum action import_spectrum_action = QAction(QIcon(':/oi/svg/account-login.svg'), 'Import spectrum', self) import_spectrum_action.setShortcut('Ctrl+I') import_spectrum_action.setStatusTip('Import spectrum') import_spectrum_action.triggered.connect(self.import_spectrum) export_spectrum_action = QAction(QIcon(':/oi/svg/account-logout.svg'), 'Export spectrum', self) # export_spectrum_action.setShortcut('Ctrl+I') export_spectrum_action.setStatusTip('Export spectrum') export_spectrum_action.triggered.connect(self.export_spectrum) # Exit action exit_action = QAction(QIcon(':/oi/svg/x.svg'), 'Exit', self) exit_action.setShortcut('Ctrl+Q') exit_action.setStatusTip('Exit application') exit_action.triggered.connect(self.close) # Status bar. self.statusBar() # Menu bar. menubar = self.menuBar() file_menu = menubar.addMenu('&File') file_menu.addAction(new_project_action) file_menu.addAction(open_project_action) file_menu.addAction(save_project_action) file_menu.addAction(saveas_project_action) file_menu.addAction(close_project_action) file_menu.addSeparator() file_menu.addAction(exit_action) view_menu = menubar.addMenu('&View') spectrum_menu = menubar.addMenu('&Spectrum') spectrum_menu.addAction(import_spectrum_action) analysis_menu = menubar.addMenu('&Analysis') # Toolbar file_toolbar = self.addToolBar('File') file_toolbar.addAction(new_project_action) file_toolbar.addAction(open_project_action) file_toolbar.addAction(save_project_action) file_toolbar.addAction(saveas_project_action) file_toolbar.addAction(close_project_action) file_toolbar.addAction(exit_action) view_menu.addAction(file_toolbar.toggleViewAction()) spectrum_toolbar = self.addToolBar('Spectrum') spectrum_toolbar.addAction(import_spectrum_action) view_menu.addAction(spectrum_toolbar.toggleViewAction()) analysis_toolbar = self.addToolBar('Analysis') view_menu.addAction(analysis_toolbar.toggleViewAction()) view_menu.addSeparator() # Dock widget. self.graphic_settings_dock = QDockWidget("Graphic settings", self) self.graphic_settings_dock.setObjectName("graphic_settings_dock") self.graphic_settings_dock.setAllowedAreas(Qt.AllDockWidgetAreas) label_test = QLabel("Test label") self.graphic_settings_dock.setWidget(label_test) view_menu.addAction(self.graphic_settings_dock.toggleViewAction()) self.addDockWidget(Qt.AllDockWidgetAreas, self.graphic_settings_dock) print(self.graphic_settings_dock.objectName()) # Final options. self.setWindowTitle('X-ray spectrum analyzer') self.show() def closeEvent(self, event): self.save_settings() super(MainWindow, self).closeEvent(event) def save_settings(self): settings = QSettings("openMicroanalysis", "xrayspectrumanalyzergui") # print(settings.fileName()) settings.beginGroup("MainWindow") settings.setValue("geometry", self.saveGeometry()) settings.setValue("window_state", self.saveState()) settings.endGroup() settings.beginGroup("graphic_settings_dock") settings.setValue("visible", self.graphic_settings_dock.isVisible()) settings.endGroup() # settings.beginGroup("zero_loss_peak_dock") # settings.setValue("visible", self.zero_loss_peak_dock.isVisible()) # settings.endGroup() def read_settings(self): settings = QSettings("openMicroanalysis", "xrayspectrumanalyzergui") # print(settings.fileName()) # settings.clear() settings.beginGroup("MainWindow") geometry_value = settings.value("geometry") if geometry_value is None: self.setGeometry(300, 300, 600, 400) else: self.restoreGeometry(geometry_value) window_state_value = settings.value("window_state") if window_state_value is not None: self.restoreState(window_state_value) settings.endGroup() settings.beginGroup("graphic_settings_dock") visible_value = settings.value("visible") if visible_value is not None: if visible_value == "true": self.graphic_settings_dock.setVisible(True) elif visible_value == "false": self.graphic_settings_dock.setVisible(False) settings.endGroup() # settings.beginGroup("zero_loss_peak_dock") # visible_value = settings.value("visible") # if visible_value is not None: # if visible_value == "true": # self.zero_loss_peak_dock.setVisible(True) # elif visible_value == "false": # self.zero_loss_peak_dock.setVisible(False) # settings.endGroup() def import_spectrum(self): self.statusBar().showMessage("Import spectrum", 2000) path = os.path.dirname(__file__) formats = ["*.msa", "*.txt"] file_filters = "Spectrum file ({:s})".format(" ".join(formats)) file_names = QFileDialog.getOpenFileName(self, "Import an x-ray spectrum", path, file_filters) def export_spectrum(self): self.statusBar().showMessage("Export spectrum", 2000) def new_project(self): self.statusBar().showMessage("New project", 2000) def open_project(self): self.statusBar().showMessage("Open project", 2000) def close_project(self): self.statusBar().showMessage("Close project", 2000) def save_project(self): self.statusBar().showMessage("Save project", 2000) def saveas_project(self): self.statusBar().showMessage("Save project as ...", 2000) def create_gui(self): self.logger.info("MainWindow.create_gui") self._create_main_window() self._create_actions() self._create_menus() self._create_toolbars() self._create_tooltip() self._create_spectra_display() self._create_data_display() self._create_operations_display() self._create_layout() self._create_statusbar() self._read_settings() self.show() def _create_main_window(self): self.setGeometry(300, 300, 500, 500) self.setWindowTitle('Spectrum Analyzer') # self.setWindowIcon(QIcon('../../../images/cog.svg')) self.setWindowIcon(self.style().standardIcon(QStyle.SP_DesktopIcon)) self._center_main_window() def _center_main_window(self): self.logger.info("MainWindow._center_main_window") qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def _create_menus(self): self.logger.info("MainWindow._create_menus") self.fileMenu = self.menuBar().addMenu("&File") self.fileMenu.addAction(self.newAct) self.fileMenu.addAction(self.openAct) self.fileMenu.addAction(self.saveAct) self.fileMenu.addAction(self.saveAsAct) self.fileMenu.addSeparator() self.fileMenu.addAction(self.exitAct) self.menuBar().addSeparator() self.helpMenu = self.menuBar().addMenu("&Help") self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) def _create_layout(self): mainLayout = QHBoxLayout() mainLayout.addWidget(self.dataGroupBox) mainLayout.addWidget(self.plotGroupBox) mainLayout.addWidget(self.operationsGroupBox) self.mainGroupBox = QGroupBox("Main layout") self.mainGroupBox.setLayout(mainLayout) self.setCentralWidget(self.mainGroupBox) def _create_spectra_display(self): self.plotGroupBox = QGroupBox("Plot layout") self.figure1 = Figure(facecolor=(1, 1, 1), edgecolor=(0, 0, 0)) self.canvas1 = FigureCanvas(self.figure1) self.canvas1.setParent(self.plotGroupBox) self.canvas1.setFocusPolicy(Qt.StrongFocus) self.canvas1.setFocus() self.canvas1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.canvas1.updateGeometry() self.mpl_toolbar1 = NavigationToolbar(self.canvas1, self.plotGroupBox) self.canvas1.mpl_connect('key_press_event', self.on_key_press) self.figure2 = Figure(facecolor=(1, 1, 1), edgecolor=(0, 0, 0)) self.canvas2 = FigureCanvas(self.figure2) self.canvas2.setParent(self.plotGroupBox) self.mpl_toolbar2 = NavigationToolbar(self.canvas1, self.plotGroupBox) layout = QVBoxLayout() layout.addWidget(self.canvas1) layout.addWidget(self.mpl_toolbar1) layout.addWidget(self.canvas2) layout.addWidget(self.mpl_toolbar2) self.plotGroupBox.setLayout(layout) def _create_data_display(self): self.dataGroupBox = QGroupBox("Data layout") data_layout = QVBoxLayout() group_box = QGroupBox("Spectra") self.spectra_list_view = QListWidget(self) self.spectra_list_view.setMinimumWidth(200) layout = QVBoxLayout() layout.addWidget(self.spectra_list_view) group_box.setLayout(layout) data_layout.addWidget(group_box) group_box = QGroupBox("ROI") roi_list_view = QListWidget(self) layout = QVBoxLayout() layout.addWidget(roi_list_view) group_box.setLayout(layout) data_layout.addWidget(group_box) group_box = QGroupBox("Elements") element_list_view = QListWidget(self) layout = QVBoxLayout() layout.addWidget(element_list_view) group_box.setLayout(layout) data_layout.addWidget(group_box) self.dataGroupBox.setLayout(data_layout) def _create_operations_display(self): self.operationsGroupBox = QGroupBox("Operations layout") results_layout = QVBoxLayout() group_box = QGroupBox("Operation") results_layout.addWidget(group_box) group_box = QGroupBox("Results") results_layout.addWidget(group_box) self.operationsGroupBox.setLayout(results_layout) def _create_tooltip(self): QToolTip.setFont(QFont('SansSerif', 10)) self.setToolTip('This is a <b>QWidget</b> widget') def _create_actions(self): self.logger.info("MainWindow._create_actions") self.newAct = QAction(self.style().standardIcon(QStyle.SP_FileIcon), "&New", self, shortcut=QKeySequence.New, statusTip="Create a new file", triggered=self.newFile) self.openAct = QAction(self.style().standardIcon( QStyle.SP_DirOpenIcon), "&Open...", self, shortcut=QKeySequence.Open, statusTip="Open an existing file", triggered=self.open) self.saveAct = QAction(self.style().standardIcon( QStyle.SP_DialogSaveButton), "&Save", self, shortcut=QKeySequence.Save, statusTip="Save the document to disk", triggered=self.save) self.saveAsAct = QAction( self.style().standardIcon(QStyle.SP_DialogSaveButton), "Save &As...", self, shortcut=QKeySequence.SaveAs, statusTip="Save the document under a new name", triggered=self.saveAs) self.exitAct = QAction(self.style().standardIcon( QStyle.SP_DialogCloseButton), "E&xit", self, shortcut="Ctrl+Q", statusTip="Exit the application", triggered=self.close) self.textEdit = QTextEdit() self.aboutAct = QAction(self.style().standardIcon( QStyle.SP_MessageBoxInformation), "&About", self, statusTip="Show the application's About box", triggered=self.about) self.aboutQtAct = QAction(self.style().standardIcon( QStyle.SP_TitleBarMenuButton), "About &Qt", self, statusTip="Show the Qt library's About box", triggered=QApplication().aboutQt) def _create_toolbars(self): self.logger.info("MainWindow._create_toolbars") self.fileToolBar = self.addToolBar("File") self.fileToolBar.addAction(self.newAct) self.fileToolBar.addAction(self.openAct) self.fileToolBar.addAction(self.saveAct) def _create_statusbar(self): self.logger.info("MainWindow._create_statusbar") self.statusBar().showMessage("Ready") def _read_settings(self): self.logger.info("MainWindow._read_settings") settings = QSettings(ORGANIZATION_NAME, APPLICATION_NAME) pos = settings.value("pos", QPoint(200, 200)) size = settings.value("size", QSize(400, 400)) self.resize(size) self.move(pos) def _write_settings(self): self.logger.info("MainWindow._write_settings") settings = QSettings(ORGANIZATION_NAME, APPLICATION_NAME) settings.setValue("pos", self.pos()) settings.setValue("size", self.size()) def maybeSave(self): self.logger.info("MainWindow.maybeSave") if self.textEdit.document().isModified(): ret = QMessageBox.warning( self, "Application", "The document has been modified.\nDo you want to save " "your changes?", QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel) if ret == QMessageBox.Save: return self.save() elif ret == QMessageBox.Cancel: return False return True def closeEvent(self, event): self.logger.info("MainWindow.closeEvent") if self.maybeSave(): self._write_settings() event.accept() else: event.ignore() def newFile(self): self.logger.info("MainWindow.newFile") if self.maybeSave(): self.textEdit.clear() self.setCurrentFile('') def open(self): self.logger.info("MainWindow.open") if self.maybeSave(): filepath, _filtr = QFileDialog.getOpenFileName(self) if filepath: self.spectrumAnalyzer.readSpectrum(filepath) filename = os.path.basename(filepath) self.spectra_list_view.addItem(filename) self.spectrumAnalyzer.plotSpectrum(self.figure1) self.canvas1.draw() def save(self): self.logger.info("MainWindow.save") if self.curFile: return self.saveFile(self.curFile) return self.saveAs() def saveAs(self): self.logger.info("MainWindow.saveAs") fileName, _filtr = QFileDialog.getSaveFileName(self) if fileName: return self.saveFile(fileName) return False def about(self): self.logger.info("MainWindow.about") QMessageBox.about( self, "About xrayspectrumanalyzer", "The <b>xrayspectrumanalyzer</b> extract peak intensity from EDS spectrum." ) def documentWasModified(self): self.logger.info("MainWindow.documentWasModified") self.setWindowModified(self.textEdit.document().isModified()) def on_key_press(self, event): print('you pressed', event.key) # implement the default mpl key press events described at # http://matplotlib.org/users/navigation_toolbar.html#navigation-keyboard-shortcuts key_press_handler(event, self.canvas1, self.mpl_toolbar1)
class QtPluginErrReporter(QDialog): """Dialog that allows users to review and report PluginError tracebacks. Parameters ---------- parent : QWidget, optional Optional parent widget for this widget. initial_plugin : str, optional If provided, errors from ``initial_plugin`` will be shown when the dialog is created, by default None Attributes ---------- text_area : qtpy.QtWidgets.QTextEdit The text area where traceback information will be shown. plugin_combo : qtpy.QtWidgets.QComboBox The dropdown menu used to select the current plugin github_button : qtpy.QtWidgets.QPushButton A button that, when pressed, will open an issue at the current plugin's github issue tracker, prepopulated with a formatted traceback. Button is only visible if a github URL is detected in the package metadata for the current plugin. clipboard_button : qtpy.QtWidgets.QPushButton A button that, when pressed, copies the current traceback information to the clipboard. (HTML tags are removed in the copied text.) plugin_meta : qtpy.QtWidgets.QLabel A label that will show available plugin metadata (such as home page). """ NULL_OPTION = trans._('select plugin... ') def __init__( self, *, parent: Optional[QWidget] = None, initial_plugin: Optional[str] = None, ) -> None: super().__init__(parent) from ...plugins import plugin_manager self.plugin_manager = plugin_manager self.setWindowTitle(trans._('Recorded Plugin Exceptions')) self.setWindowModality(Qt.NonModal) self.layout = QVBoxLayout() self.layout.setSpacing(0) self.layout.setContentsMargins(10, 10, 10, 10) self.setLayout(self.layout) self.text_area = QTextEdit() theme = get_theme(get_settings().appearance.theme, as_dict=False) self._highlight = Pylighter(self.text_area.document(), "python", theme.syntax_style) self.text_area.setTextInteractionFlags(Qt.TextSelectableByMouse) self.text_area.setMinimumWidth(360) # Create plugin dropdown menu self.plugin_combo = QComboBox() self.plugin_combo.addItem(self.NULL_OPTION) bad_plugins = [e.plugin_name for e in self.plugin_manager.get_errors()] self.plugin_combo.addItems(list(sorted(set(bad_plugins)))) self.plugin_combo.currentTextChanged.connect(self.set_plugin) self.plugin_combo.setCurrentText(self.NULL_OPTION) # create github button (gets connected in self.set_plugin) self.github_button = QPushButton(trans._('Open issue on GitHub'), self) self.github_button.setToolTip( trans._( "Open a web browser to submit this error log\nto the developer's GitHub issue tracker", )) self.github_button.hide() # create copy to clipboard button self.clipboard_button = QPushButton() self.clipboard_button.hide() self.clipboard_button.setObjectName("QtCopyToClipboardButton") self.clipboard_button.setToolTip( trans._("Copy error log to clipboard")) self.clipboard_button.clicked.connect(self.copyToClipboard) # plugin_meta contains a URL to the home page, (and/or other details) self.plugin_meta = QLabel('', parent=self) self.plugin_meta.setObjectName("pluginInfo") self.plugin_meta.setTextFormat(Qt.RichText) self.plugin_meta.setTextInteractionFlags(Qt.TextBrowserInteraction) self.plugin_meta.setOpenExternalLinks(True) self.plugin_meta.setAlignment(Qt.AlignRight) # make layout row_1_layout = QHBoxLayout() row_1_layout.setContentsMargins(11, 5, 10, 0) row_1_layout.addStretch(1) row_1_layout.addWidget(self.plugin_meta) row_2_layout = QHBoxLayout() row_2_layout.setContentsMargins(11, 5, 10, 0) row_2_layout.addWidget(self.plugin_combo) row_2_layout.addStretch(1) row_2_layout.addWidget(self.github_button) row_2_layout.addWidget(self.clipboard_button) row_2_layout.setSpacing(5) self.layout.addLayout(row_1_layout) self.layout.addLayout(row_2_layout) self.layout.addWidget(self.text_area, 1) self.setMinimumWidth(750) self.setMinimumHeight(600) if initial_plugin: self.set_plugin(initial_plugin) def set_plugin(self, plugin: str) -> None: """Set the current plugin shown in the dropdown and text area. Parameters ---------- plugin : str name of a plugin that has created an error this session. """ self.github_button.hide() self.clipboard_button.hide() try: self.github_button.clicked.disconnect() # when disconnecting a non-existent signal # PySide2 raises runtimeError, PyQt5 raises TypeError except (RuntimeError, TypeError): pass if not plugin or (plugin == self.NULL_OPTION): self.plugin_meta.setText('') self.text_area.setText('') return if not self.plugin_manager.get_errors(plugin): raise ValueError( trans._("No errors reported for plugin '{plugin}'", plugin=plugin)) self.plugin_combo.setCurrentText(plugin) err_string = format_exceptions(plugin, as_html=False, color="NoColor") self.text_area.setText(err_string) self.clipboard_button.show() # set metadata and outbound links/buttons err0 = self.plugin_manager.get_errors(plugin)[0] meta = standard_metadata(err0.plugin) if err0.plugin else {} meta_text = '' if not meta: self.plugin_meta.setText(meta_text) return url = meta.get('url') if url: meta_text += ( '<span style="color:#999;">plugin home page: ' f'</span><a href="{url}" style="color:#999">{url}</a>') if 'github.com' in url: def onclick(): import webbrowser err = format_exceptions(plugin, as_html=False) err = ( "<!--Provide detail on the error here-->\n\n\n\n" "<details>\n<summary>Traceback from napari</summary>" f"\n\n```\n{err}\n```\n</details>") url = f'{meta.get("url")}/issues/new?&body={err}' webbrowser.open(url, new=2) self.github_button.clicked.connect(onclick) self.github_button.show() self.plugin_meta.setText(meta_text) def copyToClipboard(self) -> None: """Copy current plugin traceback info to clipboard as plain text.""" plugin = self.plugin_combo.currentText() err_string = format_exceptions(plugin, as_html=False) cb = QGuiApplication.clipboard() cb.setText(err_string)
class NoteEditor(QMainWindow): def __init__(self, parent, noteType, noteFileName="", b=None, c=None, v=None): super().__init__() self.parent, self.noteType = parent, noteType self.noteFileName = noteFileName if not self.noteType == "file": if v: self.b, self.c, self.v = b, c, v else: self.b, self.c, self.v = config.studyB, config.studyC, config.studyV # default - "Rich" mode for editing self.html = True # default - text is not modified; no need for saving new content self.parent.noteSaved = True config.noteOpened = True config.lastOpenedNote = (noteType, b, c, v) # specify window size self.resizeWindow(2/3, 2/3) # setup interface self.setupMenuBar() self.addToolBarBreak() self.setupToolBar() if config.hideNoteEditorStyleToolbar: self.toolBar.hide() self.addToolBarBreak() self.setupTextUtility() if config.hideNoteEditorTextUtility: self.ttsToolbar.hide() self.translateToolbar.hide() self.setupLayout() # display content when first launched self.displayInitialContent() self.editor.setFocus() # specify window title self.updateWindowTitle() # re-implementing close event, when users close this widget def closeEvent(self, event): if self.parent.noteSaved: config.noteOpened = False event.accept() if config.lastOpenedNote and config.openBibleNoteAfterEditorClosed: #if config.lastOpenedNote[0] == "file": # self.parent.externalFileButtonClicked() if config.lastOpenedNote[0] == "book": self.parent.openStudyBookNote() elif config.lastOpenedNote[0] == "chapter": self.parent.openStudyChapterNote() elif config.lastOpenedNote[0] == "verse": self.parent.openStudyVerseNote() else: if self.parent.warningNotSaved(): self.parent.noteSaved = True config.noteOpened = False event.accept() else: self.parent.bringToForeground(self) event.ignore() # re-implement keyPressEvent, control+S for saving file def keyPressEvent(self, event): keys = { Qt.Key_O: self.openFileDialog, Qt.Key_S: self.saveNote, Qt.Key_B: self.format_bold, Qt.Key_I: self.format_italic, Qt.Key_U: self.format_underline, Qt.Key_M: self.format_custom, Qt.Key_D: self.format_clear, Qt.Key_F: self.focusSearchField, } key = event.key() if event.modifiers() == Qt.ControlModifier and key in keys: keys[key]() # window appearance def resizeWindow(self, widthFactor, heightFactor): availableGeometry = QGuiApplication.instance().desktop().availableGeometry() self.resize(availableGeometry.width() * widthFactor, availableGeometry.height() * heightFactor) def updateWindowTitle(self): if self.noteType == "file": if self.noteFileName: *_, title = os.path.split(self.noteFileName) else: title = "NEW" else: title = self.parent.bcvToVerseReference(self.b, self.c, self.v) if self.noteType == "book": title, *_ = title.split(" ") elif self.noteType == "chapter": title, *_ = title.split(":") mode = {True: "rich", False: "plain"} notModified = {True: "", False: " [modified]"} self.setWindowTitle("Note Editor ({1} mode) - {0}{2}".format(title, mode[self.html], notModified[self.parent.noteSaved])) # switching between "rich" & "plain" mode def switchMode(self): if self.html: note = self.editor.toHtml() note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note) self.editor.setPlainText(note) self.html = False self.updateWindowTitle() else: note = self.editor.toPlainText() self.editor.setHtml(note) self.html = True self.updateWindowTitle() # without this hide / show command below, QTextEdit does not update the text in some devices self.hide() self.show() def setupMenuBar(self): if config.toolBarIconFullSize: self.setupMenuBarFullIconSize() else: self.setupMenuBarStandardIconSize() def setupMenuBarStandardIconSize(self): self.menuBar = QToolBar() self.menuBar.setWindowTitle(config.thisTranslation["note_title"]) self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu) # In QWidget, self.menuBar is treated as the menubar without the following line # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.menuBar) newButton = QPushButton() newButton.setToolTip("{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"])) newButtonFile = os.path.join("htmlResources", "newfile.png") newButton.setIcon(QIcon(newButtonFile)) newButton.clicked.connect(self.newNoteFile) self.menuBar.addWidget(newButton) openButton = QPushButton() openButton.setToolTip("{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"])) openButtonFile = os.path.join("htmlResources", "open.png") openButton.setIcon(QIcon(openButtonFile)) openButton.clicked.connect(self.openFileDialog) self.menuBar.addWidget(openButton) self.menuBar.addSeparator() saveButton = QPushButton() saveButton.setToolTip("{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"])) saveButtonFile = os.path.join("htmlResources", "save.png") saveButton.setIcon(QIcon(saveButtonFile)) saveButton.clicked.connect(self.saveNote) self.menuBar.addWidget(saveButton) saveAsButton = QPushButton() saveAsButton.setToolTip(config.thisTranslation["note_saveAs"]) saveAsButtonFile = os.path.join("htmlResources", "saveas.png") saveAsButton.setIcon(QIcon(saveAsButtonFile)) saveAsButton.clicked.connect(self.openSaveAsDialog) self.menuBar.addWidget(saveAsButton) self.menuBar.addSeparator() toolBarButton = QPushButton() toolBarButton.setToolTip(config.thisTranslation["note_print"]) toolBarButtonFile = os.path.join("htmlResources", "print.png") toolBarButton.setIcon(QIcon(toolBarButtonFile)) toolBarButton.clicked.connect(self.printNote) self.menuBar.addWidget(toolBarButton) self.menuBar.addSeparator() switchButton = QPushButton() switchButton.setToolTip(config.thisTranslation["note_mode"]) switchButtonFile = os.path.join("htmlResources", "switch.png") switchButton.setIcon(QIcon(switchButtonFile)) switchButton.clicked.connect(self.switchMode) self.menuBar.addWidget(switchButton) self.menuBar.addSeparator() # decreaseFontSizeButton = QPushButton() # decreaseFontSizeButton.setToolTip(config.thisTranslation["menu2_smaller"]) # decreaseFontSizeButtonFile = os.path.join("htmlResources", "fontMinus.png") # decreaseFontSizeButton.setIcon(QIcon(decreaseFontSizeButtonFile)) # decreaseFontSizeButton.clicked.connect(self.decreaseNoteEditorFontSize) # self.menuBar.addWidget(decreaseFontSizeButton) # # increaseFontSizeButton = QPushButton() # increaseFontSizeButton.setToolTip(config.thisTranslation["menu2_larger"]) # increaseFontSizeButtonFile = os.path.join("htmlResources", "fontPlus.png") # increaseFontSizeButton.setIcon(QIcon(increaseFontSizeButtonFile)) # increaseFontSizeButton.clicked.connect(self.increaseNoteEditorFontSize) # self.menuBar.addWidget(increaseFontSizeButton) # self.menuBar.addSeparator() self.searchLineEdit = QLineEdit() self.searchLineEdit.setClearButtonEnabled(True) self.searchLineEdit.setToolTip(config.thisTranslation["menu5_search"]) self.searchLineEdit.setMaximumWidth(400) self.searchLineEdit.returnPressed.connect(self.searchLineEntered) self.menuBar.addWidget(self.searchLineEdit) self.menuBar.addSeparator() toolBarButton = QPushButton() toolBarButton.setToolTip(config.thisTranslation["note_toolbar"]) toolBarButtonFile = os.path.join("htmlResources", "toolbar.png") toolBarButton.setIcon(QIcon(toolBarButtonFile)) toolBarButton.clicked.connect(self.toggleToolbar) self.menuBar.addWidget(toolBarButton) toolBarButton = QPushButton() toolBarButton.setToolTip(config.thisTranslation["note_textUtility"]) toolBarButtonFile = os.path.join("htmlResources", "textUtility.png") toolBarButton.setIcon(QIcon(toolBarButtonFile)) toolBarButton.clicked.connect(self.toggleTextUtility) self.menuBar.addWidget(toolBarButton) self.menuBar.addSeparator() def setupMenuBarFullIconSize(self): self.menuBar = QToolBar() self.menuBar.setWindowTitle(config.thisTranslation["note_title"]) self.menuBar.setContextMenuPolicy(Qt.PreventContextMenu) # In QWidget, self.menuBar is treated as the menubar without the following line # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.menuBar) iconFile = os.path.join("htmlResources", "newfile.png") self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + N]".format(config.thisTranslation["menu7_create"]), self.newNoteFile) iconFile = os.path.join("htmlResources", "open.png") self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + O]".format(config.thisTranslation["menu7_open"]), self.openFileDialog) self.menuBar.addSeparator() iconFile = os.path.join("htmlResources", "save.png") self.menuBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + S]".format(config.thisTranslation["note_save"]), self.saveNote) iconFile = os.path.join("htmlResources", "saveas.png") self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_saveAs"], self.openSaveAsDialog) self.menuBar.addSeparator() iconFile = os.path.join("htmlResources", "print.png") self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_print"], self.printNote) self.menuBar.addSeparator() iconFile = os.path.join("htmlResources", "switch.png") self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_mode"], self.switchMode) self.menuBar.addSeparator() # iconFile = os.path.join("htmlResources", "fontMinus.png") # self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_smaller"], self.decreaseNoteEditorFontSize) # # iconFile = os.path.join("htmlResources", "fontPlus.png") # self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["menu2_larger"], self.increaseNoteEditorFontSize) # self.menuBar.addSeparator() self.searchLineEdit = QLineEdit() self.searchLineEdit.setToolTip("{0}\n[Ctrl/Cmd + F]".format(config.thisTranslation["menu5_search"])) self.searchLineEdit.setMaximumWidth(400) self.searchLineEdit.returnPressed.connect(self.searchLineEntered) self.menuBar.addWidget(self.searchLineEdit) self.menuBar.addSeparator() iconFile = os.path.join("htmlResources", "toolbar.png") self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_toolbar"], self.toggleToolbar) iconFile = os.path.join("htmlResources", "textUtility.png") self.menuBar.addAction(QIcon(iconFile), config.thisTranslation["note_textUtility"], self.toggleTextUtility) self.menuBar.addSeparator() def toggleToolbar(self): if config.hideNoteEditorStyleToolbar: self.toolBar.show() config.hideNoteEditorStyleToolbar = False else: self.toolBar.hide() config.hideNoteEditorStyleToolbar = True def toggleTextUtility(self): if config.hideNoteEditorTextUtility: self.ttsToolbar.show() self.translateToolbar.show() config.hideNoteEditorTextUtility = False else: self.ttsToolbar.hide() self.translateToolbar.hide() config.hideNoteEditorTextUtility = True def printNote(self): #document = QTextDocument("Sample Page") document = self.editor.document() printer = QPrinter() myPrintDialog = QPrintDialog(printer, self) if myPrintDialog.exec_() == QDialog.Accepted: return document.print_(printer) def setupToolBar(self): if config.toolBarIconFullSize: self.setupToolBarFullIconSize() else: self.setupToolBarStandardIconSize() def setupToolBarStandardIconSize(self): self.toolBar = QToolBar() self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"]) self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu) # self.toolBar can be treated as an individual widget and positioned with a specified layout # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.toolBar) items = ( ("noteTool_textFont", "font.png", self.format_font), ("noteTool_textColor", "textColor.png", self.format_textColor), ("noteTool_textBackgroundColor", "textBgColor.png", self.format_textBackgroundColor), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() items = ( ("noteTool_header1", "header1.png", self.format_header1), ("noteTool_header2", "header2.png", self.format_header2), ("noteTool_header3", "header3.png", self.format_header3), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() items = ( ("{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), "bold.png", self.format_bold), ("{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), "italic.png", self.format_italic), ("{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), "underline.png", self.format_underline), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar, translation=False) self.toolBar.addSeparator() items = ( ("noteTool_superscript", "superscript.png", self.format_superscript), ("noteTool_subscript", "subscript.png", self.format_subscript), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), "custom.png", self.format_custom, self.toolBar, translation=False) self.toolBar.addSeparator() items = ( ("noteTool_left", "align_left.png", self.format_left), ("noteTool_centre", "align_center.png", self.format_center), ("noteTool_right", "align_right.png", self.format_right), ("noteTool_justify", "align_justify.png", self.format_justify), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() self.parent.addStandardIconButton("{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), "clearFormat.png", self.format_clear, self.toolBar, translation=False) self.toolBar.addSeparator() items = ( ("noteTool_hyperlink", "hyperlink.png", self.openHyperlinkDialog), ("noteTool_externalImage", "gallery.png", self.openImageDialog), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() items = ( ("noteTool_image", "addImage.png", self.addInternalImage), ("noteTool_exportImage", "export.png", self.exportNoteImages), ) for item in items: toolTip, icon, action = item self.parent.addStandardIconButton(toolTip, icon, action, self.toolBar) self.toolBar.addSeparator() def setupToolBarFullIconSize(self): self.toolBar = QToolBar() self.toolBar.setWindowTitle(config.thisTranslation["noteTool_title"]) self.toolBar.setContextMenuPolicy(Qt.PreventContextMenu) # self.toolBar can be treated as an individual widget and positioned with a specified layout # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.toolBar) iconFile = os.path.join("htmlResources", "font.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textFont"], self.format_font) iconFile = os.path.join("htmlResources", "textColor.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textColor"], self.format_textColor) iconFile = os.path.join("htmlResources", "textBgColor.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_textBackgroundColor"], self.format_textBackgroundColor) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "header1.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header1"], self.format_header1) iconFile = os.path.join("htmlResources", "header2.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header2"], self.format_header2) iconFile = os.path.join("htmlResources", "header3.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_header3"], self.format_header3) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "bold.png") self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + B]".format(config.thisTranslation["noteTool_bold"]), self.format_bold) iconFile = os.path.join("htmlResources", "italic.png") self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + I]".format(config.thisTranslation["noteTool_italic"]), self.format_italic) iconFile = os.path.join("htmlResources", "underline.png") self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + U]".format(config.thisTranslation["noteTool_underline"]), self.format_underline) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "custom.png") self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + M]\n\n{1}\n* {4}\n* {5}\n* {6}\n\n{2}\n*1 {4}\n*2 {5}\n*3 {6}\n\n{3}\n{10}{4}|{5}|{6}{11}\n{10}{7}|{8}|{9}{11}".format(config.thisTranslation["noteTool_trans0"], config.thisTranslation["noteTool_trans1"], config.thisTranslation["noteTool_trans2"], config.thisTranslation["noteTool_trans3"], config.thisTranslation["noteTool_no1"], config.thisTranslation["noteTool_no2"], config.thisTranslation["noteTool_no3"], config.thisTranslation["noteTool_no4"], config.thisTranslation["noteTool_no5"], config.thisTranslation["noteTool_no6"], "{", "}"), self.format_custom) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "align_left.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_left"], self.format_left) iconFile = os.path.join("htmlResources", "align_center.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_centre"], self.format_center) iconFile = os.path.join("htmlResources", "align_right.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_right"], self.format_right) iconFile = os.path.join("htmlResources", "align_justify.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_justify"], self.format_justify) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "clearFormat.png") self.toolBar.addAction(QIcon(iconFile), "{0}\n[Ctrl/Cmd + D]".format(config.thisTranslation["noteTool_delete"]), self.format_clear) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "hyperlink.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_hyperlink"], self.openHyperlinkDialog) iconFile = os.path.join("htmlResources", "gallery.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_externalImage"], self.openImageDialog) self.toolBar.addSeparator() iconFile = os.path.join("htmlResources", "addImage.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_image"], self.addInternalImage) iconFile = os.path.join("htmlResources", "export.png") self.toolBar.addAction(QIcon(iconFile), config.thisTranslation["noteTool_exportImage"], self.exportNoteImages) self.toolBar.addSeparator() def setupLayout(self): self.editor = QTextEdit() self.editor.setStyleSheet("font-family:'{0}'; font-size:{1}pt;".format(config.font, config.fontSize)); self.editor.textChanged.connect(self.textChanged) self.setCentralWidget(self.editor) #self.layout = QGridLayout() #self.layout.setMenuBar(self.menuBar) #self.layout.addWidget(self.toolBar, 0, 0) #self.layout.addWidget(self.editor, 1, 0) #self.setLayout(self.layout) # adjustment of note editor font size def increaseNoteEditorFontSize(self): if self.html: self.editor.selectAll() config.noteEditorFontSize += 1 self.editor.setFontPointSize(config.noteEditorFontSize) self.hide() self.show() def decreaseNoteEditorFontSize(self): if self.html and not config.noteEditorFontSize == 0: self.editor.selectAll() config.noteEditorFontSize -= 1 self.editor.setFontPointSize(config.noteEditorFontSize) self.hide() self.show() # search field entered def searchLineEntered(self): searchString = self.searchLineEdit.text() if searchString: cursor = self.editor.document().find(searchString, self.editor.textCursor()) if cursor: self.editor.setTextCursor(cursor) self.hide() self.show() def focusSearchField(self): self.searchLineEdit.setFocus() # track if the text being modified def textChanged(self): if self.parent.noteSaved: self.parent.noteSaved = False self.updateWindowTitle() # display content when first launched def displayInitialContent(self): if self.noteType == "file": if self.noteFileName: self.openNoteFile(self.noteFileName) else: self.newNoteFile() else: self.openBibleNote() self.editor.selectAll() self.editor.setFontPointSize(config.noteEditorFontSize) self.editor.moveCursor(QTextCursor.Start, QTextCursor.MoveAnchor) self.parent.noteSaved = True def getEmptyPage(self): strict = '' if config.includeStrictDocTypeInNote: strict = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">' return """{4}<html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li {0} white-space: pre-wrap; {1} </style></head><body style="font-family:'{2}'; font-size:{3}pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>"""\ .format("{", "}", config.font, config.fontSize, strict) # load chapter / verse notes from sqlite database def openBibleNote(self): if self.noteType == "book": note = NoteService.getBookNote(self.b) elif self.noteType == "chapter": note = NoteService.getChapterNote(self.b, self.c) elif self.noteType == "verse": note = NoteService.getVerseNote(self.b, self.c, self.v) if note == config.thisTranslation["empty"]: note = self.getEmptyPage() else: note = self.fixNoteFont(note) if self.html: self.editor.setHtml(note) else: self.editor.setPlainText(note) # File I / O def newNoteFile(self): if self.parent.noteSaved: self.newNoteFileAction() elif self.parent.warningNotSaved(): self.newNoteFileAction() def newNoteFileAction(self): self.noteType = "file" self.noteFileName = "" #self.editor.clear() defaultText = self.getEmptyPage() if self.html: self.editor.setHtml(defaultText) else: self.editor.setPlainText(defaultText) self.parent.noteSaved = True self.updateWindowTitle() self.hide() self.show() def openFileDialog(self): if self.parent.noteSaved: self.openFileDialogAction() elif self.parent.warningNotSaved(): self.openFileDialogAction() def openFileDialogAction(self): options = QFileDialog.Options() fileName, filtr = QFileDialog.getOpenFileName(self, config.thisTranslation["menu7_open"], "notes", "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options) if fileName: self.openNoteFile(fileName) def openNoteFile(self, fileName): try: f = open(fileName, "r", encoding="utf-8") except: print("Failed to open '{0}'".format(fileName)) note = f.read() f.close() self.noteType = "file" self.noteFileName = fileName note = self.fixNoteFont(note) if self.html: self.editor.setHtml(note) else: self.editor.setPlainText(note) self.parent.noteSaved = True self.updateWindowTitle() self.hide() self.show() def saveNote(self): if self.html: note = self.editor.toHtml() else: note = self.editor.toPlainText() note = self.fixNoteFont(note) if self.noteType == "book": NoteService.saveBookNote(self.b, note) if config.openBibleNoteAfterSave: self.parent.openBookNote(self.b,) self.parent.noteSaved = True self.updateWindowTitle() elif self.noteType == "chapter": NoteService.saveChapterNote(self.b, self.c, note) if config.openBibleNoteAfterSave: self.parent.openChapterNote(self.b, self.c) self.parent.noteSaved = True self.updateWindowTitle() elif self.noteType == "verse": NoteService.saveVerseNote(self.b, self.c, self.v, note) if config.openBibleNoteAfterSave: self.parent.openVerseNote(self.b, self.c, self.v) self.parent.noteSaved = True self.updateWindowTitle() elif self.noteType == "file": if self.noteFileName == "": self.openSaveAsDialog() else: self.saveAsNote(self.noteFileName) def openSaveAsDialog(self): if self.noteFileName: *_, defaultName = os.path.split(self.noteFileName) else: defaultName = "new.uba" options = QFileDialog.Options() fileName, filtr = QFileDialog.getSaveFileName(self, config.thisTranslation["note_saveAs"], os.path.join("notes", defaultName), "UniqueBible.app Note Files (*.uba);;HTML Files (*.html);;HTM Files (*.htm);;All Files (*)", "", options) if fileName: if not "." in os.path.basename(fileName): fileName = fileName + ".uba" self.saveAsNote(fileName) def saveAsNote(self, fileName): if self.html: note = self.editor.toHtml() else: note = self.editor.toPlainText() note = self.fixNoteFont(note) f = open(fileName, "w", encoding="utf-8") f.write(note) f.close() self.noteFileName = fileName self.parent.addExternalFileHistory(fileName) self.parent.setExternalFileButton() self.parent.noteSaved = True self.updateWindowTitle() def fixNoteFont(self, note): note = re.sub("<body style={0}[ ]*?font-family:[ ]*?'[^']*?';[ ]*?font-size:[ ]*?[0-9]+?pt;".format('"'), "<body style={0}font-family:'{1}'; font-size:{2}pt;".format('"', config.font, config.fontSize), note) if not config.includeStrictDocTypeInNote: note = re.sub("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">\n""", "", note) return note # formatting styles def format_clear(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: selectedText = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, selectedText) self.editor.insertHtml(selectedText) else: selectedText = re.sub("<[^\n<>]*?>", "", selectedText) self.editor.insertPlainText(selectedText) else: self.selectTextFirst() def format_header1(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.insertHtml("<h1>{0}</h1>".format(selectedText)) else: self.editor.insertPlainText("<h1>{0}</h1>".format(selectedText)) else: self.selectTextFirst() def format_header2(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.insertHtml("<h2>{0}</h2>".format(selectedText)) else: self.editor.insertPlainText("<h2>{0}</h2>".format(selectedText)) else: self.selectTextFirst() def format_header3(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.insertHtml("<h3>{0}</h3>".format(selectedText)) else: self.editor.insertPlainText("<h3>{0}</h3>".format(selectedText)) else: self.selectTextFirst() def format_font(self): selectedText = self.editor.textCursor().selectedText() if selectedText: ok, font = QFontDialog.getFont(QFont(config.font, config.fontSize), self) if ok: if self.html: self.editor.setCurrentFont(font) else: fontFamily, fontSize, i1, i2, fontWeight, italic, underline, strikeout, *_ = font.key().split(",") spanTag = """<span style="font-family:'{0}'; font-size:{1}pt;""".format(fontFamily, fontSize) # add font weight if fontWeight == "25": spanTag += " font-weight:200;" elif fontWeight == "75": spanTag += " font-weight:600;" # add italic style if italic == "1": spanTag += " font-style:italic;" # add both underline and strikeout style if underline == "1" and strikeout == "1": spanTag += " text-decoration: underline line-through;" # add underline style elif underline == "1": spanTag += " text-decoration: underline;" # add strikeout style elif strikeout == "1": spanTag += " text-decoration: line-through;" # close tag spanTag += '">' self.editor.insertPlainText("{0}{1}</span>".format(spanTag, selectedText)) else: self.selectTextFirst() def format_textColor(self): selectedText = self.editor.textCursor().selectedText() if selectedText: color = QColorDialog.getColor(Qt.darkRed, self) if color.isValid(): if self.html: self.editor.setTextColor(color) else: self.editor.insertPlainText('<span style="color:{0};">{1}</span>'.format(color.name(), self.editor.textCursor().selectedText())) else: self.selectTextFirst() def format_textBackgroundColor(self): selectedText = self.editor.textCursor().selectedText() if selectedText: color = QColorDialog.getColor(Qt.yellow, self) if color.isValid(): if self.html: self.editor.setTextBackgroundColor(color) else: self.editor.insertPlainText('<span style="background-color:{0};">{1}</span>'.format(color.name(), selectedText)) else: self.selectTextFirst() def format_bold(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: # Reference: https://doc.qt.io/qt-5/qfont.html#Weight-enum # Bold = 75 self.editor.setFontWeight(75) else: self.editor.insertPlainText("<b>{0}</b>".format(selectedText)) else: self.selectTextFirst() def format_italic(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setFontItalic(True) else: self.editor.insertPlainText("<i>{0}</i>".format(selectedText)) else: self.selectTextFirst() def format_underline(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setFontUnderline(True) else: self.editor.insertPlainText("<u>{0}</u>".format(selectedText)) else: self.selectTextFirst() def format_superscript(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.insertHtml("<sup>{0}</sup>".format(selectedText)) else: self.editor.insertPlainText("<sup>{0}</sup>".format(selectedText)) else: self.selectTextFirst() def format_subscript(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.insertHtml("<sub>{0}</sub>".format(selectedText)) else: self.editor.insertPlainText("<sub>{0}</sub>".format(selectedText)) else: self.selectTextFirst() def format_center(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setAlignment(Qt.AlignCenter) else: self.editor.insertPlainText("<div style='text-align:center;'>{0}</div>".format(selectedText)) else: self.selectTextFirst() def format_justify(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setAlignment(Qt.AlignJustify) else: self.editor.insertPlainText("<div style='text-align:justify;'>{0}</div>".format(selectedText)) else: self.selectTextFirst() def format_left(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setAlignment(Qt.AlignLeft) else: self.editor.insertPlainText("<div style='text-align:left;'>{0}</div>".format(selectedText)) else: self.selectTextFirst() def format_right(self): selectedText = self.editor.textCursor().selectedText() if selectedText: if self.html: self.editor.setAlignment(Qt.AlignRight) else: self.editor.insertPlainText("<div style='text-align:right;'>{0}</div>".format(selectedText)) else: self.selectTextFirst() def format_custom(self): selectedText = self.editor.textCursor().selectedText() if selectedText: selectedText = self.customFormat(selectedText) if self.html: self.editor.insertHtml(selectedText) else: self.editor.insertPlainText(selectedText) else: self.selectTextFirst() def customFormat(self, text): # QTextEdit's line break character by pressing ENTER in plain & html mode " " # please note that " " is not an empty string text = text.replace(" ", "\n") text = re.sub("^\*[0-9]+? (.*?)$", r"<ol><li>\1</li></ol>", text, flags=re.M) text = text.replace("</ol>\n<ol>", "\n") text = re.sub("^\* (.*?)$", r"<ul><li>\1</li></ul>", text, flags=re.M) text = text.replace("</ul>\n<ul>", "\n") text = re.sub("^{.*?}$", self.formatHTMLTable, text, flags=re.M) text = text.replace("</table>\n<table>", "\n") # add style to table here # please note that QTextEdit supports HTML 4, rather than HTML 5 # take this old reference: https://www.w3schools.com/tags/tag_table.asp text = text.replace('<table>', '<table border="1" cellpadding="5">') # convert back to QTextEdit linebreak text = text.replace("\n", " ") # wrap with default font and font-size text = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, text) return text def formatHTMLTable(self, match): row = match.group()[1:-1] row = "".join(["<td>{0}</td>".format(cell) for cell in row.split("|")]) return "<table><tr>{0}</tr></table>".format(row) def addInternalImage(self): self.openImageDialog(external=False) def openImageDialog(self, external=True): options = QFileDialog.Options() fileName, filtr = QFileDialog.getOpenFileName(self, config.thisTranslation["html_open"], self.parent.openFileNameLabel.text(), "JPG Files (*.jpg);;JPEG Files (*.jpeg);;PNG Files (*.png);;GIF Files (*.gif);;BMP Files (*.bmp);;All Files (*)", "", options) if fileName: if external: self.linkExternalImage(fileName) else: self.embedImage(fileName) def embedImage(self, fileName): name, extension = os.path.splitext(os.path.basename(fileName)) with open(fileName, "rb") as fileObject: binaryData = fileObject.read() encodedData = base64.b64encode(binaryData) asciiString = encodedData.decode('ascii') imageTag = '<img src="data:image/{2};base64,{0}" alt="{1}">'.format(asciiString, name, extension[1:]) if self.html: self.editor.insertHtml(imageTag) else: self.editor.insertPlainText(imageTag) def exportNoteImages(self): options = QFileDialog.DontResolveSymlinks | QFileDialog.ShowDirsOnly directory = QFileDialog.getExistingDirectory(self, config.thisTranslation["select_a_folder"], self.parent.directoryLabel.text(), options) if directory: if self.html: htmlText = self.editor.toHtml() else: htmlText = self.editor.toPlainText() searchPattern = r'src=(["{0}])data:image/([^<>]+?);[ ]*?base64,[ ]*?([^ <>]+?)\1'.format("'") for counter, value in enumerate(re.findall(searchPattern, htmlText)): *_, ext, asciiString = value binaryString = asciiString.encode("ascii") binaryData = base64.b64decode(binaryString) imageFilePath = os.path.join(directory, "image{0}.{1}".format(counter + 1, ext)) with open(imageFilePath, "wb") as fileObject: fileObject.write(binaryData) def linkExternalImage(self, fileName): imageTag = '<img src="{0}" alt="UniqueBible.app">'.format(fileName) if self.html: self.editor.insertHtml(imageTag) else: self.editor.insertPlainText(imageTag) def openHyperlinkDialog(self): selectedText = self.editor.textCursor().selectedText() if selectedText: text, ok = QInputDialog.getText(self, "UniqueBible.app", config.thisTranslation["noteTool_hyperlink"], QLineEdit.Normal, selectedText) if ok and text != '': hyperlink = '<a href="{0}">{1}</a>'.format(text, selectedText) hyperlink = """<span style="font-family:'{0}'; font-size:{1}pt;">{2}</span>""".format(config.font, config.fontSize, hyperlink) if self.html: self.editor.insertHtml(hyperlink) else: self.editor.insertPlainText(hyperlink) else: self.selectTextFirst() def setupTextUtility(self): self.ttsToolbar = QToolBar() self.ttsToolbar.setWindowTitle(config.thisTranslation["noteTool_title"]) self.ttsToolbar.setContextMenuPolicy(Qt.PreventContextMenu) # self.toolBar can be treated as an individual widget and positioned with a specified layout # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.ttsToolbar) self.languageCombo = QComboBox() self.ttsToolbar.addWidget(self.languageCombo) if config.espeak: languages = TtsLanguages().isoLang2epeakLang else: languages = TtsLanguages().isoLang2qlocaleLang self.languageCodes = list(languages.keys()) for code in self.languageCodes: self.languageCombo.addItem(languages[code][1]) # Check if selected tts engine has the language user specify. if not (config.ttsDefaultLangauge in self.languageCodes): config.ttsDefaultLangauge = "en" # Set initial item initialIndex = self.languageCodes.index(config.ttsDefaultLangauge) self.languageCombo.setCurrentIndex(initialIndex) button = QPushButton(config.thisTranslation["speak"]) button.setToolTip(config.thisTranslation["speak"]) button.clicked.connect(self.speakText) self.ttsToolbar.addWidget(button) button = QPushButton(config.thisTranslation["stop"]) button.setToolTip(config.thisTranslation["stop"]) button.clicked.connect(self.parent.textCommandParser.stopTtsAudio) self.ttsToolbar.addWidget(button) self.translateToolbar = QToolBar() self.translateToolbar.setWindowTitle(config.thisTranslation["noteTool_title"]) self.translateToolbar.setContextMenuPolicy(Qt.PreventContextMenu) # self.toolBar can be treated as an individual widget and positioned with a specified layout # In QMainWindow, the following line adds the configured QToolBar as part of the toolbar of the main window self.addToolBar(self.translateToolbar) self.fromLanguageCombo = QComboBox() self.translateToolbar.addWidget(self.fromLanguageCombo) self.fromLanguageCombo.addItems(["[Auto]"] +Translator.fromLanguageNames) initialIndex = 0 self.fromLanguageCombo.setCurrentIndex(initialIndex) button = QPushButton(config.thisTranslation["context1_translate"]) button.setToolTip(config.thisTranslation["context1_translate"]) button.clicked.connect(self.translateText) self.translateToolbar.addWidget(button) self.toLanguageCombo = QComboBox() self.translateToolbar.addWidget(self.toLanguageCombo) self.toLanguageCombo.addItems(Translator.toLanguageNames) initialIndex = Translator.toLanguageNames.index(config.userLanguage) self.toLanguageCombo.setCurrentIndex(initialIndex) def speakText(self): text = self.editor.textCursor().selectedText() if text: if config.isTtsInstalled: if ":::" in text: text = text.split(":::")[-1] command = "SPEAK:::{0}:::{1}".format(self.languageCodes[self.languageCombo.currentIndex()], text) self.parent.runTextCommand(command) else: self.displayMessage(config.thisTranslation["message_noSupport"]) else: self.selectTextFirst() def translateText(self): text = self.editor.textCursor().selectedText() if text: translator = Translator() if translator.language_translator is not None: fromLanguage = Translator.fromLanguageCodes[self.fromLanguageCombo.currentIndex() - 1] if self.fromLanguageCombo.currentIndex() != 0 else translator.identify(text) toLanguage = Translator.toLanguageCodes[self.toLanguageCombo.currentIndex()] result = translator.translate(text, fromLanguage, toLanguage) self.editor.insertPlainText(result) else: self.displayMessage(config.thisTranslation["ibmWatsonNotEnalbed"]) webbrowser.open("https://github.com/eliranwong/UniqueBible/wiki/IBM-Watson-Language-Translator") else: self.selectTextFirst() def selectTextFirst(self): self.displayMessage(config.thisTranslation["selectTextFirst"]) def displayMessage(self, message="", title="UniqueBible"): reply = QMessageBox.information(self, title, message)
class QtAbout(QDialog): """Qt dialog window for displaying 'About napari' information. Parameters ---------- parent : QWidget, optional Parent of the dialog, to correctly inherit and apply theme. Default is None. Attributes ---------- citationCopyButton : napari._qt.qt_about.QtCopyToClipboardButton Button to copy citation information to the clipboard. citationTextBox : qtpy.QtWidgets.QTextEdit Text box containing napari citation information. citation_layout : qtpy.QtWidgets.QHBoxLayout Layout widget for napari citation information. infoCopyButton : napari._qt.qt_about.QtCopyToClipboardButton Button to copy napari version information to the clipboard. info_layout : qtpy.QtWidgets.QHBoxLayout Layout widget for napari version information. infoTextBox : qtpy.QtWidgets.QTextEdit Text box containing napari version information. layout : qtpy.QtWidgets.QVBoxLayout Layout widget for the entire 'About napari' dialog. """ def __init__(self, parent=None): super().__init__(parent) self.layout = QVBoxLayout() # Description title_label = QLabel( trans._( "<b>napari: a multi-dimensional image viewer for python</b>")) title_label.setTextInteractionFlags(Qt.TextSelectableByMouse) self.layout.addWidget(title_label) # Add information self.infoTextBox = QTextEdit() self.infoTextBox.setTextInteractionFlags(Qt.TextSelectableByMouse) self.infoTextBox.setLineWrapMode(QTextEdit.NoWrap) # Add text copy button self.infoCopyButton = QtCopyToClipboardButton(self.infoTextBox) self.info_layout = QHBoxLayout() self.info_layout.addWidget(self.infoTextBox, 1) self.info_layout.addWidget(self.infoCopyButton, 0, Qt.AlignTop) self.info_layout.setAlignment(Qt.AlignTop) self.layout.addLayout(self.info_layout) self.infoTextBox.setText(sys_info(as_html=True)) self.infoTextBox.setMinimumSize( int(self.infoTextBox.document().size().width() + 19), int(min(self.infoTextBox.document().size().height() + 10, 500)), ) self.layout.addWidget(QLabel(trans._('<b>citation information:</b>'))) self.citationTextBox = QTextEdit(citation_text) self.citationTextBox.setFixedHeight(64) self.citationCopyButton = QtCopyToClipboardButton(self.citationTextBox) self.citation_layout = QHBoxLayout() self.citation_layout.addWidget(self.citationTextBox, 1) self.citation_layout.addWidget(self.citationCopyButton, 0, Qt.AlignTop) self.layout.addLayout(self.citation_layout) self.setLayout(self.layout) @staticmethod def showAbout(parent=None): """Display the 'About napari' dialog box. Parameters ---------- parent : QWidget, optional Parent of the dialog, to correctly inherit and apply theme. Default is None. """ d = QtAbout(parent) d.setObjectName('QtAbout') d.setWindowTitle(trans._('About')) d.setWindowModality(Qt.ApplicationModal) d.exec_()
class QtAbout(QDialog): """Qt dialog window for displaying 'About napari' information. Attributes ---------- citationCopyButton : napari._qt.qt_about.QtCopyToClipboardButton Button to copy citation information to the clipboard. citationTextBox : qtpy.QtWidgets.QTextEdit Text box containing napari citation information. citation_layout : qtpy.QtWidgets.QHBoxLayout Layout widget for napari citation information. infoCopyButton : napari._qt.qt_about.QtCopyToClipboardButton Button to copy napari version information to the clipboard. info_layout : qtpy.QtWidgets.QHBoxLayout Layout widget for napari version information. infoTextBox : qtpy.QtWidgets.QTextEdit Text box containing napari version information. layout : qtpy.QtWidgets.QVBoxLayout Layout widget for the entire 'About napari' dialog. """ def __init__(self): super().__init__() self.layout = QVBoxLayout() # Description title_label = QLabel( "<b>napari: a multi-dimensional image viewer for python</b>") title_label.setTextInteractionFlags(Qt.TextSelectableByMouse) self.layout.addWidget(title_label) # Add information self.infoTextBox = QTextEdit() self.infoTextBox.setTextInteractionFlags(Qt.TextSelectableByMouse) self.infoTextBox.setLineWrapMode(QTextEdit.NoWrap) # Add text copy button self.infoCopyButton = QtCopyToClipboardButton(self.infoTextBox) self.info_layout = QHBoxLayout() self.info_layout.addWidget(self.infoTextBox, 1) self.info_layout.addWidget(self.infoCopyButton, 0, Qt.AlignTop) self.info_layout.setAlignment(Qt.AlignTop) self.layout.addLayout(self.info_layout) self.infoTextBox.setText(sys_info(as_html=True)) self.infoTextBox.setMinimumSize( self.infoTextBox.document().size().width() + 19, self.infoTextBox.document().size().height() + 10, ) self.layout.addWidget(QLabel('<b>citation information:</b>')) self.citationTextBox = QTextEdit(citation_text) self.citationTextBox.setFixedHeight(64) self.citationCopyButton = QtCopyToClipboardButton(self.citationTextBox) self.citation_layout = QHBoxLayout() self.citation_layout.addWidget(self.citationTextBox, 1) self.citation_layout.addWidget(self.citationCopyButton, 0, Qt.AlignTop) self.layout.addLayout(self.citation_layout) self.setLayout(self.layout) @staticmethod def showAbout(qt_viewer): """Display the 'About napari' dialog box. Paramters --------- qt_viewer : QtViewer QtViewer instance that the `About napari` dialog box belongs to. """ d = QtAbout() d.setObjectName('QtAbout') d.setStyleSheet(qt_viewer.styleSheet()) d.setWindowTitle('About') d.setWindowModality(Qt.ApplicationModal) d.exec_()
def on_edit(self): list_widget = self.toolbox.currentWidget() curr_row = list_widget.currentRow() if curr_row >= 0: group_name = self.toolbox.itemText(self.toolbox.currentIndex()) curr_text = list_widget.currentItem().text() dic = self.node_info_dic[group_name][curr_text] edit_layout = QHBoxLayout() input_widget = QTextEdit() edit_layout.addWidget(input_widget) check_button = QPushButton(text='check') edit_layout.addWidget(check_button) input_widget.setText(repr(dic['params'])) views = [('line_ctrl', 'text', 'Node Text', dic['text']), ('check_ctrl', 'inputs_changeable', 'Input Ports Changeable', dic['ports_changeable'][0]), ('check_ctrl', 'outputs_changeable', 'Output Ports Changeble', dic['ports_changeable'][1]), ('editor_ctrl', 'code', 'Input Python Code', dic['code'], 'python'), ('list_ctrl', 'inputs', 'Set Inputs', [[None] * len(dic['inputs']), dic['inputs']], lambda: None), ('list_ctrl', 'outputs', 'Set Outputs', [[None] * len(dic['outputs']), dic['outputs']], lambda: None), ('file_ctrl', 'icon', 'Set Icon', dic['icon']), ('combo_ctrl', 'group', 'Group Name', dic['group'], self.groups)] sp = PMGPanel(parent=None, views=views) dialog = QDialog(self) def verify(): try: text = input_widget.document().toPlainText() l = eval(text) if isinstance(l, list): dialog2 = QDialog(dialog) sp2 = PMGPanel(parent=None, views=l) dialog2.setLayout(QHBoxLayout()) dialog2.layout().addWidget(sp2) dialog2.layout().addLayout(edit_layout) dialog2.exec_() except: import traceback traceback.print_exc() check_button.clicked.connect(verify) dialog.setLayout(QVBoxLayout()) dialog.layout().addWidget(sp) dialog.layout().addLayout(edit_layout) dialog.exec_() dic = sp.get_value() params = None try: params = eval(input_widget.document().toPlainText()) except: import traceback traceback.print_exc() group = self.get_current_list_widget_group() if isinstance(params, list): self.node_info_dic[group][curr_text]['params'] = params self.node_info_dic[group][curr_text]['text'] = dic['text'] self.node_info_dic[group][curr_text]['icon'] = dic['icon'] self.node_info_dic[group][curr_text]['code'] = dic['code'] self.node_info_dic[group][curr_text]['inputs'] = dic['inputs'][1] self.node_info_dic[group][curr_text]['outputs'] = dic['outputs'][1] self.node_info_dic[group][curr_text]['group'] = dic['group'] self.node_info_dic[group][curr_text]['ports_changeable'] = [ dic['inputs_changeable'], dic['outputs_changeable'] ] list_widget.item(curr_row).setText(dic['text']) self.save_node_templetes() self.load_nodes() else: return