pygui: added simple error dialog call to app, also added blocking option for some error dialogs when needed

This commit is contained in:
Blake Harnden 2021-02-19 10:35:59 -08:00
parent 2387812a76
commit b163b06596
4 changed files with 37 additions and 21 deletions

View file

@ -1,7 +1,7 @@
import logging import logging
import math import math
import tkinter as tk import tkinter as tk
from tkinter import PhotoImage, font, ttk from tkinter import PhotoImage, font, messagebox, ttk
from tkinter.ttk import Progressbar from tkinter.ttk import Progressbar
from typing import Any, Dict, Optional, Type from typing import Any, Dict, Optional, Type
@ -168,17 +168,30 @@ class Application(ttk.Frame):
def hide_info(self) -> None: def hide_info(self) -> None:
self.infobar.grid_forget() self.infobar.grid_forget()
def show_grpc_exception(self, title: str, e: grpc.RpcError) -> None: def show_grpc_exception(
self, message: str, e: grpc.RpcError, blocking: bool = False
) -> None:
logging.exception("app grpc exception", exc_info=e) logging.exception("app grpc exception", exc_info=e)
message = e.details() dialog = ErrorDialog(self, "GRPC Exception", message, e.details())
self.show_error(title, message) if blocking:
dialog.show()
else:
self.after(0, lambda: dialog.show())
def show_exception(self, title: str, e: Exception) -> None: def show_exception(self, message: str, e: Exception) -> None:
logging.exception("app exception", exc_info=e) logging.exception("app exception", exc_info=e)
self.show_error(title, str(e)) self.after(
0, lambda: ErrorDialog(self, "App Exception", message, str(e)).show()
)
def show_error(self, title: str, message: str) -> None: def show_exception_data(self, title: str, message: str, details: str) -> None:
self.after(0, lambda: ErrorDialog(self, title, message).show()) self.after(0, lambda: ErrorDialog(self, title, message, details).show())
def show_error(self, title: str, message: str, blocking: bool = False) -> None:
if blocking:
messagebox.showerror(title, message, parent=self)
else:
self.after(0, lambda: messagebox.showerror(title, message, parent=self))
def on_closing(self) -> None: def on_closing(self) -> None:
if self.toolbar.picker: if self.toolbar.picker:

View file

@ -41,7 +41,6 @@ from core.api.grpc.wrappers import (
from core.gui import nodeutils as nutils from core.gui import nodeutils as nutils
from core.gui.appconfig import XMLS_PATH, CoreServer, Observer from core.gui.appconfig import XMLS_PATH, CoreServer, Observer
from core.gui.dialogs.emaneinstall import EmaneInstallDialog from core.gui.dialogs.emaneinstall import EmaneInstallDialog
from core.gui.dialogs.error import ErrorDialog
from core.gui.dialogs.mobilityplayer import MobilityPlayer from core.gui.dialogs.mobilityplayer import MobilityPlayer
from core.gui.dialogs.sessions import SessionsDialog from core.gui.dialogs.sessions import SessionsDialog
from core.gui.graph.edges import CanvasEdge from core.gui.graph.edges import CanvasEdge
@ -418,10 +417,11 @@ class CoreClient:
if session_id: if session_id:
session_ids = set(x.id for x in sessions) session_ids = set(x.id for x in sessions)
if session_id not in session_ids: if session_id not in session_ids:
dialog = ErrorDialog( self.app.show_error(
self.app, "Join Session Error", f"{session_id} does not exist" "Join Session Error",
f"{session_id} does not exist",
blocking=True,
) )
dialog.show()
self.app.close() self.app.close()
else: else:
self.join_session(session_id) self.join_session(session_id)
@ -433,8 +433,7 @@ class CoreClient:
dialog.show() dialog.show()
except grpc.RpcError as e: except grpc.RpcError as e:
logging.exception("core setup error") logging.exception("core setup error")
dialog = ErrorDialog(self.app, "Setup Error", e.details()) self.app.show_grpc_exception("Setup Error", e, blocking=True)
dialog.show()
self.app.close() self.app.close()
def edit_node(self, core_node: Node) -> None: def edit_node(self, core_node: Node) -> None:

View file

@ -13,9 +13,11 @@ if TYPE_CHECKING:
class ErrorDialog(Dialog): class ErrorDialog(Dialog):
def __init__(self, app: "Application", title: str, details: str) -> None: def __init__(
super().__init__(app, "CORE Exception") self, app: "Application", title: str, message: str, details: str
self.title: str = title ) -> None:
super().__init__(app, title)
self.message: str = message
self.details: str = details self.details: str = details
self.error_message: Optional[CodeText] = None self.error_message: Optional[CodeText] = None
self.draw() self.draw()
@ -25,13 +27,13 @@ class ErrorDialog(Dialog):
self.top.rowconfigure(1, weight=1) self.top.rowconfigure(1, weight=1)
image = images.from_enum(ImageEnum.ERROR, width=images.ERROR_SIZE) image = images.from_enum(ImageEnum.ERROR, width=images.ERROR_SIZE)
label = ttk.Label( label = ttk.Label(
self.top, text=self.title, image=image, compound=tk.LEFT, anchor=tk.CENTER self.top, text=self.message, image=image, compound=tk.LEFT, anchor=tk.CENTER
) )
label.image = image label.image = image
label.grid(sticky=tk.EW, pady=PADY) label.grid(sticky=tk.W, pady=PADY)
self.error_message = CodeText(self.top) self.error_message = CodeText(self.top)
self.error_message.text.insert("1.0", self.details) self.error_message.text.insert("1.0", self.details)
self.error_message.text.config(state=tk.DISABLED) self.error_message.text.config(state=tk.DISABLED)
self.error_message.grid(sticky=tk.NSEW, pady=PADY) self.error_message.grid(sticky=tk.EW, pady=PADY)
button = ttk.Button(self.top, text="Close", command=lambda: self.destroy()) button = ttk.Button(self.top, text="Close", command=lambda: self.destroy())
button.grid(sticky=tk.EW) button.grid(sticky=tk.EW)

View file

@ -310,7 +310,9 @@ class Toolbar(ttk.Frame):
enable_buttons(self.design_frame, enabled=True) enable_buttons(self.design_frame, enabled=True)
if exceptions: if exceptions:
message = "\n".join(exceptions) message = "\n".join(exceptions)
self.app.show_error("Start Session Error", message) self.app.show_exception_data(
"Start Exception", "Session failed to start", message
)
def set_runtime(self) -> None: def set_runtime(self) -> None:
enable_buttons(self.runtime_frame, enabled=True) enable_buttons(self.runtime_frame, enabled=True)