def ErrorManager(self, msg): """ An error is occurred. """ ### try to find the file which have the error from traceback devs_error = False try: typ, val, tb = msg.date if wx.VERSION_STRING < '2.9' else msg trace = traceback.format_exception(typ, val, tb) mainW = wx.GetApp().GetTopWindow() ### paths in traceback paths = [ a for a in trace if a.split(',')[0].strip().startswith('File') ] ### find if DOMAIN_PATH is in the first file path of the trace path = paths[-1] devs_error = DOMAIN_PATH in path or HOME_PATH not in path except Exception as info: sys.stdout.write(_("Error in ErrorManager: %s" % info)) ### if error come from devs python file if devs_error: try: ### simulate event button for the code editor event = wx.PyCommandEvent(wx.EVT_BUTTON.typeId, self._btn1.GetId()) except: pass else: ### Error dialog if not Container.MsgBoxError( event, self.parent, msg.date if wx.VERSION_STRING < '2.9' else msg): ### if user dont want correct the error, we destroy the simulation windows self.PrepareDestroyWin() self.Destroy() else: ### if user want to correct error through an editor, we stop simulation process for trying again after the error is corrected. self.OnStop(event) else: print(msg) raise MyBad(msg)
class SimulationDialog(wx.Frame, wx.Panel): """ SimulationDialog(parent, id, title, master) Frame or Panel with progress bar """ def __init__(self, parent, id, title, master): """ Constructor """ if isinstance(parent, wx.Panel): wx.Panel.__init__(self, parent, id) self.SetBackgroundColour(wx.NullColour) self.panel = self ### panel inherit of the left splitter size self.panel.SetSize(parent.GetParent().GetSize()) # status bar of main application self.statusbar = parent.GetTopLevelParent().statusbar else: wx.Frame.__init__(self, parent, id, title, style=wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP) ### adapt size of frame depending on the plate-form if '__WXMSW__' in wx.PlatformInfo: self.SetSize((320, 280)) else: self.SetSize((280, 160)) # disable the roll out of the frame self.SetMinSize(self.GetSize()) self.panel = wx.Panel(self, -1) wx.CallAfter(self.CreateBar) self.__set_properties() # local copy self.parent = parent self.master = master self.title = title ### current master for multi-simulation without simulationDialog reloading (show OnOk) self.current_master = None # simulator strategy self.selected_strategy = DEFAULT_SIM_STRATEGY ### profiling simulation with hotshot self.prof = False ### No time limit simulation (defined in the builtin dictionary from .devsimpy file) self.ntl = __builtin__.__dict__['NTL'] self.verbose = False # definition of the thread, the timer and the counter for the simulation progress self.thread = None self.timer = wx.Timer(self, wx.NewId()) self.count = 10.0 self.stdioWin = None self.__widgets() self.__do_layout() self.__set_events() ### create a pubsub receiver (simple way to communicate with thread) Publisher.subscribe(self.ErrorManager, "error") def CreateBar(self): self.statusbar = self.CreateStatusBar(2) def __set_properties(self): icon = wx.EmptyIcon() icon.CopyFromBitmap( wx.Bitmap(os.path.join(ICON_PATH_16_16, "simulation.png"), wx.BITMAP_TYPE_ANY)) self.SetIcon(icon) self.Center() def __widgets(self): self._text1 = wx.StaticText(self.panel, wx.ID_ANY, _('Final time:')) self._value = wx.TextCtrl(self.panel, wx.ID_ANY, str(float(self.master.FINAL_TIME)), validator=TextObjectValidator()) self._btn1 = wx.Button(self.panel, wx.NewId(), _('Run')) self._btn2 = wx.Button(self.panel, wx.NewId(), _('Stop')) self._btn3 = wx.Button(self.panel, wx.NewId(), _('Suspend')) self._btn4 = wx.Button(self.panel, wx.NewId(), _('Log')) self._gauge = wx.Gauge(self.panel, wx.ID_ANY, 100, size=(-1, 25), style=wx.GA_HORIZONTAL | wx.GA_SMOOTH) self._cp = CollapsiblePanel(self.panel, self) self._text1.Enable(not self.ntl) self._value.Enable(not self.ntl) self._btn1.SetToolTipString(_("Begin simulation process.")) self._btn2.SetToolTipString(_("Stop the simulation process.")) self._btn3.SetToolTipString(_("Suspend the simulation process.")) self._btn4.SetToolTipString( _("Launch the log window (often depends on some plug-ins (verbose, activity, ...))." )) def __do_layout(self): #vbox_top = wx.BoxSizer(wx.VERTICAL) vbox_body = wx.BoxSizer(wx.VERTICAL) #panel 1 grid1 = wx.GridSizer(1, 2) grid1.Add(self._text1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL) grid1.Add(self._value, 1, wx.EXPAND | wx.ALIGN_CENTER_HORIZONTAL) # panel2 grid2 = wx.GridSizer(3, 2, 2, 2) grid2.Add( self._btn1, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND) grid2.Add( self._btn3, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND) grid2.Add( self._btn2, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND) grid2.Add( self._btn4, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND) # panel4 #hbox1 = wx.BoxSizer(wx.HORIZONTAL) #hbox1.Add(self._gauge, 1, wx.EXPAND, 9) ## panel5 #hbox2 = wx.BoxSizer(wx.HORIZONTAL) #hbox2.Add(self._cp, 1, wx.EXPAND, 9) vbox_body.Add(grid1, 0, wx.EXPAND, 9) vbox_body.Add(grid2, 0, wx.EXPAND, 9) vbox_body.Add(self._gauge, 0, wx.EXPAND, 9) vbox_body.Add(self._cp, 0, wx.EXPAND, 9) # fin panel #vbox_top.Add(vbox_body, 0, wx.EXPAND|wx.ALL, 9) self.panel.SetSizer(vbox_body) # vbox_body.Fit(self) self._text1.SetFocus() self._btn1.SetDefault() self._btn2.Disable() self._btn3.Disable() ### def __set_events(self): ### binding event self.Bind(wx.EVT_BUTTON, self.OnOk, self._btn1) self.Bind(wx.EVT_BUTTON, self.OnStop, self._btn2) self.Bind(wx.EVT_BUTTON, self.OnSuspend, self._btn3) self.Bind(wx.EVT_BUTTON, self.OnViewLog, self._btn4) self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) self.Bind(wx.EVT_TEXT, self.OnText, self._value) self.Bind(wx.EVT_CLOSE, self.OnQuit) ### def ChangeButtonLabel(self, btn, new_label): """ Change the label of the Log button depending on the active plug-in """ ### if activity plug-in is enabled if is_enable('start_activity_tracking'): self._btn4.SetLabel("Activity") ### def OnText(self, event): self._gauge.SetValue(0) ### @BuzyCursorNotification def OnViewLog(self, event): """ When View button is clicked """ # The simulation verbose event occurs trigger_event("START_SIM_VERBOSE", parent=self) # The simulation verbose event occurs trigger_event("VIEW_ACTIVITY_REPORT", parent=self, master=self.current_master) ### def OnOk(self, event): """ When Run button is clicked """ assert (self.master is not None) if self._value.GetValidator().Validate(self._value) or self.ntl: ### pour prendre en compte les simulations multiples sans relancer un SimulationDialog ### si le thread n'est pas lancé (pas pendant un suspend) if self.thread is not None and not self.thread.thread_suspend: diagram = self.master.getBlockModel() diagram.Clean() self.current_master = Container.Diagram.makeDEVSInstance( diagram) else: self.current_master = self.master if isinstance(self.parent, wx.Panel): # redirection du stdout ici dans le cas du Panel (sinon dans OnSimulation) mainW = self.parent.GetTopLevelParent() sys.stdout = mainW.stdioWin ### test si le modele et bien charge if (self.current_master == None) or (self.current_master.componentSet == []): return self.MsgBoxEmptyModel() ### dont erase the gauge if ntl if not self.ntl: # stockage du temps de simulation dans le master self.current_master.FINAL_TIME = float(self._value.GetValue()) self._gauge.SetValue(0) ### if _gauge is wx.Slider #self._gauge.SetMax(self.current_master.FINAL_TIME) self.statusbar.SetBackgroundColour('') self.statusbar.SetStatusText("", 1) if self.statusbar.GetFieldsCount() > 2: self.statusbar.SetStatusText("", 2) 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) ### The START_ACTIVITY_TRACKING event occurs 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) ### The START_CONCURRENT_SIMULATION event occurs 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) ### clear all log file for fn in filter(lambda f: f.endswith('.devsimpy.log'), os.listdir(gettempdir())): os.remove(os.path.join(gettempdir(), fn)) self.thread = simulator_factory(self.current_master, self.selected_strategy, self.prof, self.ntl, self.verbose) self.thread.setName(self.title) ### si le modele n'a pas de couplage, ou si pas de generateur: alors pas besoin de simuler if self.thread.end_flag: self.OnTimer(event) else: self.timer.Start(100) else: #print self.thread.getAlgorithm().trace ### for back simulation #self.thread.s = shelve.open(self.thread.f.name+'.db',flag='r') #self.thread.model = self.thread.s['s'][str(float(self._gauge.GetValue()))] ### restart the hiding gauge if self.ntl: self._gauge.Show() ### restart thread self.thread.resume_thread() self.Interact(False) if self.count >= 100: return # aucune possibilité d'interagir avec le modele #self.parent.Enable(False) def Interact(self, access=True): """ Enabling and disabling options (buttons, checkbox, ...) """ self._btn1.Enable(access) self._btn2.Enable(not access) self._btn3.Enable(not access) self._value.Enable(not self.ntl) self._cp.Enable(access) ### def OnStop(self, event): """ When Stop button is clicked """ self.Interact() self.thread.terminate() self.timer.Stop() wx.Bell() self._gauge.SetValue(0) self.statusbar.SetBackgroundColour('') self.statusbar.SetStatusText(_('Interrupted'), 0) self.statusbar.SetStatusText("", 1) if self.statusbar.GetFieldsCount() > 2: self.statusbar.SetStatusText("", 2) ### def OnSuspend(self, event): """ When Stop button is clicked """ self.Interact() self.thread.suspend() if self.ntl: self._gauge.Hide() if self.count == 0 or self.count >= 100 or not self.timer.IsRunning(): return self.statusbar.SetStatusText(_('Suspended'), 0) # way to interact with the model #self.parent.Enable(True) wx.Bell() ### def OnTimer(self, event): """ Give the pourcentage of simulation progress """ ### if no time limit, gauge pulse if self.ntl: self._gauge.Pulse() else: if not isinstance(self.thread.model.timeLast, tuple): timeLast = self.thread.model.timeLast else: timeLast = self.thread.model.timeLast[0] self.count = (timeLast / self.thread.model.FINAL_TIME) * 100 self._gauge.SetValue(self.count) ### if simulation is over if self.thread.end_flag: ### update the status of buttons self._btn1.Enable(True) self._btn2.Disable() self._btn3.Disable() self._value.Enable(not self.ntl) self._cp.Enable() ### check if gauge is full (can appear if timer is too slow) if self.count != 100: self.count = 100 self._gauge.SetValue(self.count) ### update the status bar self.statusbar.SetBackgroundColour('') self.statusbar.SetStatusText(_("Completed!"), 0) self.statusbar.SetStatusText("%0.4f s" % (self.thread.cpu_time), 1) ### is no time limit add some informations in status bar if not self.ntl: if self.statusbar.GetFieldsCount() > 2: self.statusbar.SetStatusText(str(100) + "%", 2) ### stop the timer self.timer.Stop() ### if the simulation is suspended elif not self.thread.thread_suspend: ### udpate the status bar self.statusbar.SetBackgroundColour('GREY') self.statusbar.SetStatusText(_("Processing..."), 0) self.statusbar.SetStatusText("%0.4f s" % (self.thread.cpu_time), 1) ### is no time limit, add some information in status bar if not self.ntl: if self.statusbar.GetFieldsCount() > 2: self.statusbar.SetStatusText(str(self.count)[:4] + "%", 2) #wx.Yield() wx.YieldIfNeeded() ### def MsgBoxEmptyModel(self): """ Pop-up alert for empty model """ dial = wx.MessageDialog( self, _('You want to simulate an empty master model!'), _('Simulation Manager'), wx.OK | wx.ICON_EXCLAMATION) if (dial.ShowModal() == wx.ID_OK) and (isinstance( self.parent, wx.Frame)): self.DestroyWin() else: return def DestroyWin(self): """ To destroy the simulation frame """ ### clean status bar self.statusbar.SetBackgroundColour('') self.statusbar.SetFields([""] * self.statusbar.GetFieldsCount()) ### try to hidden stdioWin try: self.parent.stdioWin.frame.Show(False) except: pass try: ## left panel enabled nb1 = self.parent.mainW.GetControlNotebook() nb1.Enable() ## menu enabled self.parent.tb.Enable() for i in xrange(self.parent.menuBar.GetMenuCount()): self.parent.menuBar.EnableTop(i, True) ### other tab diagram enabled nb2 = self.parent.GetDiagramNotebook() for p in xrange(nb2.GetPageCount()): ## pour tout les tab non selectionner if p != nb2.GetSelection(): nb2.GetPage(p).Enable() except Exception: #sys.stdout.write(_("Empty mode over\n")) pass ### destroy the frame self.Destroy() def OnQuit(self, event): """ When the simulation are stopping """ # if the simulation is running if self.timer.IsRunning(): dial = wx.MessageDialog( self, _('Are you sure to stop simulation?'), _('Simulation Manager'), wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) self.thread.suspend() ### if user wants to stop simulation process if dial.ShowModal() == wx.ID_YES: self.DestroyWin() self.thread.terminate() else: self.thread.resume_thread() else: self.DestroyWin() def ErrorManager(self, msg): """ An error is occurred. """ ### try to find the file which have the error from traceback devs_error = False try: typ, val, tb = msg.data trace = traceback.format_exception(typ, val, tb) mainW = wx.GetApp().GetTopWindow() ### paths in traceback paths = filter( lambda a: a.split(',')[0].strip().startswith('File'), trace) ### find if DOMAIN_PATH is in paths list (inversed because traceback begin by the end) for path in paths[::-1]: ### find if one path in trace comes from Domain or exported path list for d in [DOMAIN_PATH] + mainW.GetExportPathsList(): if d in path: devs_error = True break except Exception, info: print _("Error in ErrorManager: %s" % info) ### if error come from devs python file if devs_error: ### simulate event button for the code editor event = wx.PyCommandEvent(wx.EVT_BUTTON.typeId, self._btn1.GetId()) ### Error dialog if not Container.MsgBoxError(event, self.parent, msg.data): ### if user dont want correct the error, we destroy the simulation windows self.DestroyWin() else: ### if user want to correct error through an editor, we stop simulation process for trying again after the error is corrected. self.OnStop(event) else: raise msg
def SelectProp(self, evt): """ """ row, col = evt.GetRow(), evt.GetCol() table = self.GetTable() typ = table.dataTypes[row][1] prop = self.GetCellValue(row, 0) if prop == 'fill' or re.findall( "[.]*color[.]*", prop, flags=re.IGNORECASE): val = self.GetCellValue(row, 1) dlg = wx.ColourDialog(self.parent) dlg.GetColourData().SetChooseFull(True) if dlg.ShowModal() == wx.ID_OK: data = dlg.GetColourData() val = str([RGBToHEX(data.GetColour().Get())]) self.SetCellValue(row, 1, val) else: dlg.Destroy() return False dlg.Destroy() self.AcceptProp(row, col) elif prop == 'font': val = eval(self.GetCellValue(row, 1)) default_font = wx.Font(val[0], val[1], val[2], val[3], False, val[4]) data = wx.FontData() if sys.platform == 'win32': data.EnableEffects(True) data.SetAllowSymbols(False) data.SetInitialFont(default_font) data.SetRange(10, 30) dlg = wx.FontDialog(self.parent, data) if dlg.ShowModal() == wx.ID_OK: data = dlg.GetFontData() font = data.GetChosenFont() color = data.GetColour() val = [ font.GetPointSize(), font.GetFamily(), font.GetStyle(), font.GetWeight(), font.GetFaceName() ] self.SetCellValue(row, 1, str(val)) else: dlg.Destroy() return False dlg.Destroy() self.AcceptProp(row, col) elif prop == 'label': d = LabelGUI.LabelDialog(self.parent, self.parent.model) d.ShowModal() self.SetCellValue(row, 1, str(self.parent.model.label)) self.AcceptProp(row, col) elif prop == 'image_path': dlg = ib.ImageDialog(self, os.path.join(HOME_PATH)) dlg.Centre() if dlg.ShowModal() == wx.ID_OK: val = os.path.normpath(dlg.GetFile()) if val != self.GetCellValue(row, 1): self.SetCellValue(row, 1, val) self.canvas.UpdateShapes([self.parent.model]) else: dlg.Destroy() return False dlg.Destroy() self.AcceptProp(row, col) elif 'filename' in str(prop).lower(): wcd = _('Data files All files (*)|*') val = self.GetCellValue(row, 1) default_dir = os.path.dirname(val) if os.path.exists( os.path.dirname(val)) else HOME_PATH dlg = wx.FileDialog(self, message=_("Select file ..."), defaultDir=default_dir, defaultFile="", wildcard=wcd, style=wx.OPEN | wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: val = os.path.normpath(dlg.GetPath()) if val != self.GetCellValue(row, 1): self.SetCellValue(row, 1, val) self.canvas.UpdateShapes([self.parent.model]) else: dlg.Destroy() return False dlg.Destroy() self.AcceptProp(row, col) elif prop == 'python_path': model = self.parent.model ### for .amd or .cmd if model.model_path != '': wcd = _( 'Atomic DEVSimPy model (*.amd)|*.amd|Coupled DEVSimPy model (*.cmd)|*.cmd|All files (*)|*' ) else: wcd = _('Python files (*.py)|*.py|All files (*)|*') default_dir = os.path.dirname(model.python_path) if os.path.exists( os.path.dirname(model.python_path)) else DOMAIN_PATH dlg = wx.FileDialog(self, message=_("Select file ..."), defaultDir=default_dir, defaultFile="", wildcard=wcd, style=wx.OPEN | wx.CHANGE_DIR) if dlg.ShowModal() == wx.ID_OK: new_python_path = os.path.normpath(dlg.GetPath()) ### if the user would like to load a compressed python file, he just give the name of compressed file that contain the python file if zipfile.is_zipfile(new_python_path): zf = zipfile.ZipFile(new_python_path, 'r') new_python_path = os.path.join( new_python_path, filter( lambda f: f.endswith('.py') and f != 'plugins.py', zf.namelist())[0]) ### update model path model.model_path = os.path.dirname(new_python_path) self.SetCellValue(row, 1, new_python_path) # behavioral args update (because depends of the new class coming from new python file) new_cls = Components.GetClass(new_python_path) if inspect.isclass(new_cls): ### update attributes (behavioral ang graphic) model.args = Components.GetArgs(new_cls) model.SetAttributes(Attributable.GRAPHICAL_ATTR) ### TODO: when ScopeGUI and DiskGUI will be amd models, delete this line) ### delete xlabel and ylabel attributes if exist model.RemoveAttribute('xlabel') model.RemoveAttribute('ylabel') ### Update of DEVSimPy model from new python behavioral file (ContainerBlock is not considered because he did not behavioral) if new_cls.__name__ in ('To_Disk', 'MessagesCollector'): model.__class__ = Container.DiskGUI elif new_cls.__name__ == 'QuickScope': model.__class__ = Container.ScopeGUI model.AddAttribute("xlabel") model.AddAttribute("ylabel") elif True in map(lambda a: 'DomainStructure' in str(a), new_cls.__bases__): model.__class__ = Container.ContainerBlock else: model.__class__ = Container.CodeBlock ### if we change the python file from zipfile we compresse the new python file and we update the python_path value if zipfile.is_zipfile(model.model_path): zf = ZipManager.Zip(model.model_path) zf.Update([new_python_path]) #model.model_path = ### update flag and color if bad filename if model.bad_filename_path_flag: model.bad_filename_path_flag = False else: Container.MsgBoxError(evt, self, new_cls) dlg.Destroy() return False else: dlg.Destroy() return False dlg.Destroy() self.AcceptProp(row, col) elif typ == "list": frame = ListEditor(self, wx.ID_ANY, _('List editor'), values=self.GetCellValue(row, 1)) if frame.ShowModal() == wx.ID_CANCEL: self.SetCellValue(row, 1, frame.GetValueAsString()) else: frame.Destroy() self.AcceptProp(row, col) elif typ == 'dict': frame = DictionaryEditor(self, wx.ID_ANY, _('List editor'), values=self.GetCellValue(row, 1)) if frame.ShowModal() == wx.ID_CANCEL: self.SetCellValue(row, 1, frame.GetValueAsString()) else: frame.Destroy() self.AcceptProp(row, col) elif 'choice' in typ: self.AcceptProp(row, col) else: pass ### all properties grid update (because the python classe has been changed) ### here, because OnAcceptProp should be executed before if prop == 'python_path': ### Update table from new model table.UpdateRowBehavioralData(model) self.SetTable(table, False) self.ForceRefresh() self.AutoSizeColumns() # code updating if isinstance(model, Achievable): new_code = CodeCB(self.parent, wx.ID_ANY, model) #self.parent.boxH.Remove(0) if hasattr(self.parent, '_boxH'): # DeleteWindows work better in vista if wx.VERSION_STRING < '4.0': self.parent._boxH.DeleteWindows() self.parent._boxH.AddWindow(new_code, 1, wx.EXPAND, userData='code') else: self.parent._boxH.Clear() self.parent._boxH.Add(new_code, 1, wx.EXPAND, userData='code') self.parent._boxH.Layout() else: sys.stdout.write("_boxH is unknown!")