def check_executable_path_error_qt(path: Path, /) -> None: """Display an error using Qt about the app not running from the right path.""" from nxdrive.qt import constants as qt from nxdrive.qt.imports import QApplication, QMessageBox, QPixmap from nxdrive.translator import Translator from nxdrive.utils import find_icon, find_resource app = QApplication([]) app.setQuitOnLastWindowClosed(True) Translator(find_resource("i18n")) content = Translator.get("RUNNING_FROM_WRONG_PATH", values=[str(path), f"{APP_NAME}.app"]) icon = QPixmap(str(find_icon("app_icon.svg"))) msg = QMessageBox() msg.setIconPixmap(icon) msg.setText(content) msg.setWindowTitle(APP_NAME) msg.addButton(Translator.get("QUIT"), qt.AcceptRole) msg.exec_()
def fatal_error_qt(exc_formatted: str) -> None: """Display a "friendly" dialog box on fatal error using Qt.""" from PyQt5.QtCore import Qt, QUrl from PyQt5.QtGui import QDesktopServices, QIcon from PyQt5.QtWidgets import ( QApplication, QDialog, QDialogButtonBox, QLabel, QTextEdit, QVBoxLayout, ) from nxdrive.translator import Translator from nxdrive.utils import find_icon, find_resource def section(header: str, content: str) -> str: """Format a "section" of information.""" return f"{header}\n```\n{content.strip()}\n```" Translator(find_resource("i18n")) tr = Translator.get app = QApplication([]) app.setQuitOnLastWindowClosed(True) dialog = QDialog() dialog.setWindowTitle(tr("FATAL_ERROR_TITLE", [APP_NAME])) dialog.setWindowIcon(QIcon(str(find_icon("app_icon.svg")))) dialog.resize(800, 600) layout = QVBoxLayout() css = "font-family: monospace; font-size: 12px;" details = [] # Display a little message to apologize info = QLabel(tr("FATAL_ERROR_MSG", [APP_NAME, COMPANY])) info.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) layout.addWidget(info) # Display CLI arguments if sys.argv[1:]: text = tr("FATAL_ERROR_CLI_ARGS") label_cli = QLabel(text) label_cli.setAlignment(Qt.AlignVCenter) cli_args = QTextEdit() cli_args.setStyleSheet(css) cli_args.setReadOnly(True) args = "\n".join(arg for arg in sys.argv[1:]) details.append(section(text, args)) cli_args.setText(args) cli_args.setSizeAdjustPolicy(QTextEdit.AdjustToContents) layout.addWidget(label_cli) layout.addWidget(cli_args) # Display the exception text = tr("FATAL_ERROR_EXCEPTION") label_exc = QLabel(text) label_exc.setAlignment(Qt.AlignVCenter) exception = QTextEdit() exception.setStyleSheet(css) exception.setReadOnly(True) details.append(section(text, exc_formatted)) exception.setText(exc_formatted) layout.addWidget(label_exc) layout.addWidget(exception) # Display last lines from the memory log with suppress(Exception): from nxdrive.report import Report # Last 20th lines raw_lines = Report.export_logs(-20) lines = b"\n".join(raw_lines).decode(errors="replace") if lines: text = tr("FATAL_ERROR_LOGS") label_log = QLabel(text) details.append(section(text, lines)) label_log.setAlignment(Qt.AlignVCenter) layout.addWidget(label_log) logs = QTextEdit() logs.setStyleSheet(css) logs.setReadOnly(True) logs.setLineWrapColumnOrWidth(4096) logs.setLineWrapMode(QTextEdit.FixedPixelWidth) logs.setText(lines) layout.addWidget(logs) def open_update_site() -> None: """Open the update web site.""" with suppress(Exception): QDesktopServices.openUrl(QUrl(Options.update_site_url)) # Buttons buttons = QDialogButtonBox() buttons.setStandardButtons(QDialogButtonBox.Ok) buttons.accepted.connect(dialog.close) update_button = buttons.addButton(tr("FATAL_ERROR_UPDATE_BTN"), QDialogButtonBox.ActionRole) update_button.setToolTip(tr("FATAL_ERROR_UPDATE_TOOLTIP", [APP_NAME])) update_button.clicked.connect(open_update_site) layout.addWidget(buttons) def copy() -> None: """Copy details to the clipboard and change the text of the button. """ osi.cb_set("\n".join(details)) copy_paste.setText(tr("FATAL_ERROR_DETAILS_COPIED")) # "Copy details" button with suppress(Exception): from nxdrive.osi import AbstractOSIntegration osi = AbstractOSIntegration.get(None) copy_paste = buttons.addButton(tr("FATAL_ERROR_DETAILS_COPY"), QDialogButtonBox.ActionRole) copy_paste.clicked.connect(copy) dialog.setLayout(layout) dialog.show() app.exec_()
def show_critical_error() -> None: """ Display a "friendly" dialog box on fatal error. """ import traceback from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import ( QApplication, QDialog, QDialogButtonBox, QLabel, QTextEdit, QVBoxLayout, ) app = QApplication([]) app.setQuitOnLastWindowClosed(True) dialog = QDialog() dialog.setWindowTitle("Nuxeo Drive - Fatal error") dialog.resize(600, 400) layout = QVBoxLayout() css = "font-family: monospace; font-size: 12px;" details = ["Exception:"] with suppress(Exception): from nxdrive.utils import find_icon dialog.setWindowIcon(QIcon(find_icon("app_icon.svg"))) # Display a little message to apologize text = f"""Ooops! Unfortunately, a fatal error occurred and Nuxeo Drive has stopped. Please share the following informations with Nuxeo support : we’ll do our best to fix it! """ info = QLabel(text) info.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) layout.addWidget(info) # Display the the exception label_exc = QLabel("Exception:") label_exc.setAlignment(Qt.AlignVCenter) exception = QTextEdit() exception.setStyleSheet(css) exception.setReadOnly(True) exc_formatted = traceback.format_exception(*sys.exc_info()) details += exc_formatted exception.setText("".join(exc_formatted)) layout.addWidget(label_exc) layout.addWidget(exception) # Display last lines from the memory log with suppress(Exception): from nxdrive.report import Report # Last 20th lines lines = Report.export_logs(-20) lines = b"\n".join(lines).decode(errors="replace") details += ["Logs before the crash:", lines] label_log = QLabel("Logs before the crash:") label_log.setAlignment(Qt.AlignVCenter) layout.addWidget(label_log) logs = QTextEdit() logs.setStyleSheet(css) logs.setReadOnly(True) logs.setLineWrapColumnOrWidth(4096) logs.setLineWrapMode(QTextEdit.FixedPixelWidth) logs.setText(lines) layout.addWidget(logs) # Buttons buttons = QDialogButtonBox() buttons.setStandardButtons(QDialogButtonBox.Ok) buttons.accepted.connect(dialog.close) layout.addWidget(buttons) def copy() -> None: """Copy details to the clipboard and change the text of the button. """ copy_to_clipboard("\n".join(details)) copy_paste.setText("Details copied!") # "Copy details" button with suppress(Exception): from nxdrive.utils import copy_to_clipboard copy_paste = buttons.addButton("Copy details", QDialogButtonBox.ActionRole) copy_paste.clicked.connect(copy) dialog.setLayout(layout) dialog.show() app.exec_()