## Filename : chart_simul_controler.py
## Author(s) : Michel Le Borgne
## Created : 04/2010
## Revision :
## Source :
##
## Copyright 2012 - 2020 IRISA/IRSET
##
## This library is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License published
## by the Free Software Foundation; either version 2.1 of the License, or
## any later version.
##
## This library is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. The software and
## documentation provided here under is on an "as is" basis, and IRISA has
## no obligations to provide maintenance, support, updates, enhancements
## or modifications.
## In no event shall IRISA be liable to any party for direct, indirect,
## special, incidental or consequential damages, including lost profits,
## arising out of the use of this software and its documentation, even if
## IRISA have been advised of the possibility of such damage. See
## the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this library; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## The original code contained here was initially developed by:
##
## Michel Le Borgne.
## IRISA
## Symbiose team
## IRISA Campus de Beaulieu
## 35042 RENNES Cedex, FRANCE
##
##
## Contributor(s): Geoffroy Andrieux, Nolwenn Le Meur
##
"""
Controller and auxiliary widgets for simulations with gui.
"""
import gtk
from time import clock
import pkg_resources
from chart_chrono import ChartChrono
from cadbiom_gui.gt_gui.utils.warn import cancel_warn
from cadbiom.models.guard_transitions.simulator.simul_exceptions import \
SimulException, SimulStopException
from cadbiom.models.guard_transitions.simulator.chart_simul import ChartSimulator
from cadbiom.models.guard_transitions.simulator.simul_aux import ModelExtractorVisitor
from cadbiom.models.guard_transitions.analyser.ana_visitors import FrontierVisitor
from cadbiom_gui.gt_gui.utils.listDisplay import ToggleList
from cadbiom_gui.gt_gui.utils.fileHandling import FileChooser
from cadbiom import commons as cm
[docs]class ChartSimulControler(object):
"""
Control different parameters of a simulation and display panel
"""
def __init__(self, emvc, sim_option, reporter,
init_places = None, icseq=None, parent = None):
# loading and initializing the simulator model
self.edit_mvc = emvc
self.model = emvc.model # chart model
self.option = sim_option # free clock treatment option
self.reporter = reporter # display error messages
self.sim = ChartSimulator() # simulation model
self.__reload = True
if icseq: # simulation with conditions from checker
self.sim.set_act_input_stream(icseq)
self.__reload = False
if init_places:
self.__reload = False
self.sim.build(self.model, sim_option, reporter)
if reporter.error:
DisplayError(reporter, self.model.name)
return
self.init_places = init_places
if self.init_places:
self.sim.simul_init_places(self.init_places)
else:
self.sim.simul_init()
self.max_step = 0
self.tempo = 0.0
self.stop = False
self.selected_chrono = False
self.main_window = None
self.selected_window = None
# graphical interface
# Set the Glade
template = pkg_resources.resource_filename(
__name__,
"../chart_glade/chart_simulator.glade"
)
self.wtree = gtk.glade.XML(template)
# Get the Main Window, and connect the "destroy" event
self.main_window = self.wtree.get_widget("window1")
self.main_window.set_title("Simulation: "+self.model.name)
self.main_window.connect("destroy", self.on_destroy)
# Event on_escape key pressed
self.main_window.connect("key_press_event", self.on_escape)
self.main_window.set_position(gtk.WIN_POS_CENTER)
self.main_window.set_keep_above(True)
# Favicon
favicon = pkg_resources.resource_filename(
__name__,
"../images/favicon.ico"
)
self.main_window.set_icon_from_file(favicon)
# frontier button (disconnected when icseq are computed)
button = self.wtree.get_widget("frontier_button")
button.connect("clicked", self.on_select_front)
if icseq:
button.set_sensitive(False)
# whole button (disconnected when ic are computed)
button = self.wtree.get_widget("whole_button")
button.connect("clicked", self.on_select_whole)
if icseq:
button.set_sensitive(False)
# start button
button = self.wtree.get_widget("startbutton")
button.connect("clicked", self.on_start)
# chrono nutton
button = self.wtree.get_widget("chronobutton")
button.connect("clicked", self.on_chrono)
# input file choser (disconnected when ic are computed)
input_file_button = self.wtree.get_widget("input_file_button")
if not self.sim.has_input():
input_file_button.set_sensitive(False)
input_file_button.connect("clicked", self.on_input_file_selected)
if icseq:
input_file_button.set_sensitive(False)
# step button
button = self.wtree.get_widget("stepbutton")
button.connect("clicked", self.on_step_simul)
# check button for chronogram
self.cb_chrono = self.wtree.get_widget("cb_chrono")
# nb of steps widget
self.nb_step_entry = self.wtree.get_widget("nbsteps")
# slider
self.range = self.wtree.get_widget("hscale1")
self.range.set_update_policy(gtk.UPDATE_DISCONTINUOUS)
self.range.connect("value_changed", self.on_delay)
# init button"
button = self.wtree.get_widget("initbutton")
button.connect("clicked", self.on_init)
# reload button (disconnected when using computed input clocks)
button = self.wtree.get_widget("reloadbutton")
button.connect("clicked", self.on_reload)
if not self.__reload:
button.set_sensitive(False)
# extract button
button = self.wtree.get_widget("extractbutton1")
button.connect("clicked", self.on_extract, False)
button = self.wtree.get_widget("extractbutton2")
button.connect("clicked", self.on_extract, True)
# Tooltips
self.tooltips = gtk.Tooltips()
self.tooltips.set_tip(input_file_button, "Load one solution from a file")
self.tooltips.enable()
self.tooltips.set_delay(cm.TOOLTIPS_DELAY)
# register itself for parent or emvc
if parent:
parent.win_register(self)
else:
self.edit_mvc.win_register(self)
self.parent = parent
# display
self.main_window.show_all()
#gtk.main()
[docs] def on_destroy(self, widget):
"""
destroy the windows after all secondary windows
"""
if self.selected_window:
self.selected_window.destroy()
if self.sim.chrono:
self.sim.chrono.window.destroy()
self.model.clean()
self.model.notify()
if self.parent:
self.parent.win_remove(self)
else:
self.edit_mvc.win_remove(self)
if self.main_window:
self.main_window.destroy()
[docs] def destroy(self):
"""
Used if chart_simul_controller is itself a secondary window
"""
self.on_destroy(None)
[docs] def on_escape(self, widget, event):
"""On ESC key_press_event, destroy this window."""
if gtk.gdk.keyval_name(event.keyval) == "Escape":
self.destroy()
[docs] def on_step_simul(self, widget):
"""
callback for step by step simulation
"""
# in case a selected chrono is open"
if self.selected_chrono:
self.sim.chrono.destroy()
self.sim.chrono = None
self.selected_chrono = False
if self.sim.has_input() and not self.sim.input_buffer:
# inputs present and no input file
cancel_warn("Set input file before simulation")
return
try:
self.sim.simul_step()
if self.sim.chrono:
self.sim.chrono.register(self.sim)
self.sim.chrono.update()
except SimulStopException:
cancel_warn("Simulation reached end of input")
except SimulException as exc:
cancel_warn("Problem in simulation: " + exc.__str__())
[docs] def on_init(self, widget):
"""
initialisation of the simulator
"""
if self.sim.init_places:
self.sim.simul_init_places(self.sim.init_places)
else:
self.sim.simul_init() # standard init from graphics
if self.sim.input_buffer:
self.sim.input_buffer.rewind()
if self.sim.chrono:
if self.selected_chrono:
self.sim.chrono.window.destroy()
self.sim.chrono = None
self.selected_chrono = False
else:
self.sim.chrono.rewind()
self.sim.chrono.register(self.sim)
self.sim.chrono.update()
[docs] def on_start(self, widget):
"""
start a simulation
"""
# check inputs
if self.sim.has_input() and not self.sim.input_buffer:
# inputs present and no input file
cancel_warn("Set input file before simulation")
return
# read nb of steps
max_step = self.nb_step_entry.get_text()
if max_step == "":
self.max_step = 0
cancel_warn("Set number of simulation steps")
else:
self.max_step = int(max_step)
self.step_count = 0
self.stop = False
# a = threading.Thread(None, self.loop, None, (), None)
# a.start()
# return
# selected chrono
if self.cb_chrono.get_active():
if self.sim.chrono:
self.sim.chrono.destroy()
self.sim.chrono = ChartChrono.for_trajectory(self.sim)
self.selected_chrono = True
self.loop()
if self.selected_chrono:
self.sim.chrono.display_selected_chrono()
[docs] def loop(self):
"""
temporized loop for automatic simulation
"""
if self.sim.chrono:
self.sim.chrono.register(self.sim)
while not self.stop and self.step_count < self.max_step:
start_time = clock()
try:
self.sim.simul_step()
self.step_count = self.step_count + 1
except SimulStopException:
cancel_warn("Simulation reached end of input")
return
except SimulException as exc:
cancel_warn("Problem in simulation:" + exc.__str__())
return
self.model.notify()
if self.sim.chrono:
self.sim.chrono.register(self.sim)
self.sim.chrono.update()
# tempo
if self.tempo > 0.01:
time = clock()
delay = time - start_time
while delay < self.tempo:
time = clock()
delay = time - start_time
[docs] def on_chrono(self, widget):
"""
setup chronogram
"""
if not self.sim.chrono:
# logical analyser
self.sim.chrono = ChartChrono.from_simulation_model(self.sim)
self.sim.chrono.register(self.sim)
self.sim.chrono.update()
else:
self.sim.chrono.destroy()
self.sim.chrono = None
self.selected_chrono = False
[docs] def on_delay(self, widget):
"""
adjust the simulation timer
"""
self.tempo = self.range.get_value()/50.0
[docs] def on_reload(self, widget):
"""
reset the simulator
"""
if not self.__reload:
cancel_warn("No reload allowed")
return
if self.sim.chrono:
self.sim.chrono.destroy()
input_file = self.sim.input_file
self.sim = ChartSimulator()
self.reporter.error = False
self.sim.build(self.model, self.option, self.reporter)
if self.reporter.error:
DisplayError(self.reporter, self.model)
return
if input_file:
try:
self.set_input_file(input_file)
except SimulException:
self.sim.input_buffer = None
cancel_warn ("old input file inadequate - redefine input")
if self.sim.chrono:
self.sim.chrono.destroy()
self.sim.chrono = ChartChrono.from_simulation_model(self.sim)
if self.init_places:
self.sim.simul_init_places(self.init_places)
else:
self.sim.simul_init() # standard init from graphics
if self.sim.chrono:
self.sim.chrono.register(self.sim)
self.sim.chrono.update()
self.max_step = 0
self.tempo = 0.0
self.stop = False
[docs] def on_select_front(self, widget):
"""
selection of frontier activated places at initialization
"""
self.selected_window = SelectPlaceWindow(self, True)
[docs] def on_select_whole(self, widget):
"""
selection of activated places at initialization
"""
self.selected_window = SelectPlaceWindow(self, False)
[docs]class DisplayError(object):
"""
auxiliary widget for simulator
"""
def __init__(self, report, model_name, text=None):
self.main_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
#self.main_window.connect("destroy", gtk.main_quit)
self.main_window.set_title("Compiler errors or info: " + model_name)
self.main_window.set_position(gtk.WIN_POS_CENTER)
self.main_window.set_keep_above(True)
self.main_window.set_default_size(500, 300)
scroll = gtk.ScrolledWindow()
scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
scroll.set_shadow_type(gtk.SHADOW_IN)
self.main_window.add(scroll)
write = gtk.TextView()
if report:
write.get_buffer().set_text(report.memory)
else:
write.get_buffer().set_text(text)
scroll.add_with_viewport(write)
self.main_window.show_all()
#gtk.main()
[docs]class SelectPlaceWindow(object):
"""
Select the activated place for initialization
"""
def __init__(self, simulator, frontier_bool):
self.simulator = simulator
# graphical interface
# Set the Glade file
template = pkg_resources.resource_filename(
__name__,
"../chart_glade/simu_places.glade"
)
self.wtree = gtk.glade.XML(template)
# Get the Main Window, and connect the "destroy" event
self.window = self.wtree.get_widget("window1")
self.window.set_title("Selected window")
self.window.set_size_request(250, 400)
self.window.set_position(gtk.WIN_POS_NONE)
self.window.set_keep_above(True)
place_notebook = self.wtree.get_widget("place_notebook")
# search
if frontier_bool:
self.search_area = ToggleFrontier(self.simulator.model,
place_notebook, "Frontier nodes")
else:
self.search_area = ToggleWholeModel(self.simulator.model,
place_notebook,
"Simple nodes")
# button
button = self.wtree.get_widget("select_button")
button.connect("clicked", self.on_select)
button = self.wtree.get_widget("unselect_button")
button.connect("clicked", self.on_deselect)
button = self.wtree.get_widget("save_button")
button.connect("clicked", self.on_save)
button = self.wtree.get_widget("load_button")
button.connect("clicked", self.on_load)
button = self.wtree.get_widget("validate_button")
button.connect("clicked", self.on_validate)
# display
self.window.show_all()
[docs] def destroy(self):
"""
as usual for aux widget
"""
self.window.destroy()
[docs] def on_select(self, widget):
"""
???
"""
self.search_area.sn_viewer.select_all()
[docs] def on_deselect(self, widget):
"""
???
"""
self.search_area.sn_viewer.deselect_all()
[docs] def on_save(self, widget):
"""
open a window to save initialization
"""
choice = gtk.FileChooserDialog("Save initialization", None,
gtk.FILE_CHOOSER_ACTION_SAVE,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_SAVE, gtk.RESPONSE_OK))
choice.set_default_response(gtk.RESPONSE_OK)
#add a filter to see only txt files
filter = gtk.FileFilter()
filter.set_name("text files")
filter.add_pattern("*.txt")
choice.add_filter(filter)
#add a filter to see all
no_filter = gtk.FileFilter()
no_filter.set_name("all")
no_filter.add_pattern("*")
choice.add_filter(no_filter)
response = choice.run()
if response == gtk.RESPONSE_OK:
self.create_init_file(choice.get_filename())
elif response == gtk.RESPONSE_CANCEL:
pass
#print 'Closed, no files selected'
choice.destroy()
[docs] def on_load(self, widget):
"""
open a window to search xml file coming from PID database
"""
choice = gtk.FileChooserDialog("Import from xml", None,
gtk.FILE_CHOOSER_ACTION_OPEN,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OPEN, gtk.RESPONSE_OK))
choice.set_default_response(gtk.RESPONSE_OK)
#add a filter to see only xml files
filter = gtk.FileFilter()
filter.set_name("text files")
filter.add_pattern("*.txt")
choice.add_filter(filter)
#add a filter to see all
no_filter = gtk.FileFilter()
no_filter.set_name("all")
no_filter.add_pattern("*")
choice.add_filter(no_filter)
response = choice.run()
if response == gtk.RESPONSE_OK:
self.load_init_file(choice.get_filename())
elif response == gtk.RESPONSE_CANCEL:
#print 'Closed, no files selected'
pass
choice.destroy()
[docs] def on_validate(self, widget):
"""
validate the choice of activated places
"""
self.set_places()
self.destroy()
[docs] def create_init_file(self, file_name):
"""
make a txt file with the current selected places
"""
file = open(file_name,'w')
list_of_places = self.search_area.get_selected_items()
for place in list_of_places :
file.write(str(place)+'\n')
file.close()
return
[docs] def load_init_file(self, file_name):
"""
load a file to initialize the simulator
"""
list_of_places = []
file = open(file_name,'r')
for line in file:
name = line[:-1]
if name not in self.search_area.list_nodes :
cancel_warn("Name in the file not in the model")
return
list_of_places.append(name)
self.search_area.sn_viewer.set_selected_items(list_of_places)
# self.simulator.sim.simul_init_places(list_of_places)
# self.destroy()
[docs] def set_places(self):
"""
set the chosen activated places
"""
self.simulator.init_places = self.search_area.get_selected_items()
skw = list(self.simulator.init_places)
self.simulator.sim.simul_init_places(skw)
[docs]class ToggleWholeModel(object):
"""
List of simple nodes for searching
"""
def __init__(self, model, notebook, label):
self.model = model
self.model_changed = True
self.notebook = notebook
# simple nodes
sn_frame = gtk.Frame()
vbox = gtk.VBox(False, 0)
sn_frame.add(vbox)
# simple nodes list
self.sn_viewer = ToggleList()
label = gtk.Label(label)
# wrap into scrollwindow
scroll = gtk.ScrolledWindow()
scroll.add_with_viewport(self.sn_viewer)
vbox.pack_start(scroll, True, True, 0)
notebook.append_page(sn_frame, label)
# get node names
lnode = model.get_simple_node_names()
lnode.sort()
self.list_nodes = lnode
# display node names
self.sn_viewer.refresh(lnode)
[docs] def get_selected_items(self):
"""
retrieve the selected items
"""
return self.sn_viewer.get_selected_items()
[docs]class ToggleFrontier(ToggleWholeModel):
"""
List of frontier nodes for searching
"""
def __init__(self, model, notebook, label):
ToggleWholeModel.__init__(self, model, notebook, label)
self.model = model
# get node names
lnode = self.get_frontier_node_names()
lnode.sort()
self.list_nodes = lnode
# display node names
self.sn_viewer.refresh(lnode)
[docs] def get_frontier_node_names(self):
"""
retrieve frontier nodes from the model
"""
fvi = FrontierVisitor()
self.model.accept(fvi)
return fvi.frontier