diff --git a/Container.py b/Container.py index 0d98488a..dc4f2445 100644 --- a/Container.py +++ b/Container.py @@ -70,7 +70,7 @@ import ConnectDialog import DiagramConstantsDialog import SpreadSheet - import pluginmanager + #from PluginManager import PluginManager import ZipManager import DropTarget import PlotGUI @@ -2068,9 +2068,16 @@ def OnStartWizard(self, event): return gmwiz - def OnRefreshModel(self, event): + def OnRefreshModels(self, event): """ New model menu has been pressed. Wizard is instanciate. """ + + diagram = self.GetDiagram() + for block in diagram.GetFlatBlockShapeList(): + block.status_label = "" + color = CodeBlock.FILL if isinstance(block, CodeBlock) else ContainerBlock.FILL + block.fill = color + self.UpdateShapes([self]) def OnNewModel(self, event): @@ -2789,7 +2796,7 @@ def UpdateShapes(self, L=None): for m in [a for a in L if self.isSelected(a)]: self.deselect(m) self.select(m) - + self.Refresh() ### selection sur le canvas les ONodes car c'est le seul moyen d'y accéder pour effectuer l'appartenance avec les modèles @@ -3372,6 +3379,11 @@ def draw(self, dc): ### Draw label dc.DrawText(self.label, mx, my) + if hasattr(self,'status_label'): + dc.DrawText(self.status_label, mx, my+20) + else: + self.status_label = "" + #def OnResize(self): #Shape.OnResize(self) diff --git a/DEVSKernel/PyDEVS/simulator.py b/DEVSKernel/PyDEVS/simulator.py index 1ef316fb..6918ecfa 100644 --- a/DEVSKernel/PyDEVS/simulator.py +++ b/DEVSKernel/PyDEVS/simulator.py @@ -21,7 +21,7 @@ from .DEVS import CoupledDEVS #from Patterns.Strategy import SimStrategy1 -import pluginmanager +from PluginManager import PluginManager ### avec ce flag, on gere a totalité des messages sur les ports une seul fois dans delta_ext. WITHOUT_DELTA_EXT_FOR_ALL_PORT = True @@ -72,8 +72,8 @@ def send(self, d, msg): AS = AtomicSolver() r = AS.receive(d, msg) - pluginmanager.trigger_event("SIM_BLINK", model=d, msg=msg) - pluginmanager.trigger_event("SIM_TEST", model=d, msg=msg) + PluginManager.trigger_event("SIM_BLINK", model=d, msg=msg) + PluginManager.trigger_event("SIM_TEST", model=d, msg=msg) return r @@ -149,7 +149,7 @@ def receive(aDEVS, msg): aDEVS.elapsed = 0 # The SIM_VERBOSE event occurs - pluginmanager.trigger_event("SIM_VERBOSE", model=aDEVS, msg=0) + PluginManager.trigger_event("SIM_VERBOSE", model=aDEVS, msg=0) # Return the DEVS' output to the parent coupled-DEVS (rather than # sending $(y,\,t)$ message). @@ -176,7 +176,7 @@ def receive(aDEVS, msg): aDEVS.elapsed = 0 # The SIM_VERBOSE event occurs - pluginmanager.trigger_event("SIM_VERBOSE", model=aDEVS, msg=1) + PluginManager.trigger_event("SIM_VERBOSE", model=aDEVS, msg=1) # $(i,\,t)$ message --- sets origin of time at {\tt t}: elif msg[0] == 0: diff --git a/Domain/Generator/RandomGenerator.py b/Domain/Generator/RandomGenerator.py index b3c3609a..9034e0b3 100644 --- a/Domain/Generator/RandomGenerator.py +++ b/Domain/Generator/RandomGenerator.py @@ -26,7 +26,8 @@ def __init__(self, minValue=0, maxValue=10, minStep=1, maxStep=1, start=0): """ DomainBehavior.__init__(self) - self.state = {'sigma':start} + self.initPhase('START',start) + self.minValue = minValue self.maxValue = maxValue self.minStep = minStep diff --git a/DomainInterface/DomainBehavior.py b/DomainInterface/DomainBehavior.py index 2929368e..53b1e5b9 100644 --- a/DomainInterface/DomainBehavior.py +++ b/DomainInterface/DomainBehavior.py @@ -64,6 +64,8 @@ def __init__(self, name=""): BaseDEVS.AtomicDEVS.__init__(self, name=name) + self.state = {'status':'NOT_DEFINED', 'sigma':0.0} + ### if BaseDEVS AtomicDEVS class has the peek method, we have the PyDEVS simulator kernel ### else its the PyPDEVS simulator kernel and we adapt the peek and poke method for compatibility aspects if hasattr(BaseDEVS.AtomicDEVS, 'peek'): diff --git a/Menu.py b/Menu.py index 7dbccff5..4a04484a 100644 --- a/Menu.py +++ b/Menu.py @@ -30,8 +30,8 @@ import Container import ZipManager -import pluginmanager +from PluginManager import PluginManager from ExperimentGenerator import ExperimentGenerator _ = wx.GetTranslation @@ -835,7 +835,7 @@ def __init__(self, parent): ### binding parent.Bind(wx.EVT_MENU, parent.OnNewModel, id=ID_NEW_SHAPE) - parent.Bind(wx.EVT_MENU, parent.OnRefreshModel, id=ID_REFRESH_SHAPE) + parent.Bind(wx.EVT_MENU, parent.OnRefreshModels, id=ID_REFRESH_SHAPE) parent.Bind(wx.EVT_MENU, parent.OnPaste, id=ID_PASTE_SHAPE) parent.Bind(wx.EVT_MENU, parent.diagram.OnAddConstants, id=ID_ADD_CONSTANTS) parent.Bind(wx.EVT_MENU, parent.parent.PrintPreview, id=ID_PREVIEW_PRINT) @@ -1010,7 +1010,7 @@ def __init__(self, shape, event): Export_SubMenu1.Enable(False) ### if Wcomp general plugin is enabled, sub menu appear in contextual menu of amd (right clic) - pluginmanager.trigger_event("ADD_WCOMP_EXPORT_MENU", parent=self, model=shape, submenu= export_subMenu) + PluginManager.trigger_event("ADD_WCOMP_EXPORT_MENU", parent=self, model=shape, submenu= export_subMenu) elif isinstance(shape, Container.ContainerBlock): self.AppendSeparator() @@ -1035,10 +1035,10 @@ def __init__(self, shape, event): self.__canvas.Bind(wx.EVT_MENU, shape.OnPluginsManager, id=ID_PLUGINS_SHAPE) ### if Wcomp general plug-in is enabled, sub menu appear in contextual menu of amd (right clic) - pluginmanager.trigger_event("ADD_WCOMP_STRATEGY_MENU", parent=self, model=shape) + PluginManager.trigger_event("ADD_WCOMP_STRATEGY_MENU", parent=self, model=shape) ### if state trajectory general plug-in is enabled, sub menu appear in contextual menu (right clic) - pluginmanager.trigger_event("ADD_STATE_TRAJECTORY_MENU", parent=self, model=shape) + PluginManager.trigger_event("ADD_STATE_TRAJECTORY_MENU", parent=self, model=shape) self.AppendSeparator() Properties_menu = AppendItem(properties) diff --git a/Patterns/Singleton.py b/Patterns/Singleton.py index 7da7965e..e4343faf 100644 --- a/Patterns/Singleton.py +++ b/Patterns/Singleton.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## -# Singleton.py --- +# Observer.py --- # -------------------------------- # Copyright (c) 2020 # L. CAPOCCHI (capocchi@univ-corse.fr) # SPE Lab - SISU Group - University of Corsica # -------------------------------- -# Version 2.0 last modified: 03/15/20 +# Version 2.0 last modified: 05/14/20 ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # # GENERAL NOTES AND REMARKS: @@ -20,12 +20,19 @@ # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## -class Singleton(type): - def __init__(cls, name, bases, dict): - super(Singleton, cls).__init__(name, bases, dict) - cls.instance = None +def Singleton(myClass): + """ Signleton used as Decorator + """ + instances={} + def getInstance(*args, **kwargs): + if myClass not in instances: + instances[myClass] = myClass(*args, **kwargs) + return instances[myClass] + return getInstance - def __call__(cls,*args,**kw): - if cls.instance is None: - cls.instance = super(Singleton, cls).__call__(*args, **kw) - return cls.instance \ No newline at end of file +if __name__ == '__main__': + @Singleton + class SingletonTest(object): + pass + + SingletonTest() \ No newline at end of file diff --git a/Patterns/Strategy.py b/Patterns/Strategy.py index c7745915..a473582d 100644 --- a/Patterns/Strategy.py +++ b/Patterns/Strategy.py @@ -29,7 +29,7 @@ import threading import inspect -from pluginmanager import trigger_event +from PluginManager import PluginManager #trigger_event from Utilities import getOutDir import builtins @@ -172,7 +172,7 @@ def simulate(self, T = 100000000): else: # The SIM_VERBOSE event occurs - trigger_event("SIM_VERBOSE", clock = clock) + PluginManager.trigger_event("SIM_VERBOSE", clock = clock) send(master, (1, {}, clock)) @@ -375,9 +375,9 @@ def execExtTransition(m): m.elapsed = 0.0 # The SIM_VERBOSE event occurs - trigger_event("SIM_VERBOSE", model=m, msg=1) - trigger_event("SIM_BLINK", model=m, msg=[{}]) - trigger_event("SIM_TEST", model=m, msg=[{}]) + PluginManager.trigger_event("SIM_VERBOSE", model=m, msg=1) + PluginManager.trigger_event("SIM_BLINK", model=m, msg=[{}]) + PluginManager.trigger_event("SIM_TEST", model=m, msg=[{}]) return m @@ -401,9 +401,9 @@ def execIntTransition(m): m.elapsed = 0.0 # The SIM_VERBOSE event occurs - trigger_event("SIM_VERBOSE", model=m, msg=0) - trigger_event("SIM_BLINK", model=m, msg=[1]) - trigger_event("SIM_TEST", model=m, msg=[1]) + PluginManager.trigger_event("SIM_VERBOSE", model=m, msg=0) + PluginManager.trigger_event("SIM_BLINK", model=m, msg=[1]) + PluginManager.trigger_event("SIM_TEST", model=m, msg=[1]) class Clock(object): def __init__(self, time): @@ -476,7 +476,7 @@ def simulate(self, T = 100000000): else: ### The SIM_VERBOSE event occurs - trigger_event("SIM_VERBOSE", self.master, None, clock = self.ts.Get()) + PluginManager.trigger_event("SIM_VERBOSE", self.master, None, clock = self.ts.Get()) ### tree-like data structure ordered by devsimpy priority priority_scheduler = [a for a in formated_priority_list if self.ts.Get() == a[1].myTimeAdvance] diff --git a/PluginsGUI.py b/PluginsGUI.py index bbe3d2ee..1ccdbd1e 100644 --- a/PluginsGUI.py +++ b/PluginsGUI.py @@ -38,7 +38,7 @@ from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin from Decorators import BuzyCursorNotification -from pluginmanager import enable_plugin, disable_plugin, load_plugins +from PluginManager import PluginManager from Utilities import FormatSizeFile, getPYFileListFromInit import ZipManager @@ -305,7 +305,7 @@ def Importing(self, root, basename): """ # check the loaded module during the start of plug-ins - module = load_plugins(basename) + module = PluginManager.load_plugins(basename) ### if module is exception (or tuple) if not inspect.ismodule(module): @@ -322,7 +322,7 @@ def Importing(self, root, basename): if basename in self.active_plugins_list: self.CheckItem(index) else: - disable_plugin(basename) + PluginManager.disable_plugin(basename) else: self.SetItemImage(index, 2) @@ -378,9 +378,9 @@ def OnApply(self, event): if self.IsChecked(i): pluginsList.append(name) - enable_plugin(name) + PluginManager.enable_plugin(name) else: - disable_plugin(name) + PluginManager.disable_plugin(name) ### config file writing self.mainW.cfg.Write('active_plugins', str(pluginsList)) @@ -404,7 +404,7 @@ def __init__(self, *args, **kwargs): ### if pluginsList (2 param in constructor) is in constructor, we can populate try: - pluginsList = args[1] + PluginManager.pluginsList = args[1] except IndexError: #sys.stdout.write(_('D'ont forget to call Populate method!\n')) pass @@ -412,10 +412,10 @@ def __init__(self, *args, **kwargs): try: ### Populate Check List dynamicaly pool = ThreadPoolExecutor(3) - future = pool.submit(self.Populate, (pluginsList)) + future = pool.submit(self.Populate, (PluginManager.pluginsList)) future.done() except: - self.Populate(pluginsList) + self.Populate(PluginManager.pluginsList) self.is_populate = True diff --git a/SimulationGUI.py b/SimulationGUI.py index 8dcf3dd2..4119caf7 100644 --- a/SimulationGUI.py +++ b/SimulationGUI.py @@ -45,7 +45,7 @@ 'PyPDEVS':os.path.join(os.pardir,'DEVSKernel','PyPDEVS', 'old')} from Utilities import IsAllDigits, playSound, printOnStatusBar, NotificationMessage -from pluginmanager import trigger_event, is_enable +from PluginManager import PluginManager #trigger_event, is_enable from Patterns.Strategy import * from Decorators import BuzyCursorNotification, hotshotit @@ -404,7 +404,7 @@ def ChangeButtonLabel(self, btn, new_label): """ ### if activity plug-in is enabled - if is_enable('start_activity_tracking'): + if PluginManager.is_enable('start_activity_tracking'): self._btn4.SetLabel("Activity") ### @@ -417,10 +417,10 @@ def OnViewLog(self, event): """ When View button is clicked """ # The simulation verbose event occurs - trigger_event('START_SIM_VERBOSE', parent=self) + PluginManager.trigger_event('START_SIM_VERBOSE', parent=self) # The activity tracking event occurs - trigger_event('VIEW_ACTIVITY_REPORT', parent=self, master=self.current_master) + PluginManager.trigger_event('VIEW_ACTIVITY_REPORT', parent=self, master=self.current_master) ### def OnOk(self, event): @@ -464,20 +464,20 @@ def OnOk(self, event): if (self.thread is None) or (not self.timer.IsRunning()): - trigger_event("START_BLINK", parent=self, master=self.current_master) - trigger_event("START_TEST", parent=self, master=self.current_master) + PluginManager.trigger_event("START_BLINK", parent=self, master=self.current_master) + PluginManager.trigger_event("START_TEST", parent=self, master=self.current_master) ### The START_ACTIVITY_TRACKING event occurs - trigger_event("START_ACTIVITY_TRACKING", parent=self, master=self.current_master) + PluginManager.trigger_event("START_ACTIVITY_TRACKING", parent=self, master=self.current_master) ### The START_ACTIVITY_TRACKING event occurs - trigger_event("START_STATE_TRAJECTORY", parent=self, master=self.current_master) + PluginManager.trigger_event("START_STATE_TRAJECTORY", parent=self, master=self.current_master) ### The START_CONCURRENT_SIMULATION event occurs - trigger_event("START_CONCURRENT_SIMULATION", parent=self, master=self.current_master) + PluginManager.trigger_event("START_CONCURRENT_SIMULATION", parent=self, master=self.current_master) ### future call is required because the simulator is flattened during the execution of the strategy 3 - wx.FutureCall(1, trigger_event, 'START_DIAGRAM', parent=self, master=self.current_master) + wx.FutureCall(1, PluginManager.trigger_event, 'START_DIAGRAM', parent=self, master=self.current_master) ### clear all log file for fn in [f for f in os.listdir(gettempdir()) if f.endswith('.devsimpy.log')]: diff --git a/ZipManager.py b/ZipManager.py index 18a3fe60..897d2e2c 100644 --- a/ZipManager.py +++ b/ZipManager.py @@ -24,7 +24,7 @@ import gettext _ = gettext.gettext -from pluginmanager import trigger_event +from PluginManager import PluginManager #trigger_event from traceback import format_exception from Utilities import listf, path_to_module @@ -308,7 +308,7 @@ def GetModule(self, rcp: bool=False)->types.ModuleType: # if necessary, recompile (for update after editing code source of model) #if rcp: recompile(module_name) - trigger_event("IMPORT_STRATEGIES", fn=self.fn) + PluginManager.trigger_event("IMPORT_STRATEGIES", fn=self.fn) return self.ImportModule() if self.fullname not in sys.modules else sys.modules[self.fullname] diff --git a/devsimpy.py b/devsimpy.py index fc495494..f7fb17c7 100644 --- a/devsimpy.py +++ b/devsimpy.py @@ -182,7 +182,7 @@ from ImportLibrary import ImportLibrary from Reporter import ExceptionHook from PreferencesGUI import PreferencesGUI -from pluginmanager import load_plugins, enable_plugin +from PluginManager import PluginManager from which import which from Utilities import GetUserConfigDir, install, install_and_import, updatePiPPackages, updateFromGitRepo, updateFromGitArchive, NotificationMessage from Decorators import redirectStdout, BuzyCursorNotification, ProgressNotification, cond_decorator @@ -460,8 +460,8 @@ def SetConfig(self, cfg): ### load any plugins from the list ### here because it needs to PLUGINS_PATH macro defined in D for plugin in eval(self.cfg.Read("active_plugins")): - load_plugins(plugin) - enable_plugin(plugin) + PluginManager.load_plugins(plugin) + PluginManager.enable_plugin(plugin) else: wx.MessageBox('.devsimpy file appear to be a very old version and should be updated....\nWe rewrite a new blank version.', 'Configuration', diff --git a/pluginmanager.py b/pluginmanager.py index c91a66b4..8d32bced 100644 --- a/pluginmanager.py +++ b/pluginmanager.py @@ -13,90 +13,95 @@ import gettext _ = gettext.gettext -# list of registred plug-ins -plugins = defaultdict(list) -# list of enable/disable event plug-in -enabled_event = [] -disabled_event = [] -# list of enable/disabled plug-ins -enabled_plugin = [] -disabled_plugin = [] +class PluginManager(object): -def idle(*args, **kwargs): - pass + #def __init__(self): + # list of registred plug-ins + plugins = defaultdict(list) + # list of enable/disable event plug-in + enabled_event = [] + disabled_event = [] + # list of enable/disabled plug-ins + enabled_plugin = [] + disabled_plugin = [] -def register(*events): - """ This decorator is to be used for registering a function as a plug-in for - a specific event or list of events. - """ - def registered_plugin(funct): - for event in events: - plugins[event].append(funct) - return funct - return registered_plugin + @staticmethod + def register(*events): + """ This decorator is to be used for registering a function as a plug-in for + a specific event or list of events. + """ + def registered_plugin(funct): + for event in events: + PluginManager.plugins[event].append(funct) + return funct + return registered_plugin -def enable_plugin(plugin): - """ Remove resp. the plug-in and the event from the disabled_plugin and disabled_event lists. - """ - for event, functions in list(plugins.items()): - for f in functions: - if plugin == f.__module__ and event in disabled_event: - if event not in enabled_event: enabled_event.append(event) - if event in disabled_event: disabled_event.remove(event) - if plugin not in enabled_plugin: enabled_plugin.append(plugin) - if plugin in disabled_plugin: disabled_plugin.remove(plugin) + @staticmethod + def enable_plugin(plugin): + """ Remove resp. the plug-in and the event from the disabled_plugin and disabled_event lists. + """ + for event, functions in list(PluginManager.plugins.items()): + for f in functions: + if plugin == f.__module__: + if event not in PluginManager.enabled_event: PluginManager.enabled_event.append(event) + if event in PluginManager.disabled_event: PluginManager.disabled_event.remove(event) + if plugin not in PluginManager.enabled_plugin: PluginManager.enabled_plugin.append(plugin) + if plugin in PluginManager.disabled_plugin: PluginManager.disabled_plugin.remove(plugin) -def disable_plugin(plugin): - """ Append resp. the plug-in and the event to the disabled_plugin and disabled_event lists. - """ + @staticmethod + def disable_plugin(plugin): + """ Append resp. the plug-in and the event to the disabled_plugin and disabled_event lists. + """ - for event, functions in list(plugins.items()): - for f in functions: - if plugin == f.__module__ and event not in disabled_event: - if hasattr(sys.modules[plugin],'UnConfig'): - sys.modules[plugin].UnConfig(*()) + for event, functions in list(PluginManager.plugins.items()): + for f in functions: + if plugin == f.__module__: + if hasattr(sys.modules[plugin],'UnConfig'): + sys.modules[plugin].UnConfig(*()) + if event in PluginManager.enabled_event: PluginManager.enabled_event.remove(event) + if event not in PluginManager.disabled_event: PluginManager.disabled_event.append(event) + if plugin in PluginManager.enabled_plugin: PluginManager.enabled_plugin.remove(plugin) + if plugin not in PluginManager.disabled_plugin: PluginManager.disabled_plugin.append(plugin) - if event in enabled_event: enabled_event.remove(event) - if event not in disabled_event: disabled_event.append(event) - if plugin in enabled_plugin: enabled_plugin.remove(plugin) - if plugin not in disabled_plugin: disabled_plugin.append(plugin) + @staticmethod + def is_enable(plugin): + """ Enable plugin. + """ + + if isinstance(plugin, str): + return plugin in PluginManager.enabled_plugin + #return plugin in [l[0].__name__ for l in plugins.values() if l != [] ] + else: + return plugin in list(PluginManager.plugins.values()) + + @staticmethod + def trigger_event(event, *args, **kwargs): + """ Call this function to trigger an event. It will run any plug-ins that + have registered themselves to the event. Any additional arguments or + keyword arguments you pass in will be passed to the plugins. + """ + for plugin in PluginManager.plugins[event]: + if event not in PluginManager.disabled_event: + plugin(*args, **kwargs) + @staticmethod + def load_plugins(modulename): + """ This reads a plugins list to load. It is so plug-in + imports are more dynamic and you don't need to continue appending + import statements to the top of a file. + """ -def is_enable(plugin): - """ Enable plugin - """ - if isinstance(plugin, str): - return plugin in enabled_plugin - #return plugin in [l[0].__name__ for l in plugins.values() if l != [] ] - else: - return plugin in list(plugins.values()) - -def trigger_event(event, *args, **kwargs): - """ Call this function to trigger an event. It will run any plug-ins that - have registered themselves to the event. Any additional arguments or - keyword arguments you pass in will be passed to the plugins. - """ - for plugin in plugins[event]: - if event not in disabled_event: - plugin(*args, **kwargs) - -def load_plugins(modulename): - """ This reads a plugins list to load. It is so plug-in - imports are more dynamic and you don't need to continue appending - import statements to the top of a file. - """ - - try: - return sys.modules[modulename] - except KeyError: - try: - if PLUGINS_PATH not in sys.path: - sys.path.append(PLUGINS_PATH) - name,ext = os.path.splitext(modulename) - pkg = '.'.join(modulename.split('.')[0:-1]) - module = importlib.import_module(name, package=pkg) - return module - except Exception as info: - msg = _("Path of plugins directory is wrong.") if not os.path.exists(PLUGINS_PATH) else str(sys.exc_info()[0]) +"\r\n" + listf(format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) - sys.stderr.write(_("Error trying to import plugin %s : %s\n%s")%(modulename, info, msg)) - return info \ No newline at end of file + if modulename in sys.modules: + return sys.modules[modulename] + else: + try: + if PLUGINS_PATH not in sys.path: + sys.path.append(PLUGINS_PATH) + name,ext = os.path.splitext(modulename) + pkg = '.'.join(modulename.split('.')[0:-1]) + module = importlib.import_module(name, package=pkg) + return module + except Exception as info: + msg = _("Path of plugins directory is wrong.") if not os.path.exists(PLUGINS_PATH) else str(sys.exc_info()[0]) +"\r\n" + listf(format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) + sys.stderr.write(_("Error trying to import plugin %s : %s\n%s")%(modulename, info, msg)) + return info diff --git a/plugins/blink.py b/plugins/blink.py index aa363342..acccff61 100644 --- a/plugins/blink.py +++ b/plugins/blink.py @@ -12,18 +12,16 @@ import wx import os -import sys -import pluginmanager +import builtins from types import MethodType +from PluginManager import PluginManager from Container import DetachedFrame, ConnectionShape, CodeBlock, ContainerBlock from FindGUI import FindReplace from Utilities import MoveFromParent from Patterns.Observer import Subject -import builtins - if 'PyPDEVS' in builtins.__dict__['DEFAULT_DEVS_DIRNAME']: raise AssertionError("Blink plug-in is not compatible with the PyPDEVS simulation kernel!") @@ -33,7 +31,7 @@ def InternalLog(model): "\t Output Port Configuration:\n"] for m in model.OPorts: - if m in list(model.myOutput.keys()): + if m in model.myOutput.keys(): txt.append("\t %s: %s\n"%(m, model.myOutput[m])) else: txt.append("\t %s: None\n" %(m)) @@ -66,7 +64,7 @@ def TimeAdvanceLog(model): def GetState(self): return self.__state -@pluginmanager.register("START_BLINK") +@PluginManager.register("START_BLINK") def start_blink(*args, **kwargs): global frame @@ -91,7 +89,7 @@ def start_blink(*args, **kwargs): diagram = canvas.GetDiagram() ### define frame - frame = BlinkFrame(parent, wx.NewIdRef(), _('Blink Logger')) + frame = BlinkFrame(parent, wx.ID_ANY, _('Blink Logger')) frame.SetIcon(mainW.GetIcon()) frame.SetTitle("%s Blink Logger"%os.path.basename(diagram.last_name_saved)) frame.Show() @@ -102,11 +100,19 @@ def start_blink(*args, **kwargs): sender.__state = {} sender.GetState = MethodType(GetState, sender) + for block in diagram.GetFlatBlockShapeList(): + #### add model d to observer list + sender.attach(block) + state = sender.GetState() + state['status_label'] = "" + sender.notify() + sender.detach(block) + ### disable suspend and log button parent._btn3.Disable() parent._btn4.Disable() -@pluginmanager.register("SIM_BLINK") +@PluginManager.register("SIM_BLINK") def blink_manager(*args, **kwargs): """ Start blink. """ @@ -125,13 +131,14 @@ def blink_manager(*args, **kwargs): ### DEVSimPy block if hasattr(d, 'getBlockModel'): - if isinstance(frame, wx.Frame): + block = d.getBlockModel() - block = d.getBlockModel() + #### add model d to observer list + sender.attach(block) - #### add model d to observer list - sender.attach(block) + state = sender.GetState() + if frame and frame.IsShown(): old_fill = block.fill ### write external transition result @@ -155,170 +162,209 @@ def blink_manager(*args, **kwargs): else: color = old_fill - state = sender.GetState() - ### blink frame is always active - if frame and frame.IsShown(): - dastyle = wx.TextAttr() - dastyle.SetTextColour(color[0]) - frame.txt.SetDefaultStyle(dastyle) + #if frame and frame.IsShown(): + dastyle = wx.TextAttr() + dastyle.SetTextColour(color[0]) + frame.txt.SetDefaultStyle(dastyle) - wx.CallAfter(frame.txt.write,(f)) - #frame.txt.write(f) + wx.CallAfter(frame.txt.write,(f)) + #frame.txt.write(f) + if frame.colored_flag: state['fill'] = color sender.notify() - try: - ### step engine - frame.flag = False - while not frame.flag: - pass - except: + try: + ### step engine + frame.flag = False + while not frame.flag and frame.IsShown(): pass - - ### blink frame has been closed - else: + except: + pass + + if frame.colored_flag: ### assign the default color color = CodeBlock.FILL if isinstance(block, CodeBlock) else ContainerBlock.FILL state['fill'] = color sender.notify() - - ### add model d to observer list - sender.detach(block) + ### assign the additionnal status_label string and notify + if frame.status_flag: + status = block.devsModel.getStatus() + state['status_label'] = '('+status+')' + sender.notify() + + ### blink frame has been closed else: - wx.CallAfter(frame.txt.write,(_("Canvas is not found\n"))) + ### assign the default color tot the last colored block + if frame.colored_flag: + color = CodeBlock.FILL if isinstance(block, CodeBlock) else ContainerBlock.FILL + state['fill'] = color + sender.notify() + + ### assigne the empty status label for all block + if frame.status_flag: + diagram = canvas.GetDiagram() + for b in diagram.GetFlatBlockShapeList(): + b.status_label = "" + + ### remove model d to observer list + sender.detach(block) + else: wx.CallAfter(frame.txt.write,(_("No blink for %s dynamic model (%s)!\n")%(str(d), d.myID))) -def Config(parent): - """ Plug-in settings frame. - """ - dlg = wx.MessageDialog(parent, _('No settings available for this plug-in\n'), _('Blink configuration'), wx.OK | wx.ICON_EXCLAMATION) - dlg.ShowModal() - class BlinkFrame(wx.Frame): """ """ def __init__(self, *args, **kwds): """ Constructor. """ - super(BlinkFrame, self).__init__(*args, **kwds) - ### just for the start of the frame - self.flag = True + kwds["style"] = wx.DEFAULT_FRAME_STYLE |wx.STAY_ON_TOP + kwds["size"] = (400, 420) - self.OnInit() + wx.Frame.__init__(self, *args, **kwds) - def OnInit(self): - - panel = wx.Panel(self) + global canvas - self.button_clear = wx.Button(panel, wx.ID_CLEAR) - self.button_step = wx.Button(panel, wx.ID_FORWARD) - self.button_find = wx.Button(panel, wx.ID_FIND) - self.button_selectall = wx.Button(panel, wx.ID_SELECTALL) - self.txt = wx.TextCtrl(panel, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2) - - ### to close the frame when this attribute don't change - self.lenght = self.txt.GetNumberOfLines() + self.panel = wx.Panel(self) + self.button_clear = wx.Button(self.panel, wx.ID_CLEAR) + self.button_step = wx.Button(self.panel, wx.ID_FORWARD) + self.button_find = wx.Button(self.panel, wx.ID_FIND) + self.button_selectall = wx.Button(self.panel, wx.ID_SELECTALL) + self.txt = wx.TextCtrl(self.panel, style = wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2) + self.cb1 = wx.CheckBox(self.panel, label=_('Colored Notification')) + self.cb2 = wx.CheckBox(self.panel, label=_('Status Notification')) MoveFromParent(self, interval=10, direction='right') self.__set_properties() - sizer = self.__do_layout() + self.__do_layout() - panel.SetSizerAndFit(sizer) + ### just for the start of the frame + self.flag = True + self.colored_flag = False + self.status_flag = False + + ### to close the frame when this attribute don't change + self.lenght = self.txt.GetNumberOfLines() ### just for window - self.SetClientSize(panel.GetBestSize()) + self.SetClientSize(self.panel.GetBestSize()) self.Bind(wx.EVT_BUTTON, self.OnStep, id=self.button_step.GetId()) self.Bind(wx.EVT_BUTTON, self.OnClear, id=self.button_clear.GetId()) self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=self.button_selectall.GetId()) self.Bind(wx.EVT_BUTTON, self.OnFindReplace, id=self.button_find.GetId()) self.Bind(wx.EVT_CLOSE, self.OnClose) - + self.Bind(wx.EVT_CHECKBOX, self.OnChecked1, id=self.cb1.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.OnChecked2, id=self.cb2.GetId()) + def __set_properties(self): + """ + """ self.txt.SetMinSize((390, 300)) - txt1 = _("Press this button in order to go step by step in the simulation.") - txt2 = ("Press this button in order to clean the output of the simulation.") - txt3 = _("Press this button in order to launch the search window.") - - if wx.VERSION_STRING < '4.0': - self.button_step.SetToolTipString(txt1) - self.button_clear.SetToolTipString(txt2) - self.button_find.SetToolTipString(txt3) - else: - self.button_step.SetToolTip(txt1) - self.button_clear.SetToolTip(txt2) - self.button_find.SetToolTip(txt3) - + self.button_step.SetToolTip(_("Press this button in order to go step by step in the simulation.")) + self.button_clear.SetToolTip(_("Press this button in order to clean the output of the simulation.")) + self.button_find.SetToolTip(_("Press this button in order to launch the search window.")) + self.cb1.SetToolTip(_("Block is colored depending on the transition function.")) + self.cb2.SetToolTip(_("Status of devs model is displayed on the label of block.")) self.button_step.SetDefault() def __do_layout(self): + """ + """ + sizer_2 = wx.BoxSizer(wx.VERTICAL) + sizer_2.Add(self.txt, 1, wx.EXPAND) - vbox = wx.BoxSizer(wx.VERTICAL) - hbox = wx.BoxSizer(wx.HORIZONTAL) + grid_sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + grid_sizer_1.Add(self.button_selectall, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE) + grid_sizer_1.Add(self.button_find, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE) + grid_sizer_1.Add(self.button_clear, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE) - vbox.Add(self.txt, 1, wx.EXPAND) - vbox.Add((-1,5)) - hbox.Add(self.button_selectall, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 5) - hbox.Add(self.button_find, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 5) - hbox.Add(self.button_clear, 1, wx.ALIGN_CENTER_HORIZONTAL|wx.ADJUST_MINSIZE, 5) - vbox.Add(hbox, 0, wx.EXPAND) - vbox.Add((-1,5)) - vbox.Add(self.button_step, 0, wx.ALIGN_RIGHT, 5) + sizer_2.Add(grid_sizer_1, 0, wx.EXPAND) - return vbox + sizer_2.Add((-1, 25)) - def OnStep(self, evt): + hbox4 = wx.BoxSizer(wx.HORIZONTAL) + hbox4.Add(self.cb1) + hbox4.Add(self.cb2, flag=wx.LEFT, border=10) + + # cb3 = wx.CheckBox(self.panel, label='Non-Project classes') + # hbox4.Add(cb3, flag=wx.LEFT, border=10) + + sizer_2.Add(hbox4, flag=wx.LEFT, border=10) + + sizer_2.Add(self.button_step, 0, wx.ALIGN_RIGHT) + + self.panel.SetSizerAndFit(sizer_2) + + def OnChecked1(self, evt): + """ + """ + cb = evt.GetEventObject() + self.colored_flag = cb.GetValue() + #print(cb.GetLabel(),' is clicked',cb.GetValue()) + + def OnChecked2(self, evt): """ """ + cb = evt.GetEventObject() + self.status_flag = cb.GetValue() + #print(cb.GetLabel(),' is clicked',cb.GetValue()) + + def OnStep(self, evt): + """ Forward button has been ckicled. + """ nb = self.txt.GetNumberOfLines() + parent = self.GetParent() - ### si plus de sortie text dans le Logger, alors on ferme la fentre et on stop la simulation + ### si plus de sortie text dans le Logger, alors on ferme la fenêtre et on stop la simulation if nb != self.lenght: self.lenght = nb else: - parent = self.GetParent() - parent.OnStop(evt) self.Close() + parent.OnStop(evt) self.flag = True self.button_clear.Enable(True) ### def OnClear(self, evt): - """ Clear selection or all text + """ Clear selection or all text. """ - s = self.txt.GetSelection() ### if no text selected, we select all if s[0] == s[1]: s = self.txt.SelectAll() s = self.txt.GetSelection() - self.txt.Remove(s[0], s[1]) ### def OnSelectAll(self, evt): - """ Select all text + """ Select all text. """ self.txt.SelectAll() ### def OnFindReplace(self, evt): - """ Call find and replace dialogue + """ Call find and replace dialogue. """ - FindReplace(self, wx.NewIdRef(), _('Find/Replace')) + FindReplace(self, wx.ID_ANY, _('Find/Replace')) def OnClose(self, evt): - """ - """ + ### to stop the while in SIM_BLINK self.flag = True - self.Show(False) - #self.Destroy() - evt.Skip() \ No newline at end of file + ### Refresh all block on the diagram to clear the stauts_label info (color is already updated) + canvas.OnRefreshModels(evt) + evt.Skip() + + +def Config(parent): + """ Plug-in settings frame. + """ + dlg = wx.MessageDialog(parent, _('No settings available for this plug-in\n'), _('Blink configuration'), wx.OK | wx.ICON_EXCLAMATION) + dlg.ShowModal() \ No newline at end of file diff --git a/plugins/state_trajectory.py b/plugins/state_trajectory.py index 0888fc01..91366d68 100644 --- a/plugins/state_trajectory.py +++ b/plugins/state_trajectory.py @@ -21,7 +21,7 @@ import os import inspect -import pluginmanager +from PluginManager import PluginManager from Container import Block, CodeBlock, ContainerBlock from Utilities import install_and_import @@ -197,7 +197,7 @@ def Plot(diagram, selected_label): ### Pluginmanager Function Definition ###################################################################### -@pluginmanager.register("START_STATE_TRAJECTORY") +@PluginManager.register("START_STATE_TRAJECTORY") def start_state_trajectory(*args, **kwargs): """ Start the definition of the state trajectory attributes for all selected block model """ @@ -213,7 +213,7 @@ def start_state_trajectory(*args, **kwargs): else: sys.stdout.write("Activity pattern must be disabled!\n") -@pluginmanager.register("ADD_STATE_TRAJECTORY_MENU") +@PluginManager.register("ADD_STATE_TRAJECTORY_MENU") def add_state_trajectory_menu(*args, **kwargs): global block diff --git a/plugins/verbose.py b/plugins/verbose.py index 97a49718..dc8fa54a 100644 --- a/plugins/verbose.py +++ b/plugins/verbose.py @@ -15,7 +15,7 @@ import sys import os -import pluginmanager +from PluginManager import PluginManager global show_ext_trans global show_int_trans @@ -45,7 +45,7 @@ def write(self, string): def flush(self): pass -@pluginmanager.register("SIM_VERBOSE") +@PluginManager.register("SIM_VERBOSE") def LongRunningProcess(*args, **kwargs): """ Plug-in function for simulation printing. """ @@ -114,7 +114,7 @@ def LongRunningProcess(*args, **kwargs): txt = "\n"+"* "* 10+"CLOCK : %f \n"%(kwargs['clock']) sys.stdout.write(txt) -@pluginmanager.register("START_SIM_VERBOSE") +@PluginManager.register("START_SIM_VERBOSE") def start_print_data(*args, **kwargs): """ Start the log frame. """