pygui: update title to show xml file when one is opened, fixed issue creating nodes/links when not runtime due to refactoring, removed xml_file from coreclient and depend on the grpc GetSession wrapped data, grpc: added opened file information to GetSession call

This commit is contained in:
Blake Harnden 2020-08-01 11:00:26 -07:00
parent 04f7bc561b
commit fc44ad6fe8
7 changed files with 48 additions and 47 deletions

View file

@ -229,7 +229,7 @@ def get_config_options(
""" """
results = {} results = {}
for configuration in configurable_options.configurations(): for configuration in configurable_options.configurations():
value = config[configuration.id] value = config.get(configuration.id, configuration.default)
config_option = common_pb2.ConfigOption( config_option = common_pb2.ConfigOption(
label=configuration.label, label=configuration.label,
name=configuration.id, name=configuration.id,

View file

@ -597,6 +597,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
config_service_configs=config_service_configs, config_service_configs=config_service_configs,
mobility_configs=mobility_configs, mobility_configs=mobility_configs,
metadata=session.metadata, metadata=session.metadata,
file=session.file_name,
) )
return core_pb2.GetSessionResponse(session=session_proto) return core_pb2.GetSessionResponse(session=session_proto)

View file

@ -22,7 +22,7 @@ from core.api.grpc import (
wlan_pb2, wlan_pb2,
) )
from core.gui import appconfig from core.gui import appconfig
from core.gui.appconfig import 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.error import ErrorDialog
from core.gui.dialogs.mobilityplayer import MobilityPlayer from core.gui.dialogs.mobilityplayer import MobilityPlayer
@ -98,8 +98,6 @@ class CoreClient:
self.handling_throughputs: Optional[grpc.Future] = None self.handling_throughputs: Optional[grpc.Future] = None
self.handling_cpu_usage: Optional[grpc.Future] = None self.handling_cpu_usage: Optional[grpc.Future] = None
self.handling_events: Optional[grpc.Future] = None self.handling_events: Optional[grpc.Future] = None
self.xml_dir: Optional[str] = None
self.xml_file: Optional[str] = None
@property @property
def client(self) -> client.CoreGrpcClient: def client(self) -> client.CoreGrpcClient:
@ -311,7 +309,8 @@ class CoreClient:
response = self.client.get_session(session_id) response = self.client.get_session(session_id)
self.session = Session.from_proto(response.session) self.session = Session.from_proto(response.session)
self.client.set_session_user(self.session.id, self.user) self.client.set_session_user(self.session.id, self.user)
self.master.title(f"CORE Session({self.session.id})") title_file = self.session.file.name if self.session.file else ""
self.master.title(f"CORE Session({self.session.id}) {title_file}")
self.handling_events = self.client.events( self.handling_events = self.client.events(
self.session.id, self.handle_events self.session.id, self.handle_events
) )
@ -586,10 +585,18 @@ class CoreClient:
except grpc.RpcError as e: except grpc.RpcError as e:
self.app.show_grpc_exception("Node Terminal Error", e) self.app.show_grpc_exception("Node Terminal Error", e)
def save_xml(self, file_path: str) -> None: def get_xml_dir(self) -> str:
return str(self.session.file.parent) if self.session.file else str(XMLS_PATH)
def save_xml(self, file_path: str = None) -> None:
""" """
Save core session as to an xml file Save core session as to an xml file
""" """
if not file_path and not self.session.file:
logging.error("trying to save xml for session with no file")
return
if not file_path:
file_path = str(self.session.file)
try: try:
if not self.is_runtime(): if not self.is_runtime():
logging.debug("Send session data to the daemon") logging.debug("Send session data to the daemon")
@ -687,34 +694,17 @@ class CoreClient:
""" """
self.client.set_session_state(self.session.id, SessionState.DEFINITION.value) self.client.set_session_state(self.session.id, SessionState.DEFINITION.value)
for node in self.session.nodes.values(): for node in self.session.nodes.values():
response = self.client.add_node(self.session.id, node.to_proto()) response = self.client.add_node(
self.session.id, node.to_proto(), source=GUI_SOURCE
)
logging.debug("created node: %s", response) logging.debug("created node: %s", response)
asymmetric_links = [] asymmetric_links = []
for edge in self.links.values(): for edge in self.links.values():
link = edge.link self.add_link(edge.link)
response = self.client.add_link(
self.session.id,
link.node1_id,
link.node2_id,
link.iface1,
link.iface2,
link.options,
source=GUI_SOURCE,
)
logging.debug("created link: %s", response)
if edge.asymmetric_link: if edge.asymmetric_link:
asymmetric_links.append(edge.asymmetric_link) asymmetric_links.append(edge.asymmetric_link)
for link in asymmetric_links: for link in asymmetric_links:
response = self.client.add_link( self.add_link(link)
self.session.id,
link.node1_id,
link.node2_id,
link.iface1,
link.iface2,
link.options,
source=GUI_SOURCE,
)
logging.debug("created asymmetric link: %s", response)
def send_data(self) -> None: def send_data(self) -> None:
""" """
@ -1057,6 +1047,23 @@ class CoreClient:
if response.session_id != -1: if response.session_id != -1:
self.join_session(response.session_id) self.join_session(response.session_id)
def add_link(self, link: Link) -> None:
iface1 = link.iface1.to_proto() if link.iface1 else None
iface2 = link.iface2.to_proto() if link.iface2 else None
options = link.options.to_proto() if link.options else None
response = self.client.add_link(
self.session.id,
link.node1_id,
link.node2_id,
iface1,
iface2,
options,
source=GUI_SOURCE,
)
logging.debug("added link: %s", response)
if not response.result:
logging.error("error adding link: %s", link)
def edit_link(self, link: Link) -> None: def edit_link(self, link: Link) -> None:
iface1_id = link.iface1.id if link.iface1 else None iface1_id = link.iface1.id if link.iface1 else None
iface2_id = link.iface2.id if link.iface2 else None iface2_id = link.iface2.id if link.iface2 else None

View file

@ -181,8 +181,6 @@ class SessionsDialog(Dialog):
def join_session(self, session_id: int) -> None: def join_session(self, session_id: int) -> None:
self.destroy() self.destroy()
if self.app.core.xml_file:
self.app.core.xml_file = None
task = ProgressTask( task = ProgressTask(
self.app, "Join", self.app.core.join_session, args=(session_id,) self.app, "Join", self.app.core.join_session, args=(session_id,)
) )

View file

@ -6,7 +6,6 @@ from functools import partial
from tkinter import filedialog, messagebox from tkinter import filedialog, messagebox
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from core.gui.appconfig import XMLS_PATH
from core.gui.coreclient import CoreClient from core.gui.coreclient import CoreClient
from core.gui.dialogs.about import AboutDialog from core.gui.dialogs.about import AboutDialog
from core.gui.dialogs.canvassizeandscale import SizeAndScaleDialog from core.gui.dialogs.canvassizeandscale import SizeAndScaleDialog
@ -265,16 +264,13 @@ class Menubar(tk.Menu):
) )
def click_save(self, _event=None) -> None: def click_save(self, _event=None) -> None:
xml_file = self.core.xml_file if self.core.session.file:
if xml_file: self.core.save_xml()
self.core.save_xml(xml_file)
else: else:
self.click_save_xml() self.click_save_xml()
def click_save_xml(self, _event: tk.Event = None) -> None: def click_save_xml(self, _event: tk.Event = None) -> None:
init_dir = self.core.xml_dir init_dir = self.core.get_xml_dir()
if not init_dir:
init_dir = str(XMLS_PATH)
file_path = filedialog.asksaveasfilename( file_path = filedialog.asksaveasfilename(
initialdir=init_dir, initialdir=init_dir,
title="Save As", title="Save As",
@ -284,12 +280,9 @@ class Menubar(tk.Menu):
if file_path: if file_path:
self.add_recent_file_to_gui_config(file_path) self.add_recent_file_to_gui_config(file_path)
self.core.save_xml(file_path) self.core.save_xml(file_path)
self.core.xml_file = file_path
def click_open_xml(self, _event: tk.Event = None) -> None: def click_open_xml(self, _event: tk.Event = None) -> None:
init_dir = self.core.xml_dir init_dir = self.core.get_xml_dir()
if not init_dir:
init_dir = str(XMLS_PATH)
file_path = filedialog.askopenfilename( file_path = filedialog.askopenfilename(
initialdir=init_dir, initialdir=init_dir,
title="Open", title="Open",
@ -298,12 +291,10 @@ class Menubar(tk.Menu):
if file_path: if file_path:
self.open_xml_task(file_path) self.open_xml_task(file_path)
def open_xml_task(self, filename: str) -> None: def open_xml_task(self, file_path: str) -> None:
self.add_recent_file_to_gui_config(filename) self.add_recent_file_to_gui_config(file_path)
self.core.xml_file = filename
self.core.xml_dir = str(os.path.dirname(filename))
self.prompt_save_running_session() self.prompt_save_running_session()
task = ProgressTask(self.app, "Open XML", self.core.open_xml, args=(filename,)) task = ProgressTask(self.app, "Open XML", self.core.open_xml, args=(file_path,))
task.start() task.start()
def execute_python(self) -> None: def execute_python(self) -> None:
@ -357,7 +348,6 @@ class Menubar(tk.Menu):
def click_new(self) -> None: def click_new(self) -> None:
self.prompt_save_running_session() self.prompt_save_running_session()
self.core.create_new_session() self.core.create_new_session()
self.core.xml_file = None
def click_find(self, _event: tk.Event = None) -> None: def click_find(self, _event: tk.Event = None) -> None:
dialog = FindDialog(self.app) dialog = FindDialog(self.app)

View file

@ -1,5 +1,6 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from enum import Enum from enum import Enum
from pathlib import Path
from typing import Dict, List, Optional, Set, Tuple from typing import Dict, List, Optional, Set, Tuple
from core.api.grpc import common_pb2, configservices_pb2, core_pb2, services_pb2 from core.api.grpc import common_pb2, configservices_pb2, core_pb2, services_pb2
@ -581,6 +582,7 @@ class Session:
emane_models: List[str] emane_models: List[str]
emane_config: Dict[str, ConfigOption] emane_config: Dict[str, ConfigOption]
metadata: Dict[str, str] metadata: Dict[str, str]
file: Path
@classmethod @classmethod
def from_proto(cls, proto: core_pb2.Session) -> "Session": def from_proto(cls, proto: core_pb2.Session) -> "Session":
@ -616,6 +618,7 @@ class Session:
for node_id, mapped_config in proto.mobility_configs.items(): for node_id, mapped_config in proto.mobility_configs.items():
node = nodes[node_id] node = nodes[node_id]
node.mobility_config = ConfigOption.from_dict(mapped_config.config) node.mobility_config = ConfigOption.from_dict(mapped_config.config)
file_path = Path(proto.file) if proto.file else None
return Session( return Session(
id=proto.id, id=proto.id,
state=SessionState(proto.state), state=SessionState(proto.state),
@ -629,6 +632,7 @@ class Session:
emane_models=list(proto.emane_models), emane_models=list(proto.emane_models),
emane_config=ConfigOption.from_dict(proto.emane_config), emane_config=ConfigOption.from_dict(proto.emane_config),
metadata=dict(proto.metadata), metadata=dict(proto.metadata),
file=file_path,
) )

View file

@ -726,6 +726,7 @@ message Session {
repeated configservices.ConfigServiceConfig config_service_configs = 15; repeated configservices.ConfigServiceConfig config_service_configs = 15;
map<int32, common.MappedConfig> mobility_configs = 16; map<int32, common.MappedConfig> mobility_configs = 16;
map<string, string> metadata = 17; map<string, string> metadata = 17;
string file = 18;
} }
message SessionSummary { message SessionSummary {