Source code for rkviewer.mvc

# pylint: disable=maybe-no-member
from dataclasses import dataclass
from enum import Enum
from rkviewer.config import Color
import wx
import abc
import copy
from typing import Any, List, Optional, Set, Tuple
from .canvas.geometry import Vec2
from .canvas.data import Compartment, Node, Reaction, ModifierTipStyle, CompositeShape


[docs]class IController(abc.ABC): """The inteface class for a controller The abc.ABC (Abstract Base Class) is used to enforce the MVC interface more strictly. The methods with name beginning with Try- are usually called by the RKView after some user input. If the action tried in such a method succeeds, the Controller should request the view to be redrawn; otherwise, an error message might be shown. """
[docs] @abc.abstractmethod def group_action(self) -> Any: pass
[docs] @abc.abstractmethod def undo(self) -> bool: """Try to undo last operation""" pass
[docs] @abc.abstractmethod def redo(self) -> bool: """Try to redo last undone operation""" pass
[docs] @abc.abstractmethod def clear_network(self, neti: int): pass
[docs] @abc.abstractmethod def add_node_g(self, neti: int, node: Node) -> int: """Try to add the given Node to the canvas. Return index of the node added.""" pass
[docs] @abc.abstractmethod def add_compartment_g(self, neti: int, compartment: Compartment) -> int: """Try to add the given Compartment to the canvas. Return index of added comp.""" pass
[docs] @abc.abstractmethod def add_alias_node(self, neti: int, original_index: int, pos: Vec2, size: Vec2) -> int: pass
[docs] @abc.abstractmethod def alias_for_reaction(self, neti: int, reai: int, nodei: int, pos: Vec2, size: Vec2): """See Iodine aliasForReaction for documentation""" pass
[docs] @abc.abstractmethod def move_node(self, neti: int, nodei: int, pos: Vec2, allowNegativeCoords: bool = False) -> bool: """Try to move the give node. TODO only accept node ID and new location""" pass
[docs] @abc.abstractmethod def set_node_size(self, neti: int, nodei: int, size: Vec2) -> bool: """Try to move the give node. TODO only accept node ID and new location""" pass
[docs] @abc.abstractmethod def rename_node(self, neti: int, nodei: int, new_id: str) -> bool: pass
[docs] @abc.abstractmethod def set_node_floating_status(self, neti: int, nodei: int, floatingStatus: bool): pass
[docs] @abc.abstractmethod def set_node_locked_status(self, neti: int, nodei: int, lockedNode: bool): pass
[docs] @abc.abstractmethod def set_node_fill_rgb(self, neti: int, nodei: int, color: wx.Colour) -> bool: pass
[docs] @abc.abstractmethod def set_node_fill_alpha(self, neti: int, nodei: int, alpha: int) -> bool: pass
[docs] @abc.abstractmethod def set_node_border_rgb(self, neti: int, nodei: int, color: wx.Colour) -> bool: pass
[docs] @abc.abstractmethod def set_node_border_alpha(self, neti: int, nodei: int, alpha: int) -> bool: pass
[docs] @abc.abstractmethod def set_node_border_width(self, neti: int, nodei: int, width: float) -> bool: pass
[docs] @abc.abstractmethod def rename_reaction(self, neti: int, reai: int, new_id: str) -> bool: pass
[docs] @abc.abstractmethod def set_reaction_line_thickness(self, neti: int, reai: int, thickness: float) -> bool: pass
[docs] @abc.abstractmethod def set_reaction_fill_rgb(self, neti: int, reai: int, color: wx.Colour) -> bool: pass
[docs] @abc.abstractmethod def set_reaction_fill_alpha(self, neti: int, reai: int, alpha: int) -> bool: pass
[docs] @abc.abstractmethod def set_reaction_ratelaw(self, neti: int, reai: int, ratelaw: str) -> bool: pass
[docs] @abc.abstractmethod def set_reaction_center(self, neti: int, reai: int, center_pos: Optional[Vec2]): pass
[docs] @abc.abstractmethod def set_reaction_modifiers(self, neti: int, reai: int, modifiers: List[int]): pass
[docs] @abc.abstractmethod def get_reaction_modifiers(self, neti: int, reai: int) -> List[int]: pass
[docs] @abc.abstractmethod def set_modifier_tip_style(self, neti: int, reai: int, style: ModifierTipStyle): pass
[docs] @abc.abstractmethod def get_modifier_tip_style(self, neti: int, reai: int) -> ModifierTipStyle: pass
[docs] @abc.abstractmethod def delete_node(self, neti: int, nodei: int) -> bool: pass
[docs] @abc.abstractmethod def delete_reaction(self, neti: int, reai: int) -> bool: pass
[docs] @abc.abstractmethod def delete_compartment(self, neti: int, compi: int) -> bool: pass
[docs] @abc.abstractmethod def set_src_node_stoich(self, neti: int, reai: int, nodei: int, stoich: float) -> bool: pass
[docs] @abc.abstractmethod def get_dest_node_stoich(self, neti: int, reai: int, nodei: int) -> float: pass
[docs] @abc.abstractmethod def set_dest_node_stoich(self, neti: int, reai: int, nodei: int, stoich: float) -> bool: pass
[docs] @abc.abstractmethod def get_src_node_stoich(self, neti: int, reai: int, nodei: int) -> float: pass
[docs] @abc.abstractmethod def set_src_node_handle(self, neti: int, reai: int, nodei: int, pos: Vec2): pass
[docs] @abc.abstractmethod def set_dest_node_handle(self, neti: int, reai: int, nodei: int, pos: Vec2): pass
[docs] @abc.abstractmethod def set_center_handle(self, neti: int, reai: int, pos: Vec2): pass
[docs] @abc.abstractmethod def get_src_node_handle(self, neti: int, reai: int, nodei: int) -> Vec2: pass
[docs] @abc.abstractmethod def get_dest_node_handle(self, neti: int, reai: int, nodei: int) -> Vec2: pass
[docs] @abc.abstractmethod def get_center_handle(self, neti: int, reai: int) -> Vec2: pass
[docs] @abc.abstractmethod def get_list_of_src_indices(self, neti: int, reai: int) -> List[int]: pass
[docs] @abc.abstractmethod def get_list_of_dest_indices(self, neti: int, reai: int) -> List[int]: pass
[docs] @abc.abstractmethod def get_reactions_as_reactant(self, neti: int, nodei: int) -> Set[int]: pass
[docs] @abc.abstractmethod def get_reactions_as_product(self, neti: int, nodei: int) -> Set[int]: pass
[docs] @abc.abstractmethod def get_list_of_node_ids(self, neti: int) -> List[str]: """Try getting the list of node IDs""" pass
[docs] @abc.abstractmethod def get_node_indices(self, neti: int) -> Set[int]: pass
[docs] @abc.abstractmethod def get_reaction_indices(self, neti: int) -> Set[int]: pass
[docs] @abc.abstractmethod def get_compartment_indices(self, neti: int) -> Set[int]: pass
[docs] @abc.abstractmethod def get_list_of_nodes(self, neti: int) -> List[Node]: pass
[docs] @abc.abstractmethod def get_list_of_reactions(self, neti: int) -> List[Reaction]: pass
[docs] @abc.abstractmethod def get_list_of_compartments(self, neti: int) -> List[Compartment]: pass
[docs] @abc.abstractmethod def rename_compartment(self, neti: int, compi: int, new_id: str): pass
[docs] @abc.abstractmethod def move_compartment(self, neti: int, compi: int, pos: Vec2): pass
[docs] @abc.abstractmethod def set_compartment_size(self, neti: int, compi: int, size: Vec2): pass
[docs] @abc.abstractmethod def set_compartment_fill(self, neti: int, compi: int, fill: wx.Colour): pass
[docs] @abc.abstractmethod def set_compartment_border(self, neti: int, compi: int, fill: wx.Colour): pass
[docs] @abc.abstractmethod def set_compartment_border_width(self, neti: int, compi: int, width: float): pass
[docs] @abc.abstractmethod def set_compartment_volume(self, neti: int, compi: int, volume: float): pass
[docs] @abc.abstractmethod def set_compartment_of_node(self, neti: int, nodei: int, compi: int): pass
[docs] @abc.abstractmethod def get_compartment_of_node(self, neti: int, nodei: int) -> int: pass
[docs] @abc.abstractmethod def get_nodes_in_compartment(self, neti: int, cmpi: int) -> List[int]: pass
[docs] @abc.abstractmethod def get_node_index(self, neti: int, node_id: str) -> int: pass
[docs] @abc.abstractmethod def get_node_id(self, neti: int, nodei: int) -> str: pass
[docs] @abc.abstractmethod def get_reaction_index(self, neti: int, rxn_id: str) -> int: pass
[docs] @abc.abstractmethod def set_reaction_bezier_curves(self, neti: int, reai: int, bezierCurves: bool) -> Reaction: pass
[docs] @abc.abstractmethod def add_reaction_g(self, neti: int, reaction: Reaction) -> int: pass
[docs] @abc.abstractmethod def get_node_by_index(self, neti: int, nodei: int) -> Node: pass
[docs] @abc.abstractmethod def get_reaction_by_index(self, neti: int, reai: int) -> Reaction: pass
[docs] @abc.abstractmethod def get_compartment_by_index(self, neti: int, compi: int) -> Compartment: pass
[docs] @abc.abstractmethod def update_view(self): """Immediately update the view with using latest model.""" pass
[docs] @abc.abstractmethod def dump_network(self, neti: int): pass
[docs] @abc.abstractmethod def load_network(self, json_obj: Any) -> int: pass
[docs] @abc.abstractmethod def new_network(self): """Create a new network. Since there is only one tab for now, this merely clears the the current network. Also, does not clear undo stack. """ pass
[docs] @abc.abstractmethod def set_application_position(self, pos: wx.Point): pass
[docs] @abc.abstractmethod def get_application_position(self) -> wx.Point: pass
[docs] @abc.abstractmethod def get_composite_shape_list(self, neti: int) -> List[CompositeShape]: pass
[docs] @abc.abstractmethod def get_composite_shape_at(self, neti: int, shapei: int) -> List[CompositeShape]: pass
[docs] @abc.abstractmethod def get_node_shape(self, neti: int, nodei: int) -> CompositeShape: pass
[docs] @abc.abstractmethod def get_node_shape_index(self, neti: int, nodei: int) -> int: pass
[docs] @abc.abstractmethod def set_node_shape_index(self, neti: int, nodei: int, shapei: int): pass
[docs] @abc.abstractmethod def set_node_primitive_property(self, neti: int, nodei: int, primitive_index: int, prop_name: str, prop_value): pass
[docs]class IView(abc.ABC): """The inteface class for a controller The abc.ABC (Abstract Base Class) is used to enforce the MVC interface more strictly. """
[docs] @abc.abstractmethod def bind_controller(self, controller: IController): """Bind the controller. This needs to be called after a controller is created and before any other method is called. """ pass
[docs] @abc.abstractmethod def main_loop(self): """Run the main loop. This is blocking right now. This may be modified to become non-blocking in the future if required. """ pass
[docs] @abc.abstractmethod def update_all(self, nodes, reactions, compartments): """Update all the graph objects, and redraw everything at the end""" pass
[docs]class ModelError(Exception): """Base class for other exceptions""" pass
[docs]class IDNotFoundError(ModelError): pass
[docs]class IDRepeatError(ModelError): pass
[docs]class NodeNotFreeError(ModelError): pass
[docs]class NetIndexError(ModelError): pass
[docs]class ReactionIndexError(ModelError): pass
[docs]class NodeIndexError(ModelError): pass
[docs]class CompartmentIndexError(ModelError): pass
[docs]class StoichError(ModelError): pass
[docs]class StackEmptyError(ModelError): pass
[docs]class JSONError(ModelError): pass
[docs]class FileError(ModelError): pass