-
Notifications
You must be signed in to change notification settings - Fork 19
/
Container.py
5041 lines (4040 loc) · 145 KB
/
Container.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: utf-8 -*-
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
# Container.py ---
# --------------------------------
# Copyright (c) 2020
# L. CAPOCCHI ([email protected])
# SPE Lab - SISU Group - University of Corsica
# --------------------------------
# Version 2.0 last modified: 03/15/20
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
#
# GENERAL NOTES AND REMARKS:
#
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
#
# GLOBAL IMPORT
#
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
import builtins
if builtins.__dict__.get('GUI_FLAG',True):
import wx
import wx.lib.dragscroller
import wx.lib.dialogs
from wx.lib.newevent import NewEvent
_ = wx.GetTranslation
from pubsub import pub as Publisher
AttrUpdateEvent, EVT_ATTR_UPDATE = NewEvent()
### wx.color has been removed in wx. 2.9
if hasattr(wx, "Color"):
wx.Colour = wx.Color
else:
wx.Color = wx.Colour
if wx.VERSION_STRING >= '4.0':
wx.StockCursor = wx.Cursor
else:
import gettext
_ = gettext.gettext
import os
import sys
import copy
import re
import pickle
import zipfile
import array
import inspect
if not hasattr(inspect, 'getargspec'):
inspect.getargspec = inspect.getfullargspec
from abc import ABC
from tempfile import gettempdir
from traceback import format_exception
from math import * ### for eval
from collections import Counter
if builtins.__dict__.get('GUI_FLAG', True):
import ConnectDialog
import DiagramConstantsDialog
import SpreadSheet
import ZipManager
import DropTarget
import PlotGUI
import SimulationGUI
import PriorityGUI
import CheckerGUI
import PluginsGUI
import WizardGUI
### Color definition
RED = '#d91e1e'
RED_LIGHT = '#f2a2a2'
GREEN = '#90ee90'
BLACK = '#000000'
BLUE = '#add8e6'
ORANGE = '#ffa500'
import Components
if builtins.__dict__.get('GUI_FLAG', True):
import Menu
### Mixin
from Mixins.Attributable import Attributable
from Mixins.Achievable import Achievable
from Mixins.Resizeable import Resizeable
from Mixins.Rotatable import Rotatable
from Mixins.Connectable import Connectable
from Mixins.Plugable import Plugable
from Mixins.Structurable import Structurable
from Mixins.Savable import Savable
from Mixins.Selectable import Selectable
from Mixins.Abstractable import Abstractable
from Mixins.Iconizable import Iconizable, Icon
### for all dsp model build with old version of DEVSimPy
sys.modules['Savable'] = sys.modules['Mixins.Savable']
from Decorators import BuzyCursorNotification, Post_Undo
from Utilities import HEXToRGB, relpath, playSound, sendEvent, getInstance, FixedList, getObjectFromString, getTopLevelWindow, printOnStatusBar
from Patterns.Observer import Subject, Observer
if builtins.__dict__.get('GUI_FLAG',True):
from DetachedFrame import DetachedFrame
from AttributeEditor import AttributeEditor, QuickAttributeEditor
from PropertiesGridCtrl import PropertiesGridCtrl
#Global Stuff -------------------------------------------------
clipboard = []
PORT_RESOLUTION = True
##############################################################
# #
# GENERAL fUNCTIONS #
# #
##############################################################
def MsgBoxError(event, parent, msg):
""" Pop-up alert for error in the .py file of a model
"""
### if importation error
if isinstance(msg, str):
dial = wx.MessageDialog(parent, \
_('Error trying to import module : %s')%msg, \
_('Error Manager'), \
wx.OK | wx.ICON_ERROR)
dial.ShowModal()
### Error occurring into the constructor or during the simulation
elif isinstance(msg, tuple):
### find error info of the error
try:
typ, val, tb = msg
trace = format_exception(typ, val, tb)
# mainW = wx.GetApp().GetTopWindow()
### try to find if the error come from devs model
### paths in traceback
paths = [a for a in trace if a.split(',')[0].strip().startswith('File')]
### find if DOMAIN_PATH is in paths list (inverted because traceback begin by the end)
path = None
line = None
fct = None
### find if DOMAIN_PATH is in the first file path of the trace
p = paths[-1]
if DOMAIN_PATH in p or HOME_PATH not in p:
path,line,fct = p.split(',')[0:3]
except Exception as info:
path = None
line = None
fct = None
if path is not None:
python_path = "File: %s\n"%(path.split(' ')[-1])
else:
python_path = ""
if line is not None:
line_number = "Line: %s\n"%(line.split(' ')[-1])
else:
line_number = ""
if fct is not None:
fct = "Function: %s\n"%(fct.split('\n')[0])
else:
fct = ""
if path is not None:
### ask to correct error
dial = wx.MessageDialog(parent,\
_("Error: %s\n%s%s%s\nDo you want to remove this error?")%(str(val),str(python_path),str(fct),str(line_number)),\
_('Error Manager'), \
wx.YES_NO | wx.YES_DEFAULT | wx.ICON_ERROR)
if dial.ShowModal() == wx.ID_YES:
### delete " and cast to string
python_path = str(path.split(' ')[-1])[1:-1]
dir_name = os.path.dirname(python_path)
### create a temporary component to invoke editor windows
devscomp = Components.DEVSComponent()
devscomp.setDEVSPythonPath(python_path)
### instantiation of editor frame and go to the line of the corresponding error
editor_frame = Components.DEVSComponent.OnEditor(devscomp, event)
if zipfile.is_zipfile(dir_name): editor_frame.cb.model_path = dir_name
if editor_frame:
nb = editor_frame.GetNoteBook()
page = nb.GetCurrentPage()
pos = int(line.split(' ')[-1])
page.GotoLine(pos)
return True
else:
return False
else:
wx.MessageBox(_("There is errors in python file.\nTrying to translate error informations: %s %s %s")%(typ, val, tb), _("Error"), wx.OK|wx.ICON_ERROR)
def CheckClass(m):
""" Check if class is ok and return it.
"""
if inspect.isclass(m):
cls = m
args = Components.GetArgs(cls)
elif isinstance(m, Block):
tempdir = os.path.realpath(gettempdir())
if tempdir in os.path.dirname(m.python_path):
cls = ('','','')
else:
cls = Components.GetClass(m.python_path)
args = m.args
elif os.path.exists(m):
### if .amd or .cmd
if zipfile.is_zipfile(m):
#zf = ZipManager.Zip(m)
cls = Components.GetClass(os.path.join(m, ZipManager.getPythonModelFileName(m)))
### .py
else:
cls = Components.GetClass(m)
args = Components.GetArgs(cls)
elif m.startswith('http'):
cls = Components.GetClass(m)
args = Components.GetArgs(cls)
else:
cls = ("","","")
### check cls error
if isinstance(cls, tuple):
return cls
### check devs instance
devs = getInstance(cls, args)
### check instance error
return devs if isinstance(devs, (tuple, Exception)) else None
################################################################
# #
# GENERAL CLASS #
# #
################################################################
#-------------------------------------------------------------------------------
class Diagram(Savable, Structurable):
""" Diagram class.
"""
def __init__(self):
""" Constructor.
"""
Structurable.__init__(self)
# list of shapes in the diagram
self.shapes = []
self.parent = None
# shape priority for simulation
self.priority_list = []
# constants dico
self.constants_dico = {}
# devs Master model
self.devsModel = None
# list of number of Block and Port under the diagram
self.nbCodeBlock = 0
self.nbContainerBlock = 0
self.nbiPort = 0
self.nboPort = 0
# list of deleted id
self.deletedCodeBlockId = []
self.deletedContainerBlockId = []
self.deletediPortId = []
self.deletedoPortId = []
self.last_name_saved = ''
self.modify = False
def __getstate__(self):
"""Return state values to be pickled."""
### we copy a new state in order to dont lost the devs result of Scope for example.
new_state = self.__dict__.copy()
### delete devs instance (because is generate before the simulation)
new_state['devsModel'] = None
### set parent attribut for undo/redo
new_state['parent'] = None
return new_state
def __getattr__(self, name):
"""Called when an attribute lookup has not found the attribute in the usual places.
"""
if name == 'dump_attributes':
return ['shapes', 'priority_list', 'constants_dico']
#=======================================================================
elif name == 'dump_abstr_attributes':
return Abstractable.DUMP_ATTR if hasattr(self, 'layers') and hasattr(self, 'current_level') else []
#=======================================================================
else:
raise AttributeError(name)
@staticmethod
def makeDEVSGraph(diagram, D = {}, type = object):
""" Make a formated dictionnary to make the graph of the DEVS Network: {'S1': [{'C1': (1, 0)}, {'M': (0, 1)}], port 1 of S1 is connected to the port 0 of C1...
"""
# for all components in the diagram
for c in diagram.GetShapeList():
# if the component is the conncetionShape, then add the new element in the D dictionnary
if isinstance(c, ConnectionShape):
model1, portNumber1 = c.input
model2, portNumber2 = c.output
# return D with object representation
if type is object:
D.setdefault(model2,[]).append({model1: (portNumber2 ,portNumber1)})
if isinstance(model1, (iPort,oPort)):
D.setdefault(model1,[]).append({model2: (portNumber1 ,portNumber2)})
# return D with string representation
else:
label1 = model1.label
label2 = model2.label
D.setdefault(label2,[]).append({label1: (portNumber2 ,portNumber1)})
if isinstance(model1, (iPort,oPort)):
D.setdefault(label1,[]).append({label2: (portNumber1 ,portNumber2)})
#if the component is a container block achieve the recursivity
elif isinstance(c, ContainerBlock):
Diagram.makeDEVSGraph(c,D,type)
return D
@staticmethod
def makeDEVSInstance(diagram = None):
""" Return the DEVS instance of diagram. Iterations order is very important!
1. we make the codeblock devs instance
2. we make the devs port instance for all devsimpy port
3. we make Containerblock instance
4. we make the connection
"""
#import ReloadModule
#ReloadModule.recompile("DomainInterface.DomainBehavior")
#ReloadModule.recompile("DomainInterface.DomainStructure")
#ReloadModule.recompile("DomainInterface.MasterModel")
#import DomainInterface.MasterModel
### PyPDEVS work with this
#diagram.setDEVSModel(DomainInterface.MasterModel.Master())
### TODO to be tested with PyPDEVS !!!
# if isinstance(diagram.parent, ShapeCanvas):
# diagram.setDEVSModel(DomainInterface.MasterModel.Master())
# else:
# diagram.ClearAllPorts()
### if devs instance of diagram is not instantiated, we make it
### else one simulation has been performed then we clear all devs port instances
if diagram.getDEVSModel():
diagram.ClearAllPorts()
else:
import DomainInterface.MasterModel
diagram.setDEVSModel(DomainInterface.MasterModel.Master())
### shape list of diagram
shape_list = diagram.GetShapeList()
block_list = {c for c in shape_list if isinstance(c, Block)}
### for all codeBlock shape, we make the devs instance
for m in block_list:
### class object from python file
cls = Components.GetClass(m.python_path)
### Class is wrong ?
if isinstance(cls, (ImportError, tuple)) or cls is None:
sys.stdout.write(_('Error making DEVS instances for:\n%s (class:%s)\n'%(m.python_path,str(cls))))
return False
else:
### DEVS model recovery
devs = getInstance(cls, m.args)
### Is safe instantiation ?
if isinstance(devs, tuple):
return devs
else:
devs.name = m.label
if isinstance(m, CodeBlock):
### les ports des modeles couples sont pris en charge plus bas dans les iPorts et oPorts
## ajout des port par rapport aux ports graphiques
for i in range(m.input):
devs.addInPort(f'in_{i}')
for j in range(m.output):
devs.addOutPort(f'out_{j}')
### devs instance setting
m.setDEVSModel(devs)
m.setDEVSParent(diagram.getDEVSModel())
### allow to escape the check of the simulation running in PyPDEVS (src/DEVS.py line 565)
if hasattr(devs.parent, "fullName"):
del devs.parent.fullName
### adding
diagram.addSubModel(devs)
#### recursion
if isinstance(m, ContainerBlock):
###===================================================================
if hasattr(m, 'layers') and hasattr(m, 'current_level'):
### level is given by the first stored diagram because m.current is not updated by the spin control
level = m.layers[0].current_level
dia = m.layers[level]
m.shapes = dia.GetShapeList()
m.priority_list = dia.priority_list or []
m.constants_dico = dia.constants_dico or {}
###===================================================================
Diagram.makeDEVSInstance(m)
###============================================================================= Add abstraction level manager
if hasattr(diagram, 'current_level') and diagram.current_level>0:
### Add devs model dam to diagram
dam = diagram.DAM[diagram.current_level]
devs_dam = getObjectFromString(dam)
diagram.addSubModel(devs_dam)
### Add devs model uam to diagram
uam = diagram.UAM[diagram.current_level]
devs_uam = getObjectFromString(uam)
diagram.addSubModel(devs_uam)
### inputs/outpus of dam/uam are instantiate depending on the iPort/oPort of diagram 0
dia_0 = diagram.layers[0]
shapeL0 = dia_0.GetShapeList()
for m in (s for s in shapeL0 if isinstance(s, iPort)):
devs_dam.addInPort()
diagram.addInPort()
for m in (s for s in shapeL0 if isinstance(s, oPort)):
devs_uam.addOutPort()
diagram.addOutPort()
for m in (s for s in shape_list if isinstance(s, iPort)):
devs_dam.addOutPort()
for m in (s for s in shape_list if isinstance(s, oPort)):
devs_uam.addInPort()
###==================================================================================
### Add abstraction level manager
###==============================================================================
if hasattr(diagram, 'current_level') and diagram.current_level>0:
# for all iPort shape, we make the devs instance
for i,m in enumerate((s for s in shapeL0 if isinstance(s, iPort))):
p1 = diagram.getDEVSModel().IPorts[i]
p2 = devs_dam.IPorts[i]
Structurable.ConnectDEVSPorts(diagram, p1, p2)
###==============================================================================
else:
for m in (s for s in shape_list if isinstance(s, iPort)):
### add port to coupled model
diagram.addInPort()
assert(len(diagram.getIPorts()) <= diagram.input)
###==============================================================================
### Add abstraction level manager
if hasattr(diagram, 'current_level') and diagram.current_level>0:
# for all oPort shape, we make the devs instance
for i,m in enumerate((s for s in shapeL0 if isinstance(s, oPort))):
p1 = devs_uam.OPorts[i]
p2 = diagram.getDEVSModel().OPorts[i]
Structurable.ConnectDEVSPorts(diagram, p1, p2)
###===============================================================================
else:
for m in (s for s in shape_list if isinstance(s, oPort)):
### add port to coupled model
diagram.addOutPort()
assert(len(diagram.getOPorts()) <= diagram.output)
### Connections
for m in (s for s in shape_list if isinstance(s, ConnectionShape)):
m1,n1 = m.input
m2,n2 = m.output
if isinstance(m1, Block) and isinstance(m2, Block):
try:
p1 = m1.getDEVSModel().OPorts[n1]
except:
msg = _("It seems that the number of internal output ports (%d) of the coupled model %s is not enough!\nPlease check this.")%(len(m1.getDEVSModel().OPorts),m1.label)
sys.stdout.write(msg)
return msg
try:
p2 = m2.getDEVSModel().IPorts[n2]
except:
msg = _("It seems that the number of internal input ports (%d) of the coupled model %s is not enough!\nPlease check this.")%(len(m2.getDEVSModel().IPorts),m2.label)
sys.stdout.write(msg)
return msg
Structurable.ConnectDEVSPorts(diagram, p1, p2)
elif isinstance(m1, Block) and isinstance(m2, oPort):
### TODO insert devs_uam
p1 = m1.getDEVSModel().OPorts[n1]
###==============================================================================
### Add abstraction level manager
if hasattr(diagram, 'current_level') and diagram.current_level>0:
p2 = devs_uam.IPorts[m2.id]
else:
p2 = diagram.getDEVSModel().OPorts[m2.id]
###===============================================================================
Structurable.ConnectDEVSPorts(diagram, p1, p2)
#p1 = m1.getDEVSModel().OPorts[n1]
#p2 = diagram.getDEVSModel().OPorts[m2.id]
#Structurable.ConnectDEVSPorts(diagram, p1, p2)
elif isinstance(m1, iPort) and isinstance(m2, Block):
### TODO insert devs_dam
###==============================================================================
### Add abstraction level manager
if hasattr(diagram, 'current_level') and diagram.current_level>0:
p1 = devs_dam.OPorts[m1.id]
else:
p1 = diagram.getDEVSModel().IPorts[m1.id]
###===============================================================================
p2 = m2.getDEVSModel().IPorts[n2]
Structurable.ConnectDEVSPorts(diagram, p1, p2)
#p1 = diagram.getDEVSModel().IPorts[m1.id]
#p2 = m2.getDEVSModel().IPorts[n2]
#Structurable.ConnectDEVSPorts(diagram, p1, p2)
# elif isinstance(m1, iPort) and isinstance(m2, oPort):
# ###==============================================================================
# ### Add abstraction level manager
# if hasattr(diagram, 'current_level') and diagram.current_level>0:
# p1 = devs_dam.OPorts[m1.id]
# p2 = devs_dam.IPorts[m2.id]
# else:
# p1 = diagram.getDEVSModel().IPorts[m1.id]
# p2 = diagram.getDEVSModel().OPorts[m2.id]
# ###===============================================================================
# Structurable.ConnectDEVSPorts(diagram, p1, p2)
else:
msg = _('Direct connections between ports inside the coupled model %s have been founded.\n There are not considered by the simulation!\n'%(diagram.label))
sys.stdout.write(msg)
#return msg
### update priority_list from shape list
### Shape list can be increased or decreased (add or remove shape) without invoke the Priority list dialogue
diagram.updateDEVSPriorityList()
### reordered the componentSet of the master before the simulation
if diagram.priority_list:
L = []
devs = diagram.getDEVSModel()
# si l'utilisateur n'a pas definit d'ordre de priorité pour l'activation des modèles, on la construit
for label1 in diagram.priority_list:
for m in devs.getComponentSet():
label2 = m.getBlockModel().label
if label1 == label2:
L.append(m)
devs.setComponentSet(L)
return diagram.getDEVSModel()
def SetParent(self, parent):
"""
"""
assert isinstance(parent, ShapeCanvas)
self.parent = parent
def GetParent(self):
"""
"""
return self.parent
def GetGrandParent(self):
"""
"""
return self.GetParent().GetParent()
@BuzyCursorNotification
def LoadFile(self, fileName = None):
""" Function that load diagram from a file.
"""
load_file_result = Savable.LoadFile(self, fileName)
if isinstance(load_file_result, Exception):
### Exception propagation
return load_file_result
else:
# load constants (like Rs, Lms...) into the general builtin (to use it, <title>['Lms'] into the expr)
# give title by basename of filename
title = os.path.splitext(os.path.basename(fileName))[0]
# load constants into the general builtin
self.LoadConstants(title)
for shape in self.GetShapeList():
self.UpdateAddingCounter(shape)
return True
#@cond_decorator(builtins.__dict__.get('GUI_FLAG',True), StatusBarNotification('Load'))
def LoadConstants(self, label):
""" Load Constants to general builtin.
"""
if self.constants_dico != {}:
builtins.__dict__[label] = self.constants_dico
for s in [c for c in self.GetShapeList() if isinstance(c, ContainerBlock)]:
s.LoadConstants(s.label)
def OnPriority(self, parent):
""" Method that show the priorityGUI frame in order to define the activation priority of components
"""
shapes_list = [s.label for s in self.GetShapeList() if isinstance(s, Block)]
#list of all components
if self.priority_list == []:
self.priority_list = shapes_list
else:
### priority list manager
cpt = 1
lenght = len(shapes_list)
result = [None]*lenght
for s in shapes_list:
if s in self.priority_list :
try:
result[self.priority_list.index(s)]=s
except:
pass
else:
result[lenght-cpt] = s
cpt+=1
self.priority_list = [s for s in result if s is not None]
self.modify = True
self.parent.DiagramModified()
dlg = PriorityGUI.PriorityGUI(parent, wx.NewIdRef(), _("Priority Manager"), self.priority_list)
dlg.Bind(wx.EVT_CLOSE, self.OnClosePriorityGUI)
dlg.Show()
def OnInformation(self, event):
"""
"""
stat_dico = self.GetStat({'Atomic_nbr':0, 'Coupled_nbr':0, 'Connection_nbr':0, 'Deep_level':0, 'iPort_nbr':0, 'oPort_nbr':0})
msg = "".join( [_("Path: %s\n")%self.last_name_saved,
_("Number of atomic devs models: %d\n")%stat_dico['Atomic_nbr'],
_("Number of coupled devs models: %d\n")%stat_dico['Coupled_nbr'],
_("Number of coupling: %d\n")%stat_dico['Connection_nbr'],
_("Number of deep level (description hierarchy): %d\n")%stat_dico['Deep_level'],
_("Number of input port models: %d\n")%stat_dico['iPort_nbr'],
_("Number of output port models: %d\n")%stat_dico['oPort_nbr']]
)
dlg = wx.lib.dialogs.ScrolledMessageDialog(self.GetParent(), msg, _("Diagram Information"), style=wx.OK|wx.ICON_EXCLAMATION|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
dlg.ShowModal()
def OnClosePriorityGUI(self, event):
""" Method that update the self.priority_list and close the priorityGUI Frame
"""
obj = event.GetEventObject()
self.priority_list = [obj.listCtrl.GetItemText(i) for i in range(obj.listCtrl.GetItemCount())]
obj.Destroy()
### we can update the devs priority list during the simulation ;-)
self.updateDEVSPriorityList()
event.Skip()
def OnAddConstants(self, event):
""" Method that add constant parameters in order to simplify the modling codeBlock model
"""
obj = event.GetEventObject()
### conditional statement only for windows
win = obj.GetInvokingWindow() if isinstance(obj, wx.Menu) else obj
### event come from right click on the shapecanvas
if isinstance(win, ShapeCanvas):
win = win.GetParent()
if isinstance(win, DetachedFrame):
title = win.GetTitle()
else:
title = win.GetPageText(win.GetSelection())
### event come from Main application by the Diagram menu
else:
### needed for window
if not win: win = obj.GetWindow()
nb2 = win.GetDiagramNotebook()
title = nb2.GetPageText(nb2.GetSelection())
dlg = DiagramConstantsDialog.DiagramConstantsDialog(win, wx.NewIdRef(), title)
dlg.Populate(self.constants_dico)
if dlg.ShowModal() == wx.ID_OK:
self.constants_dico = dlg.GetData()
dlg.Destroy()
@BuzyCursorNotification
def checkDEVSInstance(self, diagram=None, D={}):
""" Recursive DEVS instance checker for a diagram.
@param diagram: diagram instance
@param D: Dictionary of models with the associated error
"""
### shape list of diagram
shape_list = set(diagram.GetShapeList())
#### for all codeBlock and containerBlock shapes, we make the devs instance
for m in [s for s in shape_list if isinstance(s, (CodeBlock, ContainerBlock))]:
D[m] = CheckClass(m)
## for all ContainerBlock shape, we make the devs instance and call the recursion
if isinstance(m, ContainerBlock):
self.checkDEVSInstance(m, D)
def DoCheck(self):
""" Check all models for validation
Return None if all models are ok, D else
"""
### dictionary composed by key = label of model and value = None if no error, exc_info() else
D = {}
self.checkDEVSInstance(self, D)
return D if [m for m in list(D.values()) if m != None] != [] else None
def OnCheck(self, event):
""" Check button has been clicked. We check if models which compose the diagram are valide.
"""
### if there are models in diagram
if self.GetCount() != 0:
obj = event.GetEventObject()
win = obj.GetTopLevelParent() if isinstance(obj, wx.ToolBar) else obj.GetWindow()
D = self.DoCheck()
### if there is no error
if D is None:
dial = wx.MessageDialog(win,
_('All DEVS model has been instantiated without error.\n\nDo you want simulate?'),
_('Error Manager'),
wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
if dial.ShowModal() == wx.ID_YES:
self.OnSimulation(event)
else:
frame = CheckerGUI.CheckerGUI(win, self.DoCheck())
frame.SetDiagram(self)
frame.Show()
### no models in diagram
else:
wx.MessageBox(_("Diagram is empty.\n\nPlease, drag-and-drop model from libraries control panel to build a diagram or load an existing diagram."),_('Error Manager'))
@BuzyCursorNotification
def OnSimulation(self, event):
""" Method calling the simulationGUI
"""
### if there are models in diagram
if self.GetCount() != 0 :
## window that contain the diagram which will be simulate
win = wx.GetApp().GetTopWindow()
obj = event.GetEventObject()
# obj = event.GetEventObject()
# win = obj.GetWindow() if isinstance(obj, wx.Menu) else obj.GetTopLevelParent()
# diagram which will be simulate
diagram = self
### Check if all models doesn't contain errors
D = self.DoCheck()
### if there is no error in models
if D is not None:
dial = wx.MessageDialog(win, \
_("There is errors in some models.\n\nDo you want to execute the error manager ?"), \
_('Simulation Manager'), \
wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
playSound(SIMULATION_ERROR_SOUND_PATH)
if dial.ShowModal() == wx.ID_YES:
frame = CheckerGUI.CheckerGUI(win, D)
frame.SetDiagram(self)
frame.Show()
return False
else:
### Check if models have the same label
L = diagram.GetLabelList([])
if len(L)!=len(set(L)):
model_with_same_label = [f"-{k}" for k,v in Counter(L).items() if v>1]
txt = "\n".join(model_with_same_label)
wx.MessageBox(_("It seems that the following models have a same label:\n\
%s\n\
\nIf you plan to use Flat simulation algorithm, all model must have a unique label.")%txt, _("Simulation Manager"))
### set the name of diagram
if isinstance(win, DetachedFrame):
title = win.GetTitle()
else:
nb2 = win.GetDiagramNotebook()
title =nb2.GetPageText(nb2.GetSelection()).rstrip()
diagram.label = os.path.splitext(os.path.basename(title))[0]
## delete all attached devs instances
diagram.Clean()
## make DEVS instance from diagram
master = Diagram.makeDEVSInstance(diagram)
if not master or isinstance(master,str):
wx.MessageBox(master, _("Simulation Manager"))
return False
## test of filename model attribute
elif all(model.bad_filename_path_flag for model in [m for m in diagram.GetShapeList() if isinstance(m, Block)] if hasattr(model, 'bad_filename_path_flag')):
dial = wx.MessageDialog(win, \
_("You don't make the simulation of the Master model.\nSome models have bad fileName path !"),\
_('Simulation Manager'), \
wx.OK | wx.ICON_EXCLAMATION)
dial.ShowModal()
return False
else:
# pluginmanager.trigger_event('START_DIAGRAM', parent = win, diagram = diagram)
### clear all log file
for fn in [f for f in os.listdir(gettempdir()) if f.endswith('.devsimpy.log')]:
os.remove(os.path.join(os.path.realpath(gettempdir()),fn))
## obj = event.GetEventObject()
# si invocation à partir du bouton dans la toolBar (apparition de la frame de simulation dans une fenetre)
if isinstance(obj, wx.ToolBar) or 'Diagram' in obj.GetTitle():
frame = SimulationGUI.SimulationDialog(win, wx.NewIdRef(), _(" %s Simulator"%diagram.label))
frame.SetMaster(master)
frame.Show()
## si invocation par le menu (apparition de la frame de simulation dans le panel)
elif isinstance(obj, (wx.Menu, wx.Frame)):
sizer3 = wx.BoxSizer(wx.VERTICAL)
win.panel3.Show()
win.SimDiag = SimulationGUI.SimulationDialog(win.panel3, wx.NewIdRef(), _("Simulation Manager"))
win.SimDiag.SetMaster(master)
sizer3.Add(win.SimDiag, 0, wx.EXPAND)
win.panel3.SetSizer(sizer3)
win.panel3.SetAutoLayout(True)
### title is Simulation because it must ne the same of the submenu in toolbar (for checking update)
nb1 = win.GetControlNotebook()
nb1.InsertPage(2, win.panel3, _("Simulation"), imageId = 2)
else:
sys.stdout.write(_("This option has not been implemented yet."))
return False
return True
else:
wx.MessageBox(_("Diagram is empty.\n\nPlease, drag-and-drop model from libraries control panel to build a diagram or load an existing diagram.."),_('Simulation Manager'))
return False
def AddShape(self, shape, after = None):
""" Method that insert shape into the diagram at the position 'after'
"""
index = self.shapes.index(after) if after else 0
self.UpdateAddingCounter(shape)
self.InsertShape(shape, index)
def InsertShape(self, shape, index = 0):
""" Method that insert shape into the diagram to the index position
"""
self.shapes.insert(index, shape)
self.modify = True
if self.parent:
self.parent.DiagramModified()
def DeleteShape(self, shape):
""" Method that delete all shape links
"""
### delete all shape connected with connection shape
for cs in [c for c in self.GetShapeList() if isinstance(c, ConnectionShape)]:
if cs.input is not None and cs.output is not None:
if shape in cs.input+cs.output:
self.shapes.remove(cs)
if isinstance(shape, Block):
if shape.label in self.priority_list:
### update priority list
self.priority_list.remove(shape.label)
if isinstance(shape, Block):
### update the devs componentSet
coupled_devs = self.getDEVSModel()
devs = shape.getDEVSModel()
if coupled_devs and devs in coupled_devs.getComponentSet():
coupled_devs.delToComponentSet([devs])
try:
### delete shape
self.shapes.remove(shape)
except ValueError:
sys.stdout.write(_("Error trying to remove %s")%shape)
### update the number of shape depending to its type
self.UpdateRemovingCounter(shape)
self.modify = True
self.parent.DiagramModified()
def UpdateRemovingCounter(self, shape):
""" Method that update the removed shape counter
"""
# update number of components
if isinstance(shape, CodeBlock):
self.deletedCodeBlockId.append(shape.id)
self.nbCodeBlock-=1
elif isinstance(shape, ContainerBlock):
self.deletedContainerBlockId.append(shape.id)
self.nbContainerBlock-=1
elif isinstance(shape, iPort):
self.deletediPortId.append(shape.id)
self.nbiPort-=1
elif isinstance(shape, oPort):
self.deletedoPortId.append(shape.id)
self.nboPort-=1
else:
pass
def UpdateAddingCounter(self, shape):
""" Method that update the added shape counter
"""
# gestion du nombre de shape
if isinstance(shape, CodeBlock):
shape.id=self.GetCodeBlockCount()
self.nbCodeBlock+=1
elif isinstance(shape, ContainerBlock):
shape.id=self.GetContainerBlockCount()
self.nbContainerBlock+=1
elif isinstance(shape, iPort):
self.nbiPort+=1