# HG changeset patch # User Andrey Skvortsov # Date 1502727181 -10800 # Node ID 64d8f52bc8c8c97fd971327c0d12710f918363e2 # Parent d51af006fa6ba13c57494a66ba9c740694dcdf56 clean-up for PEP8: fix W291 trailing whitespace diff -r d51af006fa6b -r 64d8f52bc8c8 Beremiz.py --- a/Beremiz.py Fri Aug 11 15:18:19 2017 +0300 +++ b/Beremiz.py Mon Aug 14 19:13:01 2017 +0300 @@ -60,14 +60,14 @@ def Usage(self): print "Usage:" - print "%s [Options] [Projectpath] [Buildpath]"%sys.argv[0] + print "%s [Options] [Projectpath] [Buildpath]"%sys.argv[0] print "" print "Supported options:" print "-h --help Print this help" print "-u --updatecheck URL Retrieve update information by checking URL" print "-e --extend PathToExtension Extend IDE functionality by loading at start additional extensions" print "" - print "" + print "" def SetCmdOptions(self): self.shortCmdOpts = "hu:e:" diff -r d51af006fa6b -r 64d8f52bc8c8 BeremizIDE.py --- a/BeremizIDE.py Fri Aug 11 15:18:19 2017 +0300 +++ b/BeremizIDE.py Mon Aug 14 19:13:01 2017 +0300 @@ -276,9 +276,9 @@ wx.MessageBox(version.GetCommunityHelpMsg(), _(u'Community support'), wx.OK | wx.ICON_INFORMATION) } id = wx.NewId() - parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support')) + parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support')) self.Bind(wx.EVT_MENU, handler, id=id) - + parent.Append(help='', id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL, text=_(u'About')) self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT) @@ -371,7 +371,7 @@ self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.ST_SIZEGRIP) self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range = 100) - self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2) + self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2) self.ProgressStatusBar.Hide() self.SetStatusBar(self.ConnectionStatusBar) @@ -383,13 +383,13 @@ # commands invoked by build process by default are # found here. os.environ["PATH"] = os.getcwd()+';'+os.environ["PATH"] - - + + def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): # Add beremiz's icon in top left corner of the frame self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO) self.__init_execute_path() - + IDEFrame.__init__(self, parent, debug) self.Log = LogPseudoFile(self.LogConsole,self.SelectTab) @@ -932,7 +932,7 @@ self.Close() def OnAboutMenu(self, event): - info = version.GetAboutDialogInfo() + info = version.GetAboutDialogInfo() ShowAboutDialog(self, info) def OnProjectTreeItemBeginEdit(self, event): diff -r d51af006fa6b -r 64d8f52bc8c8 Beremiz_service.py --- a/Beremiz_service.py Fri Aug 11 15:18:19 2017 +0300 +++ b/Beremiz_service.py Mon Aug 14 19:13:01 2017 +0300 @@ -306,7 +306,7 @@ def OnTaskBarChangeInterface(self, evt): ip_addr = self.pyroserver.ip_addr ip_addr = '' if ip_addr is None else ip_addr - dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr) + dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr) dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")), ( lambda x :len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4, _("IP is not valid!")) ]) diff -r d51af006fa6b -r 64d8f52bc8c8 CodeFileTreeNode.py --- a/CodeFileTreeNode.py Fri Aug 11 15:18:19 2017 +0300 +++ b/CodeFileTreeNode.py Mon Aug 14 19:13:01 2017 +0300 @@ -81,10 +81,10 @@ SECTION_TAG_ELEMENT = "" class CodeFile: - + CODEFILE_NAME = "CodeFile" SECTIONS_NAMES = [] - + def __init__(self): sections_str = {"codefile_name": self.CODEFILE_NAME} if "includes" in self.SECTIONS_NAMES: @@ -94,26 +94,26 @@ sections_str["sections"] = "\n".join( [SECTION_TAG_ELEMENT % name for name in self.SECTIONS_NAMES if name != "includes"]) - + self.CodeFileParser = GenerateParserFromXSDstring( CODEFILE_XSD % sections_str) self.CodeFileVariables = etree.XPath("variables/variable") - + filepath = self.CodeFileName() - + if os.path.isfile(filepath): xmlfile = open(filepath, 'r') codefile_xml = xmlfile.read() xmlfile.close() - + codefile_xml = codefile_xml.replace( - '<%s>' % self.CODEFILE_NAME, + '<%s>' % self.CODEFILE_NAME, '<%s xmlns:xhtml="http://www.w3.org/1999/xhtml">' % self.CODEFILE_NAME) for cre, repl in [ (re.compile("(?)(?:)(?!)"), "]]>")]: codefile_xml = cre.sub(repl, codefile_xml) - + try: self.CodeFile, error = self.CodeFileParser.LoadXMLString(codefile_xml) if error is not None: @@ -138,7 +138,7 @@ def GenerateNewName(self, format, start_idx): return self.GetCTRoot().GenerateNewName( None, None, format, start_idx, - dict([(var.getname().upper(), True) + dict([(var.getname().upper(), True) for var in self.CodeFile.variables.getvariable()])) def SetVariables(self, variables): @@ -152,12 +152,12 @@ variable.setonchange(var["OnChange"]) variable.setopts(var["Options"]) self.CodeFile.variables.appendvariable(variable) - + def GetVariables(self): datas = [] for var in self.CodeFileVariables(self.CodeFile): - datas.append({"Name" : var.getname(), - "Type" : var.gettype(), + datas.append({"Name" : var.getname(), + "Type" : var.gettype(), "Initial" : var.getinitial(), "Description" : var.getdesc(), "OnChange" : var.getonchange(), @@ -170,25 +170,25 @@ section_code = parts.get(section) if section_code is not None: getattr(self.CodeFile, section).setanyText(section_code) - + def GetTextParts(self): return dict([(section, getattr(self.CodeFile, section).getanyText()) for section in self.SECTIONS_NAMES]) - + def CTNTestModified(self): - return self.ChangesToSave or not self.CodeFileIsSaved() + return self.ChangesToSave or not self.CodeFileIsSaved() def OnCTNSave(self, from_project_path=None): filepath = self.CodeFileName() - + xmlfile = open(filepath,"w") xmlfile.write(etree.tostring( - self.CodeFile, - pretty_print=True, - xml_declaration=True, + self.CodeFile, + pretty_print=True, + xml_declaration=True, encoding='utf-8')) xmlfile.close() - + self.MarkCodeFileAsSaved() return True @@ -196,7 +196,7 @@ variables = self.CodeFileVariables(self.CodeFile) ret = [(variable.getname(), variable.gettype(), - variable.getinitial()) + variable.getinitial()) for variable in variables] ret.extend([("On"+variable.getname()+"Change", "python_poll", "") for variable in variables @@ -219,31 +219,30 @@ def BufferCodeFile(self): self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile)) - + def StartBuffering(self): self.Buffering = True - + def EndBuffering(self): if self.Buffering: self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile)) self.Buffering = False - + def MarkCodeFileAsSaved(self): self.EndBuffering() self.CodeFileBuffer.CurrentSaved() - + def CodeFileIsSaved(self): return self.CodeFileBuffer.IsCurrentSaved() and not self.Buffering - + def LoadPrevious(self): self.EndBuffering() self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Previous()) - + def LoadNext(self): self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Next()) - + def GetBufferState(self): first = self.CodeFileBuffer.IsFirst() and not self.Buffering last = self.CodeFileBuffer.IsLast() return not first, not last - diff -r d51af006fa6b -r 64d8f52bc8c8 ConfigTreeNode.py --- a/ConfigTreeNode.py Fri Aug 11 15:18:19 2017 +0300 +++ b/ConfigTreeNode.py Mon Aug 14 19:13:01 2017 +0300 @@ -67,7 +67,7 @@ LibraryControler = None EditorType = ConfTreeNodeEditor IconPath = None - + def _AddParamsMembers(self): self.CTNParams = None if self.XSD: @@ -78,7 +78,7 @@ setattr(self, name, obj) def __init__(self): - # Create BaseParam + # Create BaseParam self.BaseParams = _BaseParamsParser.CreateRoot() self.MandatoryParams = ("BaseParams", self.BaseParams) self._AddParamsMembers() @@ -86,10 +86,10 @@ self._View = None # copy ConfNodeMethods so that it can be later customized self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods] - + def ConfNodeBaseXmlFilePath(self, CTNName=None): return os.path.join(self.CTNPath(CTNName), "baseconfnode.xml") - + def ConfNodeXmlFilePath(self, CTNName=None): return os.path.join(self.CTNPath(CTNName), "confnode.xml") @@ -103,22 +103,22 @@ project_path = self.CTNParent.CTNPath() return os.path.join(project_path, CTNName + NameTypeSeparator + self.CTNType) - + def CTNName(self): return self.BaseParams.getName() - + def CTNEnabled(self): return self.BaseParams.getEnabled() - + def CTNFullName(self): parent = self.CTNParent.CTNFullName() if parent != "": return parent + "." + self.CTNName() return self.BaseParams.getName() - + def GetIconName(self): return None - + def CTNTestModified(self): return self.ChangesToSave @@ -134,10 +134,10 @@ return True return False - + def RemoteExec(self, script, **kwargs): return self.CTNParent.RemoteExec(script, **kwargs) - + def OnCTNSave(self, from_project_path=None): #Default, do nothing and return success return True @@ -154,7 +154,7 @@ if self.CTNParams: params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0])) return params - + def SetParamsAttribute(self, path, value): self.ChangesToSave = True # Filter IEC_Channel and Name, that have specific behavior @@ -169,7 +169,7 @@ res = self.FindNewName(value) self.CTNRequestSave() return res, True - + parts = path.split(".", 1) if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: self.MandatoryParams[1].setElementValue(parts[1], value) @@ -189,32 +189,32 @@ if not os.path.isdir(ctnpath): # Create it os.mkdir(ctnpath) - + # generate XML for base XML parameters controller of the confnode if self.MandatoryParams: BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(),'w') BaseXMLFile.write(etree.tostring( - self.MandatoryParams[1], - pretty_print=True, - xml_declaration=True, + self.MandatoryParams[1], + pretty_print=True, + xml_declaration=True, encoding='utf-8')) BaseXMLFile.close() - + # generate XML for XML parameters controller of the confnode if self.CTNParams: XMLFile = open(self.ConfNodeXmlFilePath(),'w') XMLFile.write(etree.tostring( - self.CTNParams[1], - pretty_print=True, - xml_declaration=True, + self.CTNParams[1], + pretty_print=True, + xml_declaration=True, encoding='utf-8')) XMLFile.close() - + # Call the confnode specific OnCTNSave method result = self.OnCTNSave(from_project_path) if not result: return _("Error while saving \"%s\"\n")%self.CTNPath() - + # mark confnode as saved self.ChangesToSave = False # go through all children and do the same @@ -226,7 +226,7 @@ if result: return result return None - + def CTNImport(self, src_CTNPath): shutil.copytree(src_CTNPath, self.CTNPath) return True @@ -236,13 +236,13 @@ @return: [(instance_name, instance_type),...] """ return [] - + def _GlobalInstances(self): instances = self.CTNGlobalInstances() for CTNChild in self.IECSortedChildren(): instances.extend(CTNChild._GlobalInstances()) return instances - + def CTNGenerate_C(self, buildpath, locations): """ Generate C code @@ -257,7 +257,7 @@ """ self.GetCTRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n") return [],"",False - + def _Generate_C(self, buildpath, locations): # Generate confnodes [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files # extra_files = [(fname,fobject), ...] @@ -280,7 +280,7 @@ LDFLAGS=CTNLDFLAGS[:] else: LDFLAGS=[] - + # recurse through all children, and stack their results for CTNChild in self.IECSortedChildren(): new_location = CTNChild.GetCurrentLocation() @@ -296,14 +296,14 @@ LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS LDFLAGS += _LDFLAGS extra_files += _extra_files - + return LocationCFilesAndCFLAGS, LDFLAGS, extra_files def IterChildren(self): for CTNType, Children in self.Children.items(): for CTNInstance in Children: yield CTNInstance - + def IECSortedChildren(self): # reorder children by IEC_channels ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChildren()] @@ -312,7 +312,7 @@ return zip(*ordered)[1] else: return [] - + def _GetChildBySomething(self, something, toks): for CTNInstance in self.IterChildren(): # if match component of the name @@ -338,7 +338,7 @@ return self._GetChildBySomething("IEC_Channel", Location) else: return self - + def GetCurrentLocation(self): """ @return: Tupple containing confnode IEC location of current confnode : %I0.0.4.5 => (0,0,4,5) @@ -372,7 +372,7 @@ This function is meant to be overridden by confnodes. It should returns an list of dictionaries - + - IEC_type is an IEC type like BOOL/BYTE/SINT/... - location is a string of this variable's location, like "%IX0.0.0" ''' @@ -409,7 +409,7 @@ while res in AllNames: res = "%s_%d"%(BaseDesiredName, suffix) suffix += 1 - + # Get old path oldname = self.CTNPath() # Check previous confnode existance @@ -444,7 +444,7 @@ #if CurrentChannel == DesiredChannel: return CurrentChannel # Build a list of used Channels out of parent's Children AllChannels = self.GetAllChannels() - + # Now, try to guess the nearest available channel res = DesiredChannel while res in AllChannels: # While channel not free @@ -466,14 +466,14 @@ if self.EditorType is not None: app_frame = self.GetCTRoot().AppFrame if self._View is None and not onlyopened: - + self._View = self.EditorType(app_frame.TabsOpened, self, app_frame) - + if self._View is not None: if name is None: name = self.CTNFullName() app_frame.EditProjectElement(self._View, name) - + return self._View return None @@ -527,23 +527,23 @@ CTNClass, CTNHelp = CTNChildrenTypes[CTNType] except KeyError: raise Exception, _("Cannot create child {a1} of type {a2} ").format(a1 = CTNName, a2 = CTNType) - + # if CTNClass is a class factory, call it. (prevent unneeded imports) if type(CTNClass) == types.FunctionType: CTNClass = CTNClass() - + # Eventualy Initialize child instance list for this class of confnode ChildrenWithSameClass = self.Children.setdefault(CTNType, list()) # Check count if getattr(CTNClass, "CTNMaxCount", None) and len(ChildrenWithSameClass) >= CTNClass.CTNMaxCount: msg = _("Max count ({a1}) reached for this confnode of type {a2} ").format(a1 = CTNClass.CTNMaxCount, a2 = CTNType) raise Exception, msg - + # create the final class, derived of provided confnode and template class FinalCTNClass(CTNClass, ConfigTreeNode): """ ConfNode class is derivated into FinalCTNClass before being instanciated - This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called + This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called before CTNClass.__init__, and to do the file related stuff. """ def __init__(_self): @@ -568,7 +568,7 @@ raise Exception, msg # Now, self.CTNPath() should be OK - + # Check that IEC_Channel is not already in use. _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel()) # Call the confnode real __init__ @@ -589,29 +589,29 @@ _self.CTNRequestSave() #just created, must be saved _self.ChangesToSave = True - + def _getBuildPath(_self): return self._getBuildPath() - + # Create the object out of the resulting class newConfNodeOpj = FinalCTNClass() # Store it in CTNgedChils ChildrenWithSameClass.append(newConfNodeOpj) - + return newConfNodeOpj - + def ClearChildren(self): for child in self.IterChildren(): child.ClearChildren() self.Children = {} - + def LoadXMLParams(self, CTNName = None): methode_name = os.path.join(self.CTNPath(CTNName), "methods.py") if os.path.isfile(methode_name): execfile(methode_name) - + ConfNodeName = CTNName if CTNName is not None else self.CTNName() - + # Get the base xml tree if self.MandatoryParams: try: @@ -626,7 +626,7 @@ msg = _("Couldn't load confnode base parameters {a1} :\n {a2}").format(a1 = ConfNodeName, a2 = unicode(exc)) self.GetCTRoot().logger.write_error(msg) self.GetCTRoot().logger.write_error(traceback.format_exc()) - + # Get the xml tree if self.CTNParams: try: @@ -643,7 +643,7 @@ msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1 = ConfNodeName, a2 = unicode(exc)) self.GetCTRoot().logger.write_error(msg) self.GetCTRoot().logger.write_error(traceback.format_exc()) - + def LoadChildren(self): # Iterate over all CTNName@CTNType in confnode directory, and try to open them for CTNDir in os.listdir(self.CTNPath()): @@ -656,4 +656,3 @@ msg = _("Could not add child \"{a1}\", type {a2} :\n{a3}\n").format(a1 = pname, a2 = ptype, a3 = unicode(exc)) self.GetCTRoot().logger.write_error(msg) self.GetCTRoot().logger.write_error(traceback.format_exc()) - diff -r d51af006fa6b -r 64d8f52bc8c8 IDEFrame.py --- a/IDEFrame.py Fri Aug 11 15:18:19 2017 +0300 +++ b/IDEFrame.py Mon Aug 14 19:13:01 2017 +0300 @@ -474,10 +474,10 @@ def _init_icon(self, parent): if self.icon: - self.SetIcon(self.icon) + self.SetIcon(self.icon) elif parent and parent.icon: - self.SetIcon(parent.icon) - + self.SetIcon(parent.icon) + def _init_ctrls(self, prnt): wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name='IDEFrame', parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600), @@ -1626,7 +1626,7 @@ self.RefreshPageTitles() elif item_infos["type"] == ITEM_TRANSITION: pou_item = self.ProjectTree.GetItemParent(event.GetItem()) - pou_name = self.ProjectTree.GetItemText(pou_item) + pou_name = self.ProjectTree.GetItemText(pou_item) if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]: message = _("A POU named \"%s\" already exists!")%new_name elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames(pou_name) if name != old_name]: @@ -2630,4 +2630,3 @@ self.Viewer.DoDrawing(dc, True) return True - diff -r d51af006fa6b -r 64d8f52bc8c8 NativeLib.py --- a/NativeLib.py Fri Aug 11 15:18:19 2017 +0300 +++ b/NativeLib.py Mon Aug 14 19:13:01 2017 +0300 @@ -29,5 +29,4 @@ class NativeLibrary(POULibrary): def GetLibraryPath(self): - return paths.AbsNeighbourFile(__file__, "NativeLib.xml") - + return paths.AbsNeighbourFile(__file__, "NativeLib.xml") diff -r d51af006fa6b -r 64d8f52bc8c8 PLCGenerator.py --- a/PLCGenerator.py Fri Aug 11 15:18:19 2017 +0300 +++ b/PLCGenerator.py Mon Aug 14 19:13:01 2017 +0300 @@ -771,7 +771,7 @@ connections = content["value"].getconnections() if not connections: raise PLCGenException, _("SFC transition in POU \"%s\" must be connected.") % self.Name - for link in connections: + for link in connections: connected = self.GetLinkedConnector(link, body) if connected is not None and not self.ConnectionTypes.has_key(connected): for related in self.ExtractRelatedConnections(connected): @@ -1662,4 +1662,3 @@ generator = ProgramGenerator(controler, project, errors, warnings) generator.GenerateProgram() return generator.GetGeneratedProgram() - diff -r d51af006fa6b -r 64d8f52bc8c8 PLCOpenEditor.py --- a/PLCOpenEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/PLCOpenEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -156,14 +156,14 @@ # kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2') #AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT, # kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3') - + handler=lambda event: { wx.MessageBox(version.GetCommunityHelpMsg(), _(u'Community support'), wx.OK | wx.ICON_INFORMATION) } id = wx.NewId() - parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support')) + parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support')) self.Bind(wx.EVT_MENU, handler, id=id) - + AppendMenu(parent, help='', id=wx.ID_ABOUT, kind=wx.ITEM_NORMAL, text=_(u'About')) self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP) @@ -505,4 +505,3 @@ frame.Show() app.MainLoop() - diff -r d51af006fa6b -r 64d8f52bc8c8 POULibrary.py --- a/POULibrary.py Fri Aug 11 15:18:19 2017 +0300 +++ b/POULibrary.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,14 +38,14 @@ def GetSTCode(self): if not self.program: self.program = self.LibraryControler.GenerateProgram()[0]+"\n" - return self.program + return self.program def GetName(self): return self.LibName def GetCTR(self): return self.CTR() - + def GetTypes(self): return {"name" : self.GetName(), "types": self.LibraryControler.Project} diff -r d51af006fa6b -r 64d8f52bc8c8 ProjectController.py --- a/ProjectController.py Fri Aug 11 15:18:19 2017 +0300 +++ b/ProjectController.py Mon Aug 14 19:13:01 2017 +0300 @@ -98,9 +98,9 @@ for p in paths: if test(p): path = p - break + break return path - + def findCmd(self): cmd="iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "") paths=[ @@ -113,7 +113,7 @@ cmd=os.path.join(path, cmd) return cmd - + def findLibPath(self): paths=[ os.path.join(base_folder, "matiec", "lib"), @@ -121,7 +121,7 @@ ] path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, "ieclib.txt"))) return path - + def findLibCPath(self): path=None paths=[ @@ -1158,14 +1158,14 @@ def ShowError(self, logger, from_location, to_location): chunk_infos = self.GetChunkInfos(from_location, to_location) for infos, (start_row, start_col) in chunk_infos: - row = 1 if from_location[0] < start_row else (from_location[0] - start_row) + row = 1 if from_location[0] < start_row else (from_location[0] - start_row) col = 1 if (start_row != from_location[0]) else (from_location[1] - start_col) start = (row, col) - row = 1 if to_location[0] < start_row else (to_location[0] - start_row) + row = 1 if to_location[0] < start_row else (to_location[0] - start_row) col = 1 if (start_row != to_location[0]) else (to_location[1] - start_col) end = (row, col) - + if self.AppFrame is not None: self.AppFrame.ShowError(infos, start, end) @@ -1198,7 +1198,7 @@ except: text = '(* No IEC code have been generated at that time ! *)' self._IECCodeView.SetText(text = text) - self._IECCodeView.Editor.SetReadOnly(True) + self._IECCodeView.Editor.SetReadOnly(True) self._IECCodeView.SetIcon(GetBitmap("ST")) setattr(self._IECCodeView, "_OnClose", self.OnCloseEditor) @@ -1305,11 +1305,11 @@ self.ShowMethod("_showIECcode", os.path.isfile(self._getIECcodepath())) if self.AppFrame is not None and not self.UpdateMethodsFromPLCStatus(): self.AppFrame.RefreshStatusToolBar() - + def UpdateButtons(self): wx.CallAfter(self._UpdateButtons) - + def UpdatePLCLog(self, log_count): if log_count: if self.AppFrame is not None: @@ -1364,7 +1364,7 @@ "Disconnected": _("Disconnected") } return msgs.get(status, status) - + def ShowPLCProgress(self, status = "", progress = 0): self.AppFrame.ProgressStatusBar.Show() self.AppFrame.ConnectionStatusBar.SetStatusText(self.GetTextStatus(status), 1) @@ -1376,7 +1376,7 @@ self.previous_plcstate = "" self.AppFrame.ProgressStatusBar.Hide() self.UpdateMethodsFromPLCStatus() - + def PullPLCStatusProc(self, event): self.UpdateMethodsFromPLCStatus() @@ -1821,7 +1821,7 @@ self.AppFrame.LogViewer.ResetLogCounters(); else: self.logger.write_error(_("Transfer failed\n")) - self.HidePLCProgress() + self.HidePLCProgress() else: self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n")) diff -r d51af006fa6b -r 64d8f52bc8c8 c_ext/CFileEditor.py --- a/c_ext/CFileEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/c_ext/CFileEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -29,20 +29,20 @@ class CppEditor(CodeEditor): - KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class", - "const", "const_cast", "continue", "default", "delete", "do", "double", - "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", - "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "operator", "private", "protected", "public", "register", - "reinterpret_cast", "return", "short", "signed", "sizeof", "static", + KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class", + "const", "const_cast", "continue", "default", "delete", "do", "double", + "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", + "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", + "namespace", "new", "operator", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", - "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", + "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while"] COMMENT_HEADER = "/" - + def SetCodeLexer(self): self.SetLexer(stc.STC_LEX_CPP) - + self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060,size:%(size)d' % faces) self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060,size:%(size)d' % faces) self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060,size:%(size)d' % faces) @@ -58,10 +58,7 @@ #------------------------------------------------------------------------------- class CFileEditor(CodeFileEditor): - + CONFNODEEDITOR_TABS = [ (_("C code"), "_create_CodePanel")] CODE_EDITOR = CppEditor - - - diff -r d51af006fa6b -r 64d8f52bc8c8 canfestival/NetworkEditor.py --- a/canfestival/NetworkEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/canfestival/NetworkEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -28,16 +28,16 @@ from networkeditortemplate import NetworkEditorTemplate from editors.ConfTreeNodeEditor import ConfTreeNodeEditor -[ID_NETWORKEDITOR, +[ID_NETWORKEDITOR, ] = [wx.NewId() for _init_ctrls in range(1)] -[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, - ID_NETWORKEDITORCONFNODEMENUMASTER, +[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, + ID_NETWORKEDITORCONFNODEMENUMASTER, ] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(3)] [ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE, ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, - ID_NETWORKEDITORMASTERMENUADD, + ID_NETWORKEDITORMASTERMENUADD, ] = [wx.NewId() for _init_coll_MasterMenu_Items in range(5)] [ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT, @@ -46,37 +46,37 @@ ] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] class NetworkEditor(ConfTreeNodeEditor, NetworkEditorTemplate): - + ID = ID_NETWORKEDITOR CONFNODEEDITOR_TABS = [ (_("CANOpen network"), "_create_NetworkEditor")] - + def _create_NetworkEditor(self, prnt): - self.NetworkEditor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0), + self.NetworkEditor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - + NetworkEditorTemplate._init_ctrls(self, self.NetworkEditor) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + main_sizer.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL) - + self.NetworkEditor.SetSizer(main_sizer) - + return self.NetworkEditor - + def __init__(self, parent, controler, window): ConfTreeNodeEditor.__init__(self, parent, controler, window) NetworkEditorTemplate.__init__(self, controler, window, False) - + self.RefreshNetworkNodes() self.RefreshBufferState() - + def __del__(self): self.Controler.OnCloseEditor(self) - + def GetConfNodeMenuItems(self): add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), (wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)), @@ -84,7 +84,7 @@ (wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), (wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), (wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] - + profile = self.Manager.GetCurrentProfileName() if profile not in ("None", "DS-301"): other_profile_text = _("%s Profile") % profile @@ -93,35 +93,35 @@ add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) else: other_profile_text = _('Other Profile') - + master_menu = [(wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)), (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), (wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), (wx.ITEM_SEPARATOR, None), (add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))] - + return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORCONFNODEMENUADDSLAVE, '', self.OnAddSlaveMenu)), (wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)), (wx.ITEM_SEPARATOR, None), (master_menu, (_('Master'), ID_NETWORKEDITORCONFNODEMENUMASTER))] - + def RefreshMainMenu(self): pass - + def RefreshConfNodeMenu(self, confnode_menu): confnode_menu.Enable(ID_NETWORKEDITORCONFNODEMENUMASTER, self.NetworkNodes.GetSelection() == 0) - + def RefreshView(self): ConfTreeNodeEditor.RefreshView(self) self.RefreshCurrentIndexList() - + def RefreshBufferState(self): NetworkEditorTemplate.RefreshBufferState(self) self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() self.ParentWindow.RefreshEditMenu() self.ParentWindow.RefreshPageTitles() - + def OnNodeSelectedChanged(self, event): NetworkEditorTemplate.OnNodeSelectedChanged(self, event) wx.CallAfter(self.ParentWindow.RefreshEditMenu) diff -r d51af006fa6b -r 64d8f52bc8c8 canfestival/SlaveEditor.py --- a/canfestival/SlaveEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/canfestival/SlaveEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,7 +30,7 @@ [ID_SLAVEEDITORCONFNODEMENUNODEINFOS, ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, - ID_SLAVEEDITORCONFNODEMENUADD, + ID_SLAVEEDITORCONFNODEMENUADD, ] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(5)] [ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT, @@ -39,22 +39,22 @@ ] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] class SlaveEditor(ConfTreeNodeEditor, NodeEditorTemplate): - + CONFNODEEDITOR_TABS = [ (_("CANOpen slave"), "_create_SlaveNodeEditor")] - + def _create_SlaveNodeEditor(self, prnt): self.SlaveNodeEditor = EditingPanel(prnt, self, self.Controler, self.Editable) return self.SlaveNodeEditor - + def __init__(self, parent, controler, window, editable=True): self.Editable = editable ConfTreeNodeEditor.__init__(self, parent, controler, window) NodeEditorTemplate.__init__(self, controler, window, False) - + def __del__(self): self.Controler.OnCloseEditor(self) - + def GetConfNodeMenuItems(self): if self.Editable: add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), @@ -63,7 +63,7 @@ (wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), (wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), (wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] - + profile = self.Controler.GetCurrentProfileName() if profile not in ("None", "DS-301"): other_profile_text = _("%s Profile") % profile @@ -72,14 +72,14 @@ add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) else: other_profile_text = _('Other Profile') - + return [(wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, '', self.OnCommunicationMenu)), (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), (wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), (wx.ITEM_SEPARATOR, None), (add_menu, (_('Add'), ID_SLAVEEDITORCONFNODEMENUADD))] return [] - + def RefreshConfNodeMenu(self, confnode_menu): if self.Editable: confnode_menu.Enable(ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, False) @@ -90,7 +90,7 @@ def RefreshCurrentIndexList(self): self.RefreshView() - + def RefreshBufferState(self): self.ParentWindow.RefreshTitle() self.ParentWindow.RefreshFileMenu() @@ -100,27 +100,26 @@ class MasterViewer(SlaveEditor): SHOW_BASE_PARAMS = False SHOW_PARAMS = False - + def __init__(self, parent, controler, window, tagname): SlaveEditor.__init__(self, parent, controler, window, False) - + self.TagName = tagname - + def GetTagName(self): return self.TagName - + def GetCurrentNodeId(self): return None - + def GetInstancePath(self): return self.Controler.CTNFullName() + ".generated_master" - + def GetTitle(self): return self.GetInstancePath() - + def IsViewing(self, tagname): return self.GetInstancePath() == tagname def RefreshView(self): self.SlaveNodeEditor.RefreshIndexList() - diff -r d51af006fa6b -r 64d8f52bc8c8 canfestival/canfestival.py --- a/canfestival/canfestival.py Fri Aug 11 15:18:19 2017 +0300 +++ b/canfestival/canfestival.py Mon Aug 14 19:13:01 2017 +0300 @@ -67,7 +67,7 @@ "size": size, "IEC_type": IECTypeConversion.get(typeinfos["name"]), "var_name": "%s_%4.4x_%2.2x" % ("_".join(name.split()), index, subindex), - "location": "%s%s"%(SizeConversion[size], ".".join(map(str, current_location + + "location": "%s%s"%(SizeConversion[size], ".".join(map(str, current_location + (index, subindex)))), "description": "", "children": []}) @@ -102,7 +102,7 @@ """ - + EditorType = SlaveEditor IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png") @@ -125,7 +125,7 @@ self.CreateNewNode(name, # Name - will be changed at build time id, # NodeID - will be changed at build time "slave", # Type - description,# description + description,# description profile, # profile filepath, # prfile filepath NMT, # NMT @@ -134,7 +134,7 @@ self.CreateNewNode("SlaveNode", # Name - will be changed at build time 0x00, # NodeID - will be changed at build time "slave", # Type - "", # description + "", # description "None", # profile "", # prfile filepath "heartbeat", # NMT @@ -156,48 +156,48 @@ if self._View is not None: self._View.SetBusId(self.GetCurrentLocation()) return self._View - + def _ExportSlave(self): - dialog = wx.FileDialog(self.GetCTRoot().AppFrame, - _("Choose a file"), - os.path.expanduser("~"), - "%s.eds" % self.CTNName(), + dialog = wx.FileDialog(self.GetCTRoot().AppFrame, + _("Choose a file"), + os.path.expanduser("~"), + "%s.eds" % self.CTNName(), _("EDS files (*.eds)|*.eds|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT) if dialog.ShowModal() == wx.ID_OK: result = eds_utils.GenerateEDSFile(dialog.GetPath(), self.GetCurrentNodeCopy()) if result: self.GetCTRoot().logger.write_error(_("Error: Export slave failed\n")) - dialog.Destroy() - + dialog.Destroy() + ConfNodeMethods = [ {"bitmap" : "ExportSlave", - "name" : _("Export slave"), + "name" : _("Export slave"), "tooltip" : _("Export CanOpen slave to EDS file"), "method" : "_ExportSlave"}, ] - + def CTNTestModified(self): return self.ChangesToSave or self.OneFileHasChanged() - + def OnCTNSave(self, from_project_path=None): return self.SaveCurrentInFile(self.GetSlaveODPath()) def SetParamsAttribute(self, path, value): result = ConfigTreeNode.SetParamsAttribute(self, path, value) - + # Filter IEC_Channel and Name, that have specific behavior if path == "BaseParams.IEC_Channel" and self._View is not None: self._View.SetBusId(self.GetCurrentLocation()) - + return result - + def GetVariableLocationTree(self): current_location = self.GetCurrentLocation() - return GetSlaveLocationTree(self.CurrentNode, - self.GetCurrentLocation(), + return GetSlaveLocationTree(self.CurrentNode, + self.GetCurrentLocation(), self.BaseParams.getName()) - + def CTNGenerate_C(self, buildpath, locations): """ Generate C code @@ -230,10 +230,10 @@ def LoadPrevious(self): self.LoadCurrentPrevious() - + def LoadNext(self): self.LoadCurrentNext() - + def GetBufferState(self): return self.GetCurrentBufferState() @@ -242,30 +242,30 @@ #-------------------------------------------------- class MiniNodeManager(NodeManager): - + def __init__(self, parent, filepath, fullname): NodeManager.__init__(self) - + self.OpenFileInCurrent(filepath) - + self.Parent = parent self.Fullname = fullname - + def GetIconName(self): return None - + def OnCloseEditor(self, view): self.Parent.OnCloseEditor(view) - + def CTNFullName(self): return self.Fullname - + def CTNTestModified(self): return False - + def GetBufferState(self): return self.GetCurrentBufferState() - + ConfNodeMethods = [] class _NodeManager(NodeManager): @@ -273,16 +273,16 @@ def __init__(self, parent, *args, **kwargs): NodeManager.__init__(self, *args, **kwargs) self.Parent = parent - + def __del__(self): self.Parent = None - + def GetCurrentNodeName(self): return self.Parent.CTNName() - + def GetCurrentNodeID(self): return self.Parent.CanFestivalNode.getNodeId() - + class _NodeListCTN(NodeList): XSD = """ @@ -295,20 +295,20 @@ - """ - + """ + EditorType = NetworkEditor IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png") - + def __init__(self): manager = _NodeManager(self) NodeList.__init__(self, manager) self.LoadProject(self.CTNPath()) self.SetNetworkName(self.BaseParams.getName()) - + def GetCanDevice(self): return self.CanFestivalNode.getCAN_Device() - + def SetParamsAttribute(self, path, value): if path == "CanFestivalNode.NodeId": nodeid = self.CanFestivalNode.getNodeId() @@ -319,10 +319,10 @@ value += dir if value < 0: value = nodeid - + value, refresh = ConfigTreeNode.SetParamsAttribute(self, path, value) refresh_network = False - + # Filter IEC_Channel and Name, that have specific behavior if path == "BaseParams.IEC_Channel" and self._View is not None: self._View.SetBusId(self.GetCurrentLocation()) @@ -331,11 +331,11 @@ refresh_network = True elif path == "CanFestivalNode.NodeId": refresh_network = True - + if refresh_network and self._View is not None: wx.CallAfter(self._View.RefreshBufferState) return value, refresh - + def GetVariableLocationTree(self): current_location = self.GetCurrentLocation() nodeindexes = self.SlaveNodes.keys() @@ -345,17 +345,17 @@ "location": self.GetFullIEC_Channel(), "children": [GetSlaveLocationTree(self.Manager.GetCurrentNodeCopy(), current_location, - _("Local entries"))] + - [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"], - current_location + (nodeid,), + _("Local entries"))] + + [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"], + current_location + (nodeid,), self.SlaveNodes[nodeid]["Name"]) for nodeid in nodeindexes] } - + _GeneratedMasterView = None def _ShowGeneratedMaster(self): self._OpenView("Generated master") - + def _OpenView(self, name=None, onlyopened=False): if name == "Generated master": app_frame = self.GetCTRoot().AppFrame @@ -365,37 +365,37 @@ if not os.path.exists(buildpath): self.GetCTRoot().logger.write_error(_("Error: No PLC built\n")) return - + masterpath = os.path.join(buildpath, "MasterGenerated.od") if not os.path.exists(masterpath): self.GetCTRoot().logger.write_error(_("Error: No Master generated\n")) return - + manager = MiniNodeManager(self, masterpath, self.CTNFullName()) self._GeneratedMasterView = MasterViewer(app_frame.TabsOpened, manager, app_frame, name) - + if self._GeneratedMasterView is not None: app_frame.EditProjectElement(self._GeneratedMasterView, self._GeneratedMasterView.GetInstancePath()) - + return self._GeneratedMasterView else: ConfigTreeNode._OpenView(self, name, onlyopened) if self._View is not None: self._View.SetBusId(self.GetCurrentLocation()) return self._View - + ConfNodeMethods = [ {"bitmap" : "ShowMaster", - "name" : _("Show Master"), + "name" : _("Show Master"), "tooltip" : _("Show Master generated by config_utils"), "method" : "_ShowGeneratedMaster"} ] - + def OnCloseEditor(self, view): ConfigTreeNode.OnCloseEditor(self, view) if self._GeneratedMasterView == view: self._GeneratedMasterView = None - + def OnCTNClose(self): ConfigTreeNode.OnCTNClose(self) self._CloseView(self._GeneratedMasterView) @@ -403,11 +403,11 @@ def CTNTestModified(self): return self.ChangesToSave or self.HasChanged() - + def OnCTNSave(self, from_project_path=None): self.SetRoot(self.CTNPath()) if from_project_path is not None: - shutil.copytree(self.GetEDSFolder(from_project_path), + shutil.copytree(self.GetEDSFolder(from_project_path), self.GetEDSFolder()) return self.SaveProject() is None @@ -438,22 +438,22 @@ res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) if res : raise Exception, res - + file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") dump(master, file) file.close() - + return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False - + def LoadPrevious(self): self.Manager.LoadCurrentPrevious() - + def LoadNext(self): self.Manager.LoadCurrentNext() - + def GetBufferState(self): return self.Manager.GetCurrentBufferState() - + class RootClass: XSD = """ @@ -464,7 +464,7 @@ """ - + CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"), ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")] def GetParamsAttributes(self, path = None): @@ -475,13 +475,13 @@ if child["name"] == "CAN_Driver": child["type"] = local_canfestival_config.DLL_LIST return infos - + def GetCanDriver(self): res = self.CanFestivalInstance.getCAN_Driver() if not res : return "" return res - + def CTNGenerate_C(self, buildpath, locations): can_driver = self.GetCanDriver() if can_driver is not None: @@ -494,7 +494,7 @@ else: can_driver_name = "" - + format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), "candriver" : can_driver_name, "nodes_includes" : "", @@ -515,7 +515,7 @@ for child in self.IECSortedChildren(): childlocstr = "_".join(map(str,child.GetCurrentLocation())) nodename = "OD_%s" % childlocstr - + # Try to get Slave Node child_data = getattr(child, "CanFestivalSlaveNode", None) if child_data is None: @@ -569,7 +569,7 @@ format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%( nodename, child_data.getNodeId()) - + # Include generated OD headers format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) # Declare CAN channels according user filled config @@ -580,7 +580,7 @@ format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename) - + filename = paths.AbsNeighbourFile(__file__,"cf_runtime.c") cf_main = open(filename).read() % format_dict cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict) @@ -589,11 +589,10 @@ f.close() res = [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True - + if can_driver is not None: can_driver_path = os.path.join(CanFestivalPath,"drivers",can_driver,can_driver_name) if os.path.exists(can_driver_path): res += ((can_driver_name, file(can_driver_path,"rb")),) return res - diff -r d51af006fa6b -r 64d8f52bc8c8 canfestival/config_utils.py --- a/canfestival/config_utils.py Fri Aug 11 15:18:19 2017 +0300 +++ b/canfestival/config_utils.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,7 +30,7 @@ "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07, "LWORD":0x1B,"WSTRING":0x0B} -# Constants for PDO types +# Constants for PDO types RPDO = 1 TPDO = 2 @@ -61,7 +61,7 @@ @param size: number of bytes generated @return: a string containing the value converted """ - + data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value list_car = [data[i:i+2] for i in xrange(0, len(data), 2)] list_car.reverse() @@ -71,12 +71,12 @@ def GetNodePDOIndexes(node, type, parameters = False): """ Find the PDO indexes of a node - @param node: node + @param node: node @param type: type of PDO searched (RPDO or TPDO or both) @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) @return: a list of indexes found """ - + indexes = [] if type & RPDO: indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF]) @@ -91,14 +91,14 @@ def SearchNodePDOMapping(loc_infos, node): """ Find the PDO indexes of a node - @param node: node + @param node: node @param type: type of PDO searched (RPDO or TPDO or both) @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) @return: a list of indexes found """ - + model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) - + for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]): values = node.GetEntry(PDOidx) if values != None: @@ -115,9 +115,9 @@ @param cobid: PDO generated COB ID @param transmittype : PDO transmit type @param pdomapping: list of PDO mappings - @return: a tuple of value and number of parameters to add to DCF - """ - + @return: a tuple of value and number of parameters to add to DCF + """ + dcfdata=[] # Create entry for RPDO or TPDO parameters and Disable PDO # ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------ @@ -152,7 +152,7 @@ self.TrashVariables = {} # Dictionary of pointed variables self.PointedVariables = {} - + self.NodeList = nodelist self.Manager = self.NodeList.Manager self.MasterNode = self.Manager.GetCurrentNodeCopy() @@ -161,18 +161,18 @@ def GetPointedVariables(self): return self.PointedVariables - + def RemoveUsedNodeCobId(self, node): """ Remove all PDO COB ID used by the given node from the list of available COB ID @param node: node @return: a tuple of number of RPDO and TPDO for the node """ - + # Get list of all node TPDO and RPDO indexes nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True) nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True) - + # Mark all the COB ID of the node already mapped PDO as not available for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes: pdo_cobid = node.GetEntry(PdoIdx, 0x01) @@ -182,20 +182,20 @@ # Remove COB ID from the list of available COB ID if pdo_cobid in self.ListCobIDAvailable: self.ListCobIDAvailable.remove(pdo_cobid) - + return len(nodeRpdoIndexes), len(nodeTpdoIndexes) - + def PrepareMasterNode(self): """ Add mandatory entries for DCF generation into MasterNode. """ - + # Adding DCF entry into Master node if not self.MasterNode.IsEntry(0x1F22): self.MasterNode.AddEntry(0x1F22, 1, "") self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode) - + # Adding trash mappable variables for unused mapped datas idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID() # Add an entry for storing unexpected all variable @@ -206,9 +206,9 @@ self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode) # Store the mapping value for this entry self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size - + RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode) - + # Store the indexes of the first RPDO and TPDO available for MasterNode self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber} @@ -216,9 +216,9 @@ for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()): node = nodeinfos["Node"] node.SetNodeID(nodeid) - + RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node) - + # Get Slave's default SDO server parameters RSDO_cobid = node.GetEntry(0x1200,0x01) if not RSDO_cobid: @@ -226,20 +226,20 @@ TSDO_cobid = node.GetEntry(0x1200,0x02) if not TSDO_cobid: TSDO_cobid = 0x580 + nodeid - + # Configure Master's SDO parameters entries self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode) self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid) self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid) - self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid) - - + self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid) + + def GetMasterNode(self): """ Return MasterNode. """ return self.MasterNode - + def AddParamsToDCF(self, nodeid, data, nbparams): """ Add entry to DCF, for the requested nodeID @@ -249,19 +249,19 @@ """ # Get current DCF for slave nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid) - + # Extract data and number of params in current DCF if nodeDCF != None and nodeDCF != '': tmpnbparams = [i for i in nodeDCF[:4]] tmpnbparams.reverse() nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16) data = nodeDCF[4:] + data - + # Build new DCF dcf = LE_to_BE(nbparams, 0x04) + data # Set new DCF for slave self.MasterNode.SetEntry(0x1F22, nodeid, dcf) - + def GetEmptyPDO(self, nodeid, pdotype, start_index=None): """ Search a not configured PDO for a slave @@ -275,7 +275,7 @@ index = PDOTypeBaseIndex[pdotype] else: index = start_index - + # Search for all PDO possible index until find a configurable PDO # starting from start_index while index < PDOTypeBaseIndex[pdotype] + 0x200: @@ -296,7 +296,7 @@ return index, cobid, values[0] index += 1 return None - + def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs): """ Record a new mapping request for a slave, and add related slave config to the DCF @@ -305,16 +305,16 @@ @param pdomapping: list od variables to map with PDO """ # Add an entry to MasterMapping - self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype], + self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype], "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]} - + # Return the data to add to DCF if sync_TPDOs: return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping) else: return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping) return 0, "" - + def GenerateDCF(self, locations, current_location, sync_TPDOs): """ Generate Concise DCF of MasterNode for the locations list given @@ -322,18 +322,18 @@ @param current_location: tuple of the located prefixes not to be considered @param sync_TPDOs: indicate if TPDO must be synchronous """ - + #------------------------------------------------------------------------------- # Verify that locations correspond to real slave variables #------------------------------------------------------------------------------- - + # Get list of locations check if exists and mappables -> put them in IECLocations for location in locations: COlocationtype = IECToCOType[location["IEC_TYPE"]] name = location["NAME"] if name in self.IECLocations: if self.IECLocations[name]["type"] != COlocationtype: - raise PDOmappingException, _("Type conflict for location \"%s\"") % name + raise PDOmappingException, _("Type conflict for location \"%s\"") % name else: # Get only the part of the location that concern this node loc = location["LOC"][len(current_location):] @@ -342,30 +342,30 @@ raise PDOmappingException, _("Bad location size : %s") % str(loc) elif len(loc) == 2: continue - + direction = location["DIR"] - + sizelocation = location["SIZE"] - + # Extract and check nodeid nodeid, index, subindex = loc[:3] - + # Check Id is in slave node list if nodeid not in self.NodeList.SlaveNodes.keys(): raise PDOmappingException, _("Non existing node ID : {a1} (variable {a2})").format(a1 = nodeid, a2 = name) - + # Get the model for this node (made from EDS) node = self.NodeList.SlaveNodes[nodeid]["Node"] - + # Extract and check index and subindex if not node.IsEntry(index, subindex): msg = _("No such index/subindex ({a1},{a2}) in ID : {a3} (variable {a4})").\ format(a1 = "%x" % index, a2 ="%x" % subindex, a3 = nodeid, a4 = name) raise PDOmappingException, msg - + # Get the entry info subentry_infos = node.GetSubentryInfos(index, subindex) - + # If a PDO mappable if subentry_infos and subentry_infos["pdo"]: if sizelocation == "X" and len(loc) > 3: @@ -376,11 +376,11 @@ raise PDOmappingException, msg else: numbit = None - + if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype: raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\ format(a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name) - + typeinfos = node.GetEntryInfos(COlocationtype) self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction], "nodeid": nodeid, "index": index,"subindex": subindex, @@ -388,21 +388,21 @@ else: raise PDOmappingException, _("Not PDO mappable variable : '{a1}' (ID:{a2},Idx:{a3},sIdx:{a4}))").\ format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex) - + #------------------------------------------------------------------------------- # Search for locations already mapped #------------------------------------------------------------------------------- - + for name, locationinfos in self.IECLocations.items(): node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"] - + # Search if slave has a PDO mapping this locations result = SearchNodePDOMapping(locationinfos, node) if result != None: index, subindex = result # Get COB ID of the PDO cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1) - + # Add PDO to MasterMapping if cobid not in self.MasterMapping.keys(): # Verify that PDO transmit type is conform to sync_TPDOs @@ -414,10 +414,10 @@ else: # Change TransmitType to ASYCHRONE data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, []) - - # Add entry to slave dcf to change transmit type of + + # Add entry to slave dcf to change transmit type of self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams) - + mapping = [None] values = node.GetEntry(index) # Store the size of each entry mapped in PDO @@ -425,7 +425,7 @@ if value != 0: mapping.append(value % 0x100) self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping} - + # Indicate that this PDO entry must be saved if locationinfos["bit"] is not None: if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType): @@ -434,24 +434,24 @@ self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name) else: self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name) - + else: # Add location to those that haven't been mapped yet if locationinfos["nodeid"] not in self.LocationsNotMapped.keys(): self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []} self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos)) - + #------------------------------------------------------------------------------- # Build concise DCF for the others locations #------------------------------------------------------------------------------- - + for nodeid, locations in self.LocationsNotMapped.items(): node = self.NodeList.SlaveNodes[nodeid]["Node"] - + # Initialize number of params and data to add to node DCF nbparams = 0 dataparams = "" - + # Generate the best PDO mapping for each type of PDO for pdotype in (TPDO, RPDO): if len(locations[pdotype]) > 0: @@ -483,78 +483,78 @@ data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs) dataparams += data nbparams += nbaddedparams - + # Add number of params and data to node DCF self.AddParamsToDCF(nodeid, dataparams, nbparams) - + #------------------------------------------------------------------------------- # Master Node Configuration #------------------------------------------------------------------------------- - + # Generate Master's Configuration from informations stored in MasterMapping for cobid, pdo_infos in self.MasterMapping.items(): # Get next PDO index in MasterNode for this PDO type current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]] - + # Search if there is already a PDO in MasterNode with this cob id for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True): if self.MasterNode.GetEntry(idx, 1) == cobid: current_idx = idx - + # Add a PDO to MasterNode if not PDO have been found if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]: addinglist = [current_idx, current_idx + 0x200] self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode) self.MasterNode.SetEntry(current_idx, 0x01, cobid) - + # Increment the number of PDO for this PDO type self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1 - + # Change the transmit type of the PDO if sync_TPDOs: self.MasterNode.SetEntry(current_idx, 0x02, 0x01) else: self.MasterNode.SetEntry(current_idx, 0x02, 0xFF) - + mapping = [] for item in pdo_infos["mapping"]: if isinstance(item, ListType): mapping.extend(item) else: mapping.append(item) - + # Add some subentries to PDO mapping if there is not enough if len(mapping) > 1: self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode) - + # Generate MasterNode's PDO mapping for subindex, variable in enumerate(mapping): if subindex == 0: continue new_index = False - + if isinstance(variable, (IntType, LongType)): # If variable is an integer then variable is unexpected self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable]) else: typeidx, varname = variable variable_infos = self.IECLocations[varname] - + # Calculate base index for storing variable mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \ VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \ variable_infos["nodeid"] - + # Generate entry name indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]], variable_infos["sizelocation"], '_'.join(map(str,current_location)), - variable_infos["nodeid"]) - - # Search for an entry that has an empty subindex + variable_infos["nodeid"]) + + # Search for an entry that has an empty subindex while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: # Entry doesn't exist - if not self.MasterNode.IsEntry(mapvariableidx): + if not self.MasterNode.IsEntry(mapvariableidx): # Add entry to MasterNode self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode) new_index = True @@ -567,7 +567,7 @@ mapvariableidx += 8 * VariableIncrement else: break - + # Verify that a not full entry has been found if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: # Generate subentry name @@ -582,13 +582,13 @@ # Add informations to the new subentry created self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname}) self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx}) - + # Set value of the PDO mapping typeinfos = self.Manager.GetEntryInfos(typeidx) if typeinfos != None: value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"] self.MasterNode.SetEntry(current_idx + 0x200, subindex, value) - + # Add variable to pointed variables self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname) @@ -605,7 +605,7 @@ @param nodelist: CanFestival network editor model @return: a modified copy of the given CanFestival network editor model """ - + dcfgenerator = ConciseDCFGenerator(nodelist, nodename) dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs) masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables() @@ -621,7 +621,7 @@ name = location["NAME"] if name in IECLocations: if IECLocations[name] != COlocationtype: - raise PDOmappingException, _("Type conflict for location \"%s\"") % name + raise PDOmappingException, _("Type conflict for location \"%s\"") % name else: # Get only the part of the location that concern this node loc = location["LOC"][len(current_location):] @@ -630,25 +630,25 @@ raise PDOmappingException, _("Bad location size : %s") % str(loc) elif len(loc) != 2: continue - + # Extract and check nodeid index, subindex = loc[:2] - + # Extract and check index and subindex if not slave.IsEntry(index, subindex): raise PDOmappingException, _("No such index/subindex ({a1},{a2}) (variable {a3})").\ format(a1 = "%x" % index, a2 = "%x" % subindex, a3 = name) - + # Get the entry info - subentry_infos = slave.GetSubentryInfos(index, subindex) + subentry_infos = slave.GetSubentryInfos(index, subindex) if subentry_infos["type"] != COlocationtype: raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\ format( a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name) - + IECLocations[name] = COlocationtype pointers[(index, subindex)] = name return pointers - + if __name__ == "__main__": import os, sys, getopt @@ -667,7 +667,7 @@ Use with caution. Be sure that config_utils is currently working properly. """%sys.argv[0] - + # Boolean that indicate if reference result must be redefined reset = False @@ -693,15 +693,15 @@ base_folder = os.path.split(base_folder)[0] # Add CanFestival folder to search pathes sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen")) - + from nodemanager import * from nodelist import * - + # Open the test nodelist contained into test_config folder manager = NodeManager() nodelist = NodeList(manager) result = nodelist.LoadProject("test_config") - + # List of locations, we try to map for test locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)}, {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)}, @@ -713,34 +713,34 @@ {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)}, {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)}, {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}] - + # Generate MasterNode configuration try: masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode") except ValueError, message: print "%s\nTest Failed!"%message sys.exit() - + import pprint - # Get Text corresponding to MasterNode + # Get Text corresponding to MasterNode result_node = masternode.PrintString() result_vars = pprint.pformat(pointedvariables) result = result_node + "\n********POINTERS*********\n" + result_vars + "\n" - + # If reset has been choosen if reset: # Write Text into reference result file testfile = open("test_config/result.txt", "w") testfile.write(result) testfile.close() - + print "Reset Successful!" else: import os - + testfile = open("test_config/result_tmp.txt", "w") testfile.write(result) testfile.close() - + os.system("diff test_config/result.txt test_config/result_tmp.txt") os.remove("test_config/result_tmp.txt") diff -r d51af006fa6b -r 64d8f52bc8c8 controls/CustomToolTip.py --- a/controls/CustomToolTip.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/CustomToolTip.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,32 +39,32 @@ """ class CustomToolTip(wx.PopupWindow): - + def __init__(self, parent, tip, restricted=True): """ Constructor @param parent: Parent window @param tip: Tip text (may be multiline) - @param restricted: Tool tip must follow size restriction in line and + @param restricted: Tool tip must follow size restriction in line and characters number defined (default True) """ wx.PopupWindow.__init__(self, parent) - + self.Restricted = restricted - + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) self.SetTip(tip) - + # Initialize text font style self.Font = wx.Font( - faces["size"], - wx.SWISS, - wx.NORMAL, - wx.NORMAL, + faces["size"], + wx.SWISS, + wx.NORMAL, + wx.NORMAL, faceName = faces["mono"]) - + self.Bind(wx.EVT_PAINT, self.OnPaint) - + def SetFont(self, font): """ Set tool tip text font style @@ -72,7 +72,7 @@ """ self.Font = font self.RefreshTip() - + def SetTip(self, tip): """ Set tool tip text @@ -97,11 +97,11 @@ self.Tip.append(new_line) else: self.Tip.append(line) - + # Restrict number of lines if len(self.Tip) > TOOLTIP_MAX_LINE: self.Tip = self.Tip[:TOOLTIP_MAX_LINE] - + # Add ... to the end of last line to indicate that tool tip # text is too long if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3: @@ -111,10 +111,10 @@ [:TOOLTIP_MAX_CHARACTERS - 3] + "..." else: self.Tip = tip.splitlines() - + # Prevent to call wx method in non-wx threads wx.CallAfter(self.RefreshTip) - + def SetToolTipPosition(self, pos): """ Set tool tip position @@ -122,32 +122,32 @@ """ # Get screen size to prevent tool tip to go out of the screen screen_width, screen_height = wx.GetDisplaySize() - + # Calculate position of tool tip to stay in screen limits tip_width, tip_height = self.GetToolTipSize() self.SetPosition(wx.Point( max(0, min(pos.x, screen_width - tip_width)), max(0, min(pos.y, screen_height - tip_height)))) - + def GetToolTipSize(self): """ Get tool tip size according to tip text and restriction @return: wx.Size(tool_tip_width, tool_tip_height) """ max_width = max_height = 0 - + # Create a memory DC for calculating text extent dc = wx.MemoryDC() dc.SetFont(self.Font) - + # Compute max tip text size for line in self.Tip: w, h = dc.GetTextExtent(line) max_width = max(max_width, w) max_height += h - + return wx.Size(max_width + 4, max_height + 4) - + def RefreshTip(self): """ Refresh tip on screen @@ -156,10 +156,10 @@ if self: # Refresh tool tip size and position self.SetClientSize(self.GetToolTipSize()) - + # Redraw tool tip self.Refresh() - + def OnPaint(self, event): """ Callback for Paint Event @@ -168,26 +168,26 @@ # Get buffered paint DC for tool tip dc = wx.AutoBufferedPaintDC(self) dc.Clear() - + # Set DC drawing style dc.SetPen(wx.BLACK_PEN) dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170))) dc.SetFont(self.Font) - + # Draw Tool tip dc.BeginDrawing() tip_width, tip_height = self.GetToolTipSize() - + # Draw background rectangle dc.DrawRectangle(0, 0, tip_width, tip_height) - + # Draw tool tip text line_offset = 0 for line in self.Tip: dc.DrawText(line, 2, line_offset + 2) line_width, line_height = dc.GetTextExtent(line) line_offset += line_height - + dc.EndDrawing() - + event.Skip() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/CustomTree.py --- a/controls/CustomTree.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/CustomTree.py Mon Aug 14 19:13:01 2017 +0300 @@ -44,30 +44,30 @@ CT.GenericTreeItem.GetCurrentCheckedImage = GetCurrentCheckedImage class CustomTree(CT.CustomTreeCtrl): - + def __init__(self, *args, **kwargs): CT.CustomTreeCtrl.__init__(self, *args, **kwargs) - + self.BackgroundBitmap = None self.BackgroundAlign = wx.ALIGN_LEFT|wx.ALIGN_TOP - + self.AddMenu = None self.Enabled = False - + self.Bind(wx.EVT_SCROLLWIN, self.OnScroll) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) - + def SetBackgroundBitmap(self, bitmap, align): self.BackgroundBitmap = bitmap self.BackgroundAlign = align - + def SetImageListCheck(self, sizex, sizey, imglist=None): CT.CustomTreeCtrl.SetImageListCheck(self, sizex, sizey, imglist=None) - + self.ExtraImages = {} for image in ["function", "functionBlock", "program"]: self.ExtraImages[image] = self._imageListCheck.Add(GetBitmap(image.upper())) - + def SetItemExtraImage(self, item, bitmap): dc = wx.ClientDC(self) image = self.ExtraImages.get(bitmap) @@ -76,45 +76,45 @@ else: item.SetExtraImage(None) self.CalculateSize(item, dc) - self.RefreshLine(item) - + self.RefreshLine(item) + def SetAddMenu(self, add_menu): self.AddMenu = add_menu - + def Enable(self, enabled): self.Enabled = enabled - + def GetBitmapRect(self): client_size = self.GetClientSize() bitmap_size = self.BackgroundBitmap.GetSize() - + if self.BackgroundAlign & wx.ALIGN_RIGHT: x = client_size[0] - bitmap_size[0] elif self.BackgroundAlign & wx.ALIGN_CENTER_HORIZONTAL: x = (client_size[0] - bitmap_size[0]) / 2 else: x = 0 - + if self.BackgroundAlign & wx.ALIGN_BOTTOM: y = client_size[1] - bitmap_size[1] elif self.BackgroundAlign & wx.ALIGN_CENTER_VERTICAL: y = (client_size[1] - bitmap_size[1]) / 2 else: y = 0 - + return wx.Rect(x, y, bitmap_size[0], bitmap_size[1]) - + def OnLeftUp(self, event): if self.Enabled: pos = event.GetPosition() item, flags = self.HitTest(pos) - + bitmap_rect = self.GetBitmapRect() - if (bitmap_rect.InsideXY(pos.x, pos.y) or + if (bitmap_rect.InsideXY(pos.x, pos.y) or flags & wx.TREE_HITTEST_NOWHERE) and self.AddMenu is not None: wx.CallAfter(self.PopupMenuXY, self.AddMenu, pos.x, pos.y) event.Skip() - + def OnEraseBackground(self, event): dc = event.GetDC() @@ -122,12 +122,12 @@ dc = wx.ClientDC(self) rect = self.GetUpdateRegion().GetBox() dc.SetClippingRect(rect) - + dc.Clear() - + bitmap_rect = self.GetBitmapRect() dc.DrawBitmap(self.BackgroundBitmap, bitmap_rect.x, bitmap_rect.y) - + def OnScroll(self, event): wx.CallAfter(self.Refresh) event.Skip() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/DebugVariableGraphicViewer.py --- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -83,23 +83,23 @@ min_value = range_min elif range_min is not None: min_value = min(min_value, range_min) - + # Update maximal range value if max_value is None: max_value = range_max elif range_min is not None: max_value = max(max_value, range_max) - + # Calculate range center and width if at least one valid range is defined if min_value is not None and max_value is not None: center = (min_value + max_value) / 2. range_size = max(1.0, max_value - min_value) - + # Set default center and with if no valid range is defined else: center = 0.5 range_size = 1.0 - + # Return range expended from 10 % return center - range_size * 0.55, center + range_size * 0.55 @@ -113,7 +113,7 @@ """ class DebugVariableGraphicDropTarget(wx.TextDropTarget): - + def __init__(self, parent, window): """ Constructor @@ -123,7 +123,7 @@ wx.TextDropTarget.__init__(self) self.ParentControl = parent self.ParentWindow = window - + def __del__(self): """ Destructor @@ -132,7 +132,7 @@ # Panel self.ParentControl = None self.ParentWindow = None - + def OnDragOver(self, x, y, d): """ Function called when mouse is dragged over Drop Target @@ -142,9 +142,9 @@ """ # Signal parent that mouse is dragged over self.ParentControl.OnMouseDragging(x, y) - + return wx.TextDropTarget.OnDragOver(self, x, y, d) - + def OnDropText(self, x, y, data): """ Function called when mouse is released in Drop Target @@ -154,9 +154,9 @@ """ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() - + message = None - + # Check that data is valid regarding DebugVariablePanel try: values = eval(data) @@ -165,54 +165,54 @@ except: message = _("Invalid value \"%s\" for debug variable")%data values = None - + # Display message if data is invalid if message is not None: wx.CallAfter(self.ShowMessage, message) - + # Data contain a reference to a variable to debug elif values[1] == "debug": target_idx = self.ParentControl.GetIndex() - + # If mouse is dropped in graph canvas bounding box and graph is # not 3D canvas, graphs will be merged rect = self.ParentControl.GetAxesBoundingBox() if not self.ParentControl.Is3DCanvas() and rect.InsideXY(x, y): # Default merge type is parallel merge_type = GRAPH_PARALLEL - + # If mouse is dropped in left part of graph canvas, graph # wall be merged orthogonally - merge_rect = wx.Rect(rect.x, rect.y, + merge_rect = wx.Rect(rect.x, rect.y, rect.width / 2., rect.height) if merge_rect.InsideXY(x, y): merge_type = GRAPH_ORTHOGONAL - + # Merge graphs - wx.CallAfter(self.ParentWindow.MergeGraphs, - values[0], target_idx, + wx.CallAfter(self.ParentWindow.MergeGraphs, + values[0], target_idx, merge_type, force=True) - + else: width, height = self.ParentControl.GetSize() - + # Get Before which Viewer the variable has to be moved or added # according to the position of mouse in Viewer. if y > height / 2: target_idx += 1 - + # Drag'n Drop is an internal is an internal move inside Debug - # Variable Panel + # Variable Panel if len(values) > 2 and values[2] == "move": - self.ParentWindow.MoveValue(values[0], + self.ParentWindow.MoveValue(values[0], target_idx) - + # Drag'n Drop was initiated by another control of Beremiz else: - self.ParentWindow.InsertValue(values[0], - target_idx, + self.ParentWindow.InsertValue(values[0], + target_idx, force=True) - + def OnLeave(self): """ Function called when mouse is leave Drop Target @@ -220,15 +220,15 @@ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() return wx.TextDropTarget.OnLeave(self) - + def ShowMessage(self, message): """ Show error message in Error Dialog @param message: Error message to display """ - dialog = wx.MessageDialog(self.ParentWindow, - message, - _("Error"), + dialog = wx.MessageDialog(self.ParentWindow, + message, + _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() @@ -243,7 +243,7 @@ """ class DebugVariableGraphicViewer(DebugVariableViewer, FigureCanvas): - + def __init__(self, parent, window, items, graph_type): """ Constructor @@ -253,36 +253,36 @@ @param graph_type: Graph display type (Parallel or orthogonal) """ DebugVariableViewer.__init__(self, window, items) - + self.GraphType = graph_type # Graph type display self.CursorTick = None # Tick of the graph cursor - + # Mouse position when start dragging self.MouseStartPos = None # Tick when moving tick start self.StartCursorTick = None # Canvas size when starting to resize canvas - self.CanvasStartSize = None - + self.CanvasStartSize = None + # List of current displayed contextual buttons self.ContextualButtons = [] # Reference to item for which contextual buttons was displayed self.ContextualButtonsItem = None - + # Flag indicating that zoom fit current displayed data range or whole # data range if False self.ZoomFit = False - + # Create figure for drawing graphs self.Figure = matplotlib.figure.Figure(facecolor='w') # Defined border around figure in canvas - self.Figure.subplotpars.update(top=0.95, left=0.1, + self.Figure.subplotpars.update(top=0.95, left=0.1, bottom=0.1, right=0.95) - + FigureCanvas.__init__(self, parent, -1, self.Figure) self.SetWindowStyle(wx.WANTS_CHARS) self.SetBackgroundColour(wx.WHITE) - + # Bind wx events self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) @@ -290,42 +290,42 @@ self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_SIZE, self.OnResize) - + # Set canvas min size canvas_size = self.GetCanvasMinSize() self.SetMinSize(canvas_size) - + # Define Viewer drop target self.SetDropTarget(DebugVariableGraphicDropTarget(self, window)) - + # Connect matplotlib events self.mpl_connect('button_press_event', self.OnCanvasButtonPressed) self.mpl_connect('motion_notify_event', self.OnCanvasMotion) self.mpl_connect('button_release_event', self.OnCanvasButtonReleased) self.mpl_connect('scroll_event', self.OnCanvasScroll) - + # Add buttons for zooming on current displayed data range self.Buttons.append( GraphButton(0, 0, "fit_graph", self.OnZoomFitButton)) - + # Add buttons for changing canvas size with predefined height for size, bitmap in zip( [SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI], ["minimize_graph", "middle_graph", "maximize_graph"]): self.Buttons.append( - GraphButton(0, 0, bitmap, + GraphButton(0, 0, bitmap, self.GetOnChangeSizeButton(size))) - + # Add buttons for exporting graph values to clipboard and close graph for bitmap, callback in [ ("export_graph_mini", self.OnExportGraphButton), ("delete_graph", self.OnCloseButton)]: self.Buttons.append(GraphButton(0, 0, bitmap, callback)) - + # Update graphs elements self.ResetGraphics() self.RefreshLabelsPosition(canvas_size.height) - + def AddItem(self, item): """ Add an item to the list of items displayed by Viewer @@ -333,14 +333,14 @@ """ DebugVariableViewer.AddItem(self, item) self.ResetGraphics() - + def RemoveItem(self, item): """ Remove an item from the list of items displayed by Viewer @param item: Item to remove from the list """ DebugVariableViewer.RemoveItem(self, item) - + # If list of items is not empty if not self.ItemsIsEmpty(): # Return to parallel graph if there is only one item @@ -348,51 +348,51 @@ if len(self.Items) == 1: self.GraphType = GRAPH_PARALLEL self.ResetGraphics() - + def SetCursorTick(self, cursor_tick): """ Set cursor tick @param cursor_tick: Cursor tick """ self.CursorTick = cursor_tick - + def SetZoomFit(self, zoom_fit): """ Set flag indicating that zoom fit current displayed data range @param zoom_fit: Flag for zoom fit (False: zoom fit whole data range) """ - # Flag is different from the actual one + # Flag is different from the actual one if zoom_fit != self.ZoomFit: # Save new flag value self.ZoomFit = zoom_fit - + # Update button for zoom fit bitmap self.Buttons[0].SetBitmap("full_graph" if zoom_fit else "fit_graph") - + # Refresh canvas self.RefreshViewer() - + def SubscribeAllDataConsumers(self): """ Function that unsubscribe and remove every item that store values of a variable that doesn't exist in PLC anymore """ DebugVariableViewer.SubscribeAllDataConsumers(self) - + # Graph still have data to display if not self.ItemsIsEmpty(): # Reset flag indicating that zoom fit current displayed data range self.SetZoomFit(False) - + self.ResetGraphics() - + def Is3DCanvas(self): """ Return if Viewer is a 3D canvas @return: True if Viewer is a 3D canvas """ return self.GraphType == GRAPH_ORTHOGONAL and len(self.Items) == 3 - + def GetButtons(self): """ Return list of buttons defined in Viewer @@ -400,7 +400,7 @@ """ # Add contextual buttons to default buttons return self.Buttons + self.ContextualButtons - + def PopupContextualButtons(self, item, rect, direction=wx.RIGHT): """ Show contextual menu for item aside a label of this item defined @@ -412,19 +412,19 @@ # Return immediately if contextual menu for item is already shown if self.ContextualButtonsItem == item: return - + # Close already shown contextual menu self.DismissContextualButtons() - + # Save item for which contextual menu is shown self.ContextualButtonsItem = item - + # If item variable is forced, add button for release variable to # contextual menu if self.ContextualButtonsItem.IsForced(): self.ContextualButtons.append( GraphButton(0, 0, "release", self.OnReleaseItemButton)) - + # Add other buttons to contextual menu for bitmap, callback in [ ("force", self.OnForceItemButton), @@ -432,13 +432,13 @@ ("delete_graph", self.OnRemoveItemButton)]: self.ContextualButtons.append( GraphButton(0, 0, bitmap, callback)) - + # If buttons are shown at left side or upper side of rect, positions # will be set in reverse order buttons = self.ContextualButtons[:] if direction in [wx.TOP, wx.LEFT]: buttons.reverse() - + # Set contextual menu buttons position aside rect depending on # direction given offset = 0 @@ -458,10 +458,10 @@ offset += h button.SetPosition(x, y) button.Show() - + # Refresh canvas self.ParentWindow.ForceRefresh() - + def DismissContextualButtons(self): """ Close current shown contextual menu @@ -469,14 +469,14 @@ # Return immediately if no contextual menu is shown if self.ContextualButtonsItem is None: return - + # Reset variables corresponding to contextual menu self.ContextualButtonsItem = None self.ContextualButtons = [] - + # Refresh canvas self.ParentWindow.ForceRefresh() - + def IsOverContextualButton(self, x, y): """ Return if point is over one contextual button of Viewer @@ -488,7 +488,7 @@ if button.HitTest(x, y): return button return None - + def ExportGraph(self, item=None): """ Export item(s) data to clipboard in CSV format @@ -497,17 +497,17 @@ """ self.ParentWindow.CopyDataToClipboard( [(item, [entry for entry in item.GetData()]) - for item in (self.Items - if item is None + for item in (self.Items + if item is None else [item])]) - + def OnZoomFitButton(self): """ Function called when Viewer Zoom Fit button is pressed """ # Toggle zoom fit flag value self.SetZoomFit(not self.ZoomFit) - + def GetOnChangeSizeButton(self, height): """ Function that generate callback function for change Viewer height to @@ -518,32 +518,32 @@ def OnChangeSizeButton(): self.SetCanvasHeight(height) return OnChangeSizeButton - + def OnExportGraphButton(self): """ Function called when Viewer Export button is pressed """ # Export data of every item in Viewer self.ExportGraph() - + def OnForceItemButton(self): """ Function called when contextual menu Force button is pressed """ - # Open dialog for forcing item variable value + # Open dialog for forcing item variable value self.ForceValue(self.ContextualButtonsItem) # Close contextual menu self.DismissContextualButtons() - + def OnReleaseItemButton(self): """ Function called when contextual menu Release button is pressed """ - # Release item variable value + # Release item variable value self.ReleaseValue(self.ContextualButtonsItem) # Close contextual menu self.DismissContextualButtons() - + def OnExportItemGraphButton(self): """ Function called when contextual menu Export button is pressed @@ -552,17 +552,17 @@ self.ExportGraph(self.ContextualButtonsItem) # Close contextual menu self.DismissContextualButtons() - - def OnRemoveItemButton(self): + + def OnRemoveItemButton(self): """ Function called when contextual menu Remove button is pressed """ # Remove item from Viewer - wx.CallAfter(self.ParentWindow.DeleteValue, self, + wx.CallAfter(self.ParentWindow.DeleteValue, self, self.ContextualButtonsItem) # Close contextual menu self.DismissContextualButtons() - + def HandleCursorMove(self, event): """ Update Cursor position according to mouse position and graph type @@ -571,7 +571,7 @@ start_tick, end_tick = self.ParentWindow.GetRange() cursor_tick = None items = self.ItemsDict.values() - + # Graph is orthogonal if self.GraphType == GRAPH_ORTHOGONAL: # Extract items data displayed in canvas figure @@ -579,31 +579,31 @@ end_tick = max(end_tick, start_tick) x_data = items[0].GetData(start_tick, end_tick) y_data = items[1].GetData(start_tick, end_tick) - + # Search for the nearest point from mouse position if len(x_data) > 0 and len(y_data) > 0: - length = min(len(x_data), len(y_data)) + length = min(len(x_data), len(y_data)) d = numpy.sqrt((x_data[:length,1]-event.xdata) ** 2 + \ (y_data[:length,1]-event.ydata) ** 2) - + # Set cursor tick to the tick of this point cursor_tick = x_data[numpy.argmin(d), 0] - + # Graph is parallel else: # Extract items tick data = items[0].GetData(start_tick, end_tick) - + # Search for point that tick is the nearest from mouse X position # and set cursor tick to the tick of this point if len(data) > 0: cursor_tick = data[numpy.argmin( numpy.abs(data[:,0] - event.xdata)), 0] - + # Update cursor tick if cursor_tick is not None: self.ParentWindow.SetCursorTick(cursor_tick) - + def OnCanvasButtonPressed(self, event): """ Function called when a button of mouse is pressed @@ -613,18 +613,18 @@ # comparing to wx width, height = self.GetSize() x, y = event.x, height - event.y - + # Return immediately if mouse is over a button if self.IsOverButton(x, y): - return - + return + # Mouse was clicked inside graph figure if event.inaxes == self.Axes: - + # Find if it was on an item label item_idx = None # Check every label paired with corresponding item - for i, t in ([pair for pair in enumerate(self.AxesLabels)] + + for i, t in ([pair for pair in enumerate(self.AxesLabels)] + [pair for pair in enumerate(self.Labels)]): # Get label bounding box (x0, y0), (x1, y1) = t.get_window_extent().get_points() @@ -633,46 +633,46 @@ if rect.InsideXY(x, y): item_idx = i break - + # If an item label have been clicked if item_idx is not None: # Hide buttons and contextual buttons self.ShowButtons(False) self.DismissContextualButtons() - + # Start a drag'n drop from mouse position in wx coordinate of # parent xw, yw = self.GetPosition() - self.ParentWindow.StartDragNDrop(self, - self.ItemsDict.values()[item_idx], + self.ParentWindow.StartDragNDrop(self, + self.ItemsDict.values()[item_idx], x + xw, y + yw, # Current mouse position x + xw, y + yw) # Mouse position when button was clicked - + # Don't handle mouse button if canvas is 3D and let matplotlib do # the default behavior (rotate 3D axes) elif not self.Is3DCanvas(): # Save mouse position when clicked self.MouseStartPos = wx.Point(x, y) - + # Mouse button was left button, start moving cursor if event.button == 1: # Save current tick in case a drag'n drop is initiate to # restore it self.StartCursorTick = self.CursorTick - + self.HandleCursorMove(event) - + # Mouse button is middle button and graph is parallel, start # moving graph along X coordinate (tick) elif event.button == 2 and self.GraphType == GRAPH_PARALLEL: self.StartCursorTick = self.ParentWindow.GetRange()[0] - + # Mouse was clicked outside graph figure and over resize highlight with # left button, start resizing Viewer elif event.button == 1 and event.y <= 5: self.MouseStartPos = wx.Point(x, y) self.CanvasStartSize = height - + def OnCanvasButtonReleased(self, event): """ Function called when a button of mouse is released @@ -686,37 +686,37 @@ # Give mouse position in wx coordinate of parent self.ParentWindow.StopDragNDrop(item.GetVariable(), xw + event.x, yw + height - event.y) - + else: # Reset any move in progress self.MouseStartPos = None self.CanvasStartSize = None - + # Handle button under mouse if it exist width, height = self.GetSize() self.HandleButton(event.x, height - event.y) - + def OnCanvasMotion(self, event): """ Function called when a button of mouse is moved over Viewer @param event: Mouse event """ width, height = self.GetSize() - + # If a drag'n drop is in progress, move canvas dragged if self.ParentWindow.IsDragging(): xw, yw = self.GetPosition() # Give mouse position in wx coordinate of parent self.ParentWindow.MoveDragNDrop( - xw + event.x, + xw + event.x, yw + height - event.y) - - # If a Viewer resize is in progress, change Viewer size + + # If a Viewer resize is in progress, change Viewer size elif event.button == 1 and self.CanvasStartSize is not None: width, height = self.GetSize() self.SetCanvasHeight( self.CanvasStartSize + height - event.y - self.MouseStartPos.y) - + # If no button is pressed, show or hide contextual buttons or resize # highlight elif event.button is None: @@ -729,13 +729,13 @@ wx.LEFT, wx.BOTTOM] # Directions for Labels else: # Graph is orthogonal in 3D directions = [wx.LEFT] * len(self.Labels) - + # Find if mouse is over an item label item_idx = None menu_direction = None for (i, t), dir in zip( - [pair for pair in enumerate(self.AxesLabels)] + - [pair for pair in enumerate(self.Labels)], + [pair for pair in enumerate(self.AxesLabels)] + + [pair for pair in enumerate(self.Labels)], directions): # Check every label paired with corresponding item (x0, y0), (x1, y1) = t.get_window_extent().get_points() @@ -745,19 +745,19 @@ item_idx = i menu_direction = dir break - - # If mouse is over an item label, + + # If mouse is over an item label, if item_idx is not None: self.PopupContextualButtons( - self.ItemsDict.values()[item_idx], + self.ItemsDict.values()[item_idx], rect, menu_direction) return - + # If mouse isn't over a contextual menu, hide the current shown one - # if it exists + # if it exists if self.IsOverContextualButton(event.x, height - event.y) is None: self.DismissContextualButtons() - + # Update resize highlight if event.y <= 5: if self.SetHighlight(HIGHLIGHT_RESIZE): @@ -767,46 +767,46 @@ if self.SetHighlight(HIGHLIGHT_NONE): self.SetCursor(wx.NullCursor) self.ParentWindow.ForceRefresh() - - # Handle buttons if canvas is not 3D + + # Handle buttons if canvas is not 3D elif not self.Is3DCanvas(): - + # If left button is pressed if event.button == 1: - + # Mouse is inside graph figure if event.inaxes == self.Axes: - + # If a cursor move is in progress, update cursor position if self.MouseStartPos is not None: self.HandleCursorMove(event) - + # Mouse is outside graph figure, cursor move is in progress and # there is only one item in Viewer, start a drag'n drop elif self.MouseStartPos is not None and len(self.Items) == 1: xw, yw = self.GetPosition() self.ParentWindow.SetCursorTick(self.StartCursorTick) - self.ParentWindow.StartDragNDrop(self, + self.ParentWindow.StartDragNDrop(self, self.ItemsDict.values()[0], # Current mouse position event.x + xw, height - event.y + yw, # Mouse position when button was clicked self.MouseStartPos.x + xw, self.MouseStartPos.y + yw) - + # If middle button is pressed and moving graph along X coordinate # is in progress elif event.button == 2 and self.GraphType == GRAPH_PARALLEL and \ self.MouseStartPos is not None: start_tick, end_tick = self.ParentWindow.GetRange() rect = self.GetAxesBoundingBox() - + # Move graph along X coordinate self.ParentWindow.SetCanvasPosition( - self.StartCursorTick + + self.StartCursorTick + (self.MouseStartPos.x - event.x) * (end_tick - start_tick) / rect.width) - + def OnCanvasScroll(self, event): """ Function called when a wheel mouse is use in Viewer @@ -815,7 +815,7 @@ # Change X range of graphs if mouse is in canvas figure and ctrl is # pressed if event.inaxes is not None and event.guiEvent.ControlDown(): - + # Calculate position of fixed tick point according to graph type # and mouse position if self.GraphType == GRAPH_ORTHOGONAL: @@ -824,10 +824,10 @@ else: tick = event.xdata self.ParentWindow.ChangeRange(int(-event.step) / 3, tick) - + # Vetoing event to prevent parent panel to be scrolled self.ParentWindow.VetoScrollEvent = True - + def OnLeftDClick(self, event): """ Function called when a left mouse button is double clicked @@ -841,17 +841,17 @@ self.ParentWindow.SetCursorTick(self.StartCursorTick) # Toggle to text Viewer(s) self.ParentWindow.ToggleViewerType(self) - + else: event.Skip() - + # Cursor tick move for each arrow key KEY_CURSOR_INCREMENT = { wx.WXK_LEFT: -1, wx.WXK_RIGHT: 1, wx.WXK_UP: 10, wx.WXK_DOWN: -10} - + def OnKeyDown(self, event): """ Function called when key is pressed @@ -863,7 +863,7 @@ if move is not None: self.ParentWindow.MoveCursorTick(move) event.Skip() - + def OnLeave(self, event): """ Function called when mouse leave Viewer @@ -876,7 +876,7 @@ DebugVariableViewer.OnLeave(self, event) else: event.Skip() - + def GetCanvasMinSize(self): """ Return the minimum size of Viewer so that all items label can be @@ -885,10 +885,10 @@ """ # The minimum height take in account the height of all items, padding # inside figure and border around figure - return wx.Size(200, - CANVAS_BORDER[0] + CANVAS_BORDER[1] + + return wx.Size(200, + CANVAS_BORDER[0] + CANVAS_BORDER[1] + 2 * CANVAS_PADDING + VALUE_LABEL_HEIGHT * len(self.Items)) - + def SetCanvasHeight(self, height): """ Set Viewer size checking that it respects Viewer minimum size @@ -899,7 +899,7 @@ self.SetMinSize(wx.Size(min_width, height)) self.RefreshLabelsPosition(height) self.ParentWindow.RefreshGraphicsSizer() - + def GetAxesBoundingBox(self, parent_coordinate=False): """ Return figure bounding box in wx coordinate @@ -911,15 +911,15 @@ ax, ay, aw, ah = self.figure.gca().get_position().bounds bbox = wx.Rect(ax * width, height - (ay + ah) * height - 1, aw * width + 2, ah * height + 1) - + # If parent_coordinate, add Viewer position in parent if parent_coordinate: xw, yw = self.GetPosition() bbox.x += xw bbox.y += yw - + return bbox - + def RefreshHighlight(self, x, y): """ Refresh Viewer highlight according to mouse position @@ -927,7 +927,7 @@ @param y: Y coordinate of mouse pointer """ width, height = self.GetSize() - + # Mouse is over Viewer figure and graph is not 3D bbox = self.GetAxesBoundingBox() if bbox.InsideXY(x, y) and not self.Is3DCanvas(): @@ -935,28 +935,28 @@ # Mouse is over Viewer left part of figure if rect.InsideXY(x, y): self.SetHighlight(HIGHLIGHT_LEFT) - + # Mouse is over Viewer right part of figure else: self.SetHighlight(HIGHLIGHT_RIGHT) - + # Mouse is over upper part of Viewer elif y < height / 2: # Viewer is upper one in Debug Variable Panel, show highlight if self.ParentWindow.IsViewerFirst(self): self.SetHighlight(HIGHLIGHT_BEFORE) - + # Viewer is not the upper one, show highlight in previous one # It prevents highlight to move when mouse leave one Viewer to # another else: self.SetHighlight(HIGHLIGHT_NONE) self.ParentWindow.HighlightPreviousViewer(self) - + # Mouse is over lower part of Viewer else: self.SetHighlight(HIGHLIGHT_AFTER) - + def OnAxesMotion(self, event): """ Function overriding default function called when mouse is dragged for @@ -969,7 +969,7 @@ if current_time - self.LastMotionTime > REFRESH_PERIOD: self.LastMotionTime = current_time Axes3D._on_move(self.Axes, event) - + def GetAddTextFunction(self): """ Return function for adding text in figure according to graph type @@ -987,58 +987,58 @@ self.Axes.set_prop_cycle(cycler('color',color)) else: self.Axes.set_color_cycle(color) - + def ResetGraphics(self): """ Reset figure and graphical elements displayed in it - Called any time list of items or graph type change + Called any time list of items or graph type change """ # Clear figure from any axes defined self.Figure.clear() - + # Add 3D projection if graph is in 3D if self.Is3DCanvas(): self.Axes = self.Figure.gca(projection='3d') self.SetAxesColor(['b']) - - # Override function to prevent too much refresh when graph is + + # Override function to prevent too much refresh when graph is # rotated self.LastMotionTime = gettime() setattr(self.Axes, "_on_move", self.OnAxesMotion) - + # Init graph mouse event so that graph can be rotated self.Axes.mouse_init() - + # Set size of Z axis labels self.Axes.tick_params(axis='z', labelsize='small') - + else: self.Axes = self.Figure.gca() self.SetAxesColor(COLOR_CYCLE) - + # Set size of X and Y axis labels self.Axes.tick_params(axis='x', labelsize='small') self.Axes.tick_params(axis='y', labelsize='small') - + # Init variables storing graphical elements added to figure self.Plots = [] # List of curves self.VLine = None # Vertical line for cursor self.HLine = None # Horizontal line for cursor (only orthogonal 2D) self.AxesLabels = [] # List of items variable path text label self.Labels = [] # List of items text label - - # Get function to add a text in figure according to graph type + + # Get function to add a text in figure according to graph type add_text_func = self.GetAddTextFunction() - + # Graph type is parallel or orthogonal in 3D if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas(): num_item = len(self.Items) for idx in xrange(num_item): - + # Get color from color cycle (black if only one item) color = ('k' if num_item == 1 else COLOR_CYCLE[idx % len(COLOR_CYCLE)]) - + # In 3D graph items variable label are not displayed as text # in figure, but as axis title if not self.Is3DCanvas(): @@ -1046,12 +1046,12 @@ self.AxesLabels.append( add_text_func(size='small', color=color, verticalalignment='top')) - + # Items variable labels are in figure lower right corner self.Labels.append( - add_text_func(size='large', color=color, + add_text_func(size='large', color=color, horizontalalignment='right')) - + # Graph type is orthogonal in 2D else: # X coordinate labels are in figure lower side @@ -1059,7 +1059,7 @@ self.Labels.append( add_text_func(size='large', horizontalalignment='right')) - + # Y coordinate labels are vertical and in figure left side self.AxesLabels.append( add_text_func(size='small', rotation='vertical', @@ -1067,11 +1067,11 @@ self.Labels.append( add_text_func(size='large', rotation='vertical', verticalalignment='top')) - + # Refresh position of labels according to Viewer size width, height = self.GetSize() self.RefreshLabelsPosition(height) - + def RefreshLabelsPosition(self, height): """ Function called when mouse leave Viewer @@ -1087,30 +1087,30 @@ graph_ratio = 1. / ( (1.0 - (CANVAS_BORDER[0] + CANVAS_BORDER[1]) * canvas_ratio) * height) # Divide by figure height in pixel - + # Update position of figure (keeping up and bottom border the same # size) self.Figure.subplotpars.update( - top= 1.0 - CANVAS_BORDER[1] * canvas_ratio, + top= 1.0 - CANVAS_BORDER[1] * canvas_ratio, bottom= CANVAS_BORDER[0] * canvas_ratio) - + # Update position of items labels if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas(): num_item = len(self.Items) for idx in xrange(num_item): - + # In 3D graph items variable label are not displayed if not self.Is3DCanvas(): # Items variable labels are in figure upper left corner self.AxesLabels[idx].set_position( - (0.05, - 1.0 - (CANVAS_PADDING + + (0.05, + 1.0 - (CANVAS_PADDING + AXES_LABEL_HEIGHT * idx) * graph_ratio)) - + # Items variable labels are in figure lower right corner self.Labels[idx].set_position( - (0.95, - CANVAS_PADDING * graph_ratio + + (0.95, + CANVAS_PADDING * graph_ratio + (num_item - idx - 1) * VALUE_LABEL_HEIGHT * graph_ratio)) else: # X coordinate labels are in figure lower side @@ -1118,16 +1118,16 @@ (0.1, CANVAS_PADDING * graph_ratio)) self.Labels[0].set_position( (0.95, CANVAS_PADDING * graph_ratio)) - + # Y coordinate labels are vertical and in figure left side self.AxesLabels[1].set_position( (0.05, 2 * CANVAS_PADDING * graph_ratio)) self.Labels[1].set_position( (0.05, 1.0 - CANVAS_PADDING * graph_ratio)) - + # Update subplots self.Figure.subplots_adjust() - + def RefreshViewer(self, refresh_graphics=True): """ Function called to refresh displayed by matplotlib canvas @@ -1138,55 +1138,55 @@ if refresh_graphics: # Get tick range of values to display start_tick, end_tick = self.ParentWindow.GetRange() - + # Graph is parallel - if self.GraphType == GRAPH_PARALLEL: + if self.GraphType == GRAPH_PARALLEL: # Init list of data range for each variable displayed ranges = [] - + # Get data and range for each variable displayed for idx, item in enumerate(self.Items): data, min_value, max_value = item.GetDataAndValueRange( start_tick, end_tick, not self.ZoomFit) - + # Check that data is not empty if data is not None: # Add variable range to list of variable data range ranges.append((min_value, max_value)) - + # Add plot to canvas if not yet created if len(self.Plots) <= idx: self.Plots.append( self.Axes.plot(data[:, 0], data[:, 1])[0]) - + # Set data to already created plot in canvas else: self.Plots[idx].set_data(data[:, 0], data[:, 1]) - + # Get X and Y axis ranges x_min, x_max = start_tick, end_tick y_min, y_max = merge_ranges(ranges) - + # Display cursor in canvas if a cursor tick is defined and it is # include in values tick range - if (self.CursorTick is not None and + if (self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick): - + # Define a vertical line to display cursor position if no # line is already defined if self.VLine is None: - self.VLine = self.Axes.axvline(self.CursorTick, + self.VLine = self.Axes.axvline(self.CursorTick, color=CURSOR_COLOR) - + # Set value of vertical line if already defined else: self.VLine.set_xdata((self.CursorTick, self.CursorTick)) self.VLine.set_visible(True) - + # Hide vertical line if cursor tick is not defined or reset elif self.VLine is not None: self.VLine.set_visible(False) - + # Graph is orthogonal else: # Update tick range, removing ticks that don't have a value for @@ -1194,76 +1194,76 @@ start_tick = max(start_tick, self.GetItemsMinCommonTick()) end_tick = max(end_tick, start_tick) items = self.ItemsDict.values() - + # Get data and range for first variable (X coordinate) x_data, x_min, x_max = items[0].GetDataAndValueRange( start_tick, end_tick, not self.ZoomFit) # Get data and range for second variable (Y coordinate) y_data, y_min, y_max = items[1].GetDataAndValueRange( start_tick, end_tick, not self.ZoomFit) - + # Normalize X and Y coordinates value range x_min, x_max = merge_ranges([(x_min, x_max)]) y_min, y_max = merge_ranges([(y_min, y_max)]) - - # Get X and Y coordinates for cursor if cursor tick is defined + + # Get X and Y coordinates for cursor if cursor tick is defined if self.CursorTick is not None: x_cursor, x_forced = items[0].GetValue( self.CursorTick, raw=True) y_cursor, y_forced = items[1].GetValue( self.CursorTick, raw=True) - + # Get common data length so that each value has an x and y # coordinate length = (min(len(x_data), len(y_data)) if x_data is not None and y_data is not None else 0) - - # Graph is orthogonal 2D + + # Graph is orthogonal 2D if len(self.Items) < 3: - + # Check that x and y data are not empty if x_data is not None and y_data is not None: - + # Add plot to canvas if not yet created if len(self.Plots) == 0: self.Plots.append( - self.Axes.plot(x_data[:, 1][:length], + self.Axes.plot(x_data[:, 1][:length], y_data[:, 1][:length])[0]) - + # Set data to already created plot in canvas else: self.Plots[0].set_data( - x_data[:, 1][:length], + x_data[:, 1][:length], y_data[:, 1][:length]) - + # Display cursor in canvas if a cursor tick is defined and it is # include in values tick range - if (self.CursorTick is not None and + if (self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick): - + # Define a vertical line to display cursor x coordinate # if no line is already defined if self.VLine is None: - self.VLine = self.Axes.axvline(x_cursor, + self.VLine = self.Axes.axvline(x_cursor, color=CURSOR_COLOR) # Set value of vertical line if already defined else: self.VLine.set_xdata((x_cursor, x_cursor)) - - + + # Define a horizontal line to display cursor y # coordinate if no line is already defined if self.HLine is None: - self.HLine = self.Axes.axhline(y_cursor, + self.HLine = self.Axes.axhline(y_cursor, color=CURSOR_COLOR) # Set value of horizontal line if already defined else: self.HLine.set_ydata((y_cursor, y_cursor)) - + self.VLine.set_visible(True) self.HLine.set_visible(True) - + # Hide vertical and horizontal line if cursor tick is not # defined or reset else: @@ -1271,42 +1271,42 @@ self.VLine.set_visible(False) if self.HLine is not None: self.HLine.set_visible(False) - + # Graph is orthogonal 3D else: # Remove all plots already defined in 3D canvas while len(self.Axes.lines) > 0: self.Axes.lines.pop() - + # Get data and range for third variable (Z coordinate) z_data, z_min, z_max = items[2].GetDataAndValueRange( start_tick, end_tick, not self.ZoomFit) - + # Normalize Z coordinate value range z_min, z_max = merge_ranges([(z_min, z_max)]) - + # Check that x, y and z data are not empty - if (x_data is not None and y_data is not None and + if (x_data is not None and y_data is not None and z_data is not None): - + # Get common data length so that each value has an x, y # and z coordinate length = min(length, len(z_data)) - + # Add plot to canvas self.Axes.plot(x_data[:, 1][:length], y_data[:, 1][:length], zs = z_data[:, 1][:length]) - + # Display cursor in canvas if a cursor tick is defined and # it is include in values tick range - if (self.CursorTick is not None and + if (self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick): - + # Get Z coordinate for cursor z_cursor, z_forced = items[2].GetValue( self.CursorTick, raw=True) - + # Add 3 lines parallel to x, y and z axis to display # cursor position in 3D for kwargs in [{"xs": numpy.array([x_min, x_max])}, @@ -1319,14 +1319,14 @@ kwargs.setdefault(param, value) kwargs["color"] = CURSOR_COLOR self.Axes.plot(**kwargs) - + # Set Z axis limits self.Axes.set_zlim(z_min, z_max) - + # Set X and Y axis limits self.Axes.set_xlim(x_min, x_max) self.Axes.set_ylim(y_min, y_max) - + # Get value and forced flag for each variable displayed in graph # If cursor tick is not defined get value and flag of last received # or get value and flag of variable at cursor tick @@ -1335,34 +1335,34 @@ if self.CursorTick is not None else (item.GetValue(), item.IsForced())) for item in self.Items]) - + # Get path of each variable displayed simplified using panel variable # name mask - labels = [item.GetVariable(self.ParentWindow.GetVariableNameMask()) + labels = [item.GetVariable(self.ParentWindow.GetVariableNameMask()) for item in self.Items] - - # Get style for each variable according to + + # Get style for each variable according to styles = map(lambda x: {True: 'italic', False: 'normal'}[x], forced) - + # Graph is orthogonal 3D, set variables path as 3D axis label if self.Is3DCanvas(): - for idx, label_func in enumerate([self.Axes.set_xlabel, + for idx, label_func in enumerate([self.Axes.set_xlabel, self.Axes.set_ylabel, self.Axes.set_zlabel]): label_func(labels[idx], fontdict={'size': 'small', 'color': COLOR_CYCLE[idx]}) - + # Graph is not orthogonal 3D, set variables path in axes labels else: for label, text in zip(self.AxesLabels, labels): label.set_text(text) - + # Set value label text and style according to value and forced flag for # each variable displayed for label, value, style in zip(self.Labels, values, styles): label.set_text(value) label.set_style(style) - + # Refresh figure self.draw() @@ -1372,51 +1372,49 @@ """ # Render figure using agg FigureCanvasAgg.draw(self) - + # Get bitmap of figure rendered self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None) - if wx.VERSION < (3, 0, 0): + if wx.VERSION < (3, 0, 0): self.bitmap.UseAlpha() - + # Create DC for rendering graphics in bitmap destDC = wx.MemoryDC() destDC.SelectObject(self.bitmap) - + # Get Graphics Context for DC, for anti-aliased and transparent # rendering destGC = wx.GCDC(destDC) - + destGC.BeginDrawing() - + # Get canvas size and figure bounding box in canvas width, height = self.GetSize() bbox = self.GetAxesBoundingBox() - + # If highlight to display is resize, draw thick grey line at bottom - # side of canvas + # side of canvas if self.Highlight == HIGHLIGHT_RESIZE: destGC.SetPen(HIGHLIGHT_RESIZE_PEN) destGC.SetBrush(HIGHLIGHT_RESIZE_BRUSH) destGC.DrawRectangle(0, height - 5, width, 5) - + # If highlight to display is merging graph, draw 50% transparent blue # rectangle on left or right part of figure depending on highlight type elif self.Highlight in [HIGHLIGHT_LEFT, HIGHLIGHT_RIGHT]: destGC.SetPen(HIGHLIGHT_DROP_PEN) destGC.SetBrush(HIGHLIGHT_DROP_BRUSH) - - x_offset = (bbox.width / 2 + + x_offset = (bbox.width / 2 if self.Highlight == HIGHLIGHT_RIGHT else 0) - destGC.DrawRectangle(bbox.x + x_offset, bbox.y, + destGC.DrawRectangle(bbox.x + x_offset, bbox.y, bbox.width / 2, bbox.height) - + # Draw other Viewer common elements self.DrawCommonElements(destGC, self.GetButtons()) - + destGC.EndDrawing() - + self._isDrawn = True self.gui_repaint(drawDC=drawDC) - - diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/DebugVariableItem.py --- a/controls/DebugVariablePanel/DebugVariableItem.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/DebugVariableItem.py Mon Aug 14 19:13:01 2017 +0300 @@ -44,7 +44,7 @@ """ class DebugVariableItem(DebugDataConsumer): - + def __init__(self, parent, variable, store_data=False): """ Constructor @@ -52,24 +52,24 @@ @param variable: Path of variable to debug """ DebugDataConsumer.__init__(self) - + self.Parent = parent self.Variable = variable self.StoreData = store_data - + # Get Variable data type self.RefreshVariableType() - + def __del__(self): """ Destructor """ # Reset reference to debug variable panel self.Parent = None - + def SetVariable(self, variable): """ - Set path of variable + Set path of variable @param variable: Path of variable to debug """ if self.Parent is not None and self.Variable != variable: @@ -77,46 +77,46 @@ self.Variable = variable # Get Variable data type self.RefreshVariableType() - + # Refresh debug variable panel self.Parent.RefreshView() - + def GetVariable(self, mask=None): """ - Return path of variable + Return path of variable @param mask: Mask to apply to variable path [var_name, '*',...] @return: String containing masked variable path """ # Apply mask to variable name if mask is not None: # '#' correspond to parts that are different between all items - + # Extract variable path parts parts = self.Variable.split('.') # Adjust mask size to size of variable path mask = mask + ['*'] * max(0, len(parts) - len(mask)) - + # Store previous mask last = None # Init masked variable path variable = "" - + for m, p in zip(mask, parts): # Part is not masked, add part prefixed with '.' is previous # wasn't masked if m == '*': variable += ('.' if last == '*' else '') + p - + # Part is mask, add '..' if first or previous wasn't masked elif last is None or last == '*': variable += '..' - + last = m - + return variable - + return self.Variable - + def RefreshVariableType(self): """ Get and store variable data type @@ -124,14 +124,14 @@ self.VariableType = self.Parent.GetDataType(self.Variable) # Reset data stored self.ResetData() - + def GetVariableType(self): """ Return variable data type @return: Variable data type """ return self.VariableType - + def GetData(self, start_tick=None, end_tick=None): """ Return data stored contained in given range @@ -142,7 +142,7 @@ # Return immediately if data empty or none if self.Data is None or len(self.Data) == 0: return self.Data - + # Find nearest data outside given range indexes start_idx = (self.GetNearestData(start_tick, -1) if start_tick is not None @@ -150,10 +150,10 @@ end_idx = (self.GetNearestData(end_tick, 1) if end_tick is not None else len(self.Data)) - + # Return data between indexes return self.Data[start_idx:end_idx] - + def GetRawValue(self, index): """ Return raw value at given index for string variables @@ -164,14 +164,14 @@ index < len(self.RawData)): return self.RawData[index][0] return "" - + def GetValueRange(self): """ Return variable value range @return: (minimum_value, maximum_value) """ return self.MinValue, self.MaxValue - + def GetDataAndValueRange(self, start_tick, end_tick, full_range=True): """ Return variable data and value range for a given tick range @@ -179,16 +179,16 @@ @param end_tick: end tick of given range (default None, last data) @param full_range: Value range is calculated on whole data (False: only calculated on data in given range) - @return: (numpy.array([(tick, value, forced),...]), + @return: (numpy.array([(tick, value, forced),...]), min_value, max_value) """ # Get data in given tick range data = self.GetData(start_tick, end_tick) - + # Value range is calculated on whole data if full_range: return data, self.MinValue, self.MaxValue - + # Check that data in given range is not empty values = data[:, 1] if len(values) > 0: @@ -196,10 +196,10 @@ return (data, data[numpy.argmin(values), 1], data[numpy.argmax(values), 1]) - + # Return default values return data, None, None - + def ResetData(self): """ Reset data stored when store data option enabled @@ -207,31 +207,31 @@ if self.StoreData and self.IsNumVariable(): # Init table storing data self.Data = numpy.array([]).reshape(0, 3) - + # Init table storing raw data if variable is strin self.RawData = ([] if self.VariableType in ["STRING", "WSTRING"] else None) - + # Init Value range variables self.MinValue = None self.MaxValue = None - + else: self.Data = None - + # Init variable value self.Value = "" - + def IsNumVariable(self): """ Return if variable data type is numeric. String variables are considered as numeric (string CRC) @return: True if data type is numeric """ - return (self.Parent.IsNumType(self.VariableType) or + return (self.Parent.IsNumType(self.VariableType) or self.VariableType in ["STRING", "WSTRING"]) - + def NewValues(self, ticks, values): """ Function called by debug thread when a new debug value is available @@ -240,24 +240,24 @@ @param forced: Forced flag, True if value is forced (default: False) """ DebugDataConsumer.NewValues(self, ticks[-1], values[-1], raw=None) - + if self.Data is not None: - + if self.VariableType in ["STRING", "WSTRING"]: last_raw_data = (self.RawData[-1] if len(self.RawData) > 0 else None) last_raw_data_idx = len(self.RawData) - 1 - + data_values = [] for tick, (value, forced) in zip(ticks, values): # Translate forced flag to float for storing in Data table forced_value = float(forced) - + # String data value is CRC num_value = (binascii.crc32(value) & STRING_CRC_MASK if self.VariableType in ["STRING", "WSTRING"] else float(value)) - + # Update variable range values self.MinValue = (min(self.MinValue, num_value) if self.MinValue is not None @@ -265,10 +265,10 @@ self.MaxValue = (max(self.MaxValue, num_value) if self.MaxValue is not None else num_value) - + # In the case of string variables, we store raw string value and # forced flag in raw data table. Only changes in this two values - # are stored. Index to the corresponding raw value is stored in + # are stored. Index to the corresponding raw value is stored in # data third column if self.VariableType in ["STRING", "WSTRING"]: raw_data = (value, forced_value) @@ -277,20 +277,20 @@ last_raw_data = raw_data self.RawData.append(raw_data) extra_value = last_raw_data_idx - + # In other case, data third column is forced flag else: extra_value = forced_value - + data_values.append( [float(tick), num_value, extra_value]) - + # Add New data to stored data table self.Data = numpy.append(self.Data, data_values, axis=0) - + # Signal to debug variable panel to refresh self.Parent.HasNewData = True - + def SetForced(self, forced): """ Update Forced flag @@ -299,10 +299,10 @@ # Store forced flag if self.Forced != forced: self.Forced = forced - + # Signal to debug variable panel to refresh self.Parent.HasNewData = True - + def SetValue(self, value): """ Update value. @@ -314,14 +314,14 @@ self.VariableType == "WSTRING" and value.startswith('"') and value.endswith('"')): value = value[1:-1] - + # Store variable value if self.Value != value: self.Value = value - + # Signal to debug variable panel to refresh self.Parent.HasNewData = True - + def GetValue(self, tick=None, raw=False): """ Return current value or value and forced flag for tick given @@ -329,26 +329,26 @@ """ # If tick given and stored data option enabled if tick is not None and self.Data is not None: - + # Return current value and forced flag if data empty if len(self.Data) == 0: return self.Value, self.IsForced() - + # Get index of nearest data from tick given idx = self.GetNearestData(tick, 0) - + # Get value and forced flag at given index value, forced = self.RawData[int(self.Data[idx, 2])] \ if self.VariableType in ["STRING", "WSTRING"] \ else self.Data[idx, 1:3] - + # Get raw value if asked if not raw: value = TYPE_TRANSLATOR.get( self.VariableType, str)(value) - + return value, forced - + # Return raw value if asked if not raw and self.VariableType in ["STRING", "WSTRING"]: return TYPE_TRANSLATOR.get( @@ -368,16 +368,16 @@ # Return immediately if data is empty if self.Data is None: return None - + # Extract data ticks ticks = self.Data[:, 0] - + # Get nearest data from tick idx = numpy.argmin(abs(ticks - tick)) - + # Adjust data index according to constraint if (adjust < 0 and ticks[idx] > tick and idx > 0 or adjust > 0 and ticks[idx] < tick and idx < len(ticks)): idx += adjust - + return idx diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/DebugVariablePanel.py --- a/controls/DebugVariablePanel/DebugVariablePanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/DebugVariablePanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -67,11 +67,11 @@ for item, data in variables: if len(data) == 0: continue - + next_tick = (data[0][0] if next_tick is None else min(next_tick, data[0][0])) - + return next_tick #------------------------------------------------------------------------------- @@ -84,7 +84,7 @@ """ class DebugVariableDropTarget(wx.TextDropTarget): - + def __init__(self, window): """ Constructor @@ -92,14 +92,14 @@ """ wx.TextDropTarget.__init__(self) self.ParentWindow = window - + def __del__(self): """ Destructor """ # Remove reference to Debug Variable Panel self.ParentWindow = None - + def OnDragOver(self, x, y, d): """ Function called when mouse is dragged over Drop Target @@ -110,7 +110,7 @@ # Signal Debug Variable Panel to refresh highlight giving mouse position self.ParentWindow.RefreshHighlight(x, y) return wx.TextDropTarget.OnDragOver(self, x, y, d) - + def OnDropText(self, x, y, data): """ Function called when mouse is released in Drop Target @@ -120,9 +120,9 @@ """ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() - + message = None - + # Check that data is valid regarding DebugVariablePanel try: values = eval(data) @@ -131,23 +131,23 @@ except: message = _("Invalid value \"%s\" for debug variable")%data values = None - + # Display message if data is invalid if message is not None: wx.CallAfter(self.ShowMessage, message) - + # Data contain a reference to a variable to debug elif values[1] == "debug": - + # Drag'n Drop is an internal is an internal move inside Debug - # Variable Panel + # Variable Panel if len(values) > 2 and values[2] == "move": self.ParentWindow.MoveValue(values[0]) - + # Drag'n Drop was initiated by another control of Beremiz else: self.ParentWindow.InsertValue(values[0], force=True) - + def OnLeave(self): """ Function called when mouse is leave Drop Target @@ -155,15 +155,15 @@ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() return wx.TextDropTarget.OnLeave(self) - + def ShowMessage(self, message): """ Show error message in Error Dialog @param message: Error message to display """ - dialog = wx.MessageDialog(self.ParentWindow, - message, - _("Error"), + dialog = wx.MessageDialog(self.ParentWindow, + message, + _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() @@ -178,7 +178,7 @@ """ class DebugVariablePanel(wx.Panel, DebugViewer): - + def __init__(self, parent, producer, window): """ Constructor @@ -188,48 +188,48 @@ @param window: Reference to Beremiz frame """ wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL) - + # Save Reference to Beremiz frame self.ParentWindow = window - + # Variable storing flag indicating that variable displayed in table # received new value and then table need to be refreshed self.HasNewData = False - + # Variable storing flag indicating that refresh has been forced, and # that next time refresh is possible, it will be done even if no new # data is available self.Force = False - + self.SetBackgroundColour(wx.WHITE) - + main_sizer = wx.BoxSizer(wx.VERTICAL) - + self.Ticks = numpy.array([]) # List of tick received self.StartTick = 0 # Tick starting range of data displayed self.Fixed = False # Flag that range of data is fixed self.CursorTick = None # Tick of cursor for displaying values - + self.DraggingAxesPanel = None self.DraggingAxesBoundingBox = None self.DraggingAxesMousePos = None self.VetoScrollEvent = False - + self.VariableNameMask = [] - + self.GraphicPanels = [] - + graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) - + range_label = wx.StaticText(self, label=_('Range:')) graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) - + self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange) - graphics_button_sizer.AddWindow(self.CanvasRange, 1, + graphics_button_sizer.AddWindow(self.CanvasRange, 1, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL) - + self.CanvasRange.Clear() default_range_idx = 0 for idx, (text, value) in enumerate(RANGE_VALUES): @@ -237,44 +237,44 @@ if text == "1s": default_range_idx = idx self.CanvasRange.SetSelection(default_range_idx) - + for name, bitmap, help in [ ("CurrentButton", "current", _("Go to current value")), ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]: - button = wx.lib.buttons.GenBitmapButton(self, - bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self, + bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT) - - self.CanvasPosition = wx.ScrollBar(self, + + self.CanvasPosition = wx.ScrollBar(self, size=wx.Size(0, 16), style=wx.SB_HORIZONTAL) - self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, + self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK, self.OnPositionChanging, self.CanvasPosition) - self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, + self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP, self.OnPositionChanging, self.CanvasPosition) - self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN, + self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN, self.OnPositionChanging, self.CanvasPosition) - self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, + self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, self.OnPositionChanging, self.CanvasPosition) - self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, + self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, self.OnPositionChanging, self.CanvasPosition) main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) - + self.TickSizer = wx.BoxSizer(wx.HORIZONTAL) main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL|wx.GROW) - + self.TickLabel = wx.StaticText(self) self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT) - + self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY|wx.TE_CENTER|wx.NO_BORDER) self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT|wx.GROW) - + self.TickTimeLabel = wx.StaticText(self) self.TickSizer.AddWindow(self.TickTimeLabel) - + self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL) self.GraphicsWindow.SetBackgroundColour(wx.WHITE) self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self)) @@ -282,17 +282,17 @@ self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint) self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize) self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel) - + main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW) - + self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL) self.GraphicsWindow.SetSizer(self.GraphicsSizer) - + DebugViewer.__init__(self, producer, True) - + self.SetSizer(main_sizer) self.SetTickTime() - + def SetTickTime(self, ticktime=0): """ Set Ticktime for calculate data range according to time range selected @@ -300,26 +300,26 @@ """ # Save ticktime self.Ticktime = ticktime - + # Set ticktime to millisecond if undefined if self.Ticktime == 0: self.Ticktime = MILLISECOND - + # Calculate range to apply to data self.CurrentRange = RANGE_VALUES[ self.CanvasRange.GetSelection()][1] / self.Ticktime - + def SetDataProducer(self, producer): """ Set Data Producer @param producer: Data Producer """ DebugViewer.SetDataProducer(self, producer) - + # Set ticktime if data producer is available if self.DataProducer is not None: self.SetTickTime(self.DataProducer.GetTicktime()) - + def RefreshNewData(self): """ Called to refresh Panel according to values received by variables @@ -329,50 +329,50 @@ if self.HasNewData or self.Force: self.HasNewData = False self.RefreshView() - + DebugViewer.RefreshNewData(self) - + def NewDataAvailable(self, ticks): """ Called by DataProducer for each tick captured or by panel to refresh graphs @param tick: PLC tick captured - All other parameters are passed to refresh function + All other parameters are passed to refresh function """ # If tick given if ticks is not None: tick = ticks[-1] - + # Save tick as start tick for range if data is still empty if len(self.Ticks) == 0: self.StartTick = ticks[0] - + # Add tick to list of ticks received self.Ticks = numpy.append(self.Ticks, ticks) - + # Update start tick for range if range follow ticks received if not self.Fixed or tick < self.StartTick + self.CurrentRange: self.StartTick = max(self.StartTick, tick - self.CurrentRange) - + # Force refresh if graph is fixed because range of data received # is too small to fill data range selected if self.Fixed and \ self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: self.Force = True - + self.HasNewData = False self.RefreshView() - + else: DebugViewer.NewDataAvailable(self, ticks) - + def ForceRefresh(self): """ Called to force refresh of graphs """ self.Force = True wx.CallAfter(self.NewDataAvailable, None) - + def SetCursorTick(self, cursor_tick): """ Set Cursor for displaying values of items at a tick given @@ -381,37 +381,37 @@ # Save cursor tick self.CursorTick = cursor_tick self.Fixed = cursor_tick is not None - self.UpdateCursorTick() - + self.UpdateCursorTick() + def MoveCursorTick(self, move): if self.CursorTick is not None: - cursor_tick = max(self.Ticks[0], - min(self.CursorTick + move, + cursor_tick = max(self.Ticks[0], + min(self.CursorTick + move, self.Ticks[-1])) cursor_tick_idx = numpy.argmin(numpy.abs(self.Ticks - cursor_tick)) if self.Ticks[cursor_tick_idx] == self.CursorTick: - cursor_tick_idx = max(0, - min(cursor_tick_idx + abs(move) / move, + cursor_tick_idx = max(0, + min(cursor_tick_idx + abs(move) / move, len(self.Ticks) - 1)) self.CursorTick = self.Ticks[cursor_tick_idx] self.StartTick = max(self.Ticks[ - numpy.argmin(numpy.abs(self.Ticks - + numpy.argmin(numpy.abs(self.Ticks - self.CursorTick + self.CurrentRange))], min(self.StartTick, self.CursorTick)) self.RefreshCanvasPosition() - self.UpdateCursorTick() - + self.UpdateCursorTick() + def ResetCursorTick(self): self.CursorTick = None self.Fixed = False self.UpdateCursorTick() - + def UpdateCursorTick(self): for panel in self.GraphicPanels: if isinstance(panel, DebugVariableGraphicViewer): panel.SetCursorTick(self.CursorTick) self.ForceRefresh() - + def StartDragNDrop(self, panel, item, x_mouse, y_mouse, x_mouse_start, y_mouse_start): if len(panel.GetItems()) > 1: self.DraggingAxesPanel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) @@ -424,21 +424,21 @@ self.DraggingAxesPanel = panel self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(parent_coordinate=True) self.DraggingAxesMousePos = wx.Point( - x_mouse_start - self.DraggingAxesBoundingBox.x, + x_mouse_start - self.DraggingAxesBoundingBox.x, y_mouse_start - self.DraggingAxesBoundingBox.y) self.MoveDragNDrop(x_mouse, y_mouse) - + def MoveDragNDrop(self, x_mouse, y_mouse): self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y self.RefreshHighlight(x_mouse, y_mouse) - + def RefreshHighlight(self, x_mouse, y_mouse): for idx, panel in enumerate(self.GraphicPanels): x, y = panel.GetPosition() width, height = panel.GetSize() rect = wx.Rect(x, y, width, height) - if (rect.InsideXY(x_mouse, y_mouse) or + if (rect.InsideXY(x_mouse, y_mouse) or idx == 0 and y_mouse < 0 or idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]): panel.RefreshHighlight(x_mouse - x, y_mouse - y) @@ -448,7 +448,7 @@ self.RefreshView() else: self.ForceRefresh() - + def ResetHighlight(self): for panel in self.GraphicPanels: panel.SetHighlight(HIGHLIGHT_NONE) @@ -456,10 +456,10 @@ self.RefreshView() else: self.ForceRefresh() - + def IsDragging(self): return self.DraggingAxesPanel is not None - + def GetDraggingAxesClippingRegion(self, panel): x, y = panel.GetPosition() width, height = panel.GetSize() @@ -468,12 +468,12 @@ bbox.x -= x bbox.y -= y return bbox - + def GetDraggingAxesPosition(self, panel): x, y = panel.GetPosition() return wx.Point(self.DraggingAxesBoundingBox.x - x, self.DraggingAxesBoundingBox.y - y) - + def StopDragNDrop(self, variable, x_mouse, y_mouse): if self.DraggingAxesPanel not in self.GraphicPanels: self.DraggingAxesPanel.Destroy() @@ -504,25 +504,25 @@ idx += 1 wx.CallAfter(self.MoveValue, variable, idx, True) self.ForceRefresh() - return + return width, height = self.GraphicsWindow.GetVirtualSize() rect = wx.Rect(0, 0, width, height) if rect.InsideXY(x_mouse, y_mouse): wx.CallAfter(self.MoveValue, variable, len(self.GraphicPanels), True) self.ForceRefresh() - + def RefreshGraphicsSizer(self): self.GraphicsSizer.Clear() - + for panel in self.GraphicPanels: self.GraphicsSizer.AddWindow(panel, flag=wx.GROW) - + self.GraphicsSizer.Layout() self.RefreshGraphicsWindowScrollbars() - + def RefreshView(self): self.RefreshCanvasPosition() - + width, height = self.GraphicsWindow.GetVirtualSize() bitmap = wx.EmptyBitmap(width, height) dc = wx.BufferedDC(wx.ClientDC(self.GraphicsWindow), bitmap) @@ -531,22 +531,22 @@ if self.DraggingAxesPanel is not None: destBBox = self.DraggingAxesBoundingBox srcBBox = self.DraggingAxesPanel.GetAxesBoundingBox() - + srcBmp = _convert_agg_to_wx_bitmap(self.DraggingAxesPanel.get_renderer(), None) srcDC = wx.MemoryDC() srcDC.SelectObject(srcBmp) - - dc.Blit(destBBox.x, destBBox.y, - int(destBBox.width), int(destBBox.height), + + dc.Blit(destBBox.x, destBBox.y, + int(destBBox.width), int(destBBox.height), srcDC, srcBBox.x, srcBBox.y) dc.EndDrawing() - + if not self.Fixed or self.Force: self.Force = False refresh_graphics = True else: refresh_graphics = False - + if self.DraggingAxesPanel is not None and self.DraggingAxesPanel not in self.GraphicPanels: self.DraggingAxesPanel.RefreshViewer(refresh_graphics) for panel in self.GraphicPanels: @@ -554,7 +554,7 @@ panel.RefreshViewer(refresh_graphics) else: panel.RefreshViewer() - + if self.CursorTick is not None: tick = self.CursorTick elif len(self.Ticks) > 0: @@ -570,27 +570,27 @@ ((tick_duration % DAY) / HOUR, _("%dh")), ((tick_duration % HOUR) / MINUTE, _("%dm")), ((tick_duration % MINUTE) / SECOND, _("%ds"))]: - + if value > 0 or not_null: duration += format % value not_null = True - - duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND) + + duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND) self.TickTimeLabel.SetLabel("t: %s" % duration) else: self.TickLabel.SetLabel("") self.TickTimeLabel.SetLabel("") self.TickSizer.Layout() - + def SubscribeAllDataConsumers(self): DebugViewer.SubscribeAllDataConsumers(self) - + if self.DataProducer is not None: if self.DataProducer is not None: self.SetTickTime(self.DataProducer.GetTicktime()) - + self.ResetCursorTick() - + for panel in self.GraphicPanels[:]: panel.SubscribeAllDataConsumers() if panel.ItemsIsEmpty(): @@ -598,28 +598,28 @@ panel.ReleaseMouse() self.GraphicPanels.remove(panel) panel.Destroy() - + self.ResetVariableNameMask() self.RefreshGraphicsSizer() self.ForceRefresh() - + def ResetView(self): self.UnsubscribeAllDataConsumers() - + self.Fixed = False for panel in self.GraphicPanels: panel.Destroy() self.GraphicPanels = [] self.ResetVariableNameMask() self.RefreshGraphicsSizer() - + def SetCanvasPosition(self, tick): tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange)) self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))] self.Fixed = True self.RefreshCanvasPosition() self.ForceRefresh() - + def RefreshCanvasPosition(self): if len(self.Ticks) > 0: pos = int(self.StartTick - self.Ticks[0]) @@ -628,7 +628,7 @@ pos = 0 range = 0 self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange) - + def ChangeRange(self, dir, tick=None): current_range = self.CurrentRange current_range_idx = self.CanvasRange.GetSelection() @@ -644,7 +644,7 @@ self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))] self.Fixed = new_start_tick < self.Ticks[-1] - self.CurrentRange self.ForceRefresh() - + def RefreshRange(self): if len(self.Ticks) > 0: if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange: @@ -654,7 +654,7 @@ else: self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) self.ForceRefresh() - + def OnRangeChanged(self, event): try: self.CurrentRange = RANGE_VALUES[self.CanvasRange.GetSelection()][1] / self.Ticktime @@ -662,13 +662,13 @@ self.CanvasRange.SetValue(str(self.CurrentRange)) wx.CallAfter(self.RefreshRange) event.Skip() - + def OnCurrentButton(self, event): if len(self.Ticks) > 0: self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange) self.ResetCursorTick() event.Skip() - + def CopyDataToClipboard(self, variables): text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables]) next_tick = NextTick(variables) @@ -693,7 +693,7 @@ text += "%d;%s;\n" % (next_tick, ";".join(values)) next_tick = NextTick(variables) self.ParentWindow.SetCopyBuffer(text) - + def OnExportGraphButton(self, event): items = reduce(lambda x, y: x + y, [panel.GetItems() for panel in self.GraphicPanels], @@ -703,25 +703,25 @@ if item.IsNumVariable()] wx.CallAfter(self.CopyDataToClipboard, variables) event.Skip() - + def OnPositionChanging(self, event): if len(self.Ticks) > 0: self.StartTick = self.Ticks[0] + event.GetPosition() self.Fixed = True self.ForceRefresh() event.Skip() - + def GetRange(self): return self.StartTick, self.StartTick + self.CurrentRange - + def GetViewerIndex(self, viewer): if viewer in self.GraphicPanels: return self.GraphicPanels.index(viewer) return None - + def IsViewerFirst(self, viewer): return viewer == self.GraphicPanels[0] - + def HighlightPreviousViewer(self, viewer): if self.IsViewerFirst(viewer): return @@ -729,7 +729,7 @@ if idx is None: return self.GraphicPanels[idx-1].SetHighlight(HIGHLIGHT_AFTER) - + def ResetVariableNameMask(self): items = [] for panel in self.GraphicPanels: @@ -743,10 +743,10 @@ self.VariableNameMask = [] self.MaskLabel.ChangeValue(".".join(self.VariableNameMask)) self.MaskLabel.SetInsertionPoint(self.MaskLabel.GetLastPosition()) - + def GetVariableNameMask(self): return self.VariableNameMask - + def InsertValue(self, iec_path, idx = None, force=False, graph=False): for panel in self.GraphicPanels: if panel.GetItem(iec_path) is not None: @@ -758,7 +758,7 @@ item = DebugVariableItem(self, iec_path, True) result = self.AddDataConsumer(iec_path.upper(), item, True) if result is not None or force: - + self.Freeze() if item.IsNumVariable() and graph: panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL) @@ -774,7 +774,7 @@ self.RefreshGraphicsSizer() self.Thaw() self.ForceRefresh() - + def MoveValue(self, iec_path, idx = None, graph=False): if idx is None: idx = len(self.GraphicPanels) @@ -787,9 +787,9 @@ break if source_panel is not None: source_panel_idx = self.GraphicPanels.index(source_panel) - + if (len(source_panel.GetItems()) == 1): - + if source_panel_idx < idx: self.GraphicPanels.insert(idx, source_panel) self.GraphicPanels.pop(source_panel_idx) @@ -798,7 +798,7 @@ self.GraphicPanels.insert(idx, source_panel) else: return - + else: source_panel.RemoveItem(item) source_size = source_panel.GetSize() @@ -807,22 +807,22 @@ panel.SetCanvasHeight(source_size.height) if self.CursorTick is not None: panel.SetCursorTick(self.CursorTick) - + else: panel = DebugVariableTextViewer(self.GraphicsWindow, self, [item]) - + self.GraphicPanels.insert(idx, panel) - + if source_panel.ItemsIsEmpty(): if source_panel.HasCapture(): source_panel.ReleaseMouse() source_panel.Destroy() self.GraphicPanels.remove(source_panel) - + self.ResetVariableNameMask() self.RefreshGraphicsSizer() self.ForceRefresh() - + def MergeGraphs(self, source, target_idx, merge_type, force=False): source_item = None source_panel = None @@ -846,11 +846,11 @@ graph_type = target_panel.GraphType if target_panel != source_panel: if (merge_type == GRAPH_PARALLEL and graph_type != merge_type or - merge_type == GRAPH_ORTHOGONAL and + merge_type == GRAPH_ORTHOGONAL and (graph_type == GRAPH_PARALLEL and len(target_panel.Items) > 1 or graph_type == GRAPH_ORTHOGONAL and len(target_panel.Items) >= 3)): return - + if source_panel is not None: source_panel.RemoveItem(source_item) if source_panel.ItemsIsEmpty(): @@ -862,7 +862,7 @@ target_panel.RemoveItem(source_item) else: target_panel = None - + if target_panel is not None: target_panel.AddItem(source_item) target_panel.GraphType = merge_type @@ -874,15 +874,15 @@ else: target_panel.SetCanvasHeight(size.height) target_panel.ResetGraphics() - + self.ResetVariableNameMask() self.RefreshGraphicsSizer() self.ForceRefresh() - + def DeleteValue(self, source_panel, item=None): source_idx = self.GetViewerIndex(source_panel) if source_idx is not None: - + if item is None: source_panel.ClearItems() source_panel.Destroy() @@ -900,7 +900,7 @@ self.Fixed = False self.ResetCursorTick() self.ForceRefresh() - + def ToggleViewerType(self, panel): panel_idx = self.GetViewerIndex(panel) if panel_idx is not None: @@ -916,7 +916,7 @@ panel.Destroy() self.RefreshGraphicsSizer() self.ForceRefresh() - + def ResetGraphicsValues(self): self.Ticks = numpy.array([]) self.StartTick = 0 @@ -931,22 +931,22 @@ posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT)) posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT)) self.GraphicsWindow.Scroll(posx, posy) - self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, + self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, posx, posy) - + def OnGraphicsWindowEraseBackground(self, event): pass - + def OnGraphicsWindowPaint(self, event): self.RefreshView() event.Skip() - + def OnGraphicsWindowResize(self, event): size = self.GetSize() for panel in self.GraphicPanels: panel_size = panel.GetSize() - if (isinstance(panel, DebugVariableGraphicViewer) and - panel.GraphType == GRAPH_ORTHOGONAL and + if (isinstance(panel, DebugVariableGraphicViewer) and + panel.GraphType == GRAPH_ORTHOGONAL and panel_size.width == panel_size.height): panel.SetCanvasHeight(size.width) self.RefreshGraphicsWindowScrollbars() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/DebugVariableTextViewer.py --- a/controls/DebugVariablePanel/DebugVariableTextViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,7 +39,7 @@ """ class DebugVariableTextDropTarget(wx.TextDropTarget): - + def __init__(self, parent, window): """ Constructor @@ -49,7 +49,7 @@ wx.TextDropTarget.__init__(self) self.ParentControl = parent self.ParentWindow = window - + def __del__(self): """ Destructor @@ -58,7 +58,7 @@ # Panel self.ParentControl = None self.ParentWindow = None - + def OnDragOver(self, x, y, d): """ Function called when mouse is dragged over Drop Target @@ -68,9 +68,9 @@ """ # Signal parent that mouse is dragged over self.ParentControl.OnMouseDragging(x, y) - + return wx.TextDropTarget.OnDragOver(self, x, y, d) - + def OnDropText(self, x, y, data): """ Function called when mouse is released in Drop Target @@ -80,9 +80,9 @@ """ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() - + message = None - + # Check that data is valid regarding DebugVariablePanel try: values = eval(data) @@ -91,50 +91,50 @@ except: message = _("Invalid value \"%s\" for debug variable") % data values = None - + # Display message if data is invalid if message is not None: wx.CallAfter(self.ShowMessage, message) - + # Data contain a reference to a variable to debug elif values[1] == "debug": - + # Get Before which Viewer the variable has to be moved or added # according to the position of mouse in Viewer. width, height = self.ParentControl.GetSize() target_idx = self.ParentControl.GetIndex() if y > height / 2: target_idx += 1 - + # Drag'n Drop is an internal is an internal move inside Debug - # Variable Panel + # Variable Panel if len(values) > 2 and values[2] == "move": - self.ParentWindow.MoveValue(values[0], + self.ParentWindow.MoveValue(values[0], target_idx) - + # Drag'n Drop was initiated by another control of Beremiz else: - self.ParentWindow.InsertValue(values[0], - target_idx, + self.ParentWindow.InsertValue(values[0], + target_idx, force=True) - + def OnLeave(self): """ Function called when mouse is leave Drop Target """ # Signal Debug Variable Panel to reset highlight self.ParentWindow.ResetHighlight() - + return wx.TextDropTarget.OnLeave(self) - + def ShowMessage(self, message): """ Show error message in Error Dialog @param message: Error message to display """ - dialog = wx.MessageDialog(self.ParentWindow, - message, - _("Error"), + dialog = wx.MessageDialog(self.ParentWindow, + message, + _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() @@ -149,7 +149,7 @@ """ class DebugVariableTextViewer(DebugVariableViewer, wx.Panel): - + def __init__(self, parent, window, items=[]): """ Constructor @@ -158,13 +158,13 @@ @param items: List of DebugVariableItem displayed by Viewer """ DebugVariableViewer.__init__(self, window, items) - + wx.Panel.__init__(self, parent) # Set panel background colour self.SetBackgroundColour(wx.WHITE) # Define panel drop target self.SetDropTarget(DebugVariableTextDropTarget(self, window)) - + # Bind events self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) @@ -174,16 +174,16 @@ self.Bind(wx.EVT_SIZE, self.OnResize) self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) self.Bind(wx.EVT_PAINT, self.OnPaint) - + # Define panel min size for parent sizer layout self.SetMinSize(wx.Size(0, 25)) - + # Add buttons to Viewer for bitmap, callback in [("force", self.OnForceButton), ("release", self.OnReleaseButton), ("delete_graph", self.OnCloseButton)]: self.Buttons.append(GraphButton(0, 0, bitmap, callback)) - + def RefreshViewer(self): """ Method that refresh the content displayed by Viewer @@ -193,24 +193,24 @@ bitmap = wx.EmptyBitmap(width, height) dc = wx.BufferedDC(wx.ClientDC(self), bitmap) dc.Clear() - + # Get Graphics Context for DC, for anti-aliased and transparent # rendering gc = wx.GCDC(dc) - + gc.BeginDrawing() - + # Get first item item = self.ItemsDict.values()[0] - + # Get item variable path masked according Debug Variable Panel mask item_path = item.GetVariable( self.ParentWindow.GetVariableNameMask()) - + # Draw item variable path at Viewer left side w, h = gc.GetTextExtent(item_path) gc.DrawText(item_path, 20, (height - h) / 2) - + # Update 'Release' button state and text color according to item forced # flag value item_forced = item.IsForced() @@ -218,17 +218,17 @@ self.RefreshButtonsPosition() if item_forced: gc.SetTextForeground(wx.BLUE) - + # Draw item current value at right side of Viewer item_value = item.GetValue() w, h = gc.GetTextExtent(item_value) gc.DrawText(item_value, width - 40 - w, (height - h) / 2) - + # Draw other Viewer common elements self.DrawCommonElements(gc) - + gc.EndDrawing() - + def OnLeftDown(self, event): """ Function called when mouse left button is pressed @@ -236,15 +236,15 @@ """ # Get first item item = self.ItemsDict.values()[0] - + # Calculate item path bounding box width, height = self.GetSize() item_path = item.GetVariable( self.ParentWindow.GetVariableNameMask()) w, h = self.GetTextExtent(item_path) - + # Test if mouse has been pressed in this bounding box. In that case - # start a move drag'n drop of item variable + # start a move drag'n drop of item variable x, y = event.GetPosition() item_path_bbox = wx.Rect(20, (height - h) / 2, w, h) if item_path_bbox.InsideXY(x, y): @@ -253,11 +253,11 @@ dragSource = wx.DropSource(self) dragSource.SetData(data) dragSource.DoDragDrop() - + # In other case handle event normally else: event.Skip() - + def OnLeftUp(self, event): """ Function called when mouse left button is released @@ -267,7 +267,7 @@ x, y = event.GetPosition() wx.CallAfter(self.HandleButton, x, y) event.Skip() - + def OnLeftDClick(self, event): """ Function called when mouse left button is double clicked @@ -276,7 +276,7 @@ # Only numeric variables can be toggled to graph canvas if self.ItemsDict.values()[0].IsNumVariable(): self.ParentWindow.ToggleViewerType(self) - + def OnPaint(self, event): """ Function called when redrawing Viewer content is needed diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/DebugVariableViewer.py --- a/controls/DebugVariablePanel/DebugVariableViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/DebugVariableViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -56,7 +56,7 @@ """ class DebugVariableViewer: - + def __init__(self, window, items=[]): """ Constructor @@ -67,26 +67,26 @@ self.ItemsDict = OrderedDict([(item.GetVariable(), item) for item in items]) self.Items = self.ItemsDict.viewvalues() - + # Variable storing current highlight displayed in Viewer self.Highlight = HIGHLIGHT_NONE # List of buttons self.Buttons = [] - + def __del__(self): """ Destructor """ # Remove reference to Debug Variable Panel self.ParentWindow = None - + def GetIndex(self): """ Return position of Viewer in Debug Variable Panel @return: Position of Viewer """ return self.ParentWindow.GetViewerIndex(self) - + def GetItem(self, variable): """ Return item storing values of a variable @@ -94,28 +94,28 @@ @return: Item storing values of this variable """ return self.ItemsDict.get(variable, None) - + def GetItems(self): """ Return items displayed by Viewer @return: List of items displayed in Viewer """ return self.ItemsDict.values() - + def AddItem(self, item): """ Add an item to the list of items displayed by Viewer @param item: Item to add to the list """ self.ItemsDict[item.GetVariable()] = item - + def RemoveItem(self, item): """ Remove an item from the list of items displayed by Viewer @param item: Item to remove from the list """ self.ItemsDict.pop(item.GetVariable(), None) - + def ClearItems(self): """ Clear list of items displayed by Viewer @@ -123,17 +123,17 @@ # Unsubscribe every items of the list for item in self.Items: self.ParentWindow.RemoveDataConsumer(item) - + # Clear list self.ItemsDict.clear() - + def ItemsIsEmpty(self): """ Return if list of items displayed by Viewer is empty @return: True if list is empty """ return len(self.Items) == 0 - + def SubscribeAllDataConsumers(self): """ Function that unsubscribe and remove every item that store values of @@ -141,7 +141,7 @@ """ for item in self.ItemsDict.values()[:]: iec_path = item.GetVariable() - + # Check that variablepath exist in PLC if self.ParentWindow.GetDataType(iec_path) is None: # If not, unsubscribe and remove it @@ -151,30 +151,30 @@ # If it exist, resubscribe and refresh data type self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True) item.RefreshVariableType() - + def ResetItemsData(self): """ Reset data stored in every items displayed in Viewer """ for item in self.Items: item.ResetData() - + def GetItemsMinCommonTick(self): """ Return the minimum tick common to all iems displayed in Viewer @return: Minimum common tick between items """ - return reduce(max, [item.GetData()[0, 0] + return reduce(max, [item.GetData()[0, 0] for item in self.Items if len(item.GetData()) > 0], 0) - + def RefreshViewer(self): """ Method that refresh the content displayed by Viewer Need to be overridden by inherited classes """ pass - + def SetHighlight(self, highlight): """ Set Highlight type displayed in Viewer @@ -183,17 +183,17 @@ # Return immediately if highlight don't change if self.Highlight == highlight: return False - + self.Highlight = highlight return True - + def GetButtons(self): """ Return list of buttons defined in Viewer @return: List of buttons """ return self.Buttons - + def IsOverButton(self, x, y): """ Return if point is over one button of Viewer @@ -205,7 +205,7 @@ if button.HitTest(x, y): return button return None - + def HandleButton(self, x, y): """ Search for the button under point and if found execute associated @@ -217,10 +217,10 @@ button = self.IsOverButton(x, y) if button is None: return False - + button.ProcessCallback() return True - + def ShowButtons(self, show): """ Set display state of buttons in Viewer @@ -229,27 +229,27 @@ # Change display of every buttons for button in self.Buttons: button.Show(show) - + # Refresh button positions self.RefreshButtonsPosition() self.RefreshViewer() - + def RefreshButtonsPosition(self): """ Function that refresh buttons position in Viewer """ # Get Viewer size width, height = self.GetSize() - + # Buttons are align right so we calculate buttons positions in # reverse order buttons = self.Buttons[:] buttons.reverse() - + # Position offset on x coordinate x_offset = 0 for button in buttons: - # Buttons are stacked right, removing those that are not active + # Buttons are stacked right, removing those that are not active if button.IsEnabled(): # Update button position according to button width and offset # on x coordinate @@ -257,7 +257,7 @@ button.SetPosition(width - 5 - w - x_offset, 5) # Update offset on x coordinate x_offset += w + 2 - + def DrawCommonElements(self, dc, buttons=None): """ Function that draw common graphics for every Viewers @@ -268,26 +268,26 @@ """ # Get Viewer size width, height = self.GetSize() - + # Set dc styling for drop before or drop after highlight dc.SetPen(HIGHLIGHT_DROP_PEN) dc.SetBrush(HIGHLIGHT_DROP_BRUSH) - + # Draw line at upper side of Viewer if highlight is drop before if self.Highlight == HIGHLIGHT_BEFORE: dc.DrawLine(0, 1, width - 1, 1) - + # Draw line at lower side of Viewer if highlight is drop before elif self.Highlight == HIGHLIGHT_AFTER: dc.DrawLine(0, height - 1, width - 1, height - 1) - + # If no specific buttons are defined, get default buttons if buttons is None: buttons = self.Buttons # Draw buttons for button in buttons: button.Draw(dc) - + # If graph dragging is processing if self.ParentWindow.IsDragging(): destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self) @@ -295,55 +295,55 @@ if destBBox.width > 0 and destBBox.height > 0: srcPanel = self.ParentWindow.DraggingAxesPanel srcBBox = srcPanel.GetAxesBoundingBox() - + srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0) srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0) - + srcBmp = _convert_agg_to_wx_bitmap( srcPanel.get_renderer(), None) srcDC = wx.MemoryDC() srcDC.SelectObject(srcBmp) - - dc.Blit(destBBox.x, destBBox.y, - int(destBBox.width), int(destBBox.height), + + dc.Blit(destBBox.x, destBBox.y, + int(destBBox.width), int(destBBox.height), srcDC, srcX, srcY) - + def OnEnter(self, event): """ Function called when entering Viewer - @param event: wx.MouseEvent + @param event: wx.MouseEvent """ # Display buttons self.ShowButtons(True) event.Skip() - + def OnLeave(self, event): """ Function called when leaving Viewer - @param event: wx.MouseEvent + @param event: wx.MouseEvent """ # Hide buttons self.ShowButtons(False) event.Skip() - + def OnCloseButton(self): """ Function called when Close button is pressed """ wx.CallAfter(self.ParentWindow.DeleteValue, self) - + def OnForceButton(self): """ Function called when Force button is pressed """ self.ForceValue(self.ItemsDict.values()[0]) - + def OnReleaseButton(self): """ Function called when Release button is pressed """ self.ReleaseValue(self.ItemsDict.values()[0]) - + def OnMouseDragging(self, x, y): """ Function called when mouse is dragged over Viewer @@ -354,7 +354,7 @@ # Refresh highlight in Debug Variable Panel (highlight can be displayed # in another Viewer self.ParentWindow.RefreshHighlight(x + xw, y + yw) - + def RefreshHighlight(self, x, y): """ Function called by Debug Variable Panel asking Viewer to refresh @@ -364,22 +364,22 @@ """ # Get Viewer size width, height = self.GetSize() - + # Mouse is in the first half of Viewer if y < height / 2: # If Viewer is the upper one, draw drop before highlight if self.ParentWindow.IsViewerFirst(self): self.SetHighlight(HIGHLIGHT_BEFORE) - + # Else draw drop after highlight in previous Viewer else: self.SetHighlight(HIGHLIGHT_NONE) self.ParentWindow.HighlightPreviousViewer(self) - - # Mouse is in the second half of Viewer, draw drop after highlight + + # Mouse is in the second half of Viewer, draw drop after highlight else: self.SetHighlight(HIGHLIGHT_AFTER) - + def OnEraseBackground(self, event): """ Function called when Viewer background is going to be erase @@ -387,7 +387,7 @@ """ # Prevent flicker on Windows pass - + def OnResize(self, event): """ Function called when Viewer size changed @@ -397,7 +397,7 @@ self.RefreshButtonsPosition() self.ParentWindow.ForceRefresh() event.Skip() - + def ForceValue(self, item): """ Force value of item given @@ -409,13 +409,13 @@ # Return immediately if not found if iec_type is None: return - + # Open a dialog to enter varaible forced value dialog = ForceVariableDialog(self, iec_type, str(item.GetValue())) if dialog.ShowModal() == wx.ID_OK: self.ParentWindow.ForceDataValue(iec_path.upper(), dialog.GetValue()) - + def ReleaseValue(self, item): """ Release value of item given diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DebugVariablePanel/GraphButton.py --- a/controls/DebugVariablePanel/GraphButton.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DebugVariablePanel/GraphButton.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,7 +35,7 @@ """ class GraphButton(): - + def __init__(self, x, y, bitmap, callback): """ Constructor @@ -48,21 +48,21 @@ self.SetPosition(x, y) # Set button bitmap self.SetBitmap(bitmap) - + # By default button is hide and enabled self.Shown = False self.Enabled = True - + # Save reference to callback function self.Callback = callback - + def __del__(self): """ Destructor """ # Remove reference to callback function self.callback = None - + def SetBitmap(self, bitmap): """ Set bitmap to use for button @@ -70,7 +70,7 @@ """ # Get wx.Bitmap object corresponding to bitmap self.Bitmap = GetBitmap(bitmap) - + def GetSize(self): """ Return size of button @@ -78,7 +78,7 @@ """ # Button size is size of bitmap return self.Bitmap.GetSize() - + def SetPosition(self, x, y): """ Set button position @@ -86,7 +86,7 @@ @param y: Y coordinate of Button in Graphic Viewer """ self.Position = wx.Point(x, y) - + def Show(self, show=True): """ Mark if button to be displayed in Graphic Viewer @@ -94,20 +94,20 @@ (default True) """ self.Shown = show - + def Hide(self): """ Hide button from Graphic Viewer """ self.Show(False) - + def IsShown(self): """ Return if button is displayed in Graphic Viewer @return: True if button is displayed in Graphic Viewer """ return self.Shown - + def Enable(self, enable=True): """ Mark if button is active in Graphic Viewer @@ -115,44 +115,44 @@ (default True) """ self.Enabled = enable - + def Disable(self): """ Deactivate button in Graphic Viewer """ self.Enabled = False - + def IsEnabled(self): """ Return if button is active in Graphic Viewer @return: True if button is active in Graphic Viewer """ return self.Enabled - + def HitTest(self, x, y): """ Test if point is inside button @param x: X coordinate of point @param y: Y coordinate of point @return: True if button is active and displayed and point is inside - button + button """ # Return immediately if button is hidden or inactive if not (self.IsShown() and self.IsEnabled()): return False - + # Test if point is inside button w, h = self.Bitmap.GetSize() rect = wx.Rect(self.Position.x, self.Position.y, w, h) return rect.InsideXY(x, y) - + def ProcessCallback(self): """ Call callback function if defined """ if self.Callback is not None: self.Callback() - + def Draw(self, dc): """ Draw button in Graphic Viewer diff -r d51af006fa6b -r 64d8f52bc8c8 controls/DurationCellEditor.py --- a/controls/DurationCellEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/DurationCellEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -27,39 +27,39 @@ from dialogs.DurationEditorDialog import DurationEditorDialog class DurationCellControl(wx.PyControl): - + ''' Custom cell editor control with a text box and a button that launches the DurationEditorDialog. ''' def __init__(self, parent): wx.Control.__init__(self, parent) - + main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + # create location text control - self.Duration = wx.TextCtrl(self, size=wx.Size(0, -1), + self.Duration = wx.TextCtrl(self, size=wx.Size(0, -1), style=wx.TE_PROCESS_ENTER) self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar) main_sizer.AddWindow(self.Duration, flag=wx.GROW) - + # create browse button self.EditButton = wx.Button(self, label='...', size=wx.Size(30, -1)) self.Bind(wx.EVT_BUTTON, self.OnEditButtonClick, self.EditButton) main_sizer.AddWindow(self.EditButton, flag=wx.GROW) - + self.Bind(wx.EVT_SIZE, self.OnSize) - + self.SetSizer(main_sizer) - + self.Default = None - + def SetValue(self, value): self.Default = value self.Duration.SetValue(value) - + def GetValue(self): return self.Duration.GetValue() @@ -90,7 +90,7 @@ def SetInsertionPoint(self, i): self.Duration.SetInsertionPoint(i) - + def SetFocus(self): self.Duration.SetFocus() @@ -100,13 +100,13 @@ ''' def __init__(self, table, colname): wx.grid.PyGridCellEditor.__init__(self) - + self.Table = table self.Colname = colname - + def __del__(self): self.CellControl = None - + def Create(self, parent, id, evt_handler): self.CellControl = DurationCellControl(parent) self.SetControl(self.CellControl) @@ -131,8 +131,8 @@ return self.EndEditInternal(row, col, grid, oldval) else: def EndEdit(self, row, col, grid): - oldval = self.Table.GetValueByName(row, self.Colname) - return self.EndEditInternal(row, col, grid, oldval) + oldval = self.Table.GetValueByName(row, self.Colname) + return self.EndEditInternal(row, col, grid, oldval) def SetSize(self, rect): self.CellControl.SetDimensions(rect.x + 1, rect.y, diff -r d51af006fa6b -r 64d8f52bc8c8 controls/EnhancedStatusBar.py --- a/controls/EnhancedStatusBar.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/EnhancedStatusBar.py Mon Aug 14 19:13:01 2017 +0300 @@ -16,7 +16,7 @@ # # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please # Write To Me At: -# +# # # andrea.gavana@agip.it # andrea_gavan@tin.it @@ -47,7 +47,7 @@ And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_VERTICAL, ESB_ALIGN_BOTTOM And ESB_ALIGN_LEFT; -EnhancedStatusBar Is Freeware And Distributed Under The wxPython License. +EnhancedStatusBar Is Freeware And Distributed Under The wxPython License. Latest Revision: 21 September 2005, 19.57.20 GMT+2 Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2 @@ -90,17 +90,17 @@ style=wx.ST_SIZEGRIP, name="EnhancedStatusBar") """ - + wx.StatusBar.__init__(self, parent, id, style, name) - + self._items = {} self._curPos = 0 self._parent = parent - - wx.EVT_SIZE(self, self.OnSize) + + wx.EVT_SIZE(self, self.OnSize) wx.CallAfter(self.OnSize, None) - + def OnSize(self, event): """Handles The wx.EVT_SIZE Events For The StatusBar. @@ -109,15 +109,15 @@ for pos, item in self._items.items(): widget, horizontalalignment, verticalalignment = item.widget, item.horizontalalignment, item.verticalalignment - + rect = self.GetFieldRect(pos) widgetpos = widget.GetPosition() widgetsize = widget.GetSize() rect = self.GetFieldRect(pos) - + if horizontalalignment == ESB_EXACT_FIT: - + if verticalalignment == ESB_EXACT_FIT: """ 1 September 2015 Fix fit align """ widget.SetSize((rect.width-4, rect.height-4)) @@ -138,7 +138,7 @@ widget.SetPosition((rect.x-1, rect.height-widgetsize[1])) elif horizontalalignment == ESB_ALIGN_LEFT: - + xpos = rect.x - 1 if verticalalignment == ESB_EXACT_FIT: widget.SetSize((widgetsize[0], rect.height-2)) @@ -154,9 +154,9 @@ widget.SetPosition((xpos, rect.y)) elif verticalalignment == ESB_ALIGN_BOTTOM: widget.SetPosition((xpos, rect.height-widgetsize[1])) - + elif horizontalalignment == ESB_ALIGN_RIGHT: - + xpos = rect.x + rect.width - widgetsize[0] - 1 if verticalalignment == ESB_EXACT_FIT: widget.SetSize((widgetsize[0], rect.height-2)) @@ -174,7 +174,7 @@ widget.SetPosition((xpos, rect.height-widgetsize[1])) elif horizontalalignment == ESB_ALIGN_CENTER_HORIZONTAL: - + xpos = rect.x + (rect.width - widgetsize[0])/2 - 1 if verticalalignment == ESB_EXACT_FIT: widget.SetSize((widgetsize[0], rect.height)) @@ -191,11 +191,11 @@ elif verticalalignment == ESB_ALIGN_BOTTOM: widget.SetPosition((xpos, rect.height-widgetsize[1])) - + if event is not None: event.Skip() - - + + def AddWidget(self, widget, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL, verticalalignment=ESB_ALIGN_CENTER_VERTICAL, pos = -1): """Add A Widget To The EnhancedStatusBar. @@ -221,7 +221,7 @@ if pos == -1: pos = self._curPos self._curPos += 1 - + if self.GetFieldsCount() <= pos: raise "\nERROR: EnhancedStatusBar has a max of %d items, you tried to set item #%d" % (self.GetFieldsCount(), pos) @@ -236,13 +236,13 @@ raise '\nERROR: Parameter "verticalalignment" Should Be One Of '\ '"ESB_ALIGN_CENTER_VERTICAL", "ESB_ALIGN_TOP", "ESB_ALIGN_BOTTOM"' \ '"ESB_EXACT_FIT"' - + try: self.RemoveChild(self._items[pos].widget) self._items[pos].widget.Destroy() except KeyError: pass - + self._items[pos] = EnhancedStatusBarItem(widget, pos, horizontalalignment, verticalalignment) - + wx.CallAfter(self.OnSize, None) diff -r d51af006fa6b -r 64d8f52bc8c8 controls/FolderTree.py --- a/controls/FolderTree.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/FolderTree.py Mon Aug 14 19:13:01 2017 +0300 @@ -47,13 +47,13 @@ return splitpath(head) + [tail] class FolderTree(wx.Panel): - + def __init__(self, parent, folder, filter=None, editable=True): wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) - + main_sizer = wx.BoxSizer(wx.VERTICAL) - - self.Tree = wx.TreeCtrl(self, + + self.Tree = wx.TreeCtrl(self, style=wx.TR_HAS_BUTTONS| wx.TR_SINGLE| wx.SUNKEN_BORDER| @@ -69,19 +69,19 @@ self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeBeginLabelEdit, self.Tree) self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeEndLabelEdit, self.Tree) main_sizer.AddWindow(self.Tree, 1, flag=wx.GROW) - + if filter is not None: self.Filter = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChanged, self.Filter) main_sizer.AddWindow(self.Filter, flag=wx.GROW) else: self.Filter = None - + self.SetSizer(main_sizer) - + self.Folder = folder self.Editable = editable - + self.TreeImageList = wx.ImageList(16, 16) self.TreeImageDict = {} for item_type, bitmap in [(DRIVE, "tree_drive"), @@ -89,7 +89,7 @@ (FILE, "tree_file")]: self.TreeImageDict[item_type] = self.TreeImageList.Add(GetBitmap(bitmap)) self.Tree.SetImageList(self.TreeImageList) - + self.Filters = {} if self.Filter is not None: filter_parts = filter.split("|") @@ -101,11 +101,11 @@ self.Filter.Append(filter_parts[idx]) if idx == 0: self.Filter.SetStringSelection(filter_parts[idx]) - + self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()] else: self.CurrentFilter = "" - + def _GetFolderChildren(self, folderpath, recursive=True): items = [] if wx.Platform == '__WXMSW__' and folderpath == "/": @@ -127,25 +127,25 @@ else: children = 0 items.append((filename, FOLDER, children)) - elif (self.CurrentFilter == "" or + elif (self.CurrentFilter == "" or os.path.splitext(filename)[1] == self.CurrentFilter): items.append((filename, FILE, None)) if recursive: items.sort(sort_folder) return items - + def SetFilter(self, filter): self.CurrentFilter = filter - + def GetTreeCtrl(self): return self.Tree - + def RefreshTree(self): root = self.Tree.GetRootItem() if not root.IsOk(): root = self.Tree.AddRoot("") self.GenerateTreeBranch(root, self.Folder) - + def GenerateTreeBranch(self, root, folderpath): item, item_cookie = self.Tree.GetFirstChild(root) for idx, (filename, item_type, children) in enumerate(self._GetFolderChildren(folderpath)): @@ -172,18 +172,18 @@ def ExpandItem(self, item): self.GenerateTreeBranch(item, self.GetPath(item)) self.Tree.Expand(item) - + def OnTreeItemActivated(self, event): self.ExpandItem(event.GetItem()) event.Skip() - + def OnTreeLeftDown(self, event): item, flags = self.Tree.HitTest(event.GetPosition()) if flags & wx.TREE_HITTEST_ONITEMBUTTON and not self.Tree.IsExpanded(item): self.ExpandItem(item) else: event.Skip() - + def OnTreeItemExpanded(self, event): item = event.GetItem() self.GenerateTreeBranch(item, self.GetPath(item)) @@ -201,7 +201,7 @@ event.Skip() else: event.Veto() - + def OnTreeEndLabelEdit(self, event): new_name = event.GetLabel() if new_name != "": @@ -212,20 +212,20 @@ os.rename(old_filepath, new_filepath) event.Skip() else: - message = wx.MessageDialog(self, - _("File '%s' already exists!") % new_name, + message = wx.MessageDialog(self, + _("File '%s' already exists!") % new_name, _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() event.Veto() else: event.Skip() - + def OnFilterChanged(self, event): self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()] self.RefreshTree() event.Skip() - + def _SelectItem(self, root, parts): if len(parts) == 0: self.Tree.SelectItem(root) @@ -233,7 +233,7 @@ item, item_cookie = self.Tree.GetFirstChild(root) while item.IsOk(): if self.Tree.GetItemText(item) == parts[0]: - if (self.Tree.ItemHasChildren(item) and + if (self.Tree.ItemHasChildren(item) and not self.Tree.IsExpanded(item)): self.Tree.Expand(item) wx.CallAfter(self._SelectItem, item, parts[1:]) @@ -241,14 +241,14 @@ self._SelectItem(item, parts[1:]) return item, item_cookie = self.Tree.GetNextChild(root, item_cookie) - + def SetPath(self, path): if path.startswith(self.Folder): root = self.Tree.GetRootItem() if root.IsOk(): relative_path = path.replace(os.path.join(self.Folder, ""), "") self._SelectItem(root, splitpath(relative_path)) - + def GetPath(self, item=None): if item is None: item = self.Tree.GetSelection() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/LibraryPanel.py --- a/controls/LibraryPanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/LibraryPanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -42,7 +42,7 @@ """ class LibraryPanel(wx.Panel): - + def __init__(self, parent, enable_drag=False): """ Constructor @@ -51,19 +51,19 @@ be drag'n drop from LibraryPanel (default: False) """ wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) - + # Define LibraryPanel main sizer main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + # Add SearchCtrl to main sizer self.SearchCtrl = wx.SearchCtrl(self) # Add a button with a magnifying glass, essentially to show that this # control is for searching in tree self.SearchCtrl.ShowSearchButton(True) self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, self.SearchCtrl) - self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, + self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearchButtonClick, self.SearchCtrl) # Bind keyboard event on SearchCtrl text control to catch UP and DOWN # for search previous and next occurrence @@ -74,16 +74,16 @@ search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown) main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW) - + # Add Splitter window for tree and block comment to main sizer splitter_window = wx.SplitterWindow(self) splitter_window.SetSashGravity(1.0) main_sizer.AddWindow(splitter_window, flag=wx.GROW) - + # Add TreeCtrl for functions and function blocks library in splitter # window self.Tree = wx.TreeCtrl(splitter_window, - size=wx.Size(0, 0), + size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS| wx.TR_SINGLE| wx.SUNKEN_BORDER| @@ -95,35 +95,35 @@ # tree to start a drag'n drop if enable_drag: self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, self.Tree) - + # Add TextCtrl for function and function block informations - self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80), + self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80), style=wx.TE_READONLY|wx.TE_MULTILINE) - + splitter_window.SplitHorizontally(self.Tree, self.Comment, -80) - + self.SetSizer(main_sizer) - + # Reference to the project controller self.Controller = None - + # Variable storing functions and function blocks library to display self.BlockList = None - + def __del__(self): """ Destructor """ # Remove reference to project controller self.Controller = None - + def SetController(self, controller): """ Set reference to project controller @param controller: Reference to project controller """ self.Controller = controller - + def SetBlockList(self, blocklist): """ Set function and function block library to display in TreeCtrl @@ -133,15 +133,15 @@ self.BlockList = blocklist # Refresh TreeCtrl values self.RefreshTree() - + def SetFocus(self): """ Called to give focus to LibraryPanel - Override wx.Window SetFocus method + Override wx.Window SetFocus method """ # Give focus to SearchCtrl self.SearchCtrl.SetFocus() - + def ResetTree(self): """ Reset LibraryPanel values displayed in controls @@ -150,7 +150,7 @@ self.SearchCtrl.SetValue("") self.Tree.DeleteAllItems() self.Comment.SetValue("") - + def RefreshTree(self): """ Refresh LibraryPanel values displayed in controls @@ -160,13 +160,13 @@ if blocktypes is None and self.Controller is not None: # Get library from project controller if not defined blocktypes = self.Controller.GetBlockTypes() - + # Refresh TreeCtrl values if a library is defined if blocktypes is not None: # List that will contain tree items to be deleted when TreeCtrl # will be refreshed items_to_delete = [] - + # Get current selected item for selected it when values refreshed selected_item = self.Tree.GetSelection() selected_pydata = (self.Tree.GetPyData(selected_item) @@ -179,16 +179,16 @@ if selected_pydata is not None and selected_pydata["type"] == BLOCK else (None, None)) - + # Get TreeCtrl root item (hidden) root = self.Tree.GetRootItem() if not root.IsOk(): # Create root if not present root = self.Tree.AddRoot("") - + # Iterate over functions and function blocks library categories and # add a tree item to root item for each of them - + # Get first child under root item category_item, root_cookie = self.Tree.GetFirstChild(root) for category in blocktypes: @@ -196,11 +196,11 @@ # extracting translated strings for gettext to consider "name" # to be translated category_name = category["name"] - + # Tree item already exists, set item label if category_item.IsOk(): self.Tree.SetItemText(category_item, _(category_name)) - + # Tree item doesn't exist, add new one to root else: category_item = self.Tree.AppendItem(root, _(category_name)) @@ -209,24 +209,24 @@ if wx.Platform != '__WXMSW__': category_item, root_cookie = \ self.Tree.GetNextChild(root, root_cookie) - - # Set data associated to tree item (only save that item is a + + # Set data associated to tree item (only save that item is a # category) self.Tree.SetPyData(category_item, {"type" : CATEGORY}) - + # Iterate over functions and function blocks defined in library - # category add a tree item to category tree item for each of + # category add a tree item to category tree item for each of # them - + # Get first child under category tree item blocktype_item, category_cookie = \ self.Tree.GetFirstChild(category_item) for blocktype in category["list"]: - + # Tree item already exists, set item label if blocktype_item.IsOk(): self.Tree.SetItemText(blocktype_item, blocktype["name"]) - + # Tree item doesn't exist, add new one to category item else: blocktype_item = self.Tree.AppendItem( @@ -234,58 +234,58 @@ # See comment when adding category if wx.Platform != '__WXMSW__': blocktype_item, category_cookie = \ - self.Tree.GetNextChild(category_item, + self.Tree.GetNextChild(category_item, category_cookie) - + # Define data to associate to block tree item comment = blocktype["comment"] - block_data = {"type" : BLOCK, - "block_type" : blocktype["type"], - "inputs" : tuple([type + block_data = {"type" : BLOCK, + "block_type" : blocktype["type"], + "inputs" : tuple([type for name, type, modifier - in blocktype["inputs"]]), + in blocktype["inputs"]]), "extension" : (len(blocktype["inputs"]) if blocktype["extensible"] else None), - "comment": _(comment) + + "comment": _(comment) + blocktype.get("usage", "")} self.Tree.SetPyData(blocktype_item, block_data) - + # Select block tree item in tree if it corresponds to # previously selected one - if selected_infos == (blocktype["name"], + if selected_infos == (blocktype["name"], blocktype["inputs"]): self.Tree.SelectItem(blocktype_item) - + # Update TextCtrl value self.Comment.SetValue(block_data["comment"]) - + # Get next block tree item under category tree item blocktype_item, category_cookie = \ self.Tree.GetNextChild(category_item, category_cookie) - + # Add every remaining tree item under category tree item after # updating all block items to the list of items to delete while blocktype_item.IsOk(): items_to_delete.append(blocktype_item) blocktype_item, category_cookie = \ self.Tree.GetNextChild(category_item, category_cookie) - + # Get next category tree item under root item category_item, root_cookie = \ self.Tree.GetNextChild(root, root_cookie) - - # Add every remaining tree item under root item after updating all + + # Add every remaining tree item under root item after updating all # category items to the list of items to delete while category_item.IsOk(): items_to_delete.append(category_item) category_item, root_cookie = \ self.Tree.GetNextChild(root, root_cookie) - + # Remove all items in list of items to delete from TreeCtrl for item in items_to_delete: self.Tree.Delete(item) - + def GetSelectedBlock(self): """ Get selected block informations @@ -298,17 +298,17 @@ if selected_item.IsOk() and selected_item != self.Tree.GetRootItem() else None) - + # Return value is None if selected tree item is root or a category - return ({"type": self.Tree.GetItemText(selected_item), + return ({"type": self.Tree.GetItemText(selected_item), "inputs": selected_pydata["inputs"]} - if selected_pydata is not None and + if selected_pydata is not None and selected_pydata["type"] == BLOCK else None) - + def SelectTreeItem(self, name, inputs): """ - Select Tree item corresponding to block informations given + Select Tree item corresponding to block informations given @param name: Block type name @param inputs: List of block inputs type [input_type,...] """ @@ -318,7 +318,7 @@ # Select tree item found self.Tree.SelectItem(item) self.Tree.EnsureVisible(item) - + def FindTreeItem(self, item, name, inputs = None): """ Find Tree item corresponding to block informations given @@ -330,12 +330,12 @@ # Return immediately if item isn't valid if not item.IsOk(): return None - + # Get data associated to item to test item_pydata = self.Tree.GetPyData(item) if item_pydata is not None and item_pydata["type"] == BLOCK: # Only test item corresponding to block - + # Test if block inputs type are the same than those given type_inputs = item_pydata.get("inputs", None) type_extension = item_pydata.get("extension", None) @@ -351,11 +351,11 @@ True) else: same_inputs = True - + # Return item if block data corresponds to informations given if self.Tree.GetItemText(item) == name and same_inputs: return item - + # Test item children if item doesn't correspond child, child_cookie = self.Tree.GetFirstChild(item) while child.IsOk(): @@ -363,9 +363,9 @@ if result: return result child, child_cookie = self.Tree.GetNextChild(item, child_cookie) - + return None - + def SearchInTree(self, value, mode="first"): """ Search in Tree and select item that name contains string given @@ -378,13 +378,13 @@ root = self.Tree.GetRootItem() if not root.IsOk(): return False - + # Set function to navigate in Tree item sibling according to search - # mode defined + # mode defined sibling_function = (self.Tree.GetPrevSibling if mode == "previous" else self.Tree.GetNextSibling) - + # Get current selected item (for next and previous mode) item = self.Tree.GetSelection() if not item.IsOk() or mode == "first": @@ -392,29 +392,29 @@ selected = None else: selected = item - + # Navigate through tree items until one matching found or reach tree # starting or ending while item.IsOk(): - + # Get item data to get item type item_pydata = self.Tree.GetPyData(item) - + # Item is a block category if (item == root) or item_pydata["type"] == CATEGORY: - - # Get category first or last child according to search mode + + # Get category first or last child according to search mode # defined child = (self.Tree.GetLastChild(item) if mode == "previous" else self.Tree.GetFirstChild(item)[0]) - + # If category has no child, go to sibling category item = (child if child.IsOk() else sibling_function(item)) - + # Item is a block else: - + # Extract item block name name = self.Tree.GetItemText(item) # Test if block name contains string given @@ -428,17 +428,17 @@ self.Tree.SelectItem(item) self.Tree.EnsureVisible(item) return True - + # Go to next item sibling if block not found next = sibling_function(item) - + # If category has no other child, go to next category sibling item = (next if next.IsOk() else sibling_function(self.Tree.GetItemParent(item))) - + return False - + def OnSearchCtrlChanged(self, event): """ Called when SearchCtrl text control value changed @@ -447,7 +447,7 @@ # Search for block containing SearchCtrl value in 'first' mode self.SearchInTree(self.SearchCtrl.GetValue()) event.Skip() - + def OnSearchButtonClick(self, event): """ Called when SearchCtrl search button was clicked @@ -456,7 +456,7 @@ # Search for block containing SearchCtrl value in 'next' mode self.SearchInTree(self.SearchCtrl.GetValue(), "next") event.Skip() - + def OnTreeItemSelected(self, event): """ Called when tree item is selected @@ -468,13 +468,13 @@ item_pydata["comment"] if item_pydata is not None and item_pydata["type"] == BLOCK else "") - + # Call extra function defined when tree item is selected if getattr(self, "_OnTreeItemSelected", None) is not None: self._OnTreeItemSelected(event) - + event.Skip() - + def OnTreeBeginDrag(self, event): """ Called when a drag is started in tree @@ -482,19 +482,19 @@ """ selected_item = event.GetItem() item_pydata = self.Tree.GetPyData(selected_item) - + # Item dragged is a block if item_pydata is not None and item_pydata["type"] == BLOCK: # Start a drag'n drop data = wx.TextDataObject(str( - (self.Tree.GetItemText(selected_item), - item_pydata["block_type"], - "", + (self.Tree.GetItemText(selected_item), + item_pydata["block_type"], + "", item_pydata["inputs"]))) dragSource = wx.DropSource(self.Tree) dragSource.SetData(data) dragSource.DoDragDrop() - + def OnKeyDown(self, event): """ Called when key is pressed in SearchCtrl text control @@ -503,17 +503,17 @@ # Get event keycode and value in SearchCtrl keycode = event.GetKeyCode() search_value = self.SearchCtrl.GetValue() - + # Up key was pressed and SearchCtrl isn't empty, search for block in - # 'previous' mode + # 'previous' mode if keycode == wx.WXK_UP and search_value != "": self.SearchInTree(search_value, "previous") - + # Down key was pressed and SearchCtrl isn't empty, search for block in - # 'next' mode + # 'next' mode elif keycode == wx.WXK_DOWN and search_value != "": self.SearchInTree(search_value, "next") - + # Handle key normally else: event.Skip() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/LocationCellEditor.py --- a/controls/LocationCellEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/LocationCellEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -27,31 +27,31 @@ from dialogs.BrowseLocationsDialog import BrowseLocationsDialog class LocationCellControl(wx.PyControl): - + ''' Custom cell editor control with a text box and a button that launches the BrowseLocationsDialog. ''' def __init__(self, parent): wx.Control.__init__(self, parent) - + main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + # create location text control - self.Location = wx.TextCtrl(self, size=wx.Size(0, -1), + self.Location = wx.TextCtrl(self, size=wx.Size(0, -1), style=wx.TE_PROCESS_ENTER) self.Location.Bind(wx.EVT_KEY_DOWN, self.OnLocationChar) main_sizer.AddWindow(self.Location, flag=wx.GROW) - + # create browse button self.BrowseButton = wx.Button(self, label='...', size=wx.Size(30, -1)) self.BrowseButton.Bind(wx.EVT_BUTTON, self.OnBrowseButtonClick) main_sizer.AddWindow(self.BrowseButton, flag=wx.GROW) - + self.Bind(wx.EVT_SIZE, self.OnSize) - + self.SetSizer(main_sizer) self.Controller = None @@ -73,7 +73,7 @@ def SetValue(self, value): self.Default = value self.Location.SetValue(value) - + def GetValue(self): return self.Location.GetValue() @@ -88,14 +88,14 @@ else: infos = None dialog.Destroy() - + if infos is not None: location = infos["location"] # set the location if not infos["location"].startswith("%"): - dialog = wx.SingleChoiceDialog(self, - _("Select a variable class:"), _("Variable class"), - [_("Input"), _("Output"), _("Memory")], + dialog = wx.SingleChoiceDialog(self, + _("Select a variable class:"), _("Variable class"), + [_("Input"), _("Output"), _("Memory")], wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: selected = dialog.GetSelection() @@ -111,7 +111,7 @@ location = "%Q" + location else: location = "%M" + location - + self.Location.SetValue(location) self.VarType = infos["IEC_type"] @@ -129,7 +129,7 @@ def SetInsertionPoint(self, i): self.Location.SetInsertionPoint(i) - + def SetFocus(self): self.Location.SetFocus() @@ -139,14 +139,14 @@ ''' def __init__(self, table, controller): wx.grid.PyGridCellEditor.__init__(self) - + self.Table = table self.Controller = controller def __del__(self): self.CellControl = None self.Controller = None - + def Create(self, parent, id, evt_handler): self.CellControl = LocationCellControl(parent) self.SetControl(self.CellControl) @@ -169,15 +169,15 @@ self.Table.SetValueByName(row, 'Type', self.CellControl.GetVarType()) self.CellControl.Disable() return changed - + if wx.VERSION >= (3, 0, 0): def EndEdit(self, row, col, grid, oldval): return self.EndEditInternal(row, col, grid, oldval) else: def EndEdit(self, row, col, grid): - old_loc = self.Table.GetValueByName(row, 'Location') + old_loc = self.Table.GetValueByName(row, 'Location') return self.EndEditInternal(row, col, grid, old_loc) - + def SetSize(self, rect): self.CellControl.SetDimensions(rect.x + 1, rect.y, rect.width, rect.height, @@ -185,4 +185,3 @@ def Clone(self): return LocationCellEditor(self.Table, self.Controller) - diff -r d51af006fa6b -r 64d8f52bc8c8 controls/PouInstanceVariablesPanel.py --- a/controls/PouInstanceVariablesPanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/PouInstanceVariablesPanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -59,14 +59,14 @@ w, h = self.GetClientSize() total_h = self.GetLineHeight(item) r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0]) - + bbox_width = (r_image_w + 4) * len(rightimages) + 4 bbox_height = r_image_h + 8 bbox_x = w - bbox_width bbox_y = item.GetY() + ((total_h > r_image_h) and [(total_h-r_image_h)/2] or [0])[0] - + return wx.Rect(bbox_x, bbox_y, bbox_width, bbox_height) - + return None def IsOverItemRightImage(self, item, point): @@ -75,30 +75,30 @@ point = self.CalcUnscrolledPosition(point) r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0]) images_bbx = self.GetItemRightImagesBBox(item) - + rect = wx.Rect(images_bbx.x + 4, images_bbx.y + 4, r_image_w, r_image_h) for r_image in rightimages: if rect.Inside(point): return r_image rect.x += r_image_w + 4 - + return None - + def PaintItem(self, item, dc, level, align): CT.CustomTreeCtrl.PaintItem(self, item, dc, level, align) - + rightimages = item.GetRightImages() if len(rightimages) > 0: images_bbx = self.GetItemRightImagesBBox(item) r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0]) - + dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(wx.TRANSPARENT_PEN) - + bg_width = (r_image_w + 4) * len(rightimages) + 4 bg_height = r_image_h + 8 - dc.DrawRectangle(images_bbx.x, images_bbx.y, + dc.DrawRectangle(images_bbx.x, images_bbx.y, images_bbx.width, images_bbx.height) x_pos = images_bbx.x + 4 for r_image in rightimages: @@ -106,7 +106,7 @@ r_image, dc, x_pos, images_bbx.y + 4, wx.IMAGELIST_DRAW_TRANSPARENT) x_pos += r_image_w + 4 - + _ButtonCallbacks = namedtuple("ButtonCallbacks", ["leftdown", "dclick"]) from PLCControler import ITEMS_VARIABLE, ITEM_CONFIGURATION, ITEM_RESOURCE, ITEM_POU, ITEM_TRANSITION, ITEM_ACTION @@ -115,26 +115,26 @@ class PouInstanceVariablesPanel(wx.Panel): def __init__(self, parent, window, controller, debug): - wx.Panel.__init__(self, name='PouInstanceTreePanel', - parent=parent, pos=wx.Point(0, 0), + wx.Panel.__init__(self, name='PouInstanceTreePanel', + parent=parent, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - + self.ParentButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("top"), size=wx.Size(28, 28), style=wx.NO_BORDER) self.ParentButton.SetToolTipString(_("Parent instance")) - self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick, + self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick, self.ParentButton) - + self.InstanceChoice = wx.ComboBox(self, size=wx.Size(0, 0), style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnInstanceChoiceChanged, self.InstanceChoice) - - self.DebugButton = wx.lib.buttons.GenBitmapButton(self, + + self.DebugButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("debug_instance"), size=wx.Size(28, 28), style=wx.NO_BORDER) self.DebugButton.SetToolTipString(_("Debug instance")) - self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick, + self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick, self.DebugButton) - + self.VariablesList = CustomTreeCtrlWithRightImage(self, style=wx.SUNKEN_BORDER, agwStyle=CT.TR_NO_BUTTONS| @@ -150,54 +150,54 @@ self.OnVariablesListItemActivated) self.VariablesList.Bind(wx.EVT_LEFT_DOWN, self.OnVariablesListLeftDown) self.VariablesList.Bind(wx.EVT_KEY_DOWN, self.OnVariablesListKeyDown) - + self.TreeRightImageList = wx.ImageList(24, 24) self.EditImage = self.TreeRightImageList.Add(GetBitmap("edit")) self.DebugInstanceImage = self.TreeRightImageList.Add(GetBitmap("debug_instance")) self.VariablesList.SetRightImageList(self.TreeRightImageList) - + self.ButtonCallBacks = { self.EditImage: _ButtonCallbacks( self.EditButtonCallback, None), self.DebugInstanceImage: _ButtonCallbacks( self.DebugButtonCallback, self.DebugButtonDClickCallback)} - + buttons_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0) buttons_sizer.AddWindow(self.ParentButton) buttons_sizer.AddWindow(self.InstanceChoice, flag=wx.GROW) buttons_sizer.AddWindow(self.DebugButton) buttons_sizer.AddGrowableCol(1) buttons_sizer.AddGrowableRow(0) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) main_sizer.AddSizer(buttons_sizer, flag=wx.GROW) main_sizer.AddWindow(self.VariablesList, flag=wx.GROW) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + self.SetSizer(main_sizer) - + self.ParentWindow = window self.Controller = controller self.Debug = debug if not self.Debug: self.DebugButton.Hide() - + self.PouTagName = None self.PouInfos = None self.PouInstance = None - + def __del__(self): self.Controller = None - + def SetTreeImageList(self, tree_image_list): self.VariablesList.SetImageList(tree_image_list) - + def SetController(self, controller): self.Controller = controller - + self.RefreshView() - + def SetPouType(self, tagname, pou_instance=None): if self.Controller is not None: if tagname == "Project": @@ -206,7 +206,7 @@ tagname = self.Controller.ComputeConfigurationName(config_name) if pou_instance is not None: self.PouInstance = pou_instance - + if self.PouTagName != tagname: self.PouTagName = tagname self.RefreshView() @@ -214,20 +214,20 @@ self.RefreshInstanceChoice() else: self.RefreshView() - + def ResetView(self): self.Controller = None - + self.PouTagName = None self.PouInfos = None self.PouInstance = None - + self.RefreshView() - + def RefreshView(self): self.Freeze() self.VariablesList.DeleteAllItems() - + if self.Controller is not None and self.PouTagName is not None: if self.PouTagName.split('::')[0] in ['A', 'T']: self.PouInfos = self.Controller.GetPouVariables('P::%s' % self.PouTagName.split('::')[1], self.Debug) @@ -244,24 +244,24 @@ text = "%s (%s)" % (var_infos.name, var_infos.type) else: text = var_infos.name - + right_images = [] if var_infos.edit: right_images.append(self.EditImage) - + if var_infos.debug and self.Debug: right_images.append(self.DebugInstanceImage) - + item = self.VariablesList.AppendItem(root, text) item.SetRightImages(right_images) self.VariablesList.SetItemImage(item, self.ParentWindow.GetTreeImage(var_infos.var_class)) self.VariablesList.SetPyData(item, var_infos) - + self.RefreshInstanceChoice() self.RefreshButtons() - + self.Thaw() - + def RefreshInstanceChoice(self): self.InstanceChoice.Clear() self.InstanceChoice.SetValue("") @@ -279,12 +279,12 @@ else: self.PouInstance = None self.InstanceChoice.SetValue(_("Select an instance")) - + def RefreshButtons(self): enabled = self.InstanceChoice.GetSelection() != -1 self.ParentButton.Enable(enabled and self.PouInfos.var_class != ITEM_CONFIGURATION) self.DebugButton.Enable(enabled and self.PouInfos.debug and self.Debug) - + root = self.VariablesList.GetRootItem() if root is not None and root.IsOk(): item, item_cookie = self.VariablesList.GetFirstChild(root) @@ -295,12 +295,12 @@ if child.GetName() != "edit": child.Enable(enabled) item, item_cookie = self.VariablesList.GetNextChild(root, item_cookie) - + def EditButtonCallback(self, infos): var_class = infos.var_class if var_class == ITEM_RESOURCE: tagname = self.Controller.ComputeConfigurationResourceName( - self.InstanceChoice.GetStringSelection(), + self.InstanceChoice.GetStringSelection(), infos.name) elif var_class == ITEM_TRANSITION: tagname = self.Controller.ComputePouTransitionName( @@ -314,7 +314,7 @@ var_class = ITEM_POU tagname = self.Controller.ComputePouName(infos.type) self.ParentWindow.EditProjectElement(var_class, tagname) - + def DebugButtonCallback(self, infos): if self.InstanceChoice.GetSelection() != -1: var_class = infos.var_class @@ -344,16 +344,16 @@ var_class, var_path, self.Controller.ComputePouName(infos.type)) - + def DebugButtonDClickCallback(self, infos): if self.InstanceChoice.GetSelection() != -1: if infos.var_class in ITEMS_VARIABLE: self.ParentWindow.AddDebugVariable( - "%s.%s" % (self.InstanceChoice.GetStringSelection(), - infos.name), + "%s.%s" % (self.InstanceChoice.GetStringSelection(), + infos.name), force=True, graph=True) - + def ShowInstanceChoicePopup(self): self.InstanceChoice.SetFocusFromKbd() size = self.InstanceChoice.GetSize() @@ -364,7 +364,7 @@ #event = wx.KeyEvent(wx.EVT_KEY_DOWN._getEvtType()) #event.m_keyCode = wx.WXK_SPACE self.InstanceChoice.GetEventHandler().ProcessEvent(event) - + def OnParentButtonClick(self, event): if self.InstanceChoice.GetSelection() != -1: parent_path = self.InstanceChoice.GetStringSelection().rsplit(".", 1)[0] @@ -373,11 +373,11 @@ wx.CallAfter(self.SetPouType, tagname, parent_path) wx.CallAfter(self.ParentWindow.SelectProjectTreeItem, tagname) event.Skip() - + def OnInstanceChoiceChanged(self, event): self.RefreshButtons() event.Skip() - + def OnDebugButtonClick(self, event): if self.InstanceChoice.GetSelection() != -1: self.ParentWindow.OpenDebugViewer( @@ -385,26 +385,26 @@ self.InstanceChoice.GetStringSelection(), self.PouTagName) event.Skip() - + def OnVariablesListItemActivated(self, event): selected_item = event.GetItem() if selected_item is not None and selected_item.IsOk(): item_infos = self.VariablesList.GetPyData(selected_item) if item_infos is not None: - + item_button = self.VariablesList.IsOverItemRightImage( selected_item, event.GetPoint()) if item_button is not None: callback = self.ButtonCallBacks[item_button].dclick if callback is not None: callback(item_infos) - + elif item_infos.var_class not in ITEMS_VARIABLE: instance_path = self.InstanceChoice.GetStringSelection() if item_infos.var_class == ITEM_RESOURCE: if instance_path != "": tagname = self.Controller.ComputeConfigurationResourceName( - instance_path, + instance_path, item_infos.name) else: tagname = None @@ -424,7 +424,7 @@ self.SetPouType(tagname, item_path) self.ParentWindow.SelectProjectTreeItem(tagname) event.Skip() - + def OnVariablesListLeftDown(self, event): if self.InstanceChoice.GetSelection() == -1: wx.CallAfter(self.ShowInstanceChoicePopup) @@ -434,15 +434,15 @@ if item is not None: item_infos = self.VariablesList.GetPyData(item) if item_infos is not None: - + item_button = self.VariablesList.IsOverItemRightImage( item, event.GetPosition()) if item_button is not None: callback = self.ButtonCallBacks[item_button].leftdown if callback is not None: callback(item_infos) - - elif (flags & CT.TREE_HITTEST_ONITEMLABEL and + + elif (flags & CT.TREE_HITTEST_ONITEMLABEL and item_infos.var_class in ITEMS_VARIABLE): self.ParentWindow.EnsureTabVisible( self.ParentWindow.DebugVariablePanel) @@ -457,4 +457,3 @@ keycode = event.GetKeyCode() if keycode != wx.WXK_LEFT: event.Skip() - diff -r d51af006fa6b -r 64d8f52bc8c8 controls/ProjectPropertiesPanel.py --- a/controls/ProjectPropertiesPanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/ProjectPropertiesPanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -31,7 +31,7 @@ REQUIRED_PARAMS = ["projectName", "productName", "productVersion", "companyName"] -[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, +[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES ] = range(10) @@ -40,7 +40,7 @@ #------------------------------------------------------------------------------- class ProjectPropertiesPanel(wx.Notebook): - + def AddSizerParams(self, parent, sizer, params): for idx, (name, label) in enumerate(params): border = 0 @@ -48,17 +48,17 @@ border |= wx.TOP elif idx == len(params) - 1: border |= wx.BOTTOM - + st = wx.StaticText(parent, label=label) - sizer.AddWindow(st, border=10, + sizer.AddWindow(st, border=10, flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT) - + tc = wx.TextCtrl(parent, style=wx.TE_PROCESS_ENTER) setattr(self, name, tc) callback = self.GetTextCtrlChangedFunction(tc, name) self.Bind(wx.EVT_TEXT_ENTER, callback, tc) tc.Bind(wx.EVT_KILL_FOCUS, callback) - sizer.AddWindow(tc, border=10, + sizer.AddWindow(tc, border=10, flag=wx.GROW|border|wx.RIGHT) def __init__(self, parent, controller=None, window=None, enable_required=True): @@ -67,36 +67,36 @@ self.Controller = controller self.ParentWindow = window self.Values = None - + # Project Panel elements self.ProjectPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15) projectpanel_sizer.AddGrowableCol(1) self.ProjectPanel.SetSizer(projectpanel_sizer) - + self.AddSizerParams(self.ProjectPanel, projectpanel_sizer, [("projectName", _('Project Name (required):')), ("projectVersion", _('Project Version (optional):')), ("productName", _('Product Name (required):')), ("productVersion", _('Product Version (required):')), ("productRelease", _('Product Release (optional):'))]) - + self.AddPage(self.ProjectPanel, _("Project")) - + # Author Panel elements self.AuthorPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) authorpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15) authorpanel_sizer.AddGrowableCol(1) self.AuthorPanel.SetSizer(authorpanel_sizer) - + self.AddSizerParams(self.AuthorPanel, authorpanel_sizer, [("companyName", _('Company Name (required):')), ("companyURL", _('Company URL (optional):')), ("authorName", _('Author Name (optional):')), ("organization", _('Organization (optional):'))]) - + self.AddPage(self.AuthorPanel, _("Author")) # Graphics Panel elements @@ -106,47 +106,47 @@ graphicpanel_sizer.AddGrowableCol(0) graphicpanel_sizer.AddGrowableRow(3) self.GraphicsPanel.SetSizer(graphicpanel_sizer) - + pageSize_st = wx.StaticText(self.GraphicsPanel, label=_('Page Size (optional):')) - graphicpanel_sizer.AddWindow(pageSize_st, border=10, + graphicpanel_sizer.AddWindow(pageSize_st, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT|wx.RIGHT) - + pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) pageSize_sizer.AddGrowableCol(1) - graphicpanel_sizer.AddSizer(pageSize_sizer, border=10, + graphicpanel_sizer.AddSizer(pageSize_sizer, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + for name, label in [('PageWidth', _('Width:')), ('PageHeight', _('Height:'))]: st = wx.StaticText(self.GraphicsPanel, label=label) - pageSize_sizer.AddWindow(st, border=12, + pageSize_sizer.AddWindow(st, border=12, flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT) - - sp = wx.SpinCtrl(self.GraphicsPanel, + + sp = wx.SpinCtrl(self.GraphicsPanel, min=0, max=2**16, style=wx.TE_PROCESS_ENTER) setattr(self, name, sp) callback = self.GetPageSizeChangedFunction(sp, name) self.Bind(wx.EVT_TEXT_ENTER, callback, sp) sp.Bind(wx.EVT_KILL_FOCUS, callback) pageSize_sizer.AddWindow(sp, flag=wx.GROW) - + scaling_st = wx.StaticText(self.GraphicsPanel, label=_('Grid Resolution:')) - graphicpanel_sizer.AddWindow(scaling_st, border=10, + graphicpanel_sizer.AddWindow(scaling_st, border=10, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + scaling_nb = wx.Notebook(self.GraphicsPanel) - graphicpanel_sizer.AddWindow(scaling_nb, border=10, + graphicpanel_sizer.AddWindow(scaling_nb, border=10, flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.Scalings = {} for language, translation in [("FBD",_("FBD")), ("LD",_("LD")), ("SFC",_("SFC"))]: scaling_panel = wx.Panel(scaling_nb, style=wx.TAB_TRAVERSAL) scalingpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) scalingpanel_sizer.AddGrowableCol(1) scaling_panel.SetSizer(scalingpanel_sizer) - + scaling_controls = [] for idx, (name, label) in enumerate([('XScale', _('Horizontal:')), ('YScale', _('Vertical:'))]): @@ -154,67 +154,67 @@ border = wx.TOP else: border = wx.BOTTOM - + st = wx.StaticText(scaling_panel, label=label) - scalingpanel_sizer.AddWindow(st, border=10, + scalingpanel_sizer.AddWindow(st, border=10, flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT) - - sp = wx.SpinCtrl(scaling_panel, + + sp = wx.SpinCtrl(scaling_panel, min=0, max=2**16, style=wx.TE_PROCESS_ENTER) scaling_controls.append(sp) callback = self.GetScalingChangedFunction(sp, language, name) self.Bind(wx.EVT_TEXT_ENTER, callback, sp) sp.Bind(wx.EVT_KILL_FOCUS, callback) - scalingpanel_sizer.AddWindow(sp, border=10, + scalingpanel_sizer.AddWindow(sp, border=10, flag=wx.GROW|border|wx.RIGHT) - + self.Scalings[language] = scaling_controls scaling_nb.AddPage(scaling_panel, translation) - + self.AddPage(self.GraphicsPanel, _("Graphics")) # Miscellaneous Panel elements - self.MiscellaneousPanel = wx.Panel(id=-1, parent=self, + self.MiscellaneousPanel = wx.Panel(id=-1, parent=self, name='MiscellaneousPanel', pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) miscellaneouspanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15) miscellaneouspanel_sizer.AddGrowableCol(1) miscellaneouspanel_sizer.AddGrowableRow(1) self.MiscellaneousPanel.SetSizer(miscellaneouspanel_sizer) - + language_label = wx.StaticText(self.MiscellaneousPanel, label=_('Language (optional):')) - miscellaneouspanel_sizer.AddWindow(language_label, border=10, + miscellaneouspanel_sizer.AddWindow(language_label, border=10, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT) - - self.Language = wx.ComboBox(self.MiscellaneousPanel, + + self.Language = wx.ComboBox(self.MiscellaneousPanel, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language) - miscellaneouspanel_sizer.AddWindow(self.Language, border=10, + miscellaneouspanel_sizer.AddWindow(self.Language, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT) - + description_label = wx.StaticText(self.MiscellaneousPanel, label=_('Content Description (optional):')) - miscellaneouspanel_sizer.AddWindow(description_label, border=10, + miscellaneouspanel_sizer.AddWindow(description_label, border=10, flag=wx.BOTTOM|wx.LEFT) - - self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel, + + self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel, size=wx.Size(240,150), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) - self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged, + self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged, self.ContentDescription) - self.ContentDescription.Bind(wx.EVT_KILL_FOCUS, + self.ContentDescription.Bind(wx.EVT_KILL_FOCUS, self.OnContentDescriptionChanged) - miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10, + miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10, flag=wx.GROW|wx.BOTTOM|wx.RIGHT) - + self.AddPage(self.MiscellaneousPanel, _("Miscellaneous")) - + for param in REQUIRED_PARAMS: getattr(self, param).Enable(enable_required) - + languages = ["", "en-US", "fr-FR", "zh-CN", "ru-RU"] - + for language in languages: self.Language.Append(language) @@ -241,13 +241,13 @@ tc = getattr(self, item, None) if tc is not None: tc.SetValue(value) - + def GetValues(self): values = {} for param in ["projectName", "projectVersion", "productName", "productVersion", "productRelease", "companyName", - "companyURL", "authorName", + "companyURL", "authorName", "organization"]: value = getattr(self, param).GetValue() if param in REQUIRED_PARAMS or value != "": @@ -270,7 +270,7 @@ values["scaling"][language] = (self.Scalings[language][0].GetValue(), self.Scalings[language][1].GetValue()) return values - + def GetTextCtrlChangedFunction(self, textctrl, name): def TextCtrlChangedFunction(event): if self.Controller is not None and self.Values is not None: @@ -304,7 +304,7 @@ wx.CallAfter(self.RefreshView) event.Skip() return PageSizeChangedFunction - + def GetScalingChangedFunction(self, spinctrl, language, name): def ScalingChangedFunction(event): if self.Controller is not None: @@ -324,7 +324,7 @@ wx.CallAfter(self.RefreshView) event.Skip() return ScalingChangedFunction - + def OnLanguageChanged(self, event): if self.Controller is not None: if self.Values is not None: @@ -339,7 +339,7 @@ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) wx.CallAfter(self.RefreshView) event.Skip() - + def OnContentDescriptionChanged(self, event): if self.Controller is not None: if self.Values is not None: diff -r d51af006fa6b -r 64d8f52bc8c8 controls/SearchResultPanel.py --- a/controls/SearchResultPanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/SearchResultPanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -45,7 +45,7 @@ #------------------------------------------------------------------------------- [ID_SEARCHRESULTPANEL, ID_SEARCHRESULTPANELHEADERLABEL, - ID_SEARCHRESULTPANELSEARCHRESULTSTREE, ID_SEARCHRESULTPANELRESETBUTTON, + ID_SEARCHRESULTPANELSEARCHRESULTSTREE, ID_SEARCHRESULTPANELRESETBUTTON, ] = [wx.NewId() for _init_ctrls in range(4)] class SearchResultPanel(wx.Panel): @@ -60,7 +60,7 @@ def _init_coll_MainSizer_Items(self, parent): parent.AddSizer(self.HeaderSizer, 0, border=0, flag=wx.GROW) parent.AddWindow(self.SearchResultsTree, 1, border=0, flag=wx.GROW) - + def _init_coll_MainSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) @@ -68,18 +68,18 @@ def _init_coll_HeaderSizer_Items(self, parent): parent.AddWindow(self.HeaderLabel, 1, border=5, flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) parent.AddWindow(self.ResetButton, 0, border=0, flag=0) - + def _init_coll_HeaderSizer_Growables(self, parent): parent.AddGrowableCol(0) - + def _init_sizers(self): self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0) self.HeaderSizer = wx.BoxSizer(wx.HORIZONTAL) - + self._init_coll_MainSizer_Items(self.MainSizer) self._init_coll_MainSizer_Growables(self.MainSizer) self._init_coll_HeaderSizer_Items(self.HeaderSizer) - + self.SetSizer(self.MainSizer) def _init_ctrls(self, prnt): @@ -90,7 +90,7 @@ self.HeaderLabel = wx.StaticText(id=ID_SEARCHRESULTPANELHEADERLABEL, name='HeaderLabel', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0) - + search_results_tree_style = CT.TR_HAS_BUTTONS|CT.TR_NO_LINES|CT.TR_HAS_VARIABLE_ROW_HEIGHT self.SearchResultsTree = CT.CustomTreeCtrl(id=ID_SEARCHRESULTPANELSEARCHRESULTSTREE, name="SearchResultsTree", parent=self, @@ -99,23 +99,23 @@ self.SearchResultsTree.SetAGWWindowStyleFlag(search_results_tree_style) self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnSearchResultsTreeItemActivated, id=ID_SEARCHRESULTPANELSEARCHRESULTSTREE) - + self.ResetButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("reset"), size=wx.Size(28, 28), style=wx.NO_BORDER) self.ResetButton.SetToolTipString(_("Reset search result")) self.Bind(wx.EVT_BUTTON, self.OnResetButton, self.ResetButton) - + self._init_sizers() def __init__(self, parent, window): self.ParentWindow = window - + self._init_ctrls(parent) - + # Define Tree item icon list self.TreeImageList = wx.ImageList(16, 16) self.TreeImageDict = {} - + # Icons for other items for imgname, itemtype in [ #editables @@ -129,40 +129,40 @@ ("IL", "IL"), ("ST", "ST")]: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname)) - + for itemtype in ["function", "functionBlock", "program", "comment", "block", "io_variable", "connector", "contact", "coil", - "step", "transition", "jump", - "var_local", "var_input", + "step", "transition", "jump", + "var_local", "var_input", "var_inout", "var_output"]: self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(itemtype.upper())) - + # Assign icon list to TreeCtrl self.SearchResultsTree.SetImageList(self.TreeImageList) - + self.ResetSearchResults() def SetSearchResults(self, criteria, search_results): self.Criteria = criteria self.SearchResults = {} self.ElementsOrder = [] - + for infos, start, end, text in search_results: if infos[0] not in self.ElementsOrder: self.ElementsOrder.append(infos[0]) - + results = self.SearchResults.setdefault(infos[0], []) results.append((infos, start, end, text)) - + self.RefreshView() - + def ResetSearchResults(self): self.Criteria = None self.ElementsOrder = [] self.SearchResults = {} self.RefreshView() - + def RefreshView(self): self.SearchResultsTree.DeleteAllItems() if self.Criteria is None: @@ -180,19 +180,19 @@ for tagname in self.ElementsOrder: results = self.SearchResults.get(tagname, []) matches_number += len(results) - + words = tagname.split("::") - + element_type = self.ParentWindow.Controler.GetElementType(tagname) if element_type == ITEM_POU: element_type = self.ParentWindow.Controler.GetPouType(words[1]) - + element_infos = {"name": words[-1], "type": element_type, "data": tagname, "text": None, "matches": len(results)} - + children = element_infos.setdefault("children", []) for infos, start, end, text in results: if infos[1] == "name" or element_type == ITEM_DATATYPE: @@ -223,7 +223,7 @@ "children": [], } children.append(child_infos) - + if len(words) > 2: for _element_infos in search_results_tree_children: if _element_infos["name"] == words[1]: @@ -234,41 +234,41 @@ search_results_tree_children.append(element_infos) else: search_results_tree_children.append(element_infos) - + if matches_number < 2: header_format = _("'{a1}' - {a2} match in project") else: header_format = _("'{a1}' - {a2} matches in project") - + self.HeaderLabel.SetLabel(header_format.format(a1 = self.Criteria["find_pattern"], a2 = matches_number)) self.ResetButton.Enable(True) - + if matches_number > 0: root = self.SearchResultsTree.GetRootItem() if root is None: root = self.SearchResultsTree.AddRoot(search_results_tree_infos["name"]) self.GenerateSearchResultsTreeBranch(root, search_results_tree_infos) self.SearchResultsTree.Expand(root) - + def GetTextCtrlClickFunction(self, item): def OnTextCtrlClick(event): self.SearchResultsTree.SelectItem(item) event.Skip() return OnTextCtrlClick - + def GetTextCtrlDClickFunction(self, item): def OnTextCtrlDClick(event): self.ShowSearchResults(item) event.Skip() return OnTextCtrlDClick - + def GenerateSearchResultsTreeBranch(self, root, infos): to_delete = [] if infos["name"] == "body": item_name = "%d:" % infos["data"][1][0] else: item_name = infos["name"] - + self.SearchResultsTree.SetItemText(root, item_name) self.SearchResultsTree.SetPyData(root, infos["data"]) self.SearchResultsTree.SetItemBackgroundColour(root, wx.WHITE) @@ -278,7 +278,7 @@ self.SearchResultsTree.SetItemImage(root, self.TreeImageDict[self.ParentWindow.Controler.GetPouType(infos["name"])]) else: self.SearchResultsTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) - + text = None if infos["text"] is not None: text = infos["text"] @@ -291,12 +291,12 @@ text = _("(%d matches)") % infos["matches"] start_idx, end_idx = 0, len(text) style = wx.TextAttr(wx.Colour(0, 127, 174)) - + if text is not None: text_ctrl_style = wx.BORDER_NONE|wx.TE_READONLY|wx.TE_RICH2 if wx.Platform != '__WXMSW__' or len(text.splitlines()) > 1: text_ctrl_style |= wx.TE_MULTILINE - text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0), + text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0), value=text, style=text_ctrl_style) width, height = text_ctrl.GetTextExtent(text) text_ctrl.SetClientSize(wx.Size(width + 1, height)) @@ -306,7 +306,7 @@ text_ctrl.SetInsertionPoint(0) text_ctrl.SetStyle(start_idx, end_idx, style) self.SearchResultsTree.SetItemWindow(root, text_ctrl) - + if wx.VERSION >= (2, 6, 0): item, root_cookie = self.SearchResultsTree.GetFirstChild(root) else: @@ -317,7 +317,7 @@ item, root_cookie = self.SearchResultsTree.GetNextChild(root, root_cookie) self.GenerateSearchResultsTreeBranch(item, child) item, root_cookie = self.SearchResultsTree.GetNextChild(root, root_cookie) - + def ShowSearchResults(self, item): data = self.SearchResultsTree.GetPyData(item) if isinstance(data, TupleType): @@ -327,11 +327,11 @@ self.ParentWindow.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) for infos, start, end, text in search_results: self.ParentWindow.ShowSearchResult(infos, start, end) - + def OnSearchResultsTreeItemActivated(self, event): self.ShowSearchResults(event.GetItem()) event.Skip() - + def OnResetButton(self, event): self.ResetSearchResults() self.ParentWindow.ClearSearchResults() diff -r d51af006fa6b -r 64d8f52bc8c8 controls/VariablePanel.py --- a/controls/VariablePanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/controls/VariablePanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -533,7 +533,7 @@ self.ColFixedSizeFlag=[True,False, True, False, True, True, False] self.PanelWidthMin = sum(self.ColSizes) - + self.ElementType = element_type self.BodyType = None @@ -643,7 +643,7 @@ panel_width = window.Parent.ScreenRect.Width - 35 if panel_width > self.PanelWidthMin: stretch_cols_width = panel_width - stretch_cols_sum = 0 + stretch_cols_sum = 0 for col in range(len(self.ColFixedSizeFlag)): if self.ColFixedSizeFlag[col]: stretch_cols_width -= self.ColSizes[col] @@ -759,7 +759,7 @@ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() - + def OnVariablesGridCellChange(self, event): row, col = event.GetRow(), event.GetCol() colname = self.Table.GetColLabelValue(col, False) @@ -793,7 +793,7 @@ if message is not None: wx.CallAfter(self.ShowErrorMessage, message) - event.Veto() + event.Veto() else: event.Skip() diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/ActionBlockDialog.py --- a/dialogs/ActionBlockDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/ActionBlockDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -47,7 +47,7 @@ #------------------------------------------------------------------------------- class ActionTable(CustomTable): - + def GetValue(self, row, col): if row < self.GetNumberRows(): colname = self.GetColLabelValue(col, False) @@ -55,7 +55,7 @@ if colname == "Type": return _(value) return value - + def SetValue(self, row, col, value): if col < len(self.colnames): colname = self.GetColLabelValue(col, False) @@ -64,7 +64,7 @@ elif colname == "Qualifier" and not self.Parent.DurationList[value]: self.data[row].duration = "" setattr(self.data[row], colname.lower(), value) - + def _updateColAttrs(self, grid): """ wx.Grid -> update the column attributes to add the @@ -72,7 +72,7 @@ Otherwise default to the default renderer. """ - + for row in range(self.GetNumberRows()): for col in range(self.GetNumberCols()): editor = None @@ -103,11 +103,11 @@ elif colname == "Indicator": editor = wx.grid.GridCellChoiceEditor() editor.SetParameters(self.Parent.VariableList) - + grid.SetCellEditor(row, col, editor) grid.SetCellRenderer(row, col, renderer) grid.SetReadOnly(row, col, readonly) - + grid.SetCellBackgroundColour(row, col, wx.WHITE) self.ResizeRow(grid, row) @@ -116,56 +116,56 @@ #------------------------------------------------------------------------------- class ActionBlockDialog(wx.Dialog): - + def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Edit action block properties')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + top_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) top_sizer.AddGrowableCol(0) top_sizer.AddGrowableRow(0) main_sizer.AddSizer(top_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + actions_label = wx.StaticText(self, label=_('Actions:')) top_sizer.AddWindow(actions_label, flag=wx.ALIGN_BOTTOM) - + for name, bitmap, help in [ ("AddButton", "add_element", _("Add action")), ("DeleteButton", "remove_element", _("Remove action")), ("UpButton", "up", _("Move action up")), ("DownButton", "down", _("Move action down"))]: - button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) top_sizer.AddWindow(button) - + self.ActionsGrid = CustomGrid(self, size=wx.Size(-1, 250), style=wx.VSCROLL) self.ActionsGrid.DisableDragGridSize() self.ActionsGrid.EnableScrolling(False, True) - self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, + self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnActionsGridCellChange) main_sizer.AddSizer(self.ActionsGrid, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.SetSizer(main_sizer) - + self.Table = ActionTable(self, [], GetActionTableColnames()) - typelist = GetTypeList() + typelist = GetTypeList() self.TypeList = ",".join(map(_,typelist)) self.TranslateType = dict([(_(value), value) for value in typelist]) self.ColSizes = [60, 90, 130, 200, 50] self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] - + self.ActionsGrid.SetTable(self.Table) self.ActionsGrid.SetDefaultValue(_ActionInfos("N", "Action", "", "", "")) self.ActionsGrid.SetButtons({"Add": self.AddButton, @@ -173,19 +173,19 @@ "Up": self.UpButton, "Down": self.DownButton}) self.ActionsGrid.SetRowLabelSize(0) - + for col in range(self.Table.GetNumberCols()): attr = wx.grid.GridCellAttr() attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) self.ActionsGrid.SetColAttr(col, attr) self.ActionsGrid.SetColMinimalWidth(col, self.ColSizes[col]) self.ActionsGrid.AutoSizeColumn(col, False) - + self.Table.ResetView(self.ActionsGrid) self.ActionsGrid.SetFocus() self.ActionsGrid.RefreshButtons() self.Fit() - + def OnOK(self, event): self.ActionsGrid.CloseEditControl() self.EndModal(wx.ID_OK) @@ -193,14 +193,14 @@ def OnActionsGridCellChange(self, event): wx.CallAfter(self.Table.ResetView, self.ActionsGrid) event.Skip() - + def SetQualifierList(self, list): self.QualifierList = ",".join(list) self.DurationList = list def SetVariableList(self, list): self.VariableList = "," + ",".join([variable.Name for variable in list]) - + def SetActionList(self, list): self.ActionList = "," + ",".join(list) @@ -218,7 +218,7 @@ if len(actions) > 0: self.ActionsGrid.SetGridCursor(0, 0) self.ActionsGrid.RefreshButtons() - + def GetValues(self): actions = self.Table.GetData() for action in actions: diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/ArrayTypeDialog.py --- a/dialogs/ArrayTypeDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/ArrayTypeDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,56 +39,56 @@ #------------------------------------------------------------------------------- class ArrayTypeDialog(wx.Dialog): - + def __init__(self, parent, datatypes, infos): wx.Dialog.__init__(self, parent, title=_('Edit array type properties')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + top_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(top_sizer, border=20, + main_sizer.AddSizer(top_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + basetype_label = wx.StaticText(self, label=_('Base Type:')) top_sizer.AddWindow(basetype_label, 1, flag=wx.ALIGN_BOTTOM) - + self.BaseType = wx.ComboBox(self, style=wx.CB_READONLY) top_sizer.AddWindow(self.BaseType, 1, flag=wx.GROW) - - self.Dimensions = CustomEditableListBox(self, label=_("Dimensions:"), + + self.Dimensions = CustomEditableListBox(self, label=_("Dimensions:"), style=wx.gizmos.EL_ALLOW_NEW| wx.gizmos.EL_ALLOW_EDIT| wx.gizmos.EL_ALLOW_DELETE) - for func in ["_OnLabelEndEdit", - "_OnAddButton", - "_OnDelButton", - "_OnUpButton", + for func in ["_OnLabelEndEdit", + "_OnAddButton", + "_OnDelButton", + "_OnUpButton", "_OnDownButton"]: setattr(self.Dimensions, func, self.OnDimensionsChanged) - main_sizer.AddSizer(self.Dimensions, border=20, + main_sizer.AddSizer(self.Dimensions, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.SetSizer(main_sizer) - + for datatype in datatypes: self.BaseType.Append(datatype) - + if isinstance(infos, TupleType) and infos[0] == "array": self.BaseType.SetStringSelection(infos[1]) self.Dimensions.SetStrings(map(lambda x : "..".join(x), infos[2])) elif infos in datatypes: self.BaseType.SetStringSelection(infos) - + self.BaseType.SetFocus() self.Fit() - + def GetDimensions(self): message = None dimensions_list = [] @@ -113,14 +113,14 @@ dlg.Destroy() return None return dimensions_list - + def OnDimensionsChanged(self, event): wx.CallAfter(self.GetDimensions) event.Skip() - + def OnOK(self, event): if self.GetDimensions() is not None: self.EndModal(wx.ID_OK) - + def GetValue(self): return "array", self.BaseType.GetStringSelection(), self.GetDimensions() diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/BlockPreviewDialog.py --- a/dialogs/BlockPreviewDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/BlockPreviewDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,7 +38,7 @@ """ class BlockPreviewDialog(wx.Dialog): - + def __init__(self, parent, controller, tagname, title): """ Constructor @@ -48,50 +48,50 @@ @param title: Title of dialog frame """ wx.Dialog.__init__(self, parent, title=title) - + # Save reference to self.Controller = controller self.TagName = tagname - + # Label for preview self.PreviewLabel = wx.StaticText(self, label=_('Preview:')) - + # Create Preview panel self.Preview = wx.Panel(self, style=wx.SIMPLE_BORDER) self.Preview.SetBackgroundColour(wx.WHITE) - + # Add function to preview panel so that it answers to graphic elements # like Viewer setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE) setattr(self.Preview, "GetScaling", lambda:None) setattr(self.Preview, "GetBlockType", controller.GetBlockType) setattr(self.Preview, "IsOfType", controller.IsOfType) - + # Bind paint event on Preview panel self.Preview.Bind(wx.EVT_PAINT, self.OnPaint) - + # Add default dialog buttons sizer self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, + self.Bind(wx.EVT_BUTTON, self.OnOK, self.ButtonSizer.GetAffirmativeButton()) - + self.Element = None # Graphic element to display in preview self.MinElementSize = None # Graphic element minimal size - + # Variable containing the graphic element name when dialog is opened self.DefaultElementName = None self.Fit() - + # List of variables defined in POU {var_name: (var_class, var_type),...} self.VariableList = {} - + def __del__(self): """ Destructor """ # Remove reference to project controller self.Controller = None - + def _init_sizers(self, main_rows, main_growable_row, left_rows, left_growable_row, right_rows, right_growable_row): @@ -108,44 +108,44 @@ None if no row is growable """ # Create dialog main sizer - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=main_rows, vgap=10) self.MainSizer.AddGrowableCol(0) if main_growable_row is not None: self.MainSizer.AddGrowableRow(main_growable_row) - + # Create a sizer for dividing parameters in two columns self.ColumnSizer = wx.BoxSizer(wx.HORIZONTAL) - self.MainSizer.AddSizer(self.ColumnSizer, border=20, + self.MainSizer.AddSizer(self.ColumnSizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + # Create a sizer for left column - self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0, + self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=left_rows, vgap=5) self.LeftGridSizer.AddGrowableCol(0) if left_growable_row is not None: self.LeftGridSizer.AddGrowableRow(left_growable_row) - self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5, + self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5, flag=wx.GROW|wx.RIGHT|wx.EXPAND) - + # Create a sizer for right column - self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0, + self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=right_rows, vgap=0) self.RightGridSizer.AddGrowableCol(0) if right_growable_row is not None: self.RightGridSizer.AddGrowableRow(right_growable_row) - self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5, + self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5, flag=wx.GROW|wx.LEFT) - + self.SetSizer(self.MainSizer) - + def SetMinElementSize(self, size): """ Define minimal graphic element size @param size: Tuple containing minimal size (width, height) """ self.MinElementSize = size - + def GetMinElementSize(self): """ Get minimal graphic element size @@ -155,16 +155,16 @@ """ if self.Element is None: return None - + return self.Element.GetMinSize() - + def SetPreviewFont(self, font): """ Set font of Preview panel @param font: wx.Font object containing font style """ self.Preview.SetFont(font) - + def RefreshVariableList(self): """ Extract list of variables defined in POU @@ -175,20 +175,20 @@ for var in self.Controller.GetEditedElementInterfaceVars( self.TagName) if var.Edit} - - # Add POU name to variable list if POU is a function + + # Add POU name to variable list if POU is a function returntype = self.Controller.GetEditedElementInterfaceReturnType( self.TagName) if returntype is not None: self.VariableList[ self.Controller.GetEditedElementName(self.TagName)] = \ ("Output", returntype) - + # Add POU name if POU is a transition words = self.TagName.split("::") if words[0] == "T": self.VariableList[words[2]] = ("Output", "BOOL") - + def TestElementName(self, element_name): """ Test displayed graphic element name @@ -198,47 +198,47 @@ message_format = None # Get graphic element name in upper case uppercase_element_name = element_name.upper() - + # Test if graphic element name is a valid identifier if not TestIdentifier(element_name): message_format = _("\"%s\" is not a valid identifier!") - + # Test that graphic element name isn't a keyword elif uppercase_element_name in IEC_KEYWORDS: message_format = _("\"%s\" is a keyword. It can't be used!") - + # Test that graphic element name isn't a POU name elif uppercase_element_name in self.Controller.GetProjectPouNames(): message_format = _("\"%s\" pou already exists!") - + # Test that graphic element name isn't already used in POU by a variable # or another graphic element - elif ((self.DefaultElementName is None or - self.DefaultElementName.upper() != uppercase_element_name) and + elif ((self.DefaultElementName is None or + self.DefaultElementName.upper() != uppercase_element_name) and uppercase_element_name in self.Controller.\ GetEditedElementVariables(self.TagName)): message_format = _("\"%s\" element for this pou already exists!") - + # If an error have been identify, show error message dialog if message_format is not None: self.ShowErrorMessage(message_format % element_name) # Test failed return False - + # Test succeed return True - + def ShowErrorMessage(self, message): """ Show an error message dialog over this dialog @param message: Error message to display """ - dialog = wx.MessageDialog(self, message, - _("Error"), + dialog = wx.MessageDialog(self, message, + _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() - + def OnOK(self, event): """ Called when dialog OK button is pressed @@ -248,7 +248,7 @@ """ # Close dialog self.EndModal(wx.ID_OK) - + def RefreshPreview(self): """ Refresh preview panel of graphic element @@ -258,42 +258,42 @@ dc = wx.ClientDC(self.Preview) dc.SetFont(self.Preview.GetFont()) dc.Clear() - + # Return immediately if no graphic element defined if self.Element is None: return - + # Calculate block size according to graphic element min size due to its # parameters and graphic element min size defined min_width, min_height = self.GetMinElementSize() width = max(self.MinElementSize[0], min_width) height = max(self.MinElementSize[1], min_height) self.Element.SetSize(width, height) - + # Get element position and bounding box to center in preview posx, posy = self.Element.GetPosition() bbox = self.Element.GetBoundingBox() - + # Get Preview panel size client_size = self.Preview.GetClientSize() - + # If graphic element is too big to be displayed in preview panel, # calculate preview panel scale so that graphic element fit inside - scale = (max(float(bbox.width) / client_size.width, + scale = (max(float(bbox.width) / client_size.width, float(bbox.height) / client_size.height) * 1.1 - if bbox.width * 1.1 > client_size.width or + if bbox.width * 1.1 > client_size.width or bbox.height * 1.1 > client_size.height else 1.0) dc.SetUserScale(1.0 / scale, 1.0 / scale) - + # Center graphic element in preview panel x = int(client_size.width * scale - bbox.width) / 2 + posx - bbox.x y = int(client_size.height * scale - bbox.height) / 2 + posy - bbox.y self.Element.SetPosition(x, y) - + # Draw graphic element self.Element.Draw(dc) - + def OnPaint(self, event): """ Called when Preview panel need to be redraw @@ -301,4 +301,3 @@ """ self.RefreshPreview() event.Skip() - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/BrowseLocationsDialog.py --- a/dialogs/BrowseLocationsDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/BrowseLocationsDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -37,16 +37,16 @@ def GetDirFilterChoiceOptions(): _ = lambda x : x - return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]), - (_("Input"), [LOCATION_VAR_INPUT]), - (_("Output"), [LOCATION_VAR_OUTPUT]), + return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]), + (_("Input"), [LOCATION_VAR_INPUT]), + (_("Output"), [LOCATION_VAR_OUTPUT]), (_("Memory"), [LOCATION_VAR_MEMORY])] DIRFILTERCHOICE_OPTIONS = dict([(_(option), filter) for option, filter in GetDirFilterChoiceOptions()]) def GetTypeFilterChoiceOptions(): _ = lambda x : x - return [_("All"), - _("Type and derivated"), + return [_("All"), + _("Type and derivated"), _("Type strict")] # turn LOCATIONDATATYPES inside-out @@ -60,81 +60,81 @@ #------------------------------------------------------------------------------- class BrowseLocationsDialog(wx.Dialog): - + def __init__(self, parent, var_type, controller): wx.Dialog.__init__(self, parent, title=_('Browse Locations'), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + locations_label = wx.StaticText(self, label=_('Locations available:')) - main_sizer.AddWindow(locations_label, border=20, + main_sizer.AddWindow(locations_label, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) - - self.LocationsTree = wx.TreeCtrl(self, + + self.LocationsTree = wx.TreeCtrl(self, style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) self.LocationsTree.SetInitialSize(wx.Size(-1, 300)) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, self.LocationsTree) - main_sizer.AddWindow(self.LocationsTree, border=20, + main_sizer.AddWindow(self.LocationsTree, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) - + button_gridsizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) button_gridsizer.AddGrowableCol(1) button_gridsizer.AddGrowableCol(3) button_gridsizer.AddGrowableRow(0) - main_sizer.AddSizer(button_gridsizer, border=20, + main_sizer.AddSizer(button_gridsizer, border=20, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.GROW) - + direction_label = wx.StaticText(self, label=_('Direction:')) button_gridsizer.AddWindow(direction_label, flag=wx.ALIGN_CENTER_VERTICAL) - + self.DirFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.DirFilterChoice) button_gridsizer.AddWindow(self.DirFilterChoice, flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL) - + filter_label = wx.StaticText(self, label=_('Type:')) button_gridsizer.AddWindow(filter_label, flag=wx.ALIGN_CENTER_VERTICAL) - + self.TypeFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.TypeFilterChoice) button_gridsizer.AddWindow(self.TypeFilterChoice, flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL) - + button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) button_gridsizer.AddSizer(button_sizer, flag=wx.ALIGN_RIGHT) - + self.SetSizer(main_sizer) - + self.Controller = controller self.VarType = var_type self.BaseVarType = self.Controller.GetBaseType(self.VarType) self.VarTypeSize = LOCATION_SIZES[self.BaseVarType] self.Locations = self.Controller.GetVariableLocationTree() - + # Define Tree item icon list self.TreeImageList = wx.ImageList(16, 16) self.TreeImageDict = {} - + # Icons for items for imgname, itemtype in [ - ("CONFIGURATION", LOCATION_CONFNODE), - ("RESOURCE", LOCATION_MODULE), - ("PROGRAM", LOCATION_GROUP), - ("VAR_INPUT", LOCATION_VAR_INPUT), - ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), + ("CONFIGURATION", LOCATION_CONFNODE), + ("RESOURCE", LOCATION_MODULE), + ("PROGRAM", LOCATION_GROUP), + ("VAR_INPUT", LOCATION_VAR_INPUT), + ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: self.TreeImageDict[itemtype]=self.TreeImageList.Add(GetBitmap(imgname)) - + # Assign icon list to TreeCtrls self.LocationsTree.SetImageList(self.TreeImageList) - + # Set a options for the choice for option, filter in GetDirFilterChoiceOptions(): self.DirFilterChoice.Append(_(option)) @@ -143,34 +143,34 @@ self.TypeFilterChoice.Append(_(option)) self.TypeFilterChoice.SetStringSelection(_("All")) self.RefreshFilters() - + self.RefreshLocationsTree() self.Fit() - + def RefreshFilters(self): self.DirFilter = DIRFILTERCHOICE_OPTIONS[self.DirFilterChoice.GetStringSelection()] self.TypeFilter = self.TypeFilterChoice.GetSelection() - + def RefreshLocationsTree(self): root = self.LocationsTree.GetRootItem() if not root.IsOk(): root = self.LocationsTree.AddRoot("") self.GenerateLocationsTreeBranch(root, self.Locations) - + def FilterType(self, location_type, location_size): if self.TypeFilter == 0: return True - + if location_size != self.VarTypeSize: return False - + if self.TypeFilter == 1: return self.Controller.IsOfType(location_type, self.BaseVarType) elif self.TypeFilter == 2: return location_type == self.VarType - + return True - + def GenerateLocationsTreeBranch(self, root, locations): to_delete = [] item, root_cookie = self.LocationsTree.GetFirstChild(root) @@ -194,21 +194,21 @@ item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) for item in to_delete: self.LocationsTree.Delete(item) - + def OnLocationsTreeItemActivated(self, event): infos = self.LocationsTree.GetPyData(event.GetItem()) if infos["type"] not in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]: wx.CallAfter(self.EndModal, wx.ID_OK) event.Skip() - + def OnFilterChoice(self, event): self.RefreshFilters() self.RefreshLocationsTree() - + def GetValues(self): selected = self.LocationsTree.GetSelection() return self.LocationsTree.GetPyData(selected) - + def OnOK(self, event): selected = self.LocationsTree.GetSelection() var_infos = None diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/BrowseValuesLibraryDialog.py --- a/dialogs/BrowseValuesLibraryDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/BrowseValuesLibraryDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -29,7 +29,7 @@ class BrowseValuesLibraryDialog(wx.Dialog): """ Modal dialog that helps in selecting predefined XML attributes sets out of hierarchically organized list - """ + """ def __init__(self, parent, name, library, default=None): wx.Dialog.__init__(self, @@ -40,27 +40,27 @@ self.staticText1 = wx.StaticText( label=_('Choose a value for %s:') % name, name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - + self.ValuesLibrary = wx.TreeCtrl( name='ValuesLibrary', parent=self, pos=wx.Point(0, 0), size=wx.Size(400, 200), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) - + self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) - + self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) - + self.flexGridSizer1.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) self.flexGridSizer1.AddWindow(self.ValuesLibrary, 0, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) self.flexGridSizer1.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.flexGridSizer1.AddGrowableCol(0) self.flexGridSizer1.AddGrowableRow(1) - + self.SetSizer(self.flexGridSizer1) self.Fit() - + root = self.ValuesLibrary.AddRoot("") self.GenerateValuesLibraryBranch(root, library, default) @@ -85,4 +85,3 @@ message.Destroy() else: self.EndModal(wx.ID_OK) - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/ConnectionDialog.py --- a/dialogs/ConnectionDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/ConnectionDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,7 +39,7 @@ """ class ConnectionDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname, apply_button=False): """ Constructor @@ -49,49 +49,49 @@ @param apply_button: Enable button for applying connector modification to all connector having the same name in POU (default: False) """ - BlockPreviewDialog.__init__(self, parent, controller, tagname, + BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Connection Properties')) - + # Init common sizers self._init_sizers(2, 0, 7, 1, 0, None) - + # Create label for connection type type_label = wx.StaticText(self, label=_('Type:')) self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) - + # Create radio buttons for selecting connection type self.TypeRadioButtons = {} first = True for type, label in [(CONNECTOR, _('Connector')), (CONTINUATION, _('Continuation'))]: - radio_button = wx.RadioButton(self, label=label, + radio_button = wx.RadioButton(self, label=label, style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) self.TypeRadioButtons[type] = radio_button first = False - + # Create label for connection name name_label = wx.StaticText(self, label=_('Name:')) self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW) - + # Create text control for defining connection name self.ConnectionName = wx.TextCtrl(self) self.ConnectionName.SetMinSize(wx.Size(200,-1)) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.ConnectionName) self.LeftGridSizer.AddWindow(self.ConnectionName, flag=wx.GROW) - + # Add preview panel and associated label to sizers self.Preview.SetMinSize(wx.Size(-1,100)) self.LeftGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.LeftGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) self.ColumnSizer.RemoveSizer(self.RightGridSizer) - + # Add button for applying connection name modification to all connection # of POU if apply_button: @@ -105,10 +105,10 @@ controller.GenerateNewName( tagname, None, "Connection%d", 0)) self.Fit() - + # Connector radio button is default control having keyboard focus self.TypeRadioButtons[CONNECTOR].SetFocus() - + def GetConnectionType(self): """ Return type selected for connection @@ -117,7 +117,7 @@ return (CONNECTOR if self.TypeRadioButtons[CONNECTOR].GetValue() else CONTINUATION) - + def SetValues(self, values): """ Set default connection parameters @@ -125,18 +125,18 @@ """ # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is connection type if name == "type": self.TypeRadioButtons[value].SetValue(True) - + # Parameter is connection name elif name == "name": self.ConnectionName.SetValue(value) - + # Refresh preview panel self.RefreshPreview() - + def GetValues(self): """ Return connection parameters defined in dialog @@ -154,23 +154,23 @@ @return: True if connection name is valid """ message = None - + # Get connection name typed by user connection_name = self.ConnectionName.GetValue() - + # Test that a name have been defined if connection_name == "": message = _("Form isn't complete. Name must be filled!") - + # If an error have been identify, show error message dialog if message is not None: self.ShowErrorMessage(message) # Test failed return False - + # Return result of element name test return self.TestElementName(connection_name) - + def OnOK(self, event): """ Called when dialog OK button is pressed @@ -206,17 +206,16 @@ """ self.RefreshPreview() event.Skip() - + def RefreshPreview(self): """ Refresh preview panel of graphic element Override BlockPreviewDialog function """ # Set graphic element displayed, creating a FBD connection element - self.Element = FBD_Connector(self.Preview, + self.Element = FBD_Connector(self.Preview, self.GetConnectionType(), self.ConnectionName.GetValue()) - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/DiscoveryDialog.py --- a/dialogs/DiscoveryDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/DiscoveryDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,56 +38,56 @@ wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name) listmix.ListCtrlAutoWidthMixin.__init__(self) -[ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1, - ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON, - ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON, +[ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1, + ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON, + ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON, ] = [wx.NewId() for _init_ctrls in range(6)] class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin): - + def _init_coll_MainSizer_Items(self, parent): parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) - + def _init_coll_MainSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) - + def _init_coll_ButtonGridSizer_Items(self, parent): parent.AddWindow(self.RefreshButton, 0, border=0, flag=0) parent.AddWindow(self.LocalButton, 0, border=0, flag=0) parent.AddWindow(self.IpButton, 0, border=0, flag=0) parent.AddSizer(self.ButtonSizer, 0, border=0, flag=0) - + def _init_coll_ButtonGridSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableCol(1) parent.AddGrowableRow(0) - + def _init_sizers(self): self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) self.ButtonGridSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=1, vgap=0) - + self._init_coll_MainSizer_Items(self.MainSizer) self._init_coll_MainSizer_Growables(self.MainSizer) self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) - + self.SetSizer(self.MainSizer) - + def _init_ctrls(self, prnt): - wx.Dialog.__init__(self, id=ID_DISCOVERYDIALOG, + wx.Dialog.__init__(self, id=ID_DISCOVERYDIALOG, name='DiscoveryDialog', parent=prnt, style=wx.DEFAULT_DIALOG_STYLE, title=_('Service Discovery')) - + self.staticText1 = wx.StaticText(id=ID_DISCOVERYDIALOGSTATICTEXT1, label=_('Services available:'), name='staticText1', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) - + # Set up list control self.ServicesList = AutoWidthListCtrl(id=ID_DISCOVERYDIALOGSERVICESLIST, - name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), + name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.LC_REPORT|wx.LC_EDIT_LABELS|wx.LC_SORT_ASCENDING|wx.LC_SINGLE_SEL) self.ServicesList.InsertColumn(0, _('NAME')) self.ServicesList.InsertColumn(1, _('TYPE')) @@ -100,14 +100,14 @@ self.ServicesList.SetInitialSize(wx.Size(-1, 300)) self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_DISCOVERYDIALOGSERVICESLIST) self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_DISCOVERYDIALOGSERVICESLIST) - + listmix.ColumnSorterMixin.__init__(self, 4) - + self.RefreshButton = wx.Button(id=ID_DISCOVERYDIALOGREFRESHBUTTON, label=_('Refresh'), name='RefreshButton', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, id=ID_DISCOVERYDIALOGREFRESHBUTTON) - + self.LocalButton = wx.Button(id=ID_DISCOVERYDIALOGLOCALBUTTON, label=_('Local'), name='LocalButton', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) @@ -117,29 +117,29 @@ label=_('Add IP'), name='IpButton', parent=self, pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) self.Bind(wx.EVT_BUTTON, self.OnIpButton, id=ID_DISCOVERYDIALOGIPBUTTON) - + self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTER) - + self._init_sizers() self.Fit() - + def __init__(self, parent): self._init_ctrls(parent) - + self.itemDataMap = {} self.nextItemId = 0 - + self.URI = None self.Browser = None - + self.ZeroConfInstance = Zeroconf() self.RefreshList() self.LatestSelection=None - + def __del__(self): if self.Browser is not None : self.Browser.cancel() self.ZeroConfInstance.close() - + def RefreshList(self): if self.Browser is not None : self.Browser.cancel() self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self) @@ -181,18 +181,18 @@ # connect_type = self.getColumnText(idx, 1) # connect_address = self.getColumnText(idx, 2) # connect_port = self.getColumnText(idx, 3) -# +# # self.URI = "%s://%s:%s"%(connect_type, connect_address, connect_port) def SetURI(self, idx): self.LatestSelection = idx - svcname = self.getColumnText(idx, 0) + svcname = self.getColumnText(idx, 0) connect_type = self.getColumnText(idx, 1) self.URI = "%s://%s"%(connect_type, svcname + '.' + service_type) - + def GetURI(self): return self.URI - + def removeService(self, zeroconf, _type, name): wx.CallAfter(self._removeService, name) @@ -201,7 +201,7 @@ ''' called when a service with the desired type goes offline. ''' - + # loop through the list items looking for the service that went offline for idx in xrange(self.ServicesList.GetItemCount()): # this is the unique identifier assigned to the item @@ -213,7 +213,7 @@ if item_name == name: self.ServicesList.DeleteItem(idx) break - + def addService(self, zeroconf, _type, name): wx.CallAfter(self._addService, _type, name) @@ -240,7 +240,7 @@ # we assign every list item a unique id (that won't change when items # are added or removed) self.ServicesList.SetItemData(new_item, self.nextItemId) - + # the value of each column has to be stored in the itemDataMap # so that ColumnSorterMixin knows how to sort the column. @@ -249,4 +249,3 @@ self.itemDataMap[self.nextItemId] = [ svcname, typename, ip, port, name ] self.nextItemId += 1 - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/DurationEditorDialog.py --- a/dialogs/DurationEditorDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/DurationEditorDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -57,43 +57,43 @@ def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Edit Duration')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + controls_sizer = wx.FlexGridSizer(cols=len(CONTROLS), hgap=10, rows=2, vgap=10) - main_sizer.AddSizer(controls_sizer, border=20, + main_sizer.AddSizer(controls_sizer, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) - + controls = [] for i, (name, label) in enumerate(CONTROLS): controls_sizer.AddGrowableCol(i) - + st = wx.StaticText(self, label=label) txtctrl = wx.TextCtrl(self, value='0', style=wx.TE_PROCESS_ENTER) - self.Bind(wx.EVT_TEXT_ENTER, - self.GetControlValueTestFunction(txtctrl), + self.Bind(wx.EVT_TEXT_ENTER, + self.GetControlValueTestFunction(txtctrl), txtctrl) setattr(self, name, txtctrl) - + controls.append((st, txtctrl)) - + for st, txtctrl in controls: controls_sizer.AddWindow(st, flag=wx.GROW) - + for st, txtctrl in controls: controls_sizer.AddWindow(txtctrl, flag=wx.GROW) - + button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.SetSizer(main_sizer) self.Fit() self.Days.SetFocus() - + def SetDuration(self, value): result = IEC_TIME_MODEL.match(value.upper()) if result is not None: @@ -112,7 +112,7 @@ else: self.Milliseconds.SetValue("0") self.Microseconds.SetValue("0") - + def GetControlValueTestFunction(self, control): def OnValueChanged(event): try: @@ -130,29 +130,29 @@ for control, factor in [(self.Days, DAY), (self.Hours, HOUR), (self.Minutes, MINUTE), (self.Seconds, SECOND), (self.Milliseconds, MILLISECONDS), (self.Microseconds, MICROSECONDS)]: - + milliseconds += float(control.GetValue()) * factor - + not_null = False duration = "T#" for value, format in [(int(milliseconds) / DAY, "%dd"), ((int(milliseconds) % DAY) / HOUR, "%dh"), ((int(milliseconds) % HOUR) / MINUTE, "%dm"), ((int(milliseconds) % MINUTE) / SECOND, "%ds")]: - + if value > 0 or not_null: duration += format % value not_null = True - + duration += "%gms" % (milliseconds % SECOND) return duration - + def OnOK(self, event): self.OnCloseDialog() def OnCloseDialog(self): errors = [] - for control, name in [(self.Days, _("days")), (self.Hours, _("hours")), + for control, name in [(self.Days, _("days")), (self.Hours, _("hours")), (self.Minutes, _("minutes")), (self.Seconds, _("seconds")), (self.Milliseconds, _("milliseconds"))]: try: diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/FBDBlockDialog.py --- a/dialogs/FBDBlockDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/FBDBlockDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -48,7 +48,7 @@ """ class FBDBlockDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname): """ Constructor @@ -58,83 +58,83 @@ """ BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Block Properties')) - + # Init common sizers self._init_sizers(2, 0, 1, 0, 3, 2) - + # Create static box around library panel type_staticbox = wx.StaticBox(self, label=_('Type:')) left_staticboxsizer = wx.StaticBoxSizer(type_staticbox, wx.VERTICAL) self.LeftGridSizer.AddSizer(left_staticboxsizer, border=5, flag=wx.GROW) - + # Create Library panel and add it to static box self.LibraryPanel = LibraryPanel(self) self.LibraryPanel.SetInitialSize(wx.Size(-1, 400)) - + # Set function to call when selection in Library panel changed - setattr(self.LibraryPanel, "_OnTreeItemSelected", + setattr(self.LibraryPanel, "_OnTreeItemSelected", self.OnLibraryTreeItemSelected) - left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5, + left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5, flag=wx.GROW|wx.TOP) - + # Create sizer for other block parameters top_right_gridsizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=5) top_right_gridsizer.AddGrowableCol(1) self.RightGridSizer.AddSizer(top_right_gridsizer, flag=wx.GROW) - + # Create label for block name name_label = wx.StaticText(self, label=_('Name:')) - top_right_gridsizer.AddWindow(name_label, + top_right_gridsizer.AddWindow(name_label, flag=wx.ALIGN_CENTER_VERTICAL) - + # Create text control for defining block name self.BlockName = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.BlockName) top_right_gridsizer.AddWindow(self.BlockName, flag=wx.GROW) - + # Create label for extended block input number inputs_label = wx.StaticText(self, label=_('Inputs:')) - top_right_gridsizer.AddWindow(inputs_label, + top_right_gridsizer.AddWindow(inputs_label, flag=wx.ALIGN_CENTER_VERTICAL) - + # Create spin control for defining extended block input number self.Inputs = wx.SpinCtrl(self, min=2, max=20, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_SPINCTRL, self.OnInputsChanged, self.Inputs) top_right_gridsizer.AddWindow(self.Inputs, flag=wx.GROW) - + # Create label for block execution order - execution_order_label = wx.StaticText(self, + execution_order_label = wx.StaticText(self, label=_('Execution Order:')) - top_right_gridsizer.AddWindow(execution_order_label, + top_right_gridsizer.AddWindow(execution_order_label, flag=wx.ALIGN_CENTER_VERTICAL) - + # Create spin control for defining block execution order self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) - self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, + self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, self.ExecutionOrder) top_right_gridsizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) - + # Create label for block execution control - execution_control_label = wx.StaticText(self, + execution_control_label = wx.StaticText(self, label=_('Execution Control:')) - top_right_gridsizer.AddWindow(execution_control_label, + top_right_gridsizer.AddWindow(execution_control_label, flag=wx.ALIGN_CENTER_VERTICAL) - + # Create check box to enable block execution control self.ExecutionControl = wx.CheckBox(self) - self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged, + self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged, self.ExecutionControl) top_right_gridsizer.AddWindow(self.ExecutionControl, flag=wx.GROW) - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + # Dictionary containing correspondence between parameter exchanged and # control to fill with parameter value self.ParamsControl = { @@ -142,20 +142,20 @@ "executionOrder": self.ExecutionOrder, "executionControl": self.ExecutionControl } - + # Init controls value and sensibility self.BlockName.SetValue("") self.BlockName.Enable(False) self.Inputs.Enable(False) - + # Variable containing last name typed self.CurrentBlockName = None - + # Refresh Library panel values self.LibraryPanel.SetBlockList(controller.GetBlockTypes(tagname)) self.Fit() self.LibraryPanel.SetFocus() - + def SetValues(self, values): """ Set default block parameters @@ -163,38 +163,38 @@ """ # Extract block type defined in parameters blocktype = values.get("type", None) - - # Select block type in library panel + + # Select block type in library panel if blocktype is not None: - self.LibraryPanel.SelectTreeItem(blocktype, + self.LibraryPanel.SelectTreeItem(blocktype, values.get("inputs", None)) - + # Define regular expression for determine if block name is block # default name default_name_model = GetBlockTypeDefaultNameModel(blocktype) - + # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is block name if name == "name": if value != "": # Set default graphic element name for testing self.DefaultElementName = value - + # Test if block name is type default block name and save # block name if not (name have been typed by user) if default_name_model.match(value) is None: self.CurrentBlockName = value - + self.BlockName.ChangeValue(value) - + # Set value of other controls else: control = self.ParamsControl.get(name, None) if control is not None: control.SetValue(value) - + # Refresh preview panel self.RefreshPreview() @@ -211,7 +211,7 @@ name: control.GetValue() for name, control in self.ParamsControl.iteritems()}) return values - + def OnOK(self, event): """ Called when dialog OK button is pressed @@ -219,31 +219,31 @@ @param event: wx.Event from OK button """ message = None - + # Get block type selected selected = self.LibraryPanel.GetSelectedBlock() - + # Get block type name and if block is a function block block_name = self.BlockName.GetValue() name_enabled = self.BlockName.IsEnabled() - + # Test that a type has been selected for block if selected is None: message = _("Form isn't complete. Valid block type must be selected!") - + # Test, if block is a function block, that a name have been defined elif name_enabled and block_name == "": message = _("Form isn't complete. Name must be filled!") - + # Show error message if an error is detected if message is not None: self.ShowErrorMessage(message) - + # Test block name validity if necessary elif not name_enabled or self.TestElementName(block_name): # Call BlockPreviewDialog function BlockPreviewDialog.OnOK(self, event) - + def OnLibraryTreeItemSelected(self, event): """ Called when block type selected in library panel @@ -251,12 +251,12 @@ """ # Get type selected in library panel values = self.LibraryPanel.GetSelectedBlock() - + # Get block type informations - blocktype = (self.Controller.GetBlockType(values["type"], + blocktype = (self.Controller.GetBlockType(values["type"], values["inputs"]) if values is not None else None) - + # Set input number spin control according to block type informations if blocktype is not None: self.Inputs.SetValue(len(blocktype["inputs"])) @@ -264,12 +264,12 @@ else: self.Inputs.SetValue(2) self.Inputs.Enable(False) - + # Update block name with default value if block type is a function and # current block name wasn't typed by user if blocktype is not None and blocktype["type"] != "function": self.BlockName.Enable(True) - + if self.CurrentBlockName is None: # Generate new block name according to block type, taking # default element name if it was already a default name for this @@ -277,21 +277,21 @@ default_name_model = GetBlockTypeDefaultNameModel(values["type"]) block_name = ( self.DefaultElementName - if (self.DefaultElementName is not None and + if (self.DefaultElementName is not None and default_name_model.match(self.DefaultElementName)) else self.Controller.GenerateNewName( self.TagName, None, values["type"]+"%d", 0)) else: block_name = self.CurrentBlockName - + self.BlockName.ChangeValue(block_name) else: self.BlockName.Enable(False) self.BlockName.ChangeValue("") - + # Refresh preview panel self.RefreshPreview() - + def OnNameChanged(self, event): """ Called when block name value changed @@ -302,7 +302,7 @@ self.CurrentBlockName = self.BlockName.GetValue() self.RefreshPreview() event.Skip() - + def OnInputsChanged(self, event): """ Called when block inputs number changed @@ -311,7 +311,7 @@ if self.Inputs.IsEnabled(): self.RefreshPreview() event.Skip() - + def OnExecutionOrderChanged(self, event): """ Called when block execution order value changed @@ -319,7 +319,7 @@ """ self.RefreshPreview() event.Skip() - + def OnExecutionControlChanged(self, event): """ Called when block execution control value changed @@ -327,7 +327,7 @@ """ self.RefreshPreview() event.Skip() - + def RefreshPreview(self): """ Refresh preview panel of graphic element @@ -335,22 +335,22 @@ """ # Get type selected in library panel values = self.LibraryPanel.GetSelectedBlock() - + # If a block type is selected in library panel if values is not None: # Set graphic element displayed, creating a FBD block element - self.Element = FBD_Block(self.Preview, values["type"], + self.Element = FBD_Block(self.Preview, values["type"], (self.BlockName.GetValue() if self.BlockName.IsEnabled() - else ""), - extension = self.Inputs.GetValue(), - inputs = values["inputs"], - executionControl = self.ExecutionControl.GetValue(), + else ""), + extension = self.Inputs.GetValue(), + inputs = values["inputs"], + executionControl = self.ExecutionControl.GetValue(), executionOrder = self.ExecutionOrder.GetValue()) - + # Reset graphic element displayed else: - self.Element = None - + self.Element = None + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/FBDVariableDialog.py --- a/dialogs/FBDVariableDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/FBDVariableDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -62,69 +62,69 @@ """ BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Variable Properties')) - + # Init common sizers self._init_sizers(4, 2, 4, None, 3, 2) - + # Create label for variable class class_label = wx.StaticText(self, label=_('Class:')) self.LeftGridSizer.AddWindow(class_label, flag=wx.GROW) - + # Create a combo box for defining variable class self.Class = wx.ComboBox(self, style=wx.CB_READONLY) self.Bind(wx.EVT_COMBOBOX, self.OnClassChanged, self.Class) self.LeftGridSizer.AddWindow(self.Class, flag=wx.GROW) - + # Create label for variable execution order - execution_order_label = wx.StaticText(self, + execution_order_label = wx.StaticText(self, label=_('Execution Order:')) self.LeftGridSizer.AddWindow(execution_order_label, flag=wx.GROW) - + # Create spin control for defining variable execution order self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) - self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, + self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged, self.ExecutionOrder) self.LeftGridSizer.AddWindow(self.ExecutionOrder, flag=wx.GROW) - + # Create label for variable expression name_label = wx.StaticText(self, label=_('Expression:')) - self.RightGridSizer.AddWindow(name_label, border=5, + self.RightGridSizer.AddWindow(name_label, border=5, flag=wx.GROW|wx.BOTTOM) - + # Create text control for defining variable expression self.Expression = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnExpressionChanged, self.Expression) self.RightGridSizer.AddWindow(self.Expression, flag=wx.GROW) - + # Create a list box to selected variable expression in the list of # variables defined in POU self.VariableName = wx.ListBox(self, size=wx.Size(-1,120), style=wx.LB_SINGLE|wx.LB_SORT) self.Bind(wx.EVT_LISTBOX, self.OnNameChanged, self.VariableName) self.RightGridSizer.AddWindow(self.VariableName, border=4, flag=wx.GROW|wx.TOP) - + # Add preview panel and associated label to sizers self.MainSizer.AddWindow(self.PreviewLabel, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) self.MainSizer.AddWindow(self.Preview, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + # Set options that can be selected in class combo box for var_class, choice in VARIABLE_CLASSES_DICT.iteritems(): if not exclude_input or var_class != INPUT: self.Class.Append(choice) self.Class.SetSelection(0) - + # Extract list of variables defined in POU self.RefreshVariableList() - + # Refresh values in name list box self.RefreshNameList() - + self.Preview.SetInitialSize(wx.Size(-1, 60)) self.Fit() @@ -138,32 +138,32 @@ # Get variable class to select POU variable applicable var_class = VARIABLE_CLASSES_DICT_REVERSE[ self.Class.GetStringSelection()] - + # Refresh names in name list box by selecting variables in POU variables # list that can be applied to variable class self.VariableName.Clear() for name, (var_type, value_type) in self.VariableList.iteritems(): if var_type != "Input" or var_class == INPUT: self.VariableName.Append(name) - + # Get variable expression and select corresponding value in name list # box if it exists selected = self.Expression.GetValue() - if (selected != "" and + if (selected != "" and self.VariableName.FindString(selected) != wx.NOT_FOUND): self.VariableName.SetStringSelection(selected) else: self.VariableName.SetSelection(wx.NOT_FOUND) - + # Disable name list box if no name present inside self.VariableName.Enable(self.VariableName.GetCount() > 0) - + def SetValues(self, values): """ Set default variable parameters @param values: Variable parameters values """ - + # Get class parameter value var_class = values.get("class", None) if var_class is not None: @@ -171,10 +171,10 @@ self.Class.SetStringSelection(VARIABLE_CLASSES_DICT[var_class]) # Refresh names in name list box according to var class self.RefreshNameList() - + # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is variable expression if name == "expression": # Set expression text control value @@ -184,15 +184,15 @@ self.VariableName.SetStringSelection(value) else: self.VariableName.SetSelection(wx.NOT_FOUND) - + # Parameter is variable execution order elif name == "executionOrder": self.ExecutionOrder.SetValue(value) - + # Refresh preview panel self.RefreshPreview() self.Fit() - + def GetValues(self): """ Return block parameters defined in dialog @@ -215,16 +215,16 @@ @param event: wx.Event from OK button """ message = None - + # Test that an expression have been selected or typed by user value = self.Expression.GetValue() if value == "": message = _("At least a variable or an expression must be selected!") - + # Show error message if an error is detected if message is not None: self.ShowErrorMessage(message) - + else: # Call BlockPreviewDialog function BlockPreviewDialog.OnOK(self, event) @@ -236,7 +236,7 @@ """ # Refresh name list box values self.RefreshNameList() - + self.RefreshPreview() event.Skip() @@ -249,10 +249,10 @@ # list box if value selected is valid if self.VariableName.GetSelection() != wx.NOT_FOUND: self.Expression.ChangeValue(self.VariableName.GetStringSelection()) - - self.RefreshPreview() - event.Skip() - + + self.RefreshPreview() + event.Skip() + def OnExpressionChanged(self, event): """ Called when expression text control is changed by user @@ -261,10 +261,10 @@ # Select the corresponding value in name list box if it exists self.VariableName.SetSelection( self.VariableName.FindString(self.Expression.GetValue())) - - self.RefreshPreview() - event.Skip() - + + self.RefreshPreview() + event.Skip() + def OnExecutionOrderChanged(self, event): """ Called when block execution control value changed @@ -272,7 +272,7 @@ """ self.RefreshPreview() event.Skip() - + def RefreshPreview(self): """ Refresh preview panel of graphic element @@ -280,16 +280,14 @@ """ # Get expression value to put in FBD variable element name = self.Expression.GetValue() - + # Set graphic element displayed, creating a FBD variable element - self.Element = FBD_Variable(self.Preview, + self.Element = FBD_Variable(self.Preview, VARIABLE_CLASSES_DICT_REVERSE[ - self.Class.GetStringSelection()], - name, - self.VariableList.get(name, ("", ""))[1], + self.Class.GetStringSelection()], + name, + self.VariableList.get(name, ("", ""))[1], executionOrder = self.ExecutionOrder.GetValue()) - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) - - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/FindInPouDialog.py --- a/dialogs/FindInPouDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/FindInPouDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -32,80 +32,80 @@ if parent and parent.icon: self.SetIcon(parent.icon) - + def __init__(self, parent): - wx.Dialog.__init__(self, parent, title=_("Find"), + wx.Dialog.__init__(self, parent, title=_("Find"), style=wx.CAPTION|wx.CLOSE_BOX|wx.CLIP_CHILDREN|wx.RESIZE_BORDER) - + self._init_icon(parent) panel = wx.Panel(self, style=wx.TAB_TRAVERSAL) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + controls_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(controls_sizer, border=20, + main_sizer.AddSizer(controls_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + patterns_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5) patterns_sizer.AddGrowableCol(1) controls_sizer.AddSizer(patterns_sizer, border=5, flag=wx.GROW|wx.BOTTOM) - + find_label = wx.StaticText(panel, label=_("Find:")) patterns_sizer.AddWindow(find_label, flag=wx.ALIGN_CENTER_VERTICAL) - + self.FindPattern = wx.TextCtrl(panel) self.Bind(wx.EVT_TEXT, self.OnFindPatternChanged, self.FindPattern) self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey) patterns_sizer.AddWindow(self.FindPattern, flag=wx.GROW) - + params_sizer = wx.BoxSizer(wx.HORIZONTAL) controls_sizer.AddSizer(params_sizer, border=5, flag=wx.GROW|wx.BOTTOM) - + direction_staticbox = wx.StaticBox(panel, label=_("Direction")) direction_staticboxsizer = wx.StaticBoxSizer( direction_staticbox, wx.VERTICAL) - params_sizer.AddSizer(direction_staticboxsizer, 1, border=5, + params_sizer.AddSizer(direction_staticboxsizer, 1, border=5, flag=wx.GROW|wx.RIGHT) - - self.Forward = wx.RadioButton(panel, label=_("Forward"), + + self.Forward = wx.RadioButton(panel, label=_("Forward"), style=wx.RB_GROUP) - direction_staticboxsizer.AddWindow(self.Forward, border=5, + direction_staticboxsizer.AddWindow(self.Forward, border=5, flag=wx.ALL|wx.GROW) - + self.Backward = wx.RadioButton(panel, label=_("Backward")) - direction_staticboxsizer.AddWindow(self.Backward, border=5, + direction_staticboxsizer.AddWindow(self.Backward, border=5, flag=wx.ALL|wx.GROW) - + options_staticbox = wx.StaticBox(panel, label=_("Options")) options_staticboxsizer = wx.StaticBoxSizer( options_staticbox, wx.VERTICAL) params_sizer.AddSizer(options_staticboxsizer, 1, flag=wx.GROW) - + self.CaseSensitive = wx.CheckBox(panel, label=_("Case sensitive")) self.CaseSensitive.SetValue(True) - options_staticboxsizer.AddWindow(self.CaseSensitive, border=5, + options_staticboxsizer.AddWindow(self.CaseSensitive, border=5, flag=wx.ALL|wx.GROW) - + self.WrapSearch = wx.CheckBox(panel, label=_("Wrap search")) self.WrapSearch.SetValue(True) - options_staticboxsizer.AddWindow(self.WrapSearch, border=5, + options_staticboxsizer.AddWindow(self.WrapSearch, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) - + self.RegularExpressions = wx.CheckBox(panel, label=_("Regular expressions")) - options_staticboxsizer.AddWindow(self.RegularExpressions, border=5, + options_staticboxsizer.AddWindow(self.RegularExpressions, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) - + buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) - main_sizer.AddSizer(buttons_sizer, border=20, + main_sizer.AddSizer(buttons_sizer, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_RIGHT) - + self.FindButton = wx.Button(panel, label=_("Find")) self.FindButton.SetDefault() self.Bind(wx.EVT_BUTTON, self.OnFindButton, self.FindButton) buttons_sizer.AddWindow(self.FindButton, border=5, flag=wx.RIGHT) - + self.CloseButton = wx.Button(panel, label=_("Close")) self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) buttons_sizer.AddWindow(self.CloseButton) @@ -115,30 +115,30 @@ self.RegExpSyntaxErrMsg = _("Syntax error in regular expression of pattern to search!") self.StatusLabel = wx.StaticText(panel, label= self.RegExpSyntaxErrMsg) controls_sizer.AddWindow(self.StatusLabel, flag=wx.ALIGN_CENTER_VERTICAL) - + panel.SetSizer(main_sizer) main_sizer.Fit(self) # clear message after dialog size calculation self.SetStatusText("") - + self.ParentWindow = parent - + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) self.infosPrev = {} self.criteria = {} self.FindPattern.SetFocus() self.RefreshButtonsState() - + def RefreshButtonsState(self): find_pattern = self.FindPattern.GetValue() self.FindButton.Enable(find_pattern != "") - + def OnCloseFrame(self, event): self.Hide() event.Veto() - + def OnCloseButton(self, event): self.Hide() event.Skip() @@ -157,7 +157,7 @@ def SetStatusText(self, msg): self.StatusLabel.SetLabel(msg) self.Layout() - + def OnFindButton(self, event): infos = { "find_pattern": self.FindPattern.GetValue(), diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/ForceVariableDialog.py --- a/dialogs/ForceVariableDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/ForceVariableDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -34,7 +34,7 @@ "B" : ["SINT", "USINT", "BYTE", "STRING"], "W" : ["INT", "UINT", "WORD", "WSTRING"], "D" : ["DINT", "UDINT", "REAL", "DWORD"], - "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} + "L" : ["LINT", "ULINT", "LREAL", "LWORD"]} def gen_get_function(f): def get_function(v): @@ -68,7 +68,7 @@ IEC_DATETIME_MODEL = re.compile("(?:(?:DT|DATE_AND_TIME)#)?([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$") IEC_TIMEOFDAY_MODEL = re.compile("(?:(?:TOD|TIME_OF_DAY)#)?([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$") -def gettime(v): +def gettime(v): result = IEC_TIME_MODEL.match(v.upper()) if result is not None: negative, days, hours, minutes, seconds, milliseconds = result.groups() @@ -87,8 +87,8 @@ if negative is not None: microseconds = -microseconds return datetime.timedelta(microseconds=microseconds) - - else: + + else: return None def getdate(v): @@ -101,7 +101,7 @@ return None base_date = datetime.datetime(1970, 1, 1) return date - base_date - else: + else: return None def getdatetime(v): @@ -114,7 +114,7 @@ return None base_date = datetime.datetime(1970, 1, 1) return date - base_date - else: + else: return None def gettimeofday(v): @@ -159,13 +159,13 @@ class ForceVariableDialog(wx.TextEntryDialog): def __init__(self, parent, iec_type, defaultValue=""): - wx.TextEntryDialog.__init__(self, parent, message = _("Forcing Variable Value"), - caption = _("Please enter value for a \"%s\" variable:") % iec_type, defaultValue = defaultValue, + wx.TextEntryDialog.__init__(self, parent, message = _("Forcing Variable Value"), + caption = _("Please enter value for a \"%s\" variable:") % iec_type, defaultValue = defaultValue, style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition) - - self.IEC_Type = iec_type - - self.Bind(wx.EVT_BUTTON, self.OnOK, + + self.IEC_Type = iec_type + + self.Bind(wx.EVT_BUTTON, self.OnOK, self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) self.ValueTextCtrl=self.GetSizer().GetItem(1).GetWindow() if self.IEC_Type == "BOOL": diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/LDElementDialog.py --- a/dialogs/LDElementDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/LDElementDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -41,7 +41,7 @@ """ class LDElementDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname, type): """ Constructor @@ -50,24 +50,24 @@ @param tagname: Tagname of project POU edited @param type: Type of LD element ('contact or 'coil') """ - BlockPreviewDialog.__init__(self, parent, controller, tagname, + BlockPreviewDialog.__init__(self, parent, controller, tagname, title=(_("Edit Contact Values") if type == "contact" else _("Edit Coil Values"))) - + # Init common sizers - self._init_sizers(2, 0, + self._init_sizers(2, 0, (7 if type == "contact" else 9), None, 2, 1) - + # Create label for LD element modifier modifier_label = wx.StaticText(self, label=_('Modifier:')) - self.LeftGridSizer.AddWindow(modifier_label, border=5, + self.LeftGridSizer.AddWindow(modifier_label, border=5, flag=wx.GROW|wx.BOTTOM) - + # Create radio buttons for selecting LD element modifier self.ModifierRadioButtons = {} first = True - element_modifiers = ([CONTACT_NORMAL, CONTACT_REVERSE, + element_modifiers = ([CONTACT_NORMAL, CONTACT_REVERSE, CONTACT_RISING, CONTACT_FALLING] if type == "contact" else [COIL_NORMAL, COIL_REVERSE, COIL_SET, @@ -75,55 +75,55 @@ modifiers_label = [_("Normal"), _("Negated")] + \ ([_("Set"), _("Reset")] if type == "coil" else []) + \ [_("Rising Edge"), _("Falling Edge")] - + for modifier, label in zip(element_modifiers, modifiers_label): - radio_button = wx.RadioButton(self, label=label, + radio_button = wx.RadioButton(self, label=label, style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnModifierChanged, radio_button) self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) self.ModifierRadioButtons[modifier] = radio_button first = False - + # Create label for LD element variable element_variable_label = wx.StaticText(self, label=_('Variable:')) self.LeftGridSizer.AddWindow(element_variable_label, border=5, flag=wx.GROW|wx.TOP) - + # Create a combo box for defining LD element variable self.ElementVariable = wx.ComboBox(self, style=wx.CB_SORT) - self.Bind(wx.EVT_COMBOBOX, self.OnVariableChanged, + self.Bind(wx.EVT_COMBOBOX, self.OnVariableChanged, self.ElementVariable) - self.Bind(wx.EVT_TEXT, self.OnVariableChanged, - self.ElementVariable) + self.Bind(wx.EVT_TEXT, self.OnVariableChanged, + self.ElementVariable) self.LeftGridSizer.AddWindow(self.ElementVariable, border=5, flag=wx.GROW|wx.TOP) - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + # Save LD element class self.ElementClass = (LD_Contact if type == "contact" else LD_Coil) - + # Extract list of variables defined in POU self.RefreshVariableList() - + # Set values in ElementVariable for name, (var_type, value_type) in self.VariableList.iteritems(): # Only select BOOL variable and avoid input for coil if (type == "contact" or var_type != "Input") and \ value_type == "BOOL": self.ElementVariable.Append(name) - + self.Fit() # Normal radio button is default control having keyboard focus self.ModifierRadioButtons[element_modifiers[0]].SetFocus() - + def GetElementModifier(self): """ Return modifier selected for LD element @@ -143,15 +143,15 @@ """ # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is LD element variable if name == "variable": self.ElementVariable.SetValue(value) - + # Set value of other controls elif name == "modifier": self.ModifierRadioButtons[value].SetValue(True) - + # Refresh preview panel self.RefreshPreview() @@ -188,20 +188,19 @@ Override BlockPreviewDialog function """ value = self.ElementVariable.GetValue() - + # Set graphic element displayed, creating a LD element self.Element = self.ElementClass( - self.Preview, + self.Preview, self.GetElementModifier(), value) button = self.ButtonSizer.GetAffirmativeButton() button.Enable(value != "") - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) - + def OnOK(self, event): if self.ElementVariable.GetValue() != "": self.EndModal(wx.ID_OK) - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/LDPowerRailDialog.py --- a/dialogs/LDPowerRailDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/LDPowerRailDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,7 +39,7 @@ """ class LDPowerRailDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname): """ Constructor @@ -49,50 +49,50 @@ """ BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Power Rail Properties')) - + # Init common sizers self._init_sizers(2, 0, 5, None, 2, 1) - + # Create label for connection type type_label = wx.StaticText(self, label=_('Type:')) self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) - + # Create radio buttons for selecting power rail type self.TypeRadioButtons = {} first = True for type, label in [(LEFTRAIL, _('Left PowerRail')), (RIGHTRAIL, _('Right PowerRail'))]: - radio_button = wx.RadioButton(self, label=label, + radio_button = wx.RadioButton(self, label=label, style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW) self.TypeRadioButtons[type] = radio_button first = False - + # Create label for power rail pin number pin_number_label = wx.StaticText(self, label=_('Pin number:')) self.LeftGridSizer.AddWindow(pin_number_label, flag=wx.GROW) - + # Create spin control for defining power rail pin number self.PinNumber = wx.SpinCtrl(self, min=1, max=50, style=wx.SP_ARROW_KEYS) self.PinNumber.SetValue(1) self.Bind(wx.EVT_SPINCTRL, self.OnPinNumberChanged, self.PinNumber) self.LeftGridSizer.AddWindow(self.PinNumber, flag=wx.GROW) - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) self.Fit() - + # Left Power Rail radio button is default control having keyboard focus self.TypeRadioButtons[LEFTRAIL].SetFocus() - + def GetMinElementSize(self): """ Get minimal graphic element size @@ -100,7 +100,7 @@ element defined """ return self.Element.GetMinSize(True) - + def GetPowerRailType(self): """ Return type selected for power rail @@ -109,7 +109,7 @@ return (LEFTRAIL if self.TypeRadioButtons[LEFTRAIL].GetValue() else RIGHTRAIL) - + def SetValues(self, values): """ Set default power rail parameters @@ -117,11 +117,11 @@ """ # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is power rail type if name == "type": self.TypeRadioButtons[value].SetValue(True) - + # Parameter is power rail pin number elif name == "pin_number": self.PinNumber.SetValue(value) @@ -158,11 +158,11 @@ Refresh preview panel of graphic element Override BlockPreviewDialog function """ - + # Set graphic element displayed, creating a power rail element - self.Element = LD_PowerRail(self.Preview, - self.GetPowerRailType(), + self.Element = LD_PowerRail(self.Preview, + self.GetPowerRailType(), connectors = self.PinNumber.GetValue()) - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/PouActionDialog.py --- a/dialogs/PouActionDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/PouActionDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -33,48 +33,48 @@ ACTION_LANGUAGES_DICT = dict([(_(language), language) for language in GetActionLanguages()]) class PouActionDialog(wx.Dialog): - + def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Create a new action')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15) infos_sizer.AddGrowableCol(1) - main_sizer.AddSizer(infos_sizer, border=20, + main_sizer.AddSizer(infos_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + actionname_label = wx.StaticText(self, label=_('Action Name:')) - infos_sizer.AddWindow(actionname_label, border=4, + infos_sizer.AddWindow(actionname_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) - + self.ActionName = wx.TextCtrl(self, size=wx.Size(180,-1)) infos_sizer.AddWindow(self.ActionName, flag=wx.GROW) - + language_label = wx.StaticText(self, label=_('Language:')) - infos_sizer.AddWindow(language_label, border=4, + infos_sizer.AddWindow(language_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) - + self.Language = wx.ComboBox(self, style=wx.CB_READONLY) infos_sizer.AddWindow(self.Language, flag=wx.GROW) - + button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, + self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) - main_sizer.AddSizer(button_sizer, border=20, + main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.SetSizer(main_sizer) - + for option in GetActionLanguages(): self.Language.Append(_(option)) - + self.Fit() self.PouNames = [] self.PouElementNames = [] - + def OnOK(self, event): error = [] action_name = self.ActionName.GetValue() @@ -91,7 +91,7 @@ elif i == len(error) - 1: text += _(" and %s")%item else: - text += _(", %s")%item + text += _(", %s")%item message = _("Form isn't complete. %s must be filled!") % text elif not TestIdentifier(action_name): message = _("\"%s\" is not a valid identifier!") % action_name @@ -107,23 +107,22 @@ dialog.Destroy() else: self.EndModal(wx.ID_OK) - + def SetPouNames(self, pou_names): self.PouNames = [pou_name.upper() for pou_name in pou_names] - + def SetPouElementNames(self, element_names): self.PouElementNames = [element_name.upper() for element_name in element_names] - + def SetValues(self, values): for item, value in values.items(): if item == "actionName": self.ActionName.SetValue(value) elif item == "language": self.Language.SetStringSelection(_(value)) - + def GetValues(self): values = {} values["actionName"] = self.ActionName.GetValue() values["language"] = ACTION_LANGUAGES_DICT[self.Language.GetStringSelection()] return values - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/PouNameDialog.py --- a/dialogs/PouNameDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/PouNameDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,15 +30,15 @@ class PouNameDialog(wx.TextEntryDialog): - def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", + def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) - + self.PouNames = [] - - self.Bind(wx.EVT_BUTTON, self.OnOK, + + self.Bind(wx.EVT_BUTTON, self.OnOK, self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) - + def OnOK(self, event): message = None step_name = self.GetSizer().GetItem(1).GetWindow().GetValue() @@ -60,4 +60,3 @@ def SetPouNames(self, pou_names): self.PouNames = [pou_name.upper() for pou_name in pou_names] - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/PouTransitionDialog.py --- a/dialogs/PouTransitionDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/PouTransitionDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -37,46 +37,46 @@ TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()]) class PouTransitionDialog(wx.Dialog): - + def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Create a new transition')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - + infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=10) infos_sizer.AddGrowableCol(1) - main_sizer.AddSizer(infos_sizer, border=20, + main_sizer.AddSizer(infos_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + transitionname_label = wx.StaticText(self, label=_('Transition Name:')) - infos_sizer.AddWindow(transitionname_label, border=4, + infos_sizer.AddWindow(transitionname_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) self.TransitionName = wx.TextCtrl(self, size=wx.Size(180,-1)) infos_sizer.AddWindow(self.TransitionName, flag=wx.GROW) language_label = wx.StaticText(self, label=_('Language:')) - infos_sizer.AddWindow(language_label, border=4, + infos_sizer.AddWindow(language_label, border=4, flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP) - + self.Language = wx.ComboBox(self, style=wx.CB_READONLY) infos_sizer.AddWindow(self.Language, flag=wx.GROW) button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM) - + self.SetSizer(main_sizer) - + for language in GetTransitionLanguages(): self.Language.Append(_(language)) - + self.Fit() self.PouNames = [] self.PouElementNames = [] - + def OnOK(self, event): error = [] transition_name = self.TransitionName.GetValue() @@ -93,7 +93,7 @@ elif i == len(error) - 1: text += _(" and %s")%item else: - text += _(", %s")%item + text += _(", %s")%item message = _("Form isn't complete. %s must be filled!") % text elif not TestIdentifier(transition_name): message = _("\"%s\" is not a valid identifier!") % transition_name @@ -109,20 +109,20 @@ dialog.Destroy() else: self.EndModal(wx.ID_OK) - + def SetPouNames(self, pou_names): self.PouNames = [pou_name.upper() for pou_name in pou_names] - + def SetPouElementNames(self, pou_names): self.PouElementNames = [pou_name.upper() for pou_name in pou_names] - + def SetValues(self, values): for item, value in values.items(): if item == "transitionName": self.TransitionName.SetValue(value) elif item == "language": self.Language.SetSelection(_(value)) - + def GetValues(self): values = {} values["transitionName"] = self.TransitionName.GetValue() diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/ProjectDialog.py --- a/dialogs/ProjectDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/ProjectDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -28,29 +28,29 @@ from controls.ProjectPropertiesPanel import ProjectPropertiesPanel class ProjectDialog(wx.Dialog): - + def __init__(self, parent, enable_required=True): - wx.Dialog.__init__(self, parent, title=_('Project properties'), + wx.Dialog.__init__(self, parent, title=_('Project properties'), style=wx.DEFAULT_DIALOG_STYLE) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(0) - - self.ProjectProperties = ProjectPropertiesPanel(self, + + self.ProjectProperties = ProjectPropertiesPanel(self, enable_required=enable_required) main_sizer.AddWindow(self.ProjectProperties, flag=wx.GROW) - + self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) - self.Bind(wx.EVT_BUTTON, self.OnOK, + self.Bind(wx.EVT_BUTTON, self.OnOK, self.ButtonSizer.GetAffirmativeButton()) - main_sizer.AddSizer(self.ButtonSizer, border=20, + main_sizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.SetSizer(main_sizer) self.ProjectProperties.Fit() self.Fit() - + def OnOK(self, event): values = self.ProjectProperties.GetValues() error = [] @@ -69,8 +69,8 @@ text += _(" and %s")%item else: text += ", %s"%item - dialog = wx.MessageDialog(self, - _("Form isn't complete. %s must be filled!") % text, + dialog = wx.MessageDialog(self, + _("Form isn't complete. %s must be filled!") % text, _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() dialog.Destroy() @@ -79,6 +79,6 @@ def SetValues(self, values): self.ProjectProperties.SetValues(values) - + def GetValues(self): return self.ProjectProperties.GetValues() diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/SFCDivergenceDialog.py --- a/dialogs/SFCDivergenceDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/SFCDivergenceDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -40,7 +40,7 @@ """ class SFCDivergenceDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname, poss_div_types = None): """ Constructor @@ -51,14 +51,14 @@ """ BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Create a new divergence or convergence')) - + # Init common sizers self._init_sizers(2, 0, 7, None, 2, 1) - + # Create label for divergence type type_label = wx.StaticText(self, label=_('Type:')) self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) - + # Create radio buttons for selecting divergence type divergence_buttons = [ (SELECTION_DIVERGENCE, _('Selection Divergence')), @@ -75,7 +75,7 @@ first = True focusbtn = None for type, label in poss_div_btns: - radio_button = wx.RadioButton(self, label=label, + radio_button = wx.RadioButton(self, label=label, style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) @@ -85,29 +85,29 @@ first = False # Create label for number of divergence sequences - sequences_label = wx.StaticText(self, + sequences_label = wx.StaticText(self, label=_('Number of sequences:')) self.LeftGridSizer.AddWindow(sequences_label, flag=wx.GROW) - + # Create spin control for defining number of divergence sequences self.Sequences = wx.SpinCtrl(self, min=2, max=20, initial=2) self.Bind(wx.EVT_SPINCTRL, self.OnSequencesChanged, self.Sequences) self.LeftGridSizer.AddWindow(self.Sequences, flag=wx.GROW) - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + self.Fit() # Selection divergence radio button is default control having keyboard # focus self.TypeRadioButtons[focusbtn].SetFocus() - + def GetMinElementSize(self): """ Get minimal graphic element size @@ -115,7 +115,7 @@ element defined """ return self.Element.GetMinSize(True) - + def GetDivergenceType(self): """ Return type selected for SFC divergence @@ -127,7 +127,7 @@ if control.GetValue(): return type return None - + def GetValues(self): """ Set default SFC divergence parameters @@ -151,17 +151,16 @@ """ self.RefreshPreview() event.Skip() - + def RefreshPreview(self): """ Refresh preview panel of graphic element Override BlockPreviewDialog function """ # Set graphic element displayed, creating a SFC divergence - self.Element = SFC_Divergence(self.Preview, - self.GetDivergenceType(), + self.Element = SFC_Divergence(self.Preview, + self.GetDivergenceType(), self.Sequences.GetValue()) - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) - diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/SFCStepDialog.py --- a/dialogs/SFCStepDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/SFCStepDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,7 +38,7 @@ """ class SFCStepDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname, initial=False): """ Constructor @@ -47,25 +47,25 @@ @param tagname: Tagname of project POU edited @param initial: True if step is initial (default: False) """ - BlockPreviewDialog.__init__(self,parent, controller, tagname, + BlockPreviewDialog.__init__(self,parent, controller, tagname, title=_('Edit Step')) - + # Init common sizers self._init_sizers(2, 0, 6, None, 2, 1) - + # Create label for SFC step name name_label = wx.StaticText(self, label=_('Name:')) self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW) - + # Create text control for defining SFC step name self.StepName = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.StepName) self.LeftGridSizer.AddWindow(self.StepName, flag=wx.GROW) - + # Create label for SFC step connectors connectors_label = wx.StaticText(self, label=_('Connectors:')) self.LeftGridSizer.AddWindow(connectors_label, flag=wx.GROW) - + # Create check boxes for defining connectors available on SFC step self.ConnectorsCheckBox = {} for name, label in [("input", _("Input")), @@ -77,27 +77,27 @@ self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, check_box) self.LeftGridSizer.AddWindow(check_box, flag=wx.GROW) self.ConnectorsCheckBox[name] = check_box - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) - + # Save flag that indicates that step is initial self.Initial = initial - + # Set default name for step self.StepName.ChangeValue(controller.GenerateNewName( tagname, None, "Step%d", 0)) self.Fit() - + # Step name text control is default control having keyboard focus self.StepName.SetFocus() - + def SetValues(self, values): """ Set default block parameters @@ -105,20 +105,20 @@ """ # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is step name if name == "name": self.StepName.ChangeValue(value) - + # Set value of other controls else: control = self.ConnectorsCheckBox.get(name, None) if control is not None: control.SetValue(value) - + # Refresh preview panel self.RefreshPreview() - + def GetValues(self): """ Return step parameters defined in dialog @@ -130,7 +130,7 @@ for name, control in self.ConnectorsCheckBox.iteritems()}) values["width"], values["height"] = self.Element.GetSize() return values - + def OnOK(self, event): """ Called when dialog OK button is pressed @@ -138,23 +138,23 @@ @param event: wx.Event from OK button """ message = None - + # Get step name typed by user step_name = self.StepName.GetValue() - + # Test that a name have been defined if step_name == "": message = _("Form isn't complete. Name must be filled!") - + # If an error have been identify, show error message dialog if message is not None: self.ShowErrorMessage(message) - + # Test step name validity elif self.TestElementName(step_name): # Call BlockPreviewDialog function BlockPreviewDialog.OnOK(self, event) - + def OnConnectorsChanged(self, event): """ Called when a step connector value changed @@ -170,23 +170,23 @@ """ self.RefreshPreview() event.Skip() - + def RefreshPreview(self): """ Refresh preview panel of graphic element Override BlockPreviewDialog function """ # Set graphic element displayed, creating a SFC step element - self.Element = SFC_Step(self.Preview, - self.StepName.GetValue(), + self.Element = SFC_Step(self.Preview, + self.StepName.GetValue(), self.Initial) - + # Update connectors of SFC step element according to check boxes value for name, control in self.ConnectorsCheckBox.iteritems(): if control.IsChecked(): getattr(self.Element, "Add" + name.capitalize())() else: getattr(self.Element, "Remove" + name.capitalize())() - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/SFCStepNameDialog.py --- a/dialogs/SFCStepNameDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/SFCStepNameDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,17 +30,17 @@ class SFCStepNameDialog(wx.TextEntryDialog): - def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", + def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) - + self.PouNames = [] self.Variables = [] self.StepNames = [] - - self.Bind(wx.EVT_BUTTON, self.OnOK, + + self.Bind(wx.EVT_BUTTON, self.OnOK, self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton()) - + def OnOK(self, event): message = None step_name = self.GetSizer().GetItem(1).GetWindow().GetValue() diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/SFCTransitionDialog.py --- a/dialogs/SFCTransitionDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/SFCTransitionDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,7 +38,7 @@ """ class SFCTransitionDialog(BlockPreviewDialog): - + def __init__(self, parent, controller, tagname, connection=True): """ Constructor @@ -50,32 +50,32 @@ """ BlockPreviewDialog.__init__(self, parent, controller, tagname, title=_('Edit transition')) - + # Init common sizers self._init_sizers(2, 0, 8, None, 2, 1) - + # Create label for transition type type_label = wx.StaticText(self, label=_('Type:')) self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW) - + # Create combo box for selecting reference value reference = wx.ComboBox(self, style=wx.CB_READONLY) reference.Append("") for transition in controller.GetEditedElementTransitions(tagname): reference.Append(transition) self.Bind(wx.EVT_COMBOBOX, self.OnReferenceChanged, reference) - + # Create Text control for defining inline value inline = wx.TextCtrl(self) self.Bind(wx.EVT_TEXT, self.OnInlineChanged, inline) - + # Create radio buttons for selecting power rail type self.TypeRadioButtons = {} first = True for type, label, control in [('reference', _('Reference'), reference), ('inline', _('Inline'), inline), ('connection', _('Connection'), None)]: - radio_button = wx.RadioButton(self, label=label, + radio_button = wx.RadioButton(self, label=label, style=(wx.RB_GROUP if first else 0)) radio_button.SetValue(first) self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button) @@ -85,29 +85,29 @@ self.LeftGridSizer.AddWindow(control, flag=wx.GROW) self.TypeRadioButtons[type] = (radio_button, control) first = False - + # Create label for transition priority priority_label = wx.StaticText(self, label=_('Priority:')) self.LeftGridSizer.AddWindow(priority_label, flag=wx.GROW) - + # Create spin control for defining priority value self.Priority = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS) self.Bind(wx.EVT_TEXT, self.OnPriorityChanged, self.Priority) self.LeftGridSizer.AddWindow(self.Priority, flag=wx.GROW) - + # Add preview panel and associated label to sizers self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW) self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW) - + # Add buttons sizer to sizers - self.MainSizer.AddSizer(self.ButtonSizer, border=20, + self.MainSizer.AddSizer(self.ButtonSizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT) self.Fit() - + # Reference radio button is default control having keyboard focus self.TypeRadioButtons["reference"][0].SetFocus() - + def GetTransitionType(self): """ Return type selected for SFC transition and associated value @@ -124,7 +124,7 @@ else: return type, None return None, None - + def SetValues(self, values): """ Set default SFC transition parameters @@ -132,14 +132,14 @@ """ # Extract transition value according to type type_value = values.get("value", None) - + # For each parameters defined, set corresponding control value for name, value in values.items(): - + # Parameter is SFC transition priority if name == "priority": self.Priority.SetValue(values["priority"]) - + # Parameter is SFC transition type elif name == "type": for type, (radio, control) in self.TypeRadioButtons.iteritems(): @@ -152,10 +152,10 @@ control.SetStringSelection(type_value) elif isinstance(control, wx.TextCtrl): control.ChangeValue(type_value) - + # Refresh preview panel self.RefreshPreview() - + def GetValues(self): """ Return SFC transition parameters defined in dialog @@ -165,7 +165,7 @@ values["type"], values["value"] = self.GetTransitionType() values["width"], values["height"] = self.Element.GetSize() return values - + def OnOK(self, event): """ Called when dialog OK button is pressed @@ -173,18 +173,18 @@ @param event: wx.Event from OK button """ message = None - + # Get transition type and value associated type, value = self.GetTransitionType() - + # Test that value associated to type is defined if type != "connection" and value == "": message = _("Form isn't complete. %s must be filled!") % type - + # Show error message if an error is detected if message is not None: self.ShowErrorMessage(message) - + else: # Call BlockPreviewDialog function BlockPreviewDialog.OnOK(self, event) @@ -198,7 +198,7 @@ for type, (radio, control) in self.TypeRadioButtons.iteritems(): if control is not None: control.Enable(radio.GetValue()) - + # Refresh preview panel self.RefreshPreview() event.Skip() @@ -236,6 +236,6 @@ self.Element = SFC_Transition(self.Preview) self.Element.SetType(*self.GetTransitionType()) self.Element.SetPriority(self.Priority.GetValue()) - + # Call BlockPreviewDialog function BlockPreviewDialog.RefreshPreview(self) diff -r d51af006fa6b -r 64d8f52bc8c8 dialogs/SearchInProjectDialog.py --- a/dialogs/SearchInProjectDialog.py Fri Aug 11 15:18:19 2017 +0300 +++ b/dialogs/SearchInProjectDialog.py Mon Aug 14 19:13:01 2017 +0300 @@ -33,62 +33,62 @@ def GetElementsChoices(): _ = lambda x: x - return [("datatype", _("Data Type")), - ("function", _("Function")), - ("functionBlock", _("Function Block")), - ("program", _("Program")), + return [("datatype", _("Data Type")), + ("function", _("Function")), + ("functionBlock", _("Function Block")), + ("program", _("Program")), ("configuration", _("Configuration"))] class SearchInProjectDialog(wx.Dialog): - + def __init__(self, parent): wx.Dialog.__init__(self, parent, title=_('Search in Project')) - + main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) main_sizer.AddGrowableCol(0) main_sizer.AddGrowableRow(1) - + pattern_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5) pattern_sizer.AddGrowableCol(0) - main_sizer.AddSizer(pattern_sizer, border=20, + main_sizer.AddSizer(pattern_sizer, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - + pattern_label = wx.StaticText(self, label=_('Pattern to search:')) pattern_sizer.AddWindow(pattern_label, flag=wx.ALIGN_BOTTOM) - + self.CaseSensitive = wx.CheckBox(self, label=_('Case sensitive')) pattern_sizer.AddWindow(self.CaseSensitive, flag=wx.GROW) - + self.Pattern = wx.TextCtrl(self, size=wx.Size(250,-1)) self.Bind(wx.EVT_TEXT, self.FindPatternChanged, self.Pattern) pattern_sizer.AddWindow(self.Pattern, flag=wx.GROW) self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey) self.RegularExpression = wx.CheckBox(self, label=_('Regular expression')) pattern_sizer.AddWindow(self.RegularExpression, flag=wx.GROW) - + scope_staticbox = wx.StaticBox(self, label=_('Scope')) scope_sizer = wx.StaticBoxSizer(scope_staticbox, wx.HORIZONTAL) - main_sizer.AddSizer(scope_sizer, border=20, + main_sizer.AddSizer(scope_sizer, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT) - + scope_selection_sizer = wx.BoxSizer(wx.VERTICAL) - scope_sizer.AddSizer(scope_selection_sizer, 1, border=5, + scope_sizer.AddSizer(scope_selection_sizer, 1, border=5, flag=wx.GROW|wx.TOP|wx.LEFT|wx.BOTTOM) - + self.WholeProject = wx.RadioButton(self, label=_('Whole Project'), style=wx.RB_GROUP) self.WholeProject.SetValue(True) self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.WholeProject) - scope_selection_sizer.AddWindow(self.WholeProject, border=5, + scope_selection_sizer.AddWindow(self.WholeProject, border=5, flag=wx.GROW|wx.BOTTOM) - + self.OnlyElements = wx.RadioButton(self, label=_('Only Elements')) self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.OnlyElements) self.OnlyElements.SetValue(False) scope_selection_sizer.AddWindow(self.OnlyElements, flag=wx.GROW) - + self.ElementsList = wx.CheckListBox(self) self.ElementsList.Enable(False) - scope_sizer.AddWindow(self.ElementsList, 1, border=5, + scope_sizer.AddWindow(self.ElementsList, 1, border=5, flag=wx.GROW|wx.TOP|wx.RIGHT|wx.BOTTOM) buttons_sizer = wx.BoxSizer(wx.HORIZONTAL) @@ -103,9 +103,9 @@ self.CloseButton = wx.Button(self, label=_("Close")) self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton) buttons_sizer.AddWindow(self.CloseButton) - + self.SetSizer(main_sizer) - + for name, label in GetElementsChoices(): self.ElementsList.Append(_(label)) @@ -139,7 +139,7 @@ self.OnCloseButton(event) else: event.Skip() - + def OnFindButton(self, event): message = None infos = { @@ -163,7 +163,7 @@ except: self.criteria.clear() message = _("Syntax error in regular expression of pattern to search!") - + if message is not None: dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) dialog.ShowModal() diff -r d51af006fa6b -r 64d8f52bc8c8 editors/DebugViewer.py --- a/editors/DebugViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/DebugViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,12 +35,12 @@ #------------------------------------------------------------------------------- """ -Class that implements common behavior of every viewers able to display debug +Class that implements common behavior of every viewers able to display debug values """ class DebugViewer: - + def __init__(self, producer, debug, subscribe_tick=True): """ Constructor @@ -52,49 +52,49 @@ """ self.Debug = debug self.SubscribeTick = subscribe_tick - + # Flag indicating that consumer value update inhibited # (DebugViewer is refreshing) self.Inhibited = False - + # List of data consumers subscribed to DataProducer self.DataConsumers = {} - + # Time stamp indicating when last refresh have been initiated self.LastRefreshTime = gettime() # Flag indicating that DebugViewer has acquire common debug lock self.HasAcquiredLock = False # Lock for access to the two preceding variable self.AccessLock = Lock() - + # Timer to refresh Debug Viewer one last time in the case that a new # value have been received during refresh was inhibited and no one # after refresh was activated self.LastRefreshTimer = None # Lock for access to the timer self.TimerAccessLock = Lock() - + # Set DataProducer and subscribe tick if needed self.SetDataProducer(producer) - + def __del__(self): """ Destructor """ # Unsubscribe all data consumers self.UnsubscribeAllDataConsumers() - + # Delete reference to DataProducer self.DataProducer = None - + # Stop last refresh timer if self.LastRefreshTimer is not None: self.LastRefreshTimer.cancel() - + # Release Common debug lock if DebugViewer has acquired it if self.HasAcquiredLock: DEBUG_REFRESH_LOCK.release() - + def SetDataProducer(self, producer): """ Set Data Producer @@ -103,25 +103,25 @@ # In the case that tick need to be subscribed and DebugViewer is # debugging if self.SubscribeTick and self.Debug: - + # Subscribe tick to new data producer if producer is not None: producer.SubscribeDebugIECVariable("__tick__", self, True) - + # Unsubscribe tick from old data producer if getattr(self, "DataProducer", None) is not None: self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self) - + # Save new data producer self.DataProducer = producer - + def IsDebugging(self): """ Get flag indicating if Debug Viewer is debugging @return: Debugging flag """ return self.Debug - + def Inhibit(self, inhibit): """ Set consumer value update inhibit flag @@ -130,10 +130,10 @@ # Inhibit every data consumers in list for consumer, iec_path in self.DataConsumers.iteritems(): consumer.Inhibit(inhibit) - + # Save inhibit flag self.Inhibited = inhibit - + def AddDataConsumer(self, iec_path, consumer, buffer_list=False): """ Subscribe data consumer to DataProducer @@ -145,19 +145,19 @@ # Return immediately if no DataProducer defined if self.DataProducer is None: return None - + # Subscribe data consumer to DataProducer result = self.DataProducer.SubscribeDebugIECVariable( iec_path, consumer, buffer_list) if result is not None and consumer != self: - + # Store data consumer if successfully subscribed and inform # consumer of variable data type self.DataConsumers[consumer] = iec_path consumer.SetDataType(self.GetDataType(iec_path)) - + return result - + def RemoveDataConsumer(self, consumer): """ Unsubscribe data consumer from DataProducer @@ -165,12 +165,12 @@ """ # Remove consumer from data consumer list iec_path = self.DataConsumers.pop(consumer, None) - + # Unsubscribe consumer from DataProducer if iec_path is not None: self.DataProducer.UnsubscribeDebugIECVariable( iec_path, consumer) - + def SubscribeAllDataConsumers(self): """ Called to Subscribe all data consumers contained in DebugViewer. @@ -179,24 +179,24 @@ # Subscribe tick if needed if self.SubscribeTick and self.Debug and self.DataProducer is not None: self.DataProducer.SubscribeDebugIECVariable("__tick__", self, True) - + def UnsubscribeAllDataConsumers(self, tick=True): """ Called to Unsubscribe all data consumers. """ if self.DataProducer is not None: - + # Unscribe tick if needed if self.SubscribeTick and tick and self.Debug: self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self) - + # Unsubscribe all data consumers in list for consumer, iec_path in self.DataConsumers.iteritems(): self.DataProducer.UnsubscribeDebugIECVariable( iec_path, consumer) - + self.DataConsumers = {} - + def GetDataType(self, iec_path): """ Return variable data type. @@ -204,20 +204,20 @@ @return: variable data type (None if not found) """ if self.DataProducer is not None: - + # Search for variable informations in project compilation files data_type = self.DataProducer.GetDebugIECVariableType( iec_path.upper()) if data_type is not None: return data_type - + # Search for variable informations in project data infos = self.DataProducer.GetInstanceInfos(iec_path) if infos is not None: return infos.type - + return None - + def IsNumType(self, data_type): """ Indicate if data type given is a numeric data type @@ -226,9 +226,9 @@ """ if self.DataProducer is not None: return self.DataProducer.IsNumType(data_type) - + return False - + def ForceDataValue(self, iec_path, value): """ Force PLC variable value @@ -237,7 +237,7 @@ """ if self.DataProducer is not None: self.DataProducer.ForceDebugIECVariable(iec_path, value) - + def ReleaseDataValue(self, iec_path): """ Release PLC variable value @@ -245,12 +245,12 @@ """ if self.DataProducer is not None: self.DataProducer.ReleaseDebugIECVariable(iec_path) - + def NewDataAvailable(self, ticks): """ Called by DataProducer for each tick captured @param tick: PLC tick captured - All other parameters are passed to refresh function + All other parameters are passed to refresh function """ # Stop last refresh timer self.TimerAccessLock.acquire() @@ -258,27 +258,27 @@ self.LastRefreshTimer.cancel() self.LastRefreshTimer=None self.TimerAccessLock.release() - + # Only try to refresh DebugViewer if it is visible on screen and not # already refreshing if self.IsShown() and not self.Inhibited: - + # Try to get acquire common refresh lock if minimum period between # two refresh has expired if gettime() - self.LastRefreshTime > REFRESH_PERIOD and \ DEBUG_REFRESH_LOCK.acquire(False): self.StartRefreshing() - + # If common lock wasn't acquired for any reason, restart last # refresh timer else: self.StartLastRefreshTimer() - + # In the case that DebugViewer isn't visible on screen and has already # acquired common refresh lock, reset DebugViewer elif not self.IsShown() and self.HasAcquiredLock: DebugViewer.RefreshNewData(self) - + def ShouldRefresh(self): """ Callback function called when last refresh timer expired @@ -286,15 +286,15 @@ """ # Cancel if DebugViewer is not visible on screen if self and self.IsShown(): - + # Try to acquire common refresh lock if DEBUG_REFRESH_LOCK.acquire(False): self.StartRefreshing() - + # Restart last refresh timer if common refresh lock acquired failed else: self.StartLastRefreshTimer() - + def StartRefreshing(self): """ Called to initiate a refresh of DebugViewer @@ -306,13 +306,13 @@ self.HasAcquiredLock = True self.LastRefreshTime = gettime() self.AccessLock.release() - + # Inhibit data consumer value update self.Inhibit(True) - + # Initiate DebugViewer refresh wx.CallAfter(self.RefreshNewData) - + def StartLastRefreshTimer(self): """ Called to start last refresh timer for the minimum time between 2 @@ -324,19 +324,19 @@ REFRESH_PERIOD, self.ShouldRefresh) self.LastRefreshTimer.start() self.TimerAccessLock.release() - + def RefreshNewData(self): """ Called to refresh DebugViewer according to values received by data consumers May be overridden by inherited classes Can receive any parameters depending on what is needed by inherited - class + class """ if self: # Activate data consumer value update self.Inhibit(False) - + # Release common refresh lock if acquired and update # last refresh time self.AccessLock.acquire() diff -r d51af006fa6b -r 64d8f52bc8c8 editors/FileManagementPanel.py --- a/editors/FileManagementPanel.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/FileManagementPanel.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,37 +35,37 @@ FILTER = _("All files (*.*)|*.*|CSV files (*.csv)|*.csv") class FileManagementPanel(EditorPanel): - + def _init_Editor(self, parent): self.Editor = wx.Panel(parent) - + main_sizer = wx.BoxSizer(wx.HORIZONTAL) - + left_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.AddSizer(left_sizer, 1, border=5, flag=wx.GROW|wx.ALL) - + managed_dir_label = wx.StaticText(self.Editor, label=_(self.TagName) + ":") left_sizer.AddWindow(managed_dir_label, border=5, flag=wx.GROW|wx.BOTTOM) - + self.ManagedDir = FolderTree(self.Editor, self.Folder, FILTER) left_sizer.AddWindow(self.ManagedDir, 1, flag=wx.GROW) - + managed_treectrl = self.ManagedDir.GetTreeCtrl() self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, managed_treectrl) if self.EnableDragNDrop: self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, managed_treectrl) - + button_sizer = wx.BoxSizer(wx.VERTICAL) - main_sizer.AddSizer(button_sizer, border=5, + main_sizer.AddSizer(button_sizer, border=5, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL) - + for idx, (name, bitmap, help) in enumerate([ ("DeleteButton", "remove_element", _("Remove file from left folder")), ("LeftCopyButton", "LeftCopy", _("Copy file from right folder to left")), ("RightCopyButton", "RightCopy", _("Copy file from left folder to right")), ("EditButton", "edit", _("Edit file"))]): - button = wx.lib.buttons.GenBitmapButton(self.Editor, - bitmap=GetBitmap(bitmap), + button = wx.lib.buttons.GenBitmapButton(self.Editor, + bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER) button.SetToolTipString(help) setattr(self, name, button) @@ -75,62 +75,62 @@ flag = 0 self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button) button_sizer.AddWindow(button, border=20, flag=flag) - + right_sizer = wx.BoxSizer(wx.VERTICAL) main_sizer.AddSizer(right_sizer, 1, border=5, flag=wx.GROW|wx.ALL) - + if wx.Platform == '__WXMSW__': system_dir_label = wx.StaticText(self.Editor, label=_("My Computer:")) else: system_dir_label = wx.StaticText(self.Editor, label=_("Home Directory:")) right_sizer.AddWindow(system_dir_label, border=5, flag=wx.GROW|wx.BOTTOM) - + self.SystemDir = FolderTree(self.Editor, self.HomeDirectory, FILTER, False) right_sizer.AddWindow(self.SystemDir, 1, flag=wx.GROW) - + system_treectrl = self.SystemDir.GetTreeCtrl() self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, system_treectrl) - + self.Editor.SetSizer(main_sizer) - + def __init__(self, parent, controler, name, folder, enable_dragndrop=False): self.Folder = os.path.realpath(folder) self.EnableDragNDrop = enable_dragndrop - + if wx.Platform == '__WXMSW__': self.HomeDirectory = "/" else: self.HomeDirectory = os.path.expanduser("~") - + EditorPanel.__init__(self, parent, name, None, None) - + self.Controler = controler - + self.EditableFileExtensions = [] self.EditButton.Hide() - + self.SetIcon(GetBitmap("FOLDER")) - + def __del__(self): self.Controler.OnCloseEditor(self) - + def GetTitle(self): return _(self.TagName) - + def SetEditableFileExtensions(self, extensions): self.EditableFileExtensions = extensions if len(self.EditableFileExtensions) > 0: self.EditButton.Show() - + def RefreshView(self): self.ManagedDir.RefreshTree() self.SystemDir.RefreshTree() self.RefreshButtonsState() - + def RefreshButtonsState(self): managed_filepath = self.ManagedDir.GetPath() system_filepath = self.SystemDir.GetPath() - + self.DeleteButton.Enable(os.path.isfile(managed_filepath)) self.LeftCopyButton.Enable(os.path.isfile(system_filepath)) self.RightCopyButton.Enable(os.path.isfile(managed_filepath)) @@ -138,22 +138,22 @@ self.EditButton.Enable( os.path.isfile(managed_filepath) and os.path.splitext(managed_filepath)[1] in self.EditableFileExtensions) - + def OnTreeItemChanged(self, event): self.RefreshButtonsState() event.Skip() - + def OnDeleteButton(self, event): filepath = self.ManagedDir.GetPath() if os.path.isfile(filepath): folder, filename = os.path.split(filepath) - - dialog = wx.MessageDialog(self, - _("Do you really want to delete the file '%s'?") % filename, + + dialog = wx.MessageDialog(self, + _("Do you really want to delete the file '%s'?") % filename, _("Delete File"), wx.YES_NO|wx.ICON_QUESTION) remove = dialog.ShowModal() == wx.ID_YES dialog.Destroy() - + if remove: os.remove(filepath) self.ManagedDir.RefreshTree() @@ -161,11 +161,11 @@ def OnEditButton(self, event): filepath = self.ManagedDir.GetPath() - if (os.path.isfile(filepath) and + if (os.path.isfile(filepath) and os.path.splitext(filepath)[1] in self.EditableFileExtensions): self.Controler._OpenView(filepath + "::") event.Skip() - + def CopyFile(self, src, dst): if os.path.isfile(src): src_folder, src_filename = os.path.split(src) @@ -173,17 +173,17 @@ dst_folder, dst_filename = os.path.split(dst) else: dst_folder = dst - + dst_filepath = os.path.join(dst_folder, src_filename) if os.path.isfile(dst_filepath): - dialog = wx.MessageDialog(self, - _("The file '%s' already exist.\nDo you want to replace it?") % src_filename, + dialog = wx.MessageDialog(self, + _("The file '%s' already exist.\nDo you want to replace it?") % src_filename, _("Replace File"), wx.YES_NO|wx.ICON_QUESTION) copy = dialog.ShowModal() == wx.ID_YES dialog.Destroy() else: copy = True - + if copy: shutil.copyfile(src, dst_filepath) return dst_filepath @@ -202,7 +202,7 @@ self.SystemDir.RefreshTree() self.SystemDir.SetPath(filepath) event.Skip() - + def OnTreeBeginDrag(self, event): filepath = self.ManagedDir.GetPath() if os.path.isfile(filepath): @@ -211,4 +211,3 @@ dragSource = wx.DropSource(self) dragSource.SetData(data) dragSource.DoDragDrop() - diff -r d51af006fa6b -r 64d8f52bc8c8 editors/LDViewer.py --- a/editors/LDViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/LDViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -49,7 +49,7 @@ block_list.append(next) next_list.append(next) current_list = next_list - + def CalcBranchSize(elements, stops): branch_size = 0 stop_list = stops @@ -194,7 +194,7 @@ self.RungComments.insert(i, None) else: self.RungComments.insert(i, None) - + def loadInstance(self, instance, ids, selection): Viewer.loadInstance(self, instance, ids, selection) if self.GetDrawingMode() != FREEDRAWING_MODE: @@ -230,7 +230,7 @@ if len(rungs) > 1: raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"] element = self.FindElementById(instance["id"]) - element_connectors = element.GetConnectors() + element_connectors = element.GetConnectors() self.Rungs[rungs[0]].SelectElement(element) for wire, num in element_connectors["inputs"][0].GetWires(): self.Rungs[rungs[0]].SelectElement(wire) @@ -240,7 +240,7 @@ pos = element.GetPosition() i = 0 inserted = False - while i < len(self.RungComments) and not inserted: + while i < len(self.RungComments) and not inserted: ipos = self.RungComments[i].GetPosition() if pos[1] < ipos[1]: self.RungComments.insert(i, element) @@ -248,7 +248,7 @@ i += 1 if not inserted: self.RungComments.append(element) - + #------------------------------------------------------------------------------- # Search Element functions #------------------------------------------------------------------------------- @@ -262,7 +262,7 @@ def FindElement(self, event, exclude_group = False, connectors = True): if self.GetDrawingMode() == FREEDRAWING_MODE: return Viewer.FindElement(self, event, exclude_group, connectors) - + dc = self.GetLogicalDC() pos = event.GetLogicalPosition(dc) if self.SelectedElement and not isinstance(self.SelectedElement, (Graphic_Group, Wire)): @@ -286,7 +286,7 @@ def SearchElements(self, bbox): if self.GetDrawingMode() == FREEDRAWING_MODE: return Viewer.SearchElements(self, bbox) - + elements = [] for element in self.Blocks.values() + self.Comments.values(): if element.IsInSelection(bbox): @@ -345,7 +345,7 @@ self.SelectedElement.SetElements(elements) self.SelectedElement.SetSelected(True) elif self.Mode == MODE_SELECTION and self.SelectedElement: - dc = self.GetLogicalDC() + dc = self.GetLogicalDC() if not isinstance(self.SelectedElement, Graphic_Group): if self.IsWire(self.SelectedElement): result = self.SelectedElement.TestSegment(event.GetLogicalPosition(dc), True) @@ -500,7 +500,7 @@ starty = bbox.y + bbox.height starty += LD_OFFSET[1] rung = Graphic_Group(self) - + # Create comment id = self.GetNewId() comment = Comment(self, _("Comment"), id) @@ -511,7 +511,7 @@ self.Controler.AddEditedElementComment(self.TagName, id) self.RefreshCommentModel(comment) starty += LD_COMMENT_DEFAULTSIZE[1] + LD_OFFSET[1] - + # Create LeftPowerRail id = self.GetNewId() leftpowerrail = LD_PowerRail(self, LEFTRAIL, id) @@ -521,7 +521,7 @@ rung.SelectElement(leftpowerrail) self.Controler.AddEditedElementPowerRail(self.TagName, id, LEFTRAIL) self.RefreshPowerRailModel(leftpowerrail) - + # Create Coil id = self.GetNewId() coil = LD_Coil(self, values["type"], values["name"], id) @@ -530,7 +530,7 @@ self.AddBlock(coil) rung.SelectElement(coil) self.Controler.AddEditedElementCoil(self.TagName, id) - + # Create Wire between LeftPowerRail and Coil wire = Wire(self) start_connector = coil_connectors["inputs"][0] @@ -541,7 +541,7 @@ wire.ConnectEndPoint(None, end_connector) self.AddWire(wire) rung.SelectElement(wire) - + # Create RightPowerRail id = self.GetNewId() rightpowerrail = LD_PowerRail(self, RIGHTRAIL, id) @@ -550,7 +550,7 @@ self.AddBlock(rightpowerrail) rung.SelectElement(rightpowerrail) self.Controler.AddEditedElementPowerRail(self.TagName, id, RIGHTRAIL) - + # Create Wire between LeftPowerRail and Coil wire = Wire(self) start_connector = rightpowerrail_connectors["inputs"][0] @@ -778,7 +778,7 @@ if left_powerrail: powerrail = left_elements[0].GetParentBlock() index = 0 - for left_element in left_elements: + for left_element in left_elements: index = max(index, powerrail.GetConnectorIndex(left_element)) powerrail.InsertConnector(index + 1) powerrail.RefreshModel() @@ -810,12 +810,12 @@ values = dialog.GetValues() powerrail = right_elements[0].GetParentBlock() index = 0 - for right_element in right_elements: + for right_element in right_elements: index = max(index, powerrail.GetConnectorIndex(right_element)) powerrail.InsertConnector(index + 1) powerrail.RefreshModel() connectors = powerrail.GetConnectors() - + # Create Coil id = self.GetNewId() coil = LD_Coil(self, values["type"], values["name"], id) @@ -825,7 +825,7 @@ rung.SelectElement(coil) self.Controler.AddEditedElementCoil(self.TagName, id) coil_connectors = coil.GetConnectors() - + # Create Wire between LeftPowerRail and Coil wire = Wire(self) connectors["inputs"][index + 1].Connect((wire, 0), False) @@ -835,7 +835,7 @@ self.AddWire(wire) rung.SelectElement(wire) left_elements.reverse() - + for i, left_element in enumerate(left_elements): # Create Wire between LeftPowerRail and Coil new_wire = Wire(self) @@ -844,7 +844,7 @@ left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False) new_wire.ConnectStartPoint(None, coil_connectors["inputs"][0]) new_wire.ConnectEndPoint(None, left_element) - + self.RefreshPosition(coil) else: left_elements.reverse() @@ -1089,7 +1089,7 @@ if isinstance(element, LD_PowerRail) and element.GetType() == LEFTRAIL: element.RefreshModel() return - + # Extract max position of the elements connected to input connectors = element.GetConnectors() position = element.GetPosition() @@ -1103,7 +1103,7 @@ pos = leftblock.GetPosition() size = leftblock.GetSize() maxx = max(maxx, pos[0] + size[0]) - + # Refresh position of element if isinstance(element, LD_Coil): interval = LD_WIRECOIL_SIZE @@ -1114,13 +1114,13 @@ movex = maxx + interval - position[0] element.Move(movex, 0) position = element.GetPosition() - + # Extract blocks connected to inputs blocks = [] for i, connector in enumerate(connectors["inputs"]): for j, (wire, handle) in enumerate(connector.GetWires()): blocks.append(wire.EndConnected.GetParentBlock()) - + for i, connector in enumerate(connectors["inputs"]): startpoint = connector.GetPosition(False) previous_blocks = [] @@ -1168,13 +1168,13 @@ previous_blocks.append(block) blocks.remove(block) ExtractNextBlocks(block, block_list) - + element.RefreshModel(False) if recursive: for connector in connectors["outputs"]: for wire, handle in connector.GetWires(): self.RefreshPosition(wire.StartConnected.GetParentBlock()) - + def RefreshRungs(self, movey, fromidx): if movey != 0: for i in xrange(fromidx, len(self.Rungs)): @@ -1192,4 +1192,3 @@ def EditPowerRailContent(self, powerrail): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.EditPowerRailContent(self, powerrail) - diff -r d51af006fa6b -r 64d8f52bc8c8 editors/SFCViewer.py --- a/editors/SFCViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/SFCViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,7 +35,7 @@ class SFC_Viewer(Viewer): - + SFC_StandardRules = { # The key of this dict is a block that user try to connect, # and the value is a list of blocks, that can be connected with the current block @@ -85,7 +85,7 @@ def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""): Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath) self.CurrentLanguage = "SFC" - + def ConnectConnectors(self, start, end): startpoint = [start.GetPosition(False), start.GetDirection()] endpoint = [end.GetPosition(False), end.GetDirection()] @@ -96,7 +96,7 @@ wire.ConnectStartPoint(None, start) wire.ConnectEndPoint(None, end) return wire - + def CreateTransition(self, connector, next = None): previous = connector.GetParentBlock() id = self.GetNewId() @@ -124,7 +124,7 @@ next_block.RefreshPosition() transition.RefreshOutputModel(True) return transition - + def RemoveTransition(self, transition): connectors = transition.GetConnectors() input_wires = connectors["input"].GetWires() @@ -146,7 +146,7 @@ self.Controler.RemoveEditedElementInstance(self.TagName, transition.GetId()) wire = self.ConnectConnectors(next, previous) return wire - + def CreateStep(self, name, connector, next = None): previous = connector.GetParentBlock() id = self.GetNewId() @@ -289,7 +289,7 @@ self.SelectedElement.RefreshModel() self.SelectedElement.SetSelected(True) event.Skip() - + def OnViewerRightUp(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.OnViewerRightUp(self, event) @@ -307,7 +307,7 @@ self.SelectedElement.Refresh() wx.CallAfter(self.SetCurrentCursor, 0) event.Skip() - + def OnViewerLeftDClick(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.OnViewerLeftDClick(self, event) @@ -315,7 +315,7 @@ self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling) self.Refresh(False) event.Skip() - + def OnViewerMotion(self, event): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.OnViewerMotion(self, event) @@ -424,7 +424,7 @@ self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, scaling[1])), False) else: event.Skip() - + #------------------------------------------------------------------------------- # Adding element functions #------------------------------------------------------------------------------- @@ -503,7 +503,7 @@ self.RefreshScrollBars() self.Refresh(False) dialog.Destroy() - + def AddStepAction(self): if isinstance(self.SelectedElement, SFC_Step): connectors = self.SelectedElement.GetConnectors() @@ -532,9 +532,9 @@ self.RefreshScrollBars() self.Refresh(False) dialog.Destroy() - + def AddDivergence(self): - if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, Graphic_Group) or isinstance(self.SelectedElement, SFC_Step): + if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, Graphic_Group) or isinstance(self.SelectedElement, SFC_Step): dialog = SFCDivergenceDialog(self.ParentWindow) dialog.SetPreviewFont(self.GetFont()) if dialog.ShowModal() == wx.ID_OK: @@ -729,7 +729,7 @@ self.RefreshScrollBars() self.Refresh(False) dialog.Destroy() - + def AddDivergenceBranch(self, divergence): if isinstance(divergence, SFC_Divergence): if self.GetDrawingMode() == FREEDRAWING_MODE: @@ -750,7 +750,7 @@ self.RefreshBuffer() self.RefreshScrollBars() self.Refresh(False) - + def RemoveDivergenceBranch(self, divergence): if isinstance(divergence, SFC_Divergence): if self.GetDrawingMode() == FREEDRAWING_MODE: @@ -759,15 +759,15 @@ self.RefreshBuffer() self.RefreshScrollBars() self.Refresh(False) - + def AddJump(self): if isinstance(self.SelectedElement, SFC_Step) and not self.SelectedElement.Output: choices = [] for block in self.Blocks: if isinstance(block, SFC_Step): choices.append(block.GetName()) - dialog = wx.SingleChoiceDialog(self.ParentWindow, - _("Add a new jump"), _("Please choose a target"), + dialog = wx.SingleChoiceDialog(self.ParentWindow, + _("Add a new jump"), _("Please choose a target"), choices, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: value = dialog.GetStringSelection() @@ -884,7 +884,7 @@ self.DeleteDivergence(previous_block) else: self.RefreshDivergenceModel(previous_block) - + def DeleteTransition(self, transition): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteTransition(self, transition) @@ -919,7 +919,7 @@ self.DeleteDivergence(next_block) else: self.RefreshDivergenceModel(next_block) - + def DeleteDivergence(self, divergence): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteDivergence(self, divergence) @@ -979,7 +979,7 @@ next_pos = next.GetPosition(False) wire_size = GetWireSize(previous_block) previous_block.RefreshOutputPosition((0, previous_pos.y + wire_size - next_pos.y)) - wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size), + wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size), wx.Point(previous_pos.x, previous_pos.y)]) if isinstance(next_block, SFC_Divergence): next_block.RefreshPosition() @@ -1009,12 +1009,12 @@ next_pos = next.GetPosition(False) wire_size = GetWireSize(previous_block) previous_block.RefreshOutputPosition((previous_pos.x - next_pos.x, previous_pos.y + wire_size - next_pos.y)) - wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size), + wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size), wx.Point(previous_pos.x, previous_pos.y)]) if isinstance(next_block, SFC_Divergence): next_block.RefreshPosition() previous_block.RefreshOutputModel(True) - + def DeleteJump(self, jump): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteJump(self, jump) @@ -1049,7 +1049,7 @@ self.DeleteDivergence(previous_block) else: previous_block.RefreshModel() - + def DeleteActionBlock(self, actionblock): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteActionBlock(self, actionblock) @@ -1069,7 +1069,7 @@ self.RefreshStepModel(step) step.RefreshOutputPosition() step.RefreshOutputModel(True) - + def DeleteWire(self, wire): if self.GetDrawingMode() == FREEDRAWING_MODE: Viewer.DeleteWire(self, wire) @@ -1087,4 +1087,3 @@ infos["width"], infos["height"] = block.GetSize() infos["connectors"] = block.GetConnectors() self.Controler.SetEditedElementBlockInfos(self.TagName, blockid, infos) - diff -r d51af006fa6b -r 64d8f52bc8c8 editors/TextViewer.py --- a/editors/TextViewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/TextViewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -263,7 +263,7 @@ if dialog.ShowModal() == wx.ID_OK: blockname = dialog.GetValue() else: - event.SetDragText("") + event.SetDragText("") return dialog.Destroy() if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: @@ -632,7 +632,7 @@ if len(self.CallStack) > 0: current_call = self.CallStack.pop() else: - current_call = None + current_call = None elif state == PRAGMA: if line.endswith("}"): self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) @@ -961,4 +961,3 @@ self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type) self.StartStyling(highlight_start_pos, 0x00) self.SetStyling(len(self.Editor.GetText()) - highlight_end_pos, wx.stc.STC_STYLE_DEFAULT) - diff -r d51af006fa6b -r 64d8f52bc8c8 editors/Viewer.py --- a/editors/Viewer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/editors/Viewer.py Mon Aug 14 19:13:01 2017 +0300 @@ -429,7 +429,7 @@ class DebugInstanceName(DebugDataConsumer): VALUE_TRANSLATION = {True: _("Active"), False: _("Inactive")} - + def __init__(self, parent): DebugDataConsumer.__init__(self) self.Parent = parent @@ -437,7 +437,7 @@ self.ActionState = None self.x_offset = 2 self.y_offset = 2 - + def SetValue(self, value): self.ActionState = value if self.ActionState != self.ActionLastState: @@ -448,7 +448,7 @@ return _("Debug: %s") % self.Parent.InstancePath def GetRedrawRect(self): - x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset) + x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset) dc = self.Parent.GetLogicalDC() ipw, iph = dc.GetTextExtent(self.GetInstanceName()) vw, vh = 0, 0 @@ -462,13 +462,13 @@ scalex, scaley = dc.GetUserScale() dc.SetUserScale(1, 1) x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset) - + text = self.GetInstanceName() if self.ActionState is not None: text += " (" dc.DrawText(text, x, y) - tw, th = dc.GetTextExtent(text) + tw, th = dc.GetTextExtent(text) if self.ActionState is not None: text = self.VALUE_TRANSLATION[self.ActionState] @@ -478,8 +478,8 @@ if self.ActionState: dc.SetTextForeground(wx.BLACK) tw = tw + dc.GetTextExtent(text)[0] - - text = ")" + + text = ")" dc.DrawText(text, x + tw, y) dc.SetUserScale(scalex, scaley) @@ -955,7 +955,7 @@ block.GetName() == name: blocks.append(block) return blocks - + def GetConnectorByName(self, name): for block in self.Blocks.itervalues(): if isinstance(block, FBD_Connector) and\ @@ -1222,7 +1222,7 @@ if self.TagName.split("::")[0] == "A" and self.Debug: self.AddDataConsumer("%s.Q" % self.InstancePath.upper(), self.InstanceName) - + for wire in self.Wires: if not wire.IsConnectedCompatible(): wire.SetValid(False) @@ -1526,7 +1526,7 @@ return result def FindBlockConnectorWithError(self, pos, direction = None, exclude = None): - error = False + error = False startblock = None for block in self.Blocks.itervalues(): connector = block.TestConnector(pos, direction, exclude) @@ -1539,7 +1539,7 @@ error = True return connector, error return None, error - + def FindElementById(self, id): block = self.Blocks.get(id, None) if block is not None: @@ -2585,7 +2585,7 @@ break self.AddNewElement(block, bbox, wire, connector) self.RefreshVariablePanel() - self.ParentWindow.RefreshPouInstanceVariablesPanel() + self.ParentWindow.RefreshPouInstanceVariablesPanel() dialog.Destroy() def AddNewVariable(self, bbox, exclude_input=False, wire=None): @@ -2966,7 +2966,7 @@ rect = rect.Union(block.GetRedrawRect()) block.Refresh(rect) step.SetName(new_name) - + if values["input"]: step.AddInput() else: @@ -3711,5 +3711,3 @@ if self.Debug: DebugViewer.RefreshNewData(self) event.Skip() - - diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/DebugDataConsumer.py --- a/graphics/DebugDataConsumer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/DebugDataConsumer.py Mon Aug 14 19:13:01 2017 +0300 @@ -46,7 +46,7 @@ return float(value.days * DAY + \ value.seconds * SECOND + \ value.microseconds) - return + return def generate_time(value): """ @@ -56,38 +56,38 @@ @return: IEC 61131 TIME literal """ microseconds = get_microseconds(value) - + # Get absolute microseconds value and save if it was negative negative = microseconds < 0 microseconds = abs(microseconds) - + # TIME literal prefix data = "T#" if negative: data += "-" - + # In TIME literal format, it isn't mandatory to indicate null values # if no greater non-null values are available. This variable is used to # inhibit formatting until a non-null value is found not_null = False - + for val, format in [ (int(microseconds) / DAY, "%dd"), # Days ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds - - # Add value to TIME literal if value is non-null or another non-null + + # Add value to TIME literal if value is non-null or another non-null # value have already be found if val > 0 or not_null: data += format % val - + # Update non-null variable not_null = True - - # In any case microseconds have to be added to TIME literal + + # In any case microseconds have to be added to TIME literal data += "%gms" % (microseconds % SECOND / 1000.) - + return data def generate_date(value): @@ -116,22 +116,22 @@ @return: IEC 61131 TIME_OF_DAY literal """ microseconds = get_microseconds(value) - + # TIME_OF_DAY literal prefix data = "TOD#" - + for val, format in [ (int(microseconds) / HOUR, "%2.2d:"), # Hours ((int(microseconds) % HOUR) / MINUTE, "%2.2d:"), # Minutes ((int(microseconds) % MINUTE) / SECOND, "%2.2d."), # Seconds (microseconds % SECOND, "%6.6d")]: # Microseconds - + # Add value to TIME_OF_DAY literal data += format % val - + return data -# Dictionary of translation functions from value send by debugger to IEC +# Dictionary of translation functions from value send by debugger to IEC # literal stored by type TYPE_TRANSLATOR = { "TIME": generate_time, @@ -154,7 +154,7 @@ """ class DebugDataConsumer: - + def __init__(self): """ Constructor @@ -162,17 +162,17 @@ # Debug value and forced flag self.Value = None self.Forced = False - + # Store debug value and forced flag when value update is inhibited self.LastValue = None self.LastForced = False - + # Value IEC data type self.DataType = None - + # Flag that value update is inhibited self.Inhibited = False - + def Inhibit(self, inhibit): """ Set flag to inhibit or activate value update @@ -180,23 +180,23 @@ """ # Save inhibit flag self.Inhibited = inhibit - + # When reactivated update value and forced flag with stored values if not inhibit and self.LastValue is not None: self.SetForced(self.LastForced) self.SetValue(self.LastValue) - + # Reset stored values self.LastValue = None self.LastForced = False - + def SetDataType(self, data_type): """ Set value IEC data type @param data_type: Value IEC data type """ self.DataType = data_type - + def NewValues(self, tick, values, raw="BOOL"): """ Function called by debug thread when a new debug value is available @@ -206,21 +206,21 @@ @param raw: Data type of values not translated (default: 'BOOL') """ value, forced = values - + # Translate value to IEC literal if self.DataType != raw: value = TYPE_TRANSLATOR.get(self.DataType, str)(value) - + # Store value and forced flag when value update is inhibited if self.Inhibited: self.LastValue = value self.LastForced = forced - + # Update value and forced flag in any other case else: self.SetForced(forced) self.SetValue(value) - + def SetValue(self, value): """ Update value. @@ -228,14 +228,14 @@ @param value: New value """ self.Value = value - + def GetValue(self): """ Return current value @return: Current value """ return self.Value - + def SetForced(self, forced): """ Update Forced flag. @@ -243,7 +243,7 @@ @param forced: New forced flag """ self.Forced = forced - + def IsForced(self): """ Indicate if current value is forced diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/FBD_Objects.py --- a/graphics/FBD_Objects.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/FBD_Objects.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,7 +39,7 @@ return name in ["OUT", "MN", "MX"] or name.startswith("IN") and (block_type, name) != ("EXPT", "IN2") class FBD_Block(Graphic_Element): - + # Create a new block def __init__(self, parent, type, name, id = None, extension = 0, inputs = None, connectors = {}, executionControl = False, executionOrder = 0): Graphic_Element.__init__(self, parent) @@ -56,7 +56,7 @@ self.Pen = MiterPen(wx.BLACK) self.SetType(type, extension, inputs, connectors, executionControl) self.Highlights = {} - + # Make a clone of this FBD_Block def Clone(self, parent, id = None, name = "", pos = None): if self.Name != "" and name == "": @@ -70,10 +70,10 @@ block.Inputs = [input.Clone(block) for input in self.Inputs] block.Outputs = [output.Clone(block) for output in self.Outputs] return block - + def GetConnectorTranslation(self, element): return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs)) - + def Flush(self): for input in self.Inputs: input.Flush() @@ -81,7 +81,7 @@ for output in self.Outputs: output.Flush() self.Outputs = [] - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -93,26 +93,26 @@ if output.IsConnected(): rect = rect.Union(output.GetConnectedRedrawRect(movex, movey)) return rect - + # Delete this block by calling the appropriate method def Delete(self): self.Parent.DeleteBlock(self) - + # Unconnect all inputs and outputs def Clean(self): for input in self.Inputs: input.UnConnect(delete = True) for output in self.Outputs: output.UnConnect(delete = True) - + # Refresh the size of text for name def RefreshNameSize(self): self.NameSize = self.Parent.GetTextExtent(self.Name) - + # Refresh the size of text for execution order def RefreshExecutionOrderSize(self): self.ExecutionOrderSize = self.Parent.GetTextExtent(str(self.ExecutionOrder)) - + # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): if self.Name != "": @@ -121,7 +121,7 @@ test_text = False test_block = self.GetBlockBoundingBox(connectors).InsideXY(pt.x, pt.y) return test_text or test_block - + # Returns the bounding box of the name outside the block def GetTextBoundingBox(self): # Calculate the size of the name outside the block @@ -130,7 +130,7 @@ self.Pos.y - (text_height + 2), text_width, text_height) - + # Returns the bounding box of function block without name outside def GetBlockBoundingBox(self, connectors=True): bbx_x, bbx_y = self.Pos.x, self.Pos.y @@ -143,13 +143,13 @@ bbx_width = max(bbx_width, bbx_width + self.Pos.x + self.ExecutionOrderSize[0] - bbx_x - self.Size[0]) bbx_height = bbx_height + (self.ExecutionOrderSize[1] + 2) return wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1) - + # Refresh the block bounding box def RefreshBoundingBox(self): self.BoundingBox = self.GetBlockBoundingBox() if self.Name != "": self.BoundingBox.Union(self.GetTextBoundingBox()) - + # Refresh the positions of the block connectors def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -170,15 +170,15 @@ self.Outputs[i].SetPosition(wx.Point(self.Size[0], ypos)) position += linesize self.RefreshConnected() - + # Refresh the positions of wires connected to inputs and outputs def RefreshConnected(self, exclude = []): for input in self.Inputs: input.MoveConnected(exclude) for output in self.Outputs: output.MoveConnected(exclude) - - # Returns the block connector that starts with the point given if it exists + + # Returns the block connector that starts with the point given if it exists def GetConnector(self, position, output_name = None, input_name = None): if input_name is not None: # Test each input connector @@ -193,14 +193,14 @@ if input_name is None and output_name is None: return self.FindNearestConnector(position, self.Inputs + self.Outputs) return None - + def GetInputTypes(self): return tuple([input.GetType(True) for input in self.Inputs if input.GetName() != "EN"]) - + def SetOutputValues(self, values): for output in self.Outputs: output.SetValue(values.get(ouput.getName(), None)) - + def GetConnectionResultType(self, connector, connectortype): if not TestConnectorName(connector.GetName(), self.Type): return connectortype @@ -216,11 +216,11 @@ if resulttype is None or outputtype is not None and self.IsOfType(outputtype, resulttype): resulttype = outputtype return resulttype - + # Returns all the block connectors def GetConnectors(self): return {"inputs" : self.Inputs, "outputs" : self.Outputs} - + # Test if point given is on one of the block connectors def TestConnector(self, pt, direction = None, exclude = True): # Test each input connector @@ -232,10 +232,10 @@ if output.TestPoint(pt, direction, exclude): return output return None - + # Changes the block type def SetType(self, type, extension, inputs = None, connectors = {}, executionControl = False): - if type != self.Type or self.Extension != extension or executionControl != self.ExecutionControl: + if type != self.Type or self.Extension != extension or executionControl != self.ExecutionControl: if type != self.Type: self.Type = type self.TypeSize = self.Parent.GetTextExtent(self.Type) @@ -264,7 +264,7 @@ inputs.insert(0, ("EN","BOOL","none")) outputs.insert(0, ("ENO","BOOL","none")) self.Pen = MiterPen(self.Colour) - + # Extract the inputs properties and create or modify the corresponding connector input_connectors = [] for input_name, input_type, input_modifier in inputs: @@ -284,7 +284,7 @@ for input in self.Inputs: input.UnConnect(delete = True) self.Inputs = input_connectors - + # Extract the outputs properties and create or modify the corresponding connector output_connectors = [] for output_name, output_type, output_modifier in outputs: @@ -304,47 +304,47 @@ for output in self.Outputs: output.UnConnect(delete = True) self.Outputs = output_connectors - + self.RefreshMinSize() self.RefreshConnectors() for output in self.Outputs: output.RefreshWires() self.RefreshBoundingBox() - + # Returns the block type def GetType(self): return self.Type - + # Changes the block name def SetName(self, name): self.Name = name self.RefreshNameSize() - + # Returs the block name def GetName(self): return self.Name - + # Changes the extension name def SetExtension(self, extension): self.Extension = extension - + # Returs the extension name def GetExtension(self): return self.Extension - + # Changes the execution order def SetExecutionOrder(self, executionOrder): self.ExecutionOrder = executionOrder self.RefreshExecutionOrderSize() - + # Returs the execution order def GetExecutionOrder(self): return self.ExecutionOrder - + # Returs the execution order def GetExecutionControl(self): return self.ExecutionControl - + # Refresh the block minimum size def RefreshMinSize(self): # Calculate the inputs maximum width @@ -360,25 +360,25 @@ width = max(self.TypeSize[0] + 10, max_input + max_output + 15) height = (max(len(self.Inputs), len(self.Outputs)) + 1) * BLOCK_LINE_SIZE self.MinSize = width, height - + # Returns the block minimum size def GetMinSize(self): return self.MinSize - + # Changes the negated property of the connector handled def SetConnectorNegated(self, negated): handle_type, handle = self.Handle if handle_type == HANDLE_CONNECTOR: handle.SetNegated(negated) self.RefreshModel(False) - + # Changes the edge property of the connector handled def SetConnectorEdge(self, edge): handle_type, handle = self.Handle if handle_type == HANDLE_CONNECTOR: handle.SetEdge(edge) self.RefreshModel(False) - + ## # Method called when a Motion event have been generated ## def OnMotion(self, event, dc, scaling): ## if not event.Dragging(): @@ -390,12 +390,12 @@ ## tip = wx.TipWindow(self.Parent, "Test") ## tip.SetBoundingRect(rect) ## return Graphic_Element.OnMotion(self, event, dc, scaling) - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the block properties self.Parent.EditBlockContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -406,7 +406,7 @@ self.Parent.PopupBlockMenu(connector) else: self.Parent.PopupBlockMenu() - + # Refreshes the block model def RefreshModel(self, move=True): self.Parent.RefreshBlockModel(self) @@ -414,10 +414,10 @@ if move: for output in self.Outputs: output.RefreshWires() - + def GetToolTipValue(self): return self.Description - + # Adds an highlight to the block def AddHighlight(self, infos, start, end ,highlight_type): if infos[0] in ["type", "name"] and start[0] == 0 and end[0] == 0: @@ -427,7 +427,7 @@ self.Inputs[infos[1]].AddHighlight(infos[2:], start, end, highlight_type) elif infos[0] == "output" and infos[1] < len(self.Outputs): self.Outputs[infos[1]].AddHighlight(infos[2:], start, end, highlight_type) - + # Removes an highlight from the block def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] in ["type", "name"]: @@ -438,7 +438,7 @@ self.Inputs[infos[1]].RemoveHighlight(infos[2:], start, end, highlight_type) elif infos[0] == "output" and infos[1] < len(self.Outputs): self.Outputs[infos[1]].RemoveHighlight(infos[2:], start, end, highlight_type) - + # Removes all the highlights of one particular type from the block def ClearHighlight(self, highlight_type=None): if highlight_type is None: @@ -453,14 +453,14 @@ input.ClearHighlights(highlight_type) for output in self.Outputs: output.ClearHighlights(highlight_type) - + # Draws block def Draw(self, dc): Graphic_Element.Draw(self, dc) dc.SetPen(self.Pen) dc.SetBrush(wx.WHITE_BRUSH) dc.SetTextForeground(self.Colour) - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) type_size = dc.GetTextExtent(self.Type) @@ -469,7 +469,7 @@ name_size = self.NameSize type_size = self.TypeSize executionorder_size = self.ExecutionOrderSize - + # Draw a rectangle with the block size dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) # Draw block name and block type @@ -488,11 +488,11 @@ # Draw block execution order dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0], self.Pos.y + self.Size[1] + 2) - + if not getattr(dc, "printing", False): DrawHighlightedText(dc, self.Name, self.Highlights.get("name", []), name_pos[0], name_pos[1]) DrawHighlightedText(dc, self.Type, self.Highlights.get("type", []), type_pos[0], type_pos[1]) - + #------------------------------------------------------------------------------- # Function Block Diagram Variable @@ -516,7 +516,7 @@ self.Output = None self.SetType(type, value_type) self.Highlights = [] - + # Make a clone of this FBD_Variable def Clone(self, parent, id = None, pos = None): variable = FBD_Variable(parent, self.Type, self.Name, self.ValueType, id) @@ -530,7 +530,7 @@ if self.Output: variable.Output = self.Output.Clone(variable) return variable - + def GetConnectorTranslation(self, element): connectors = {} if self.Input is not None: @@ -538,7 +538,7 @@ if self.Output is not None: connectors[self.Output] = element.Output return connectors - + def Flush(self): if self.Input is not None: self.Input.Flush() @@ -546,7 +546,7 @@ if self.Output is not None: self.Output.Flush() self.Output = None - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -556,26 +556,26 @@ if self.Output and self.Output.IsConnected(): rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey)) return rect - + # Unconnect connector def Clean(self): if self.Input: self.Input.UnConnect(delete = True) if self.Output: self.Output.UnConnect(delete = True) - + # Delete this variable by calling the appropriate method def Delete(self): self.Parent.DeleteVariable(self) - + # Refresh the size of text for name def RefreshNameSize(self): self.NameSize = self.Parent.GetTextExtent(self.Name) - + # Refresh the size of text for execution order def RefreshExecutionOrderSize(self): self.ExecutionOrderSize = self.Parent.GetTextExtent(str(self.ExecutionOrder)) - + # Refresh the variable bounding box def RefreshBoundingBox(self): if self.Type in (OUTPUT, INOUT): @@ -594,7 +594,7 @@ bbx_width = max(bbx_width, bbx_width + self.Pos.x + self.ExecutionOrderSize[0] - bbx_x - self.Size[0]) bbx_height = bbx_height + (self.ExecutionOrderSize[1] + 2) self.BoundingBox = wx.Rect(bbx_x, self.Pos.y, bbx_width + 1, bbx_height + 1) - + # Refresh the position of the variable connector def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -607,14 +607,14 @@ if self.Output: self.Output.SetPosition(wx.Point(self.Size[0], position)) self.RefreshConnected() - + # Refresh the position of wires connected to connector def RefreshConnected(self, exclude = []): if self.Input: self.Input.MoveConnected(exclude) if self.Output: self.Output.MoveConnected(exclude) - + # Test if point given is on the variable connector def TestConnector(self, pt, direction = None, exclude=True): if self.Input and self.Input.TestPoint(pt, direction, exclude): @@ -622,8 +622,8 @@ if self.Output and self.Output.TestPoint(pt, direction, exclude): return self.Output return None - - # Returns the block connector that starts with the point given if it exists + + # Returns the block connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -640,8 +640,8 @@ if self.Output: connectors.append(self.Output) return self.FindNearestConnector(position, connectors) - - # Returns all the block connectors + + # Returns all the block connectors def GetConnectors(self): connectors = {"inputs": [], "outputs": []} if self.Input: @@ -649,14 +649,14 @@ if self.Output: connectors["outputs"].append(self.Output) return connectors - + # Changes the negated property of the variable connector if handled def SetConnectorNegated(self, negated): handle_type, handle = self.Handle if handle_type == HANDLE_CONNECTOR: handle.SetNegated(negated) self.RefreshModel(False) - + # Changes the variable type def SetType(self, type, value_type): if type != self.Type: @@ -680,38 +680,38 @@ if self.Input: self.Input.SetType(value_type) if self.Output: - self.Output.SetType(value_type) - + self.Output.SetType(value_type) + # Returns the variable type def GetType(self): return self.Type - + # Returns the variable value type def GetValueType(self): return self.ValueType - + # Changes the variable name def SetName(self, name): self.Name = name self.RefreshNameSize() - + # Returns the variable name def GetName(self): return self.Name - + # Changes the execution order def SetExecutionOrder(self, executionOrder): self.ExecutionOrder = executionOrder self.RefreshExecutionOrderSize() - + # Returs the execution order def GetExecutionOrder(self): return self.ExecutionOrder - + # Returns the variable minimum size def GetMinSize(self): return self.NameSize[0] + 10, self.NameSize[1] + 10 - + # Set size of the variable to the minimum size def SetBestSize(self, scaling): if self.Type == INPUT: @@ -720,22 +720,22 @@ return Graphic_Element.SetBestSize(self, scaling, x_factor=0.) else: return Graphic_Element.SetBestSize(self, scaling) - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): if event.ControlDown(): - # Change variable type + # Change variable type types = [INPUT, OUTPUT, INOUT] self.Parent.ChangeVariableType(self, types[(types.index(self.Type) + 1) % len(types)]) else: # Edit the variable properties self.Parent.EditVariableContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): self.Parent.PopupVariableMenu() - + # Refreshes the variable model def RefreshModel(self, move=True): self.Parent.RefreshVariableModel(self) @@ -744,35 +744,35 @@ if move and self.Type != OUTPUT: if self.Output: self.Output.RefreshWires() - + # Adds an highlight to the variable def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "expression" and start[0] == 0 and end[0] == 0: AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the variable def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] == "expression": RemoveHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes all the highlights of one particular type from the variable def ClearHighlight(self, highlight_type=None): ClearHighlights(self.Highlights, highlight_type) - + # Draws variable def Draw(self, dc): Graphic_Element.Draw(self, dc) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) executionorder_size = dc.GetTextExtent(str(self.ExecutionOrder)) else: name_size = self.NameSize executionorder_size = self.ExecutionOrderSize - - text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, + + text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, self.Pos.y + (self.Size[1] - name_size[1]) / 2) # Draw a rectangle with the variable size dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) @@ -781,7 +781,7 @@ # Draw connectors if self.Input: self.Input.Draw(dc) - if self.Output: + if self.Output: self.Output.Draw(dc) if self.ExecutionOrder != 0: # Draw variable execution order @@ -789,7 +789,7 @@ self.Pos.y + self.Size[1] + 2) if not getattr(dc, "printing", False): DrawHighlightedText(dc, self.Name, self.Highlights, text_pos[0], text_pos[1]) - + #------------------------------------------------------------------------------- # Function Block Diagram Connector #------------------------------------------------------------------------------- @@ -816,12 +816,12 @@ self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), EAST) self.RefreshConnectors() self.RefreshNameSize() - + def Flush(self): if self.Connector: self.Connector.Flush() self.Connector = None - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -829,7 +829,7 @@ if self.Connector and self.Connector.IsConnected(): rect = rect.Union(self.Connector.GetConnectedRedrawRect(movex, movey)) return rect - + # Make a clone of this FBD_Connector def Clone(self, parent, id = None, pos = None): connection = FBD_Connector(parent, self.Type, self.Name, id) @@ -840,7 +840,7 @@ connection.SetPosition(self.Pos.x, self.Pos.y) connection.Connector = self.Connector.Clone(connection) return connection - + def GetConnectorTranslation(self, element): return {self.Connector : element.Connector} @@ -848,15 +848,15 @@ def Clean(self): if self.Connector: self.Connector.UnConnect(delete = True) - + # Delete this connection by calling the appropriate method def Delete(self): self.Parent.DeleteConnection(self) - + # Refresh the size of text for name def RefreshNameSize(self): self.NameSize = self.Parent.GetTextExtent(self.Name) - + # Refresh the connection bounding box def RefreshBoundingBox(self): if self.Type == CONNECTOR: @@ -865,7 +865,7 @@ bbx_x = self.Pos.x bbx_width = self.Size[0] + CONNECTOR_SIZE self.BoundingBox = wx.Rect(bbx_x, self.Pos.y, bbx_width, self.Size[1]) - + # Refresh the position of the connection connector def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -878,23 +878,23 @@ else: self.Connector.SetPosition(wx.Point(self.Size[0], position)) self.RefreshConnected() - + # Refresh the position of wires connected to connector def RefreshConnected(self, exclude = []): if self.Connector: self.Connector.MoveConnected(exclude) - + # Test if point given is on the connection connector def TestConnector(self, pt, direction = None, exclude=True): if self.Connector and self.Connector.TestPoint(pt, direction, exclude): return self.Connector return None - + # Returns the connection connector def GetConnector(self, position = None, name = None): return self.Connector - - # Returns all the block connectors + + # Returns all the block connectors def GetConnectors(self): connectors = {"inputs": [], "outputs": []} if self.Type == CONNECTOR: @@ -923,45 +923,45 @@ self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), EAST) self.RefreshConnectors() self.RefreshBoundingBox() - + # Returns the connection type def GetType(self): return self.Type - + def GetConnectionResultType(self, connector, connectortype): if self.Type == CONTINUATION: connector = self.Parent.GetConnectorByName(self.Name) if connector is not None: return connector.Connector.GetConnectedType() return connectortype - + # Changes the connection name def SetName(self, name): self.Name = name self.RefreshNameSize() - + # Returns the connection name def GetName(self): return self.Name - + # Set size of the variable to the minimum size def SetBestSize(self, scaling): if self.Type == CONTINUATION: return Graphic_Element.SetBestSize(self, scaling, x_factor=1.) else: return Graphic_Element.SetBestSize(self, scaling, x_factor=0.) - + # Returns the connection minimum size def GetMinSize(self): text_width, text_height = self.NameSize if text_height % 2 == 1: text_height += 1 return text_width + text_height + 20, text_height + 10 - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): if event.ControlDown(): - # Change connection type + # Change connection type if self.Type == CONNECTOR: self.Parent.ChangeConnectionType(self, CONTINUATION) else: @@ -969,12 +969,12 @@ else: # Edit the connection properties self.Parent.EditConnectionContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupConnectionMenu() - + # Refreshes the connection model def RefreshModel(self, move=True): self.Parent.RefreshConnectionModel(self) @@ -983,51 +983,50 @@ if move and self.Type == CONTINUATION: if self.Connector: self.Connector.RefreshWires() - + # Adds an highlight to the connection def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "name" and start[0] == 0 and end[0] == 0: AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the connection def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] == "name": RemoveHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes all the highlights of one particular type from the connection def ClearHighlight(self, highlight_type=None): ClearHighlights(self.Highlights, highlight_type) - + # Draws connection def Draw(self, dc): Graphic_Element.Draw(self, dc) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) else: name_size = self.NameSize - + # Draw a rectangle with the connection size with arrows inside dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) arrowsize = min(self.Size[1] / 2, (self.Size[0] - name_size[0] - 10) / 2) - dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize, + dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2) - dc.DrawLine(self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2, + dc.DrawLine(self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2, self.Pos.x, self.Pos.y + self.Size[1]) - dc.DrawLine(self.Pos.x + self.Size[0] - arrowsize, self.Pos.y, + dc.DrawLine(self.Pos.x + self.Size[0] - arrowsize, self.Pos.y, self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2) - dc.DrawLine(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2, + dc.DrawLine(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2, self.Pos.x + self.Size[0] - arrowsize, self.Pos.y + self.Size[1]) # Draw connection name - text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, + text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, self.Pos.y + (self.Size[1] - name_size[1]) / 2) dc.DrawText(self.Name, text_pos[0], text_pos[1]) # Draw connector if self.Connector: self.Connector.Draw(dc) - + if not getattr(dc, "printing", False): DrawHighlightedText(dc, self.Name, self.Highlights, text_pos[0], text_pos[1]) - diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/GraphicCommons.py Mon Aug 14 19:13:01 2017 +0300 @@ -83,12 +83,12 @@ # Contants for defining the direction of a connector [EAST, NORTH, WEST, SOUTH] = [(1,0), (0,-1), (-1,0), (0,1)] -# Contants for defining which mode is selected for each view -[MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, - MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP, +# Contants for defining which mode is selected for each view +[MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT, + MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP, MODE_TRANSITION, MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION, MODE_MOTION] = range(15) -# Contants for defining alignment types for graphic group +# Contants for defining alignment types for graphic group [ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM] = range(6) # Contants for defining which drawing mode is selected for app @@ -122,7 +122,7 @@ else: xround = round(fraction) if constraint == 1 and xround < fraction: - xround += 1 + xround += 1 return int(xround * n) """ @@ -224,7 +224,7 @@ dc.DrawText(part, x + offset_width, y) dc.SetPen(current_pen) dc.SetTextForeground(wx.BLACK) - + #------------------------------------------------------------------------------- # Graphic element base class #------------------------------------------------------------------------------- @@ -234,7 +234,7 @@ """ class Graphic_Element(ToolTipProducer): - + # Create a new graphic element def __init__(self, parent, id = None): ToolTipProducer.__init__(self, parent) @@ -251,22 +251,22 @@ self.Size = wx.Size(0, 0) self.BoundingBox = wx.Rect(0, 0, 0, 0) self.Visible = False - + def GetDefinition(self): return [self.Id], [] - + def TestVisible(self, screen): self.Visible = self.Selected or self.GetRedrawRect().Intersects(screen) - + def IsVisible(self): return self.Visible - + def SpreadCurrent(self): pass - + def GetConnectorTranslation(self, element): return {} - + def FindNearestConnector(self, position, connectors): distances = [] for connector in connectors: @@ -278,20 +278,20 @@ if len(distances) > 0: return distances[0][1] return None - + def IsOfType(self, type, reference): return self.Parent.IsOfType(type, reference) - + def IsEndType(self, type): return self.Parent.IsEndType(type) - + def GetDragging(self): return self.Dragging - + # Make a clone of this element def Clone(self, parent): return Graphic_Element(parent, self.Id) - + # Changes the block position def SetPosition(self, x, y): self.Pos.x = x @@ -302,7 +302,7 @@ # Returns the block position def GetPosition(self): return self.Pos.x, self.Pos.y - + # Changes the element size def SetSize(self, width, height): self.Size.SetWidth(width) @@ -313,11 +313,11 @@ # Returns the element size def GetSize(self): return self.Size.GetWidth(), self.Size.GetHeight() - + # Returns the minimum element size def GetMinSize(self): return 0, 0 - + # Set size of the element to the minimum size def SetBestSize(self, scaling, x_factor=0.5, y_factor=0.5): width, height = self.GetSize() @@ -336,31 +336,31 @@ height = round_scaling(height, scaling[1], 1) self.SetSize(width, height) return self.Pos.x - posx, self.Pos.y - posy - + # Refresh the element Bounding Box def RefreshBoundingBox(self): self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]) - + # Refresh the element connectors position def RefreshConnectors(self): pass - + # Refresh the position of wires connected to element inputs and outputs def RefreshConnected(self): pass - + # Change the parent def SetParent(self, parent): self.Parent = parent - + # Override this method for defining the method to call for deleting this element def Delete(self): pass - + # Returns the Id def GetId(self): return self.Id - + # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): if connectors: @@ -368,19 +368,19 @@ else: rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]) return rect.InsideXY(pt.x, pt.y) - + # Returns if the point given is in the bounding box def IsInSelection(self, rect): return rect.InsideXY(self.BoundingBox.x, self.BoundingBox.y) and rect.InsideXY(self.BoundingBox.x + self.BoundingBox.width, self.BoundingBox.y + self.BoundingBox.height) - + # Override this method for refreshing the bounding box def RefreshBoundingBox(self): pass - + # Returns the bounding box def GetBoundingBox(self): return self.BoundingBox - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): scalex, scaley = self.Parent.GetViewScale() @@ -390,42 +390,42 @@ rect.width = self.BoundingBox.width + 2 * (int(HANDLE_SIZE / scalex) + abs(movex) + 1) + 4 rect.height = self.BoundingBox.height + 2 * (int(HANDLE_SIZE / scaley) + abs(movey) + 1) + 4 return rect - + def Refresh(self, rect = None): if self.Visible: if rect is not None: self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False) else: self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()), False) - + # Change the variable that indicates if this element is selected def SetSelected(self, selected): self.Selected = selected self.Refresh() - + # Change the variable that indicates if this element is highlighted def SetHighlighted(self, highlighted): self.Highlighted = highlighted self.Refresh() - + # Test if the point is on a handle of this element def TestHandle(self, event): dc = self.Parent.GetLogicalDC() scalex, scaley = dc.GetUserScale() pos = event.GetPosition() pt = wx.Point(*self.Parent.CalcUnscrolledPosition(pos.x, pos.y)) - + left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2 right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex - + top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2 bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley - + extern_rect = wx.Rect(left, top, right + HANDLE_SIZE - left, bottom + HANDLE_SIZE - top) intern_rect = wx.Rect(left + HANDLE_SIZE, top + HANDLE_SIZE, right - left - HANDLE_SIZE, bottom - top - HANDLE_SIZE) - + # Verify that this element is selected if self.Selected and extern_rect.InsideXY(pt.x, pt.y) and not intern_rect.InsideXY(pt.x, pt.y): # Find if point is on a handle horizontally @@ -450,7 +450,7 @@ if (handle_x, handle_y) in VALID_HANDLES: return handle_x, handle_y return 0, 0 - + # Method called when a LeftDown event have been generated def OnLeftDown(self, event, dc, scaling): pos = event.GetLogicalPosition(dc) @@ -469,7 +469,7 @@ self.oldPos = GetScaledEventPosition(event, dc, scaling) self.StartPos = wx.Point(self.Pos.x, self.Pos.y) self.CurrentDrag = wx.Point(0, 0) - + # Method called when a LeftUp event have been generated def OnLeftUp(self, event, dc, scaling): # If a dragging have been initiated @@ -498,7 +498,7 @@ # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): pass - + # Method called when a Motion event have been generated def OnMotion(self, event, dc, scaling): # If the cursor is dragging and the element have been clicked @@ -537,12 +537,12 @@ self.Pos.y += max(-self.BoundingBox.y, dy) self.RefreshConnected(exclude) self.RefreshBoundingBox() - + # Resizes the element from position and size given def Resize(self, x, y, width, height): self.Move(x, y) self.SetSize(width, height) - + # Refreshes the element state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling, width_fac = 1, height_fac = 1): handle_type, handle = self.Handle @@ -618,27 +618,27 @@ movey = self.StartPos.y - self.Pos.y else: movex = self.StartPos.x - self.Pos.x - movey = self.StartPos.y + self.CurrentDrag.y - self.Pos.y + movey = self.StartPos.y + self.CurrentDrag.y - self.Pos.y self.Move(movex, movey) return movex, movey return 0, 0 - + # Override this method for defining the method to call for adding an highlight to this element def AddHighlight(self, infos, start, end, highlight_type): pass - + # Override this method for defining the method to call for removing an highlight from this element def RemoveHighlight(self, infos, start, end, highlight_type): pass - + # Override this method for defining the method to call for removing all the highlights of one particular type from this element def ClearHighlight(self, highlight_type=None): pass - + # Override this method for defining the method to call for refreshing the model of this element def RefreshModel(self, move=True): pass - + # Draws the highlightment of this element if it is highlighted (can be overwritten) def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -646,13 +646,13 @@ dc.SetPen(MiterPen(HIGHLIGHTCOLOR)) dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) dc.SetLogicalFunction(wx.AND) - dc.DrawRectangle(int(round((self.Pos.x - 1) * scalex)) - 2, - int(round((self.Pos.y - 1) * scaley)) - 2, - int(round((self.Size.width + 3) * scalex)) + 5, + dc.DrawRectangle(int(round((self.Pos.x - 1) * scalex)) - 2, + int(round((self.Pos.y - 1) * scaley)) - 2, + int(round((self.Size.width + 3) * scalex)) + 5, int(round((self.Size.height + 3) * scaley)) + 5) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Draws the handles of this element if it is selected def Draw(self, dc): if not getattr(dc, "printing", False): @@ -663,20 +663,20 @@ dc.SetUserScale(1, 1) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.BLACK_BRUSH) - + left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2 right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex - + top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2 bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley - + for x, y in [(left, top), (center, top), (right, top), (left, middle), (right, middle), (left, bottom), (center, bottom), (right, bottom)]: dc.DrawRectangle(x, y, HANDLE_SIZE, HANDLE_SIZE) - + dc.SetUserScale(scalex, scaley) @@ -689,27 +689,27 @@ """ class Graphic_Group(Graphic_Element): - + # Create a new group of graphic elements def __init__(self, parent): Graphic_Element.__init__(self, parent) self.Elements = [] self.RefreshWireExclusion() self.RefreshBoundingBox() - + # Destructor def __del__(self): self.Elements = [] - + def GetDefinition(self): - blocks = [] + blocks = [] wires = [] for element in self.Elements: block, wire = element.GetDefinition() blocks.extend(block) wires.extend(wire) return blocks, wires - + # Make a clone of this element def Clone(self, parent, pos = None): group = Graphic_Group(parent) @@ -751,20 +751,20 @@ if not isinstance(element, Wire): parent.AddBlockInModel(element) return group - + def CanAddBlocks(self, parent): valid = True for element in self.Elements: if not isinstance(element, Wire): valid &= parent.CanAddElement(element) return valid - + def IsVisible(self): for element in self.Elements: if element.IsVisible(): return True return False - + # Refresh the list of wire excluded def RefreshWireExclusion(self): self.WireExcluded = [] @@ -774,7 +774,7 @@ endblock = element.EndConnected.GetParentBlock() if startblock in self.Elements and endblock in self.Elements: self.WireExcluded.append(element) - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = None @@ -784,41 +784,41 @@ else: rect = rect.Union(element.GetRedrawRect(movex, movey)) return rect - + # Clean this group of elements def Clean(self): # Clean all the elements of the group for element in self.Elements: element.Clean() - + # Delete this group of elements def Delete(self): # Delete all the elements of the group for element in self.Elements: element.Delete() self.WireExcluded = [] - + # Returns if the point given is in the bounding box of one of the elements of this group def HitTest(self, pt, connectors=True): result = False for element in self.Elements: result |= element.HitTest(pt, connectors) return result - + # Returns if the element given is in this group def IsElementIn(self, element): return element in self.Elements - + # Change the elements of the group def SetElements(self, elements): self.Elements = elements self.RefreshWireExclusion() self.RefreshBoundingBox() - + # Returns the elements of the group def GetElements(self): return self.Elements - + # Align the group elements def AlignElements(self, horizontally, vertically): minx = self.BoundingBox.x + self.BoundingBox.width @@ -854,11 +854,11 @@ element.Move(movex, movey) element.RefreshModel() self.RefreshBoundingBox() - + # Add the given element to the group of elements def AddElement(self, element): self.Elements.append(element) - + # Remove or select the given element if it is or not in the group def SelectElement(self, element): if element in self.Elements: @@ -867,7 +867,7 @@ self.Elements.append(element) self.RefreshWireExclusion() self.RefreshBoundingBox() - + # Move this group of elements def Move(self, movex, movey): movex = max(-self.BoundingBox.x, movex) @@ -879,7 +879,7 @@ elif element in self.WireExcluded: element.Move(movex, movey, True) self.RefreshBoundingBox() - + # Refreshes the bounding box of this group of elements def RefreshBoundingBox(self): if len(self.Elements) > 0: @@ -902,7 +902,7 @@ # Forbids to change the group position def SetPosition(x, y): pass - + # Returns the position of this group def GetPosition(self, exclude_wires=False): if exclude_wires: @@ -919,15 +919,15 @@ return 0, 0 return posx, posy return self.BoundingBox.x, self.BoundingBox.y - + # Forbids to change the group size def SetSize(width, height): pass - + # Returns the size of this group def GetSize(self): return self.BoundingBox.width, self.BoundingBox.height - + # Set size of the group elements to their minimum size def SetBestSize(self, scaling): max_movex = max_movey = 0 @@ -936,7 +936,7 @@ max_movex = max(max_movex, movex) max_movey = max(max_movey, movey) return max_movex, max_movey - + # Refreshes the group elements to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): handle_type, handle = self.Handle @@ -960,17 +960,17 @@ self.Move(movex, movey) return movex, movey return 0, 0 - + # Change the variable that indicates if this element is highlighted def SetHighlighted(self, highlighted): for element in self.Elements: element.SetHighlighted(highlighted) - + def HighlightPoint(self, pos): for element in self.Elements: if isinstance(element, Wire): element.HighlightPoint(pos) - + # Method called when a LeftDown event have been generated def OnLeftDown(self, event, dc, scaling): Graphic_Element.OnLeftDown(self, event, dc, scaling) @@ -1007,7 +1007,7 @@ """ class Connector(DebugDataConsumer, ToolTipProducer): - + # Create a new connector def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False): DebugDataConsumer.__init__(self) @@ -1033,13 +1033,13 @@ self.Selected = False self.Highlights = [] self.RefreshNameSize() - + def Flush(self): self.ParentBlock = None for wire, handle in self.Wires: wire.Flush() self.Wires = [] - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): parent_pos = self.ParentBlock.GetPosition() @@ -1072,22 +1072,22 @@ height * (self.Direction[1] - 1), width, height)) return rect - + # Change the connector selection def SetSelected(self, selected): self.Selected = selected - + # Make a clone of the connector def Clone(self, parent = None): if parent is None: parent = self.ParentBlock return Connector(parent, self.Name, self.Type, wx.Point(self.Pos[0], self.Pos[1]), self.Direction, self.Negated) - + # Returns the connector parent block def GetParentBlock(self): return self.ParentBlock - + # Returns the connector type def GetType(self, raw = False): if self.ParentBlock.IsEndType(self.Type) or raw: @@ -1096,7 +1096,7 @@ return "BOOL" else: return self.ParentBlock.GetConnectionResultType(self, self.Type) - + # Returns the connector type def GetConnectedType(self): if self.ParentBlock.IsEndType(self.Type): @@ -1104,7 +1104,7 @@ elif len(self.Wires) == 1: return self.Wires[0][0].GetOtherConnectedType(self.Wires[0][1]) return self.Type - + # Returns the connector type def GetConnectedRedrawRect(self, movex, movey): rect = None @@ -1114,22 +1114,22 @@ else: rect = rect.Union(wire.GetRedrawRect()) return rect - + # Returns if connector type is compatible with type given def IsCompatible(self, type): reference = self.GetType() return self.ParentBlock.IsOfType(type, reference) or self.ParentBlock.IsOfType(reference, type) - + # Changes the connector name def SetType(self, type): self.Type = type for wire, handle in self.Wires: wire.SetValid(wire.IsConnectedCompatible()) - + # Returns the connector name def GetName(self): return self.Name - + # Changes the connector name def SetName(self, name): self.Name = name @@ -1140,15 +1140,15 @@ self.Forced = forced if self.Visible: self.Parent.ElementNeedRefresh(self) - + def GetComputedValue(self): if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): return self.Value return None - + def GetToolTipValue(self): return self.GetComputedValue() - + def SetValue(self, value): if self.Value != value: self.Value = value @@ -1161,7 +1161,7 @@ self.ValueSize = None if self.ParentBlock.Visible: self.ParentBlock.Parent.ElementNeedRefresh(self) - + def RefreshForced(self): self.Forced = False for wire, handle in self.Wires: @@ -1169,12 +1169,12 @@ def RefreshValue(self): self.Value = self.ReceivingCurrent() - + def RefreshValid(self): self.Valid = True for wire, handle in self.Wires: self.Valid &= wire.GetValid() - + def ReceivingCurrent(self): current = False for wire, handle in self.Wires: @@ -1184,34 +1184,34 @@ elif value == "undefined": current = "undefined" return current - + def SpreadCurrent(self, spreading): for wire, handle in self.Wires: wire.SetValue(spreading) - + # Changes the connector name size def RefreshNameSize(self): if self.Name != "": self.NameSize = self.ParentBlock.Parent.GetTextExtent(self.Name) else: self.NameSize = 0, 0 - + # Returns the connector name size def GetNameSize(self): return self.NameSize - + # Returns the wires connected to the connector def GetWires(self): return self.Wires - + # Returns the parent block Id def GetBlockId(self): return self.ParentBlock.GetId() - + # Returns the connector relative position def GetRelPosition(self): return self.Pos - + # Returns the connector absolute position def GetPosition(self, size = True): parent_pos = self.ParentBlock.GetPosition() @@ -1223,23 +1223,23 @@ x = parent_pos[0] + self.Pos.x y = parent_pos[1] + self.Pos.y return wx.Point(x, y) - + # Change the connector relative position def SetPosition(self, pos): self.Pos = pos - + # Returns the connector direction def GetDirection(self): return self.Direction - + # Change the connector direction def SetDirection(self, direction): self.Direction = direction - + # Connect a wire to this connector at the last place def Connect(self, wire, refresh = True): self.InsertConnect(len(self.Wires), wire, refresh) - + # Connect a wire to this connector at the place given def InsertConnect(self, idx, wire, refresh = True): if wire not in self.Wires: @@ -1250,14 +1250,14 @@ wire[0].ConnectEndPoint(None, self) if refresh: self.ParentBlock.RefreshModel(False) - + # Returns the index of the wire given in the list of connected def GetWireIndex(self, wire): for i, (tmp_wire, handle) in enumerate(self.Wires): if tmp_wire == wire: return i return None - + # Unconnect a wire or all wires connected to the connector def UnConnect(self, wire = None, unconnect = True, delete = False): i = 0 @@ -1281,11 +1281,11 @@ if not delete: self.RefreshValid() self.ParentBlock.RefreshModel(False) - + # Returns if connector has one or more wire connected def IsConnected(self): return len(self.Wires) > 0 - + # Move the wires connected def MoveConnected(self, exclude = []): if len(self.Wires) > 0: @@ -1300,21 +1300,21 @@ wire.MoveStartPoint(wx.Point(x, y)) else: wire.MoveEndPoint(wx.Point(x, y)) - + # Refreshes the model of all the wires connected def RefreshWires(self): for wire in self.Wires: wire[0].RefreshModel() - + # Refreshes the parent block model def RefreshParentBlock(self): self.ParentBlock.RefreshModel(False) - + # Highlight the parent block def HighlightParentBlock(self, highlight): self.ParentBlock.SetHighlighted(highlight) self.ParentBlock.Refresh() - + # Returns all the blocks connected to this connector def GetConnectedBlocks(self): blocks = [] @@ -1330,31 +1330,31 @@ if block not in blocks: blocks.append(block) return blocks - + # Returns the connector negated property def IsNegated(self): return self.Negated - + # Changes the connector negated property def SetNegated(self, negated): if self.ParentBlock.IsOfType("BOOL", self.Type): self.Negated = negated self.Edge = "none" - + # Returns the connector edge property def GetEdge(self): return self.Edge - + # Changes the connector edge property def SetEdge(self, edge): if self.ParentBlock.IsOfType("BOOL", self.Type): - self.Edge = edge + self.Edge = edge self.Negated = False - + # assume that pointer is already inside of this connector def ConnectionAvailable(self, direction=None, exclude=True): wire_nums = len(self.Wires) - + connector_free = (wire_nums<= 0) connector_max_used = ((wire_nums > 0) and self.OneConnected) if (self.Parent.CurrentLanguage in ["SFC", "LD"]) and (self.Type == "BOOL"): @@ -1363,7 +1363,7 @@ # connector is available for new connection connect = connector_free or not connector_max_used return connect, connector_max_used - + # Tests if the point given is near from the end point of this connector def TestPoint(self, pt, direction=None, exclude=True): inside = False; @@ -1378,9 +1378,9 @@ height = ANCHOR_DISTANCE * 2 + abs(self.Direction[1]) * CONNECTOR_SIZE rect = wx.Rect(x, y, width, height) inside = rect.InsideXY(pt.x, pt.y); - + return inside - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -1393,7 +1393,7 @@ parent_pos = self.ParentBlock.GetPosition() posx = parent_pos[0] + self.Pos.x posy = parent_pos[1] + self.Pos.y - xstart = parent_pos[0] + self.Pos.x + xstart = parent_pos[0] + self.Pos.x ystart = parent_pos[1] + self.Pos.y if self.Direction[0] < 0: xstart += 1 @@ -1401,18 +1401,18 @@ ystart += 1 xend = xstart + CONNECTOR_SIZE * self.Direction[0] yend = ystart + CONNECTOR_SIZE * self.Direction[1] - dc.DrawLine(round((xstart + self.Direction[0]) * scalex), round((ystart + self.Direction[1]) * scaley), + dc.DrawLine(round((xstart + self.Direction[0]) * scalex), round((ystart + self.Direction[1]) * scaley), round(xend * scalex), round(yend * scaley)) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Adds an highlight to the connector def AddHighlight(self, infos, start, end, highlight_type): if highlight_type == ERROR_HIGHLIGHT: for wire, handle in self.Wires: wire.SetValid(False) AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the connector def RemoveHighlight(self, infos, start, end, highlight_type): error = False @@ -1425,7 +1425,7 @@ if not error: for wire, handle in self.Wires: wire.SetValid(wire.IsConnectedCompatible()) - + # Removes all the highlights of one particular type from the connector def ClearHighlight(self, highlight_type=None): error = False @@ -1441,7 +1441,7 @@ if not error: for wire, handle in self.Wires: wire.SetValid(wire.IsConnectedCompatible()) - + # Draws the connector def Draw(self, dc): if self.Selected: @@ -1466,19 +1466,19 @@ dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) parent_pos = self.ParentBlock.GetPosition() - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) else: name_size = self.NameSize - + if self.Negated: # If connector is negated, draw a circle xcenter = parent_pos[0] + self.Pos.x + (CONNECTOR_SIZE * self.Direction[0]) / 2 ycenter = parent_pos[1] + self.Pos.y + (CONNECTOR_SIZE * self.Direction[1]) / 2 dc.DrawCircle(xcenter, ycenter, CONNECTOR_SIZE / 2) else: - xstart = parent_pos[0] + self.Pos.x + xstart = parent_pos[0] + self.Pos.x ystart = parent_pos[1] + self.Pos.y if self.Edge == "rising": # If connector has a rising edge, draw a right arrow @@ -1524,7 +1524,7 @@ self.ValueSize = self.ParentBlock.Parent.GetMiniTextExtent(self.ComputedValue) if self.ValueSize is not None: width, height = self.ValueSize - dc.DrawText(self.ComputedValue, + dc.DrawText(self.ComputedValue, parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] + \ width * (self.Direction[0] - 1) / 2, parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] + \ @@ -1541,7 +1541,7 @@ """ class Wire(Graphic_Element, DebugDataConsumer): - + # Create a new wire def __init__(self, parent, start = None, end = None): Graphic_Element.__init__(self, parent) @@ -1568,18 +1568,18 @@ self.ComputingType = False self.Font = parent.GetMiniFont() self.ErrHighlight = False - + def GetDefinition(self): if self.StartConnected is not None and self.EndConnected is not None: startblock = self.StartConnected.GetParentBlock() endblock = self.EndConnected.GetParentBlock() return [], [(startblock.GetId(), endblock.GetId())] return [], [] - + def Flush(self): self.StartConnected = None self.EndConnected = None - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -1607,7 +1607,7 @@ y = self.Points[middle].y - height rect = rect.Union(wx.Rect(x, y, width, height)) return rect - + def Clone(self, parent, connectors = {}, dx = 0, dy = 0): start_connector = connectors.get(self.StartConnected, None) end_connector = connectors.get(self.EndConnected, None) @@ -1620,18 +1620,18 @@ wire.ConnectEndPoint(end_connector.GetPosition(), end_connector) return wire return None - + # Forbids to change the wire position def SetPosition(x, y): pass - + # Forbids to change the wire size def SetSize(width, height): pass - + # Forbids to et size of the group elements to their minimum size pass - + # Moves and Resizes the element for fitting scaling def SetBestSize(self, scaling): if scaling is not None: @@ -1664,11 +1664,11 @@ point.y += movey return movex_max, movey_max return 0, 0 - + # Returns connector to which start point is connected def GetStartConnected(self): return self.StartConnected - + # Returns connector to which start point is connected def GetStartConnectedType(self): if self.StartConnected and not self.ComputingType: @@ -1677,11 +1677,11 @@ self.ComputingType = False return computed_type return None - + # Returns connector to which end point is connected def GetEndConnected(self): return self.EndConnected - + # Returns connector to which end point is connected def GetEndConnectedType(self): if self.EndConnected and not self.ComputingType: @@ -1690,7 +1690,7 @@ self.ComputingType = False return computed_type return None - + def GetConnectionDirection(self): if self.StartConnected is None and self.EndConnected is None: return None @@ -1707,26 +1707,26 @@ else: return (-self.StartPoint[1][0], -self.StartPoint[1][1]) return None - + def GetOtherConnected(self, connector): if self.StartConnected == connector: return self.EndConnected else: return self.StartConnected - + def GetOtherConnectedType(self, handle): if handle == 0: return self.GetEndConnectedType() else: return self.GetStartConnectedType() - + def IsConnectedCompatible(self): if self.StartConnected: return self.StartConnected.IsCompatible(self.GetEndConnectedType()) elif self.EndConnected: return True return False - + def SetForced(self, forced): if self.Forced != forced: self.Forced = forced @@ -1741,7 +1741,7 @@ if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType): return self.Value return None - + def GetToolTipValue(self): return self.GetComputedValue() @@ -1773,18 +1773,18 @@ if isinstance(value, BooleanType) and self.StartConnected is not None: block = self.StartConnected.GetParentBlock() block.SpreadCurrent() - + # Unconnect the start and end points def Clean(self): if self.StartConnected: self.UnConnectStartPoint() if self.EndConnected: self.UnConnectEndPoint() - + # Delete this wire by calling the corresponding method def Delete(self): self.Parent.DeleteWire(self) - + # Select a segment and not the whole wire. It's useful for Ladder Diagram def SetSelectedSegment(self, segment): # The last segment is indicated @@ -1814,17 +1814,17 @@ self.EndConnected.SetSelected(True) self.SelectedSegment = segment self.Refresh() - + def SetValid(self, valid): self.Valid = valid if self.StartConnected: self.StartConnected.RefreshValid() if self.EndConnected: self.EndConnected.RefreshValid() - + def GetValid(self): return self.Valid - + # Reinitialize the wire points def ResetPoints(self): if self.StartPoint and self.EndPoint: @@ -1833,7 +1833,7 @@ else: self.Points = [] self.Segments = [] - + # Refresh the wire bounding box def RefreshBoundingBox(self): if len(self.Points) > 0: @@ -1862,7 +1862,7 @@ self.Pos.x, self.Pos.y = minx, miny self.Size = wx.Size(maxx - minx, maxy - miny) self.BoundingBox = wx.Rect(minbbxx, minbbxy, maxbbxx - minbbxx + 1, maxbbxy - minbbxy + 1) - + # Refresh the realpoints that permits to keep the proportionality in wire during resizing def RefreshRealPoints(self): if len(self.Points) > 0: @@ -1870,8 +1870,8 @@ # Calculate float relative position of each point with the minimum point for point in self.Points: self.RealPoints.append([float(point.x - self.Pos.x), float(point.y - self.Pos.y)]) - - # Returns the wire minimum size + + # Returns the wire minimum size def GetMinSize(self): width = 1 height = 1 @@ -1893,7 +1893,7 @@ width = MIN_SEGMENT_SIZE height = MIN_SEGMENT_SIZE return width + 1, height + 1 - + # Returns if the point given is on one of the wire segments def HitTest(self, pt, connectors=True): test = False @@ -1903,7 +1903,7 @@ x1 = self.Points[i].x - self.Segments[0][0] * CONNECTOR_SIZE y1 = self.Points[i].y - self.Segments[0][1] * CONNECTOR_SIZE else: - x1, y1 = self.Points[i].x, self.Points[i].y + x1, y1 = self.Points[i].x, self.Points[i].y if i == len(self.Points) - 2 and self.EndConnected is not None: x2 = self.Points[i + 1].x + self.Segments[-1][0] * CONNECTOR_SIZE y2 = self.Points[i + 1].y + self.Segments[-1][1] * CONNECTOR_SIZE @@ -1912,10 +1912,10 @@ # Calculate a rectangle around the segment rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE, abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE) - test |= rect.InsideXY(pt.x, pt.y) + test |= rect.InsideXY(pt.x, pt.y) return test - - # Returns the wire start or end point if the point given is on one of them + + # Returns the wire start or end point if the point given is on one of them def TestPoint(self, pt): # Test the wire start point rect = wx.Rect(self.Points[0].x - ANCHOR_DISTANCE, self.Points[0].y - ANCHOR_DISTANCE, @@ -1929,7 +1929,7 @@ if rect.InsideXY(pt.x, pt.y): return -1 return None - + # Returns the wire segment if the point given is on it def TestSegment(self, pt, all=False): for i in xrange(len(self.Segments)): @@ -1943,7 +1943,7 @@ if rect.InsideXY(pt.x, pt.y): return i, self.Segments[i] return None - + # Define the wire points def SetPoints(self, points, verify=True): if len(points) > 1: @@ -1952,9 +1952,9 @@ self.StartPoint = [None, vector(self.Points[0], self.Points[1])] self.EndPoint = [None, vector(self.Points[-1], self.Points[-2])] # Calculate the start and end points - self.StartPoint[0] = wx.Point(self.Points[0].x + CONNECTOR_SIZE * self.StartPoint[1][0], + self.StartPoint[0] = wx.Point(self.Points[0].x + CONNECTOR_SIZE * self.StartPoint[1][0], self.Points[0].y + CONNECTOR_SIZE * self.StartPoint[1][1]) - self.EndPoint[0] = wx.Point(self.Points[-1].x + CONNECTOR_SIZE * self.EndPoint[1][0], + self.EndPoint[0] = wx.Point(self.Points[-1].x + CONNECTOR_SIZE * self.EndPoint[1][0], self.Points[-1].y + CONNECTOR_SIZE * self.EndPoint[1][1]) self.Points[0] = self.StartPoint[0] self.Points[-1] = self.EndPoint[0] @@ -1979,37 +1979,37 @@ i += 1 self.RefreshBoundingBox() self.RefreshRealPoints() - + # Returns the position of the point indicated def GetPoint(self, index): if index < len(self.Points): return self.Points[index].x, self.Points[index].y return None - + # Returns a list of the position of all wire points def GetPoints(self, invert = False): points = self.VerifyPoints() - points[0] = wx.Point(points[0].x - CONNECTOR_SIZE * self.StartPoint[1][0], + points[0] = wx.Point(points[0].x - CONNECTOR_SIZE * self.StartPoint[1][0], points[0].y - CONNECTOR_SIZE * self.StartPoint[1][1]) - points[-1] = wx.Point(points[-1].x - CONNECTOR_SIZE * self.EndPoint[1][0], + points[-1] = wx.Point(points[-1].x - CONNECTOR_SIZE * self.EndPoint[1][0], points[-1].y - CONNECTOR_SIZE * self.EndPoint[1][1]) # An inversion of the list is asked if invert: points.reverse() return points - + # Returns the position of the two selected segment points def GetSelectedSegmentPoints(self): if self.SelectedSegment != None and len(self.Points) > 1: return self.Points[self.SelectedSegment:self.SelectedSegment + 2] return [] - + # Returns if the selected segment is the first and/or the last of the wire def GetSelectedSegmentConnections(self): if self.SelectedSegment != None and len(self.Points) > 1: return self.SelectedSegment == 0, self.SelectedSegment == len(self.Segments) - 1 return (True, True) - + # Returns the connectors on which the wire is connected def GetConnected(self): connected = [] @@ -2018,7 +2018,7 @@ if self.EndConnected and self.EndPoint[1] == WEST: connected.append(self.EndConnected) return connected - + # Returns the id of the block connected to the first or the last wire point def GetConnectedInfos(self, index): if index == 0 and self.StartConnected: @@ -2026,14 +2026,14 @@ elif index == -1 and self.EndConnected: return self.EndConnected.GetBlockId(), self.EndConnected.GetName() return None - + # Update the wire points position by keeping at most possible the current positions def GeneratePoints(self, realpoints = True): i = 0 # Calculate the start enad end points with the minimum segment size in the right direction end = wx.Point(self.EndPoint[0].x + self.EndPoint[1][0] * MIN_SEGMENT_SIZE, self.EndPoint[0].y + self.EndPoint[1][1] * MIN_SEGMENT_SIZE) - start = wx.Point(self.StartPoint[0].x + self.StartPoint[1][0] * MIN_SEGMENT_SIZE, + start = wx.Point(self.StartPoint[0].x + self.StartPoint[1][0] * MIN_SEGMENT_SIZE, self.StartPoint[0].y + self.StartPoint[1][1] * MIN_SEGMENT_SIZE) # Evaluate the point till it's the last while i < len(self.Points) - 1: @@ -2046,14 +2046,14 @@ # If the end point is not in the start direction, a point is added if v_end != self.Segments[0] or v_end == self.EndPoint[1]: self.Points.insert(1, wx.Point(start.x, start.y)) - self.Segments.insert(1, DirectionChoice((self.Segments[0][1], + self.Segments.insert(1, DirectionChoice((self.Segments[0][1], self.Segments[0][0]), v_end, self.EndPoint[1])) # The current point is the second elif i == 1: # The previous direction and the target direction are mainly opposed, a point is added if product(v_end, self.Segments[0]) < 0: self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) - self.Segments.insert(2, DirectionChoice((self.Segments[1][1], + self.Segments.insert(2, DirectionChoice((self.Segments[1][1], self.Segments[1][0]), v_end, self.EndPoint[1])) # The previous direction and the end direction are the same or they are # perpendiculars and the end direction points towards current segment @@ -2066,7 +2066,7 @@ # If the previous direction and the end direction are the same, a point is added if product(self.Segments[0], self.EndPoint[1]) > 0: self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) - self.Segments.insert(2, DirectionChoice((self.Segments[1][1], + self.Segments.insert(2, DirectionChoice((self.Segments[1][1], self.Segments[1][0]), v_end, self.EndPoint[1])) else: # Current point is positioned in the middle of start point @@ -2076,7 +2076,7 @@ if self.Segments[0][1] != 0: self.Points[1].y = (end.y + start.y) / 2 self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y)) - self.Segments.insert(2, DirectionChoice((self.Segments[1][1], + self.Segments.insert(2, DirectionChoice((self.Segments[1][1], self.Segments[1][0]), v_end, self.EndPoint[1])) else: # The previous direction and the end direction are perpendiculars @@ -2093,7 +2093,7 @@ self.Segments[i - 1] = (-self.Segments[i - 1][0], -self.Segments[i - 1][1]) else: test = True - # If the current point is the third, test if the second + # If the current point is the third, test if the second # point can be aligned with the end point if i == 2: test_point = wx.Point(self.Points[1].x, self.Points[1].y) @@ -2119,7 +2119,7 @@ if self.Segments[1][1] != 0: self.Points[2].y = (self.Points[1].y + end.y) / 2 self.Points.insert(3, wx.Point(self.Points[2].x, self.Points[2].y)) - self.Segments.insert(3, DirectionChoice((self.Segments[2][1], + self.Segments.insert(3, DirectionChoice((self.Segments[2][1], self.Segments[2][0]), v_end, self.EndPoint[1])) else: # Current point is aligned with end point @@ -2140,15 +2140,15 @@ self.Points[i].y = (end.y + self.Points[i - 1].y) / 2 # A point is added self.Points.insert(i + 1, wx.Point(self.Points[i].x, self.Points[i].y)) - self.Segments.insert(i + 1, DirectionChoice((self.Segments[i][1], + self.Segments.insert(i + 1, DirectionChoice((self.Segments[i][1], self.Segments[i][0]), v_end, self.EndPoint[1])) else: # Current point is the first, and second is not mainly in the first direction if i == 0 and product(vector(start, self.Points[1]), self.Segments[0]) < 0: - # If first and second directions aren't perpendiculars, a point is added + # If first and second directions aren't perpendiculars, a point is added if product(self.Segments[0], self.Segments[1]) != 0: self.Points.insert(1, wx.Point(start.x, start.y)) - self.Segments.insert(1, DirectionChoice((self.Segments[0][1], + self.Segments.insert(1, DirectionChoice((self.Segments[0][1], self.Segments[0][0]), vector(start, self.Points[1]), self.Segments[1])) else: self.Points[1].x, self.Points[1].y = start.x, start.y @@ -2165,7 +2165,7 @@ self.RefreshBoundingBox() if realpoints: self.RefreshRealPoints() - + # Verify that two consecutive points haven't the same position def VerifyPoints(self): points = [point for point in self.Points] @@ -2185,7 +2185,7 @@ self.RefreshBoundingBox() self.RefreshRealPoints() return points - + # Moves all the wire points except the first and the last if they are connected def Move(self, dx, dy, endpoints = False): for i, point in enumerate(self.Points): @@ -2195,7 +2195,7 @@ self.StartPoint[0] = self.Points[0] self.EndPoint[0] = self.Points[-1] self.GeneratePoints() - + # Resize the wire from position and size given def Resize(self, x, y, width, height): if len(self.Points) > 1: @@ -2254,25 +2254,25 @@ self.StartPoint[0] = self.Points[0] self.EndPoint[0] = self.Points[-1] self.GeneratePoints(False) - + # Moves the wire start point and update the wire points def MoveStartPoint(self, point): if len(self.Points) > 1: self.StartPoint[0] = point self.Points[0] = point self.GeneratePoints() - + # Changes the wire start direction and update the wire points def SetStartPointDirection(self, dir): if len(self.Points) > 1: self.StartPoint[1] = dir self.Segments[0] = dir self.GeneratePoints() - + # Rotates the wire start direction by an angle of 90 degrees anticlockwise def RotateStartPoint(self): self.SetStartPointDirection((self.StartPoint[1][1], -self.StartPoint[1][0])) - + # Connects wire start point to the connector given and moves wire start point # to given point def ConnectStartPoint(self, point, connector): @@ -2280,7 +2280,7 @@ self.MoveStartPoint(point) self.StartConnected = connector self.RefreshBoundingBox() - + # Unconnects wire start point def UnConnectStartPoint(self, delete = False): if delete: @@ -2290,7 +2290,7 @@ self.StartConnected.UnConnect(self, unconnect = False) self.StartConnected = None self.RefreshBoundingBox() - + # Moves the wire end point and update the wire points def MoveEndPoint(self, point): if len(self.Points) > 1: @@ -2303,7 +2303,7 @@ if len(self.Points) > 1: self.EndPoint[1] = dir self.GeneratePoints() - + # Rotates the wire end direction by an angle of 90 degrees anticlockwise def RotateEndPoint(self): self.SetEndPointDirection((self.EndPoint[1][1], -self.EndPoint[1][0])) @@ -2315,7 +2315,7 @@ self.MoveEndPoint(point) self.EndConnected = connector self.RefreshBoundingBox() - + # Unconnects wire end point def UnConnectEndPoint(self, delete = False): if delete: @@ -2325,7 +2325,7 @@ self.EndConnected.UnConnect(self, unconnect = False) self.EndConnected = None self.RefreshBoundingBox() - + # Moves the wire segment given by its index def MoveSegment(self, idx, movex, movey, scaling): if 0 < idx < len(self.Segments) - 1: @@ -2356,7 +2356,7 @@ if start_y != self.Points[idx].y: return 0, self.Points[idx].y - start_y return 0, 0 - + # Adds two points in the middle of the handled segment def AddSegment(self): handle_type, handle = self.Handle @@ -2391,7 +2391,7 @@ self.Points.insert(segment + 4, wx.Point(p2x, p2y)) self.Segments.insert(segment + 4, dir) self.GeneratePoints() - + # Delete the handled segment by removing the two segment points def DeleteSegment(self): handle_type, handle = self.Handle @@ -2402,7 +2402,7 @@ self.Segments.pop(segment) self.GeneratePoints() self.RefreshModel() - + # Method called when a LeftDown event have been generated def OnLeftDown(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -2424,7 +2424,7 @@ else: Graphic_Element.OnLeftDown(self, event, dc, scaling) self.oldPos = pos - + # Method called when a RightUp event has been generated def OnRightUp(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -2437,7 +2437,7 @@ else: # Execute the default method for a graphic element Graphic_Element.OnRightUp(self, event, dc, scaling) - + # Method called when a LeftDClick event has been generated def OnLeftDClick(self, event, dc, scaling): rect = self.GetRedrawRect() @@ -2492,7 +2492,7 @@ self.Parent.RefreshBuffer() rect.Union(self.GetRedrawRect()) self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False) - + # Method called when a Motion event has been generated def OnMotion(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -2511,7 +2511,7 @@ else: # Execute the default method for a graphic element return Graphic_Element.OnMotion(self, event, dc, scaling) - + # Refreshes the wire state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): handle_type, handle = self.Handle @@ -2572,14 +2572,14 @@ # Execute the default method for a graphic element else: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) - + # Refreshes the wire model def RefreshModel(self, move=True): if self.StartConnected and self.StartPoint[1] in [WEST, NORTH]: self.StartConnected.RefreshParentBlock() if self.EndConnected and self.EndPoint[1] in [WEST, NORTH]: self.EndConnected.RefreshParentBlock() - + # Change the variable that indicates if this element is highlighted def SetHighlighted(self, highlighted): self.Highlighted = highlighted @@ -2587,7 +2587,7 @@ self.OverStart = False self.OverEnd = False self.Refresh() - + def HighlightPoint(self, pos): refresh = False start, end = self.OverStart, self.OverEnd @@ -2602,7 +2602,7 @@ self.OverEnd = True if start != self.OverStart or end != self.OverEnd: self.Refresh() - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -2617,31 +2617,31 @@ dc.SetLogicalFunction(wx.AND) # Draw the start and end points if they are not connected or the mouse is over them if len(self.Points) > 0 and (not self.StartConnected or self.OverStart): - dc.DrawCircle(round(self.Points[0].x * scalex), - round(self.Points[0].y * scaley), + dc.DrawCircle(round(self.Points[0].x * scalex), + round(self.Points[0].y * scaley), (POINT_RADIUS + 1) * scalex + 2) if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd): dc.DrawCircle(self.Points[-1].x * scalex, self.Points[-1].y * scaley, (POINT_RADIUS + 1) * scalex + 2) # Draw the wire lines and the last point (it seems that DrawLines stop before the last point) if len(self.Points) > 1: - points = [wx.Point(round((self.Points[0].x - self.Segments[0][0]) * scalex), + points = [wx.Point(round((self.Points[0].x - self.Segments[0][0]) * scalex), round((self.Points[0].y - self.Segments[0][1]) * scaley))] points.extend([wx.Point(round(point.x * scalex), round(point.y * scaley)) for point in self.Points[1:-1]]) - points.append(wx.Point(round((self.Points[-1].x + self.Segments[-1][0]) * scalex), + points.append(wx.Point(round((self.Points[-1].x + self.Segments[-1][0]) * scalex), round((self.Points[-1].y + self.Segments[-1][1]) * scaley))) else: points = [] dc.DrawLines(points) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + if self.StartConnected is not None: self.StartConnected.DrawHighlightment(dc) self.StartConnected.Draw(dc) if self.EndConnected is not None: self.EndConnected.DrawHighlightment(dc) self.EndConnected.Draw(dc) - + # Draws the wire lines and points def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -2750,7 +2750,7 @@ self.Pos = wx.Point(0, 0) self.Size = wx.Size(0, 0) self.Highlights = [] - + # Make a clone of this comment def Clone(self, parent, id = None, pos = None): comment = Comment(parent, self.Content, id) @@ -2758,19 +2758,19 @@ comment.SetPosition(pos.x, pos.y) comment.SetSize(self.Size[0], self.Size[1]) return comment - + # Method for keeping compatibility with others def Clean(self): pass - + # Delete this comment by calling the corresponding method def Delete(self): self.Parent.DeleteComment(self) - + # Refresh the comment bounding box def RefreshBoundingBox(self): self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) - + # Changes the comment size def SetSize(self, width, height): self.Size.SetWidth(width) @@ -2780,7 +2780,7 @@ # Returns the comment size def GetSize(self): return self.Size.GetWidth(), self.Size.GetHeight() - + # Returns the comment minimum size def GetMinSize(self): dc = wx.ClientDC(self.Parent) @@ -2793,7 +2793,7 @@ min_width = max(min_width, wordwidth) min_height = max(min_height, wordheight) return min_width + 20, min_height + 20 - + # Changes the comment position def SetPosition(self, x, y): self.Pos.x = x @@ -2815,51 +2815,51 @@ # Returns the comment position def GetPosition(self): return self.Pos.x, self.Pos.y - + # Moves the comment def Move(self, dx, dy, connected = True): self.Pos.x += dx self.Pos.y += dy self.RefreshBoundingBox() - + # Resizes the comment with the position and the size given def Resize(self, x, y, width, height): self.Move(x, y) self.SetSize(width, height) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupDefaultMenu() - + # Refreshes the wire state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE and self.Parent.CurrentLanguage == "LD": movex = movey = 0 return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) - + # Refreshes the comment model def RefreshModel(self, move=True): self.Parent.RefreshCommentModel(self) - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the comment content self.Parent.EditCommentContent(self) - + # Adds an highlight to the comment def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "content": AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the comment def RemoveHighlight(self, infos, start, end, highlight_type): RemoveHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes all the highlights of one particular type from the comment def ClearHighlight(self, highlight_type=None): self.Highlights = ClearHighlights(self.Highlights, highlight_type) - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -2867,29 +2867,29 @@ dc.SetPen(MiterPen(HIGHLIGHTCOLOR)) dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) dc.SetLogicalFunction(wx.AND) - + left = (self.Pos.x - 1) * scalex - 2 right = (self.Pos.x + self.Size[0] + 1) * scalex + 2 top = (self.Pos.y - 1) * scaley - 2 bottom = (self.Pos.y + self.Size[1] + 1) * scaley + 2 angle_top = (self.Pos.x + self.Size[0] - 9) * scalex + 2 angle_right = (self.Pos.y + 9) * scaley - 2 - + polygon = [wx.Point(left, top), wx.Point(angle_top, top), wx.Point(right, angle_right), wx.Point(right, bottom), wx.Point(left, bottom)] dc.DrawPolygon(polygon) - + dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Draws the comment and its content def Draw(self, dc): Graphic_Element.Draw(self, dc) dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) # Draws the comment shape - polygon = [wx.Point(self.Pos.x, self.Pos.y), + polygon = [wx.Point(self.Pos.x, self.Pos.y), wx.Point(self.Pos.x + self.Size[0] - 10, self.Pos.y), wx.Point(self.Pos.x + self.Size[0], self.Pos.y + 10), wx.Point(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1]), @@ -2951,4 +2951,3 @@ y += wordheight + 5 if y + wordheight > self.Pos.y + self.Size[1] - 10: break - diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/LD_Objects.py --- a/graphics/LD_Objects.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/LD_Objects.py Mon Aug 14 19:13:01 2017 +0300 @@ -37,7 +37,7 @@ """ class LD_PowerRail(Graphic_Element): - + # Create a new power rail def __init__(self, parent, type, id=None, connectors=1): Graphic_Element.__init__(self, parent) @@ -47,12 +47,12 @@ self.Id = id self.Extensions = [LD_LINE_SIZE / 2, LD_LINE_SIZE / 2] self.SetType(type, connectors) - + def Flush(self): for connector in self.Connectors: connector.Flush() self.Connectors = [] - + # Make a clone of this LD_PowerRail def Clone(self, parent, id = None, pos = None): powerrail = LD_PowerRail(parent, self.Type, id) @@ -65,11 +65,11 @@ for connector in self.Connectors: powerrail.Connectors.append(connector.Clone(powerrail)) return powerrail - + def GetConnectorTranslation(self, element): return dict(zip([connector for connector in self.Connectors], [connector for connector in element.Connectors])) - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -80,7 +80,7 @@ if connector.IsConnected(): rect = rect.Union(connector.GetConnectedRedrawRect(movex, movey)) return rect - + # Forbids to change the power rail size def SetSize(self, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: @@ -88,47 +88,47 @@ else: Graphic_Element.SetSize(self, LD_POWERRAIL_WIDTH, height) self.RefreshConnectors() - + # Forbids to select a power rail def HitTest(self, pt, connectors=True): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: return Graphic_Element.HitTest(self, pt, connectors) or self.TestConnector(pt, exclude=False) != None return False - + # Forbids to select a power rail def IsInSelection(self, rect): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: return Graphic_Element.IsInSelection(self, rect) return False - + # Deletes this power rail by calling the appropriate method def Delete(self): self.Parent.DeletePowerRail(self) - + # Unconnect all connectors def Clean(self): for connector in self.Connectors: connector.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the power rail bounding box def RefreshBoundingBox(self): self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) - + # Refresh the power rail size def RefreshSize(self): self.Size = wx.Size(LD_POWERRAIL_WIDTH, max(LD_LINE_SIZE * len(self.Connectors), self.Size[1])) self.RefreshBoundingBox() - + # Returns the block minimum size def GetMinSize(self, default=False): height = (LD_LINE_SIZE * (len(self.Connectors) - 1) if default else 0) return LD_POWERRAIL_WIDTH, height + self.Extensions[0] + self.Extensions[1] - + # Add a connector or a blank to this power rail at the last place def AddConnector(self): self.InsertConnector(len(self.Connectors)) - + # Add a connector or a blank to this power rail at the place given def InsertConnector(self, idx): if self.Type == LEFTRAIL: @@ -138,7 +138,7 @@ self.Connectors.insert(idx, connector) self.RefreshSize() self.RefreshConnectors() - + # Moves the divergence connector given def MoveConnector(self, connector, movey): position = connector.GetRelPosition() @@ -163,19 +163,19 @@ self.Size[1] = max(maxy + self.Extensions[1], self.Size[1]) connector.MoveConnected() self.RefreshBoundingBox() - + # Returns the index in connectors list for the connector given def GetConnectorIndex(self, connector): if connector in self.Connectors: return self.Connectors.index(connector) return None - + # Delete the connector or blank from connectors list at the index given def DeleteConnector(self, idx): self.Connectors.pop(idx) self.RefreshConnectors() self.RefreshSize() - + # Refresh the positions of the power rail connectors def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -193,13 +193,13 @@ elif self.Type == RIGHTRAIL: connector.SetPosition(wx.Point(0, position)) self.RefreshConnected() - + # Refresh the position of wires connected to power rail def RefreshConnected(self, exclude = []): for connector in self.Connectors: connector.MoveConnected(exclude) - - # Returns the power rail connector that starts with the point given if it exists + + # Returns the power rail connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -208,22 +208,22 @@ if name == connector.GetName(): return connector return self.FindNearestConnector(position, [connector for connector in self.Connectors if connector is not None]) - - # Returns all the power rail connectors + + # Returns all the power rail connectors def GetConnectors(self): connectors = [connector for connector in self.Connectors if connector] if self.Type == LEFTRAIL: return {"inputs": [], "outputs": connectors} else: return {"inputs": connectors, "outputs": []} - + # Test if point given is on one of the power rail connectors def TestConnector(self, pt, direction = None, exclude = True): for connector in self.Connectors: if connector.TestPoint(pt, direction, exclude): return connector return None - + # Returns the power rail type def SetType(self, type, connectors): if type != self.Type or len(self.Connectors) != connectors: @@ -235,11 +235,11 @@ for connector in xrange(connectors): self.AddConnector() self.RefreshSize() - + # Returns the power rail type def GetType(self): return self.Type - + # Method called when a LeftDown event have been generated def OnLeftDown(self, event, dc, scaling): self.RealConnectors = [] @@ -253,12 +253,12 @@ else: self.RealConnectors = [0.5] Graphic_Element.OnLeftDown(self, event, dc, scaling) - + # Method called when a LeftUp event have been generated def OnLeftUp(self, event, dc, scaling): Graphic_Element.OnLeftUp(self, event, dc, scaling) self.RealConnectors = None - + # Method called when a LeftDown event have been generated def OnRightDown(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -272,12 +272,12 @@ self.oldPos = GetScaledEventPosition(event, dc, scaling) else: Graphic_Element.OnRightDown(self, event, dc, scaling) - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the powerrail properties self.Parent.EditPowerRailContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): handle_type, handle = self.Handle @@ -292,7 +292,7 @@ Graphic_Element.OnRightUp(self, event, dc, scaling) else: self.Parent.PopupDefaultMenu() - + def Resize(self, x, y, width, height): self.Move(x, y) if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: @@ -314,16 +314,16 @@ elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) return 0, 0 - + # Refreshes the power rail model def RefreshModel(self, move=True): self.Parent.RefreshPowerRailModel(self) - # If power rail has moved and power rail is of type LEFT, refresh the model + # If power rail has moved and power rail is of type LEFT, refresh the model # of wires connected to connectors if move and self.Type == LEFTRAIL: for connector in self.Connectors: connector.RefreshWires() - + # Draws power rail def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -337,7 +337,7 @@ # Draw connectors for connector in self.Connectors: connector.Draw(dc) - + #------------------------------------------------------------------------------- # Ladder Diagram Contact @@ -348,7 +348,7 @@ """ class LD_Contact(Graphic_Element, DebugDataConsumer): - + # Create a new contact def __init__(self, parent, type, name, id = None): Graphic_Element.__init__(self, parent) @@ -365,7 +365,7 @@ self.PreviousSpreading = False self.RefreshNameSize() self.RefreshTypeSize() - + def Flush(self): if self.Input is not None: self.Input.Flush() @@ -373,13 +373,13 @@ if self.Output is not None: self.Output.Flush() self.Output = None - + def SetForced(self, forced): if self.Forced != forced: self.Forced = forced if self.Visible: self.Parent.ElementNeedRefresh(self) - + def SetValue(self, value): if self.Type == CONTACT_RISING: refresh = self.Value and not self.PreviousValue @@ -393,7 +393,7 @@ if self.Visible: self.Parent.ElementNeedRefresh(self) self.SpreadCurrent() - + def SpreadCurrent(self): if self.Parent.Debug: if self.Value is None: @@ -414,7 +414,7 @@ elif not spreading and self.PreviousSpreading: self.Output.SpreadCurrent(False) self.PreviousSpreading = spreading - + # Make a clone of this LD_Contact def Clone(self, parent, id = None, pos = None): contact = LD_Contact(parent, self.Type, self.Name, id) @@ -426,10 +426,10 @@ contact.Input = self.Input.Clone(contact) contact.Output = self.Output.Clone(contact) return contact - + def GetConnectorTranslation(self, element): return {self.Input : element.Input, self.Output : element.Output} - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -446,29 +446,29 @@ if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: movex = movey = 0 return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2) - + # Forbids to change the contact size def SetSize(self, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.SetSize(self, width, height) self.RefreshConnectors() - + # Delete this contact by calling the appropriate method def Delete(self): self.Parent.DeleteContact(self) - + # Unconnect input and output def Clean(self): self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the size of text for name def RefreshNameSize(self): if self.Name != "": self.NameSize = self.Parent.GetTextExtent(self.Name) else: self.NameSize = 0, 0 - + # Refresh the size of text for type def RefreshTypeSize(self): typetext = "" @@ -482,7 +482,7 @@ self.TypeSize = self.Parent.GetTextExtent(typetext) else: self.TypeSize = 0, 0 - + # Refresh the contact bounding box def RefreshBoundingBox(self): # Calculate the size of the name outside the contact @@ -499,17 +499,17 @@ bbx_y = self.Pos.y bbx_height = self.Size[1] self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1) - + # Returns the block minimum size def GetMinSize(self): return LD_ELEMENT_SIZE - + # Refresh the position of wire connected to contact def RefreshConnected(self, exclude = []): self.Input.MoveConnected(exclude) self.Output.MoveConnected(exclude) - - # Returns the contact connector that starts with the point given if it exists + + # Returns the contact connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -519,11 +519,11 @@ if name == self.Output.GetName(): return self.Output return self.FindNearestConnector(position, [self.Input, self.Output]) - - # Returns input and output contact connectors + + # Returns input and output contact connectors def GetConnectors(self): return {"inputs": [self.Input], "outputs": [self.Output]} - + # Test if point given is on contact input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector @@ -561,24 +561,24 @@ # Returns the contact type def GetType(self): return self.Type - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the contact properties self.Parent.EditContactContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupDefaultMenu() - + # Refreshes the contact model def RefreshModel(self, move=True): self.Parent.RefreshContactModel(self) # If contact has moved, refresh the model of wires connected to output if move: self.Output.RefreshWires() - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -592,12 +592,12 @@ top = (self.Pos.y - 1) * scaley - 2 width = 4 * scalex + 5 height = (self.Size[1] + 3) * scaley + 5 - + dc.DrawRectangle(left_left, top, width, height) dc.DrawRectangle(right_left, top, width, height) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Adds an highlight to the connection def AddHighlight(self, infos, start, end, highlight_type): highlights = self.Highlights.setdefault(infos[0], []) @@ -606,13 +606,13 @@ AddHighlight(highlights, (start, end, highlight_type)) else: AddHighlight(highlights, ((0, 0), (0, 1), highlight_type)) - + # Removes an highlight from the connection def RemoveHighlight(self, infos, start, end, highlight_type): highlights = self.Highlights.get(infos[0], []) if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0: self.Highlights.pop(infos[0]) - + # Removes all the highlights of one particular type from the connection def ClearHighlight(self, highlight_type=None): if highlight_type is None: @@ -623,11 +623,11 @@ highlights = ClearHighlights(highlight, highlight_type) if len(highlights) == 0: self.Highlights.pop(name) - + # Draws contact def Draw(self, dc): Graphic_Element.Draw(self, dc) - if self.Value is not None: + if self.Value is not None: if self.Type == CONTACT_NORMAL and self.Value or \ self.Type == CONTACT_REVERSE and not self.Value or \ self.Type == CONTACT_RISING and self.Value and not self.PreviousValue or \ @@ -643,7 +643,7 @@ else: dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.BLACK_BRUSH) - + # Compiling contact type modifier symbol typetext = "" if self.Type == CONTACT_REVERSE: @@ -652,7 +652,7 @@ typetext = "P" elif self.Type == CONTACT_FALLING: typetext = "N" - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) if typetext != "": @@ -661,7 +661,7 @@ name_size = self.NameSize if typetext != "": type_size = self.TypeSize - + # Draw two rectangles for representing the contact dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1) dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1) @@ -677,7 +677,7 @@ # Draw input and output connectors self.Input.Draw(dc) self.Output.Draw(dc) - + if not getattr(dc, "printing", False): for name, highlights in self.Highlights.iteritems(): if name == "reference": @@ -694,7 +694,7 @@ """ class LD_Coil(Graphic_Element): - + # Create a new coil def __init__(self, parent, type, name, id = None): Graphic_Element.__init__(self, parent) @@ -710,7 +710,7 @@ self.PreviousValue = False self.RefreshNameSize() self.RefreshTypeSize() - + def Flush(self): if self.Input is not None: self.Input.Flush() @@ -718,7 +718,7 @@ if self.Output is not None: self.Output.Flush() self.Output = None - + def SpreadCurrent(self): if self.Parent.Debug: self.PreviousValue = self.Value @@ -729,7 +729,7 @@ self.Output.SpreadCurrent(False) if self.Value != self.PreviousValue and self.Visible: self.Parent.ElementNeedRefresh(self) - + # Make a clone of this LD_Coil def Clone(self, parent, id = None, pos = None): coil = LD_Coil(parent, self.Type, self.Name, id) @@ -741,10 +741,10 @@ coil.Input = self.Input.Clone(coil) coil.Output = self.Output.Clone(coil) return coil - + def GetConnectorTranslation(self, element): return {self.Input : element.Input, self.Output : element.Output} - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -756,34 +756,34 @@ if self.Output.IsConnected(): rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey)) return rect - + def ProcessDragging(self, movex, movey, event, scaling): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: movex = movey = 0 - return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2) - + return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2) + # Forbids to change the Coil size def SetSize(self, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.SetSize(self, width, height) self.RefreshConnectors() - + # Delete this coil by calling the appropriate method def Delete(self): self.Parent.DeleteCoil(self) - + # Unconnect input and output def Clean(self): self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the size of text for name def RefreshNameSize(self): if self.Name != "": self.NameSize = self.Parent.GetTextExtent(self.Name) else: self.NameSize = 0, 0 - + # Refresh the size of text for type def RefreshTypeSize(self): typetext = "" @@ -801,7 +801,7 @@ self.TypeSize = self.Parent.GetTextExtent(typetext) else: self.TypeSize = 0, 0 - + # Refresh the coil bounding box def RefreshBoundingBox(self): # Calculate the size of the name outside the coil @@ -818,17 +818,17 @@ bbx_y = self.Pos.y bbx_height = self.Size[1] self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1) - + # Returns the block minimum size def GetMinSize(self): return LD_ELEMENT_SIZE - + # Refresh the position of wire connected to coil def RefreshConnected(self, exclude = []): self.Input.MoveConnected(exclude) self.Output.MoveConnected(exclude) - - # Returns the coil connector that starts with the point given if it exists + + # Returns the coil connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -838,11 +838,11 @@ if self.Output and name == self.Output.GetName(): return self.Output return self.FindNearestConnector(position, [self.Input, self.Output]) - - # Returns input and output coil connectors + + # Returns input and output coil connectors def GetConnectors(self): return {"inputs": [self.Input], "outputs": [self.Output]} - + # Test if point given is on coil input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector @@ -852,7 +852,7 @@ if self.Output.TestPoint(pt, direction, exclude): return self.Output return None - + # Refresh the positions of the block connectors def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -862,7 +862,7 @@ self.Input.SetPosition(wx.Point(0, position)) self.Output.SetPosition(wx.Point(self.Size[0], position)) self.RefreshConnected() - + # Changes the coil name def SetName(self, name): self.Name = name @@ -871,33 +871,33 @@ # Returns the coil name def GetName(self): return self.Name - + # Changes the coil type def SetType(self, type): self.Type = type self.RefreshTypeSize() - + # Returns the coil type def GetType(self): return self.Type - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the coil properties self.Parent.EditCoilContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupDefaultMenu() - + # Refreshes the coil model def RefreshModel(self, move=True): self.Parent.RefreshCoilModel(self) # If coil has moved, refresh the model of wires connected to output if move: self.Output.RefreshWires() - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -906,19 +906,19 @@ dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetLogicalFunction(wx.AND) # Draw a two circle arcs for representing the coil - dc.DrawEllipticArc(round(self.Pos.x * scalex), - round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), - round(self.Size[0] * scalex), + dc.DrawEllipticArc(round(self.Pos.x * scalex), + round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), + round(self.Size[0] * scalex), round((int(self.Size[1] * sqrt(2)) - 1) * scaley), 135, 225) - dc.DrawEllipticArc(round(self.Pos.x * scalex), - round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), - round(self.Size[0] * scalex), + dc.DrawEllipticArc(round(self.Pos.x * scalex), + round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley), + round(self.Size[0] * scalex), round((int(self.Size[1] * sqrt(2)) - 1) * scaley), -45, 45) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Adds an highlight to the connection def AddHighlight(self, infos, start, end, highlight_type): highlights = self.Highlights.setdefault(infos[0], []) @@ -927,13 +927,13 @@ AddHighlight(highlights, (start, end, highlight_type)) else: AddHighlight(highlights, ((0, 0), (0, 1), highlight_type)) - + # Removes an highlight from the connection def RemoveHighlight(self, infos, start, end, highlight_type): highlights = self.Highlights.get(infos[0], []) if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0: self.Highlights.pop(infos[0]) - + # Removes all the highlights of one particular type from the connection def ClearHighlight(self, highlight_type=None): if highlight_type is None: @@ -944,7 +944,7 @@ highlights = ClearHighlights(highlight, highlight_type) if len(highlights) == 0: self.Highlights.pop(name) - + # Draws coil def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -953,8 +953,8 @@ else: dc.SetPen(MiterPen(wx.BLACK, 2, wx.SOLID)) dc.SetBrush(wx.TRANSPARENT_BRUSH) - - # Compiling coil type modifier symbol + + # Compiling coil type modifier symbol typetext = "" if self.Type == COIL_REVERSE: typetext = "/" @@ -966,7 +966,7 @@ typetext = "P" elif self.Type == COIL_FALLING: typetext = "N" - + if getattr(dc, "printing", False) and not isinstance(dc, wx.PostScriptDC): # Draw an clipped ellipse for representing the coil clipping_box = dc.GetClippingBox() @@ -992,7 +992,7 @@ name_size = self.NameSize if typetext != "": type_size = self.TypeSize - + # Draw coil name name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, self.Pos.y - (name_size[1] + 2)) @@ -1012,5 +1012,3 @@ DrawHighlightedText(dc, self.Name, highlights, name_pos[0], name_pos[1]) elif typetext != "": DrawHighlightedText(dc, typetext, highlights, type_pos[0], type_pos[1]) - - diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/RubberBand.py --- a/graphics/RubberBand.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/RubberBand.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,19 +35,19 @@ """ class RubberBand: - + def __init__(self, viewer): """ Constructor @param viewer: Viewer on which rubberband must be drawn """ self.Viewer = viewer - + # wx.Panel on which rubberband will be drawn self.DrawingSurface = viewer.Editor - + self.Reset() - + def Reset(self): """ Initialize internal attributes of rubberband @@ -55,14 +55,14 @@ self.StartPoint = None self.CurrentBBox = None self.LastBBox = None - + def IsShown(self): """ Indicate if rubberband is drawn on viewer @return: True if rubberband is drawn """ return self.CurrentBBox != None - + def GetCurrentExtent(self): """ Return the rubberband bounding box @@ -73,7 +73,7 @@ if self.IsShown(): return self.CurrentBBox return self.LastBBox - + def OnLeftDown(self, event, dc, scaling): """ Called when left mouse is pressed on Viewer. Starts to edit a new @@ -85,16 +85,16 @@ # Save the point where mouse was pressed in Viewer unit, position may # be modified by scroll and zoom applied on viewer self.StartPoint = GetScaledEventPosition(event, dc, scaling) - + # Initialize rubberband bounding box self.CurrentBBox = wx.Rect(self.StartPoint.x, self.StartPoint.y, 0, 0) - + # Change viewer mouse cursor to reflect a rubberband bounding box is # edited self.DrawingSurface.SetCursor(wx.StockCursor(wx.CURSOR_CROSS)) - + self.Redraw() - + def OnMotion(self, event, dc, scaling): """ Called when mouse is dragging over Viewer. Update the current edited @@ -106,19 +106,19 @@ # Get mouse position in Viewer unit, position may be modified by scroll # and zoom applied on viewer pos = GetScaledEventPosition(event, dc, scaling) - + # Save the last bounding box drawn for erasing it later self.LastBBox = wx.Rect(0, 0, 0, 0) self.LastBBox.Union(self.CurrentBBox) - - # Calculate new position and size of the box + + # Calculate new position and size of the box self.CurrentBBox.x = min(pos.x, self.StartPoint.x) self.CurrentBBox.y = min(pos.y, self.StartPoint.y) self.CurrentBBox.width = abs(pos.x - self.StartPoint.x) + 1 self.CurrentBBox.height = abs(pos.y - self.StartPoint.y) + 1 - + self.Redraw() - + def OnLeftUp(self, event, dc, scaling): """ Called when mouse is release from Viewer. Erase the current edited @@ -129,16 +129,16 @@ """ # Change viewer mouse cursor to default self.DrawingSurface.SetCursor(wx.NullCursor) - + # Save the last edited bounding box self.LastBBox = self.CurrentBBox self.CurrentBBox = None - + self.Redraw() - + def DrawBoundingBoxes(self, bboxes, dc=None): """ - Draw a list of bounding box on Viewer in the order given using XOR + Draw a list of bounding box on Viewer in the order given using XOR logical function @param bboxes: List of bounding boxes to draw on viewer @param dc: Device Context of Viewer (default None) @@ -146,29 +146,29 @@ # Get viewer Device Context if not given if dc is None: dc = self.Viewer.GetLogicalDC() - + # Save current viewer scale factors before resetting them in order to # avoid rubberband pen to be scaled scalex, scaley = dc.GetUserScale() dc.SetUserScale(1, 1) - + # Set DC drawing style dc.SetPen(wx.Pen(wx.WHITE, style=wx.DOT)) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetLogicalFunction(wx.XOR) - + # Draw the bounding boxes using viewer scale factor for bbox in bboxes: if bbox is not None: dc.DrawRectangle( - bbox.x * scalex, bbox.y * scaley, + bbox.x * scalex, bbox.y * scaley, bbox.width * scalex, bbox.height * scaley) - + dc.SetLogicalFunction(wx.COPY) - + # Restore Viewer scale factor dc.SetUserScale(scalex, scaley) - + def Redraw(self, dc = None): """ Redraw rubberband on Viewer @@ -176,7 +176,7 @@ """ # Erase last bbox and draw current bbox self.DrawBoundingBoxes([self.LastBBox, self.CurrentBBox], dc) - + def Erase(self, dc = None): """ Erase rubberband from Viewer diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/SFC_Objects.py --- a/graphics/SFC_Objects.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/SFC_Objects.py Mon Aug 14 19:13:01 2017 +0300 @@ -43,7 +43,7 @@ """ class SFC_Step(Graphic_Element, DebugDataConsumer): - + # Create a new step def __init__(self, parent, name, initial = False, id = None): Graphic_Element.__init__(self, parent) @@ -62,7 +62,7 @@ self.Action = None self.PreviousValue = None self.PreviousSpreading = False - + def Flush(self): if self.Input is not None: self.Input.Flush() @@ -73,13 +73,13 @@ if self.Action is not None: self.Action.Flush() self.Action = None - + def SetForced(self, forced): if self.Forced != forced: self.Forced = forced if self.Visible: self.Parent.ElementNeedRefresh(self) - + def SetValue(self, value): self.PreviousValue = self.Value self.Value = value @@ -87,7 +87,7 @@ if self.Visible: self.Parent.ElementNeedRefresh(self) self.SpreadCurrent() - + def SpreadCurrent(self): if self.Parent.Debug: spreading = self.Value @@ -102,7 +102,7 @@ if self.Action is not None: self.Action.SpreadCurrent(False) self.PreviousSpreading = spreading - + # Make a clone of this SFC_Step def Clone(self, parent, id = None, name = "Step", pos = None): step = SFC_Step(parent, name, self.Initial, id) @@ -118,7 +118,7 @@ if self.Action: step.Action = self.Action.Clone(step) return step - + def GetConnectorTranslation(self, element): connectors = {} if self.Input is not None: @@ -128,7 +128,7 @@ if self.Action is not None: connectors[self.Action] = element.Action return connectors - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -146,11 +146,11 @@ if self.Action and self.Action.IsConnected(): rect = rect.Union(self.Action.GetConnectedRedrawRect(movex, movey)) return rect - + # Delete this step by calling the appropriate method def Delete(self): self.Parent.DeleteStep(self) - + # Unconnect input and output def Clean(self): if self.Input: @@ -159,50 +159,50 @@ self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) if self.Action: self.Action.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the size of text for name def RefreshNameSize(self): self.NameSize = self.Parent.GetTextExtent(self.Name) - + # Add output connector to step def AddInput(self): if not self.Input: self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH) self.RefreshBoundingBox() - + # Remove output connector from step def RemoveInput(self): if self.Input: self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Input = None self.RefreshBoundingBox() - + # Add output connector to step def AddOutput(self): if not self.Output: self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True) self.RefreshBoundingBox() - + # Remove output connector from step def RemoveOutput(self): if self.Output: self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Output = None self.RefreshBoundingBox() - + # Add action connector to step def AddAction(self): if not self.Action: self.Action = Connector(self, "", None, wx.Point(self.Size[0], self.Size[1] / 2), EAST, onlyone = True) self.RefreshBoundingBox() - + # Remove action connector from step def RemoveAction(self): if self.Action: self.Action.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Action = None self.RefreshBoundingBox() - + # Refresh the step bounding box def RefreshBoundingBox(self): # Calculate the bounding box size @@ -222,7 +222,7 @@ bbx_height += CONNECTOR_SIZE #self.BoundingBox = wx.Rect(self.Pos.x, bbx_y, bbx_width + 1, bbx_height + 1) self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) - + # Refresh the positions of the step connectors def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -241,7 +241,7 @@ if self.Action: self.Action.SetPosition(wx.Point(self.Size[0], vertical_pos)) self.RefreshConnected() - + # Refresh the position of wires connected to step def RefreshConnected(self, exclude = []): if self.Input: @@ -250,8 +250,8 @@ self.Output.MoveConnected(exclude) if self.Action: self.Action.MoveConnected(exclude) - - # Returns the step connector that starts with the point given if it exists + + # Returns the step connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -273,12 +273,12 @@ if self.Action: connectors.append(self.Action) return self.FindNearestConnector(position, connectors) - - # Returns action step connector + + # Returns action step connector def GetActionConnector(self): return self.Action - - # Returns input and output step connectors + + # Returns input and output step connectors def GetConnectors(self): connectors = {"inputs": [], "outputs": []} if self.Input: @@ -286,7 +286,7 @@ if self.Output: connectors["outputs"].append(self.Output) return connectors - + # Test if point given is on step input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector if it exists @@ -312,7 +312,7 @@ # Returns the step initial property def GetInitial(self): return self.Initial - + # Returns the connector connected to input def GetPreviousConnector(self): if self.Input: @@ -320,7 +320,7 @@ if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Input) return None - + # Returns the connector connected to output def GetNextConnector(self): if self.Output: @@ -328,7 +328,7 @@ if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Output) return None - + # Returns the connector connected to action def GetActionConnected(self): if self.Action: @@ -336,7 +336,7 @@ if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Action) return None - + # Returns the number of action line def GetActionExtraLineNumber(self): if self.Action: @@ -346,7 +346,7 @@ action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock() return max(0, action_block.GetLineNumber() - 1) return 0 - + # Returns the step minimum size def GetMinSize(self): text_width, text_height = self.Parent.GetTextExtent(self.Name) @@ -354,7 +354,7 @@ return text_width + 14, text_height + 14 else: return text_width + 10, text_height + 10 - + # Updates the step size def UpdateSize(self, width, height): diffx = self.Size.GetWidth() / 2 - width / 2 @@ -365,7 +365,7 @@ self.RefreshConnected() else: self.RefreshOutputPosition((0, diffy)) - + # Align input element with this step def RefreshInputPosition(self): if self.Input: @@ -382,7 +382,7 @@ input_block.MoveActionBlock((diffx, 0)) input_block.Move(diffx, 0) input_block.RefreshInputPosition() - + # Align output element with this step def RefreshOutputPosition(self, move = None): if self.Output: @@ -422,7 +422,7 @@ output_block.MoveActionBlock((diffx, 0)) output_block.Move(diffx, 0) output_block.RefreshOutputPosition() - + # Refresh action element with this step def MoveActionBlock(self, move): if self.Action: @@ -432,24 +432,24 @@ action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock() action_block.Move(move[0], move[1], self.Parent.Wires) wires[0][0].Move(move[0], move[1], True) - + # Resize the divergence from position and size given def Resize(self, x, y, width, height): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: self.UpdateSize(width, height) else: Graphic_Element.Resize(self, x, y, width, height) - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the step properties self.Parent.EditStepContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the menu with special items for a step self.Parent.PopupDefaultMenu() - + # Refreshes the step state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): handle_type, handle = self.Handle @@ -477,17 +477,17 @@ return movex, 0 else: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) - + # Refresh input element model def RefreshInputModel(self): if self.Input: input = self.GetPreviousConnector() - if input: + if input: input_block = input.GetParentBlock() input_block.RefreshModel(False) if not isinstance(input_block, SFC_Divergence): input_block.RefreshInputModel() - + # Refresh output element model def RefreshOutputModel(self, move=False): if self.Output: @@ -497,7 +497,7 @@ output_block.RefreshModel(False) if not isinstance(output_block, SFC_Divergence) or move: output_block.RefreshOutputModel(move) - + # Refreshes the step model def RefreshModel(self, move=True): self.Parent.RefreshStepModel(self) @@ -513,21 +513,21 @@ self.RefreshOutputModel(self.Initial) elif self.Output: self.Output.RefreshWires() - + # Adds an highlight to the connection def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "name" and start[0] == 0 and end[0] == 0: AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the connection def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] == "name": RemoveHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes all the highlights of one particular type from the connection def ClearHighlight(self, highlight_type=None): ClearHighlights(self.Highlights, highlight_type) - + # Draws step def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -541,12 +541,12 @@ else: dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.WHITE_BRUSH) - + if getattr(dc, "printing", False): name_size = dc.GetTextExtent(self.Name) else: name_size = self.NameSize - + # Draw two rectangles for representing the step dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) if self.Initial: @@ -562,10 +562,10 @@ self.Output.Draw(dc) if self.Action: self.Action.Draw(dc) - + if not getattr(dc, "printing", False): DrawHighlightedText(dc, self.Name, self.Highlights, name_pos[0], name_pos[1]) - + #------------------------------------------------------------------------------- # Sequencial Function Chart Transition @@ -576,7 +576,7 @@ """ class SFC_Transition(Graphic_Element, DebugDataConsumer): - + # Create a new transition def __init__(self, parent, type = "reference", condition = None, priority = 0, id = None): Graphic_Element.__init__(self, parent) @@ -593,7 +593,7 @@ self.Highlights = {} self.PreviousValue = None self.PreviousSpreading = False - + def Flush(self): if self.Input is not None: self.Input.Flush() @@ -604,13 +604,13 @@ if self.Type == "connection" and self.Condition is not None: self.Condition.Flush() self.Condition = None - + def SetForced(self, forced): if self.Forced != forced: self.Forced = forced if self.Visible: self.Parent.ElementNeedRefresh(self) - + def SetValue(self, value): self.PreviousValue = self.Value self.Value = value @@ -618,7 +618,7 @@ if self.Visible: self.Parent.ElementNeedRefresh(self) self.SpreadCurrent() - + def SpreadCurrent(self): if self.Parent.Debug: if self.Value is None: @@ -629,7 +629,7 @@ elif not spreading and self.PreviousSpreading: self.Output.SpreadCurrent(False) self.PreviousSpreading = spreading - + # Make a clone of this SFC_Transition def Clone(self, parent, id = None, pos = None): transition = SFC_Transition(parent, self.Type, self.Condition, self.Priority, id) @@ -643,13 +643,13 @@ if self.Type == "connection": transition.Condition = self.Condition.Clone(transition) return transition - + def GetConnectorTranslation(self, element): connectors = {self.Input : element.Input, self.Output : element.Output} if self.Type == "connection" and self.Condition is not None: connectors[self.Condition] = element.Condition return connectors - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -665,17 +665,17 @@ if self.Type == "connection" and self.Condition.IsConnected(): rect = rect.Union(self.Condition.GetConnectedRedrawRect(movex, movey)) return rect - + # Forbids to change the transition size def SetSize(self, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.SetSize(self, width, height) - + # Forbids to resize the transition def Resize(self, x, y, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.Resize(self, x, y, width, height) - + # Refresh the size of text for name def RefreshConditionSize(self): if self.Type != "connection": @@ -683,7 +683,7 @@ self.ConditionSize = self.Parent.GetTextExtent(self.Condition) else: self.ConditionSize = self.Parent.GetTextExtent("Transition") - + # Refresh the size of text for name def RefreshPrioritySize(self): if self.Priority != "": @@ -694,14 +694,14 @@ # Delete this transition by calling the appropriate method def Delete(self): self.Parent.DeleteTransition(self) - + # Unconnect input and output def Clean(self): self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) if self.Type == "connection": self.Condition.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): if self.Type != "connection": @@ -715,7 +715,7 @@ else: test_text = False return test_text or Graphic_Element.HitTest(self, pt, connectors) - + # Refresh the transition bounding box def RefreshBoundingBox(self): bbx_x, bbx_y, bbx_width, bbx_height = self.Pos.x, self.Pos.y, self.Size[0], self.Size[1] @@ -733,21 +733,21 @@ bbx_y = min(bbx_y, self.Pos.y - max(0, (text_height - self.Size[1]) / 2)) bbx_height = max(bbx_height, self.Pos.y - bbx_y + (self.Size[1] + text_height) / 2) self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1) - + # Returns the connector connected to input def GetPreviousConnector(self): wires = self.Input.GetWires() if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Input) return None - + # Returns the connector connected to output def GetNextConnector(self): wires = self.Output.GetWires() if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Output) return None - + # Refresh the positions of the transition connectors def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -763,15 +763,15 @@ if self.Type == "connection": self.Condition.SetPosition(wx.Point(0, vertical_pos)) self.RefreshConnected() - + # Refresh the position of the wires connected to transition def RefreshConnected(self, exclude = []): self.Input.MoveConnected(exclude) self.Output.MoveConnected(exclude) if self.Type == "connection": self.Condition.MoveConnected(exclude) - - # Returns the transition connector that starts with the point given if it exists + + # Returns the transition connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -786,17 +786,17 @@ if self.Type == "connection": connectors.append(self.Condition) return self.FindNearestConnector(position, connectors) - + # Returns the transition condition connector def GetConditionConnector(self): if self.Type == "connection": return self.Condition return None - + # Returns input and output transition connectors def GetConnectors(self): return {"inputs": [self.Input], "outputs": [self.Output]} - + # Test if point given is on transition input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector @@ -814,7 +814,7 @@ def SetType(self, type, condition = None): if self.Type != type: if self.Type == "connection": - self.Condition.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) + self.Condition.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) self.Type = type if type == "connection": self.Condition = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2), WEST) @@ -829,7 +829,7 @@ self.Condition = condition self.RefreshConditionSize() self.RefreshBoundingBox() - + # Returns the transition type def GetType(self): return self.Type @@ -839,7 +839,7 @@ self.Priority = priority self.RefreshPrioritySize() self.RefreshBoundingBox() - + # Returns the transition type def GetPriority(self): return self.Priority @@ -849,11 +849,11 @@ if self.Type != "connection": return self.Condition return None - + # Returns the transition minimum size def GetMinSize(self): return SFC_TRANSITION_SIZE - + # Align input element with this step def RefreshInputPosition(self): wires = self.Input.GetWires() @@ -870,7 +870,7 @@ input_block.MoveActionBlock((diffx, 0)) input_block.Move(diffx, 0) input_block.RefreshInputPosition() - + # Align output element with this step def RefreshOutputPosition(self, move = None): wires = self.Output.GetWires() @@ -902,12 +902,12 @@ def OnLeftDClick(self, event, dc, scaling): # Edit the transition properties self.Parent.EditTransitionContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the menu with special items for a step self.Parent.PopupDefaultMenu() - + # Refreshes the transition state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -920,7 +920,7 @@ return movex, 0 else: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac = 2, height_fac = 2) - + # Refresh input element model def RefreshInputModel(self): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -930,7 +930,7 @@ input_block.RefreshModel(False) if not isinstance(input_block, SFC_Divergence): input_block.RefreshInputModel() - + # Refresh output element model def RefreshOutputModel(self, move=False): output = self.GetNextConnector() @@ -939,7 +939,7 @@ output_block.RefreshModel(False) if not isinstance(output_block, SFC_Divergence) or move: output_block.RefreshOutputModel(move) - + # Refreshes the transition model def RefreshModel(self, move=True): self.Parent.RefreshTransitionModel(self) @@ -950,20 +950,20 @@ self.RefreshOutputModel() else: self.Output.RefreshWires() - + # Adds an highlight to the block def AddHighlight(self, infos, start, end ,highlight_type): if infos[0] in ["reference", "inline", "priority"] and start[0] == 0 and end[0] == 0: highlights = self.Highlights.setdefault(infos[0], []) AddHighlight(highlights, (start, end, highlight_type)) - + # Removes an highlight from the block def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] in ["reference", "inline", "priority"]: highlights = self.Highlights.get(infos[0], []) if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0: self.Highlights.pop(infos[0]) - + # Removes all the highlights of one particular type from the block def ClearHighlight(self, highlight_type=None): if highlight_type is None: @@ -974,7 +974,7 @@ highlights = ClearHighlights(highlight, highlight_type) if len(highlights) == 0: self.Highlights.pop(name) - + # Draws transition def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -991,7 +991,7 @@ else: dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.BLACK_BRUSH) - + if getattr(dc, "printing", False): if self.Type != "connection": condition_size = dc.GetTextExtent(self.Condition) @@ -1002,14 +1002,14 @@ condition_size = self.ConditionSize if self.Priority != 0: priority_size = self.PrioritySize - + # Draw plain rectangle for representing the transition - dc.DrawRectangle(self.Pos.x, - self.Pos.y + (self.Size[1] - SFC_TRANSITION_SIZE[1])/2, + dc.DrawRectangle(self.Pos.x, + self.Pos.y + (self.Size[1] - SFC_TRANSITION_SIZE[1])/2, self.Size[0] + 1, SFC_TRANSITION_SIZE[1] + 1) vertical_line_x = self.Input.GetPosition()[0] - dc.DrawLine(vertical_line_x, self.Pos.y, vertical_line_x, self.Pos.y + self.Size[1] + 1) + dc.DrawLine(vertical_line_x, self.Pos.y, vertical_line_x, self.Pos.y + self.Size[1] + 1) # Draw transition condition if self.Type != "connection": if self.Condition != "": @@ -1028,7 +1028,7 @@ self.Output.Draw(dc) if self.Type == "connection": self.Condition.Draw(dc) - + if not getattr(dc, "printing", False): for name, highlights in self.Highlights.iteritems(): if name == "priority": @@ -1046,7 +1046,7 @@ """ class SFC_Divergence(Graphic_Element): - + # Create a new divergence def __init__(self, parent, type, number = 2, id = None): Graphic_Element.__init__(self, parent) @@ -1068,7 +1068,7 @@ self.Outputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)] self.Value = None self.PreviousValue = None - + def Flush(self): for input in self.Inputs: input.Flush() @@ -1076,7 +1076,7 @@ for output in self.Outputs: output.Flush() self.Outputs = [] - + def SpreadCurrent(self): if self.Parent.Debug: self.PreviousValue = self.Value @@ -1102,7 +1102,7 @@ self.Parent.ElementNeedRefresh(self) for output in self.Outputs: output.SpreadCurrent(False) - + # Make a clone of this SFC_Divergence def Clone(self, parent, id = None, pos = None): divergence = SFC_Divergence(parent, self.Type, max(len(self.Inputs), len(self.Outputs)), id) @@ -1114,10 +1114,10 @@ divergence.Inputs = [input.Clone(divergence) for input in self.Inputs] divergence.Outputs = [output.Clone(divergence) for output in self.Outputs] return divergence - + def GetConnectorTranslation(self, element): return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs)) - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -1129,27 +1129,27 @@ if output.IsConnected(): rect = rect.Union(output.GetConnectedRedrawRect(movex, movey)) return rect - + # Forbids to resize the divergence def Resize(self, x, y, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.Resize(self, x, 0, width, self.GetMinSize()[1]) - + # Delete this divergence by calling the appropriate method def Delete(self): self.Parent.DeleteDivergence(self) - + # Returns the divergence type def GetType(self): return self.Type - + # Unconnect input and output def Clean(self): for input in self.Inputs: input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) for output in self.Outputs: output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Add a branch to the divergence def AddBranch(self): if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: @@ -1168,7 +1168,7 @@ connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone = True) self.Inputs.append(connector) self.MoveConnector(connector, SFC_DEFAULT_SEQUENCE_INTERVAL) - + # Remove a branch from the divergence def RemoveBranch(self, connector): if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: @@ -1179,41 +1179,41 @@ if connector in self.Inputs and len(self.Inputs) > 2: self.Inputs.remove(connector) self.MoveConnector(self.Inputs[0], 0) - + # Remove the handled branch from the divergence def RemoveHandledBranch(self): handle_type, handle = self.Handle if handle_type == HANDLE_CONNECTOR: handle.UnConnect(delete=True) self.RemoveBranch(handle) - + # Return the number of branches for the divergence def GetBranchNumber(self): if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]: return len(self.Outputs) elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]: return len(self.Inputs) - + # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): return self.BoundingBox.InsideXY(pt.x, pt.y) or self.TestConnector(pt, exclude=False) != None - + # Refresh the divergence bounding box def RefreshBoundingBox(self): if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]: - self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, + self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]: - self.BoundingBox = wx.Rect(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, + self.BoundingBox = wx.Rect(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, self.Size[0] + 2 * SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Size[1] + 1) - + # Refresh the position of wires connected to divergence def RefreshConnected(self, exclude = []): for input in self.Inputs: input.MoveConnected(exclude) for output in self.Outputs: output.MoveConnected(exclude) - + # Moves the divergence connector given def MoveConnector(self, connector, movex): position = connector.GetRelPosition() @@ -1241,8 +1241,8 @@ self.Size[0] = maxx - minx connector.MoveConnected() self.RefreshBoundingBox() - - # Returns the divergence connector that starts with the point given if it exists + + # Returns the divergence connector that starts with the point given if it exists def GetConnector(self, position, name = None): # if a name is given if name is not None: @@ -1254,11 +1254,11 @@ if name == output.GetName(): return output return self.FindNearestConnector(position, self.Inputs + self.Outputs) - - # Returns input and output divergence connectors + + # Returns input and output divergence connectors def GetConnectors(self): return {"inputs": self.Inputs, "outputs": self.Outputs} - + # Test if point given is on divergence input or output connector def TestConnector(self, pt, direction = None, exclude=True): # Test input connector @@ -1270,7 +1270,7 @@ if output.TestPoint(pt, direction, exclude): return output return None - + # Changes the divergence size def SetSize(self, width, height): height = self.GetMinSize()[1] @@ -1290,7 +1290,7 @@ output.MoveConnected() self.Size = wx.Size(width, height) self.RefreshBoundingBox() - + # Returns the divergence minimum size def GetMinSize(self, default=False): width = 0 @@ -1304,7 +1304,7 @@ elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]: return width, 3 return 0, 0 - + # Refresh the position of the block connected to connector def RefreshConnectedPosition(self, connector): wires = connector.GetWires() @@ -1340,7 +1340,7 @@ self.RefreshOutputPosition((0, diffy)) for input in self.Inputs: input.MoveConnected() - + # Align output element with this divergence def RefreshOutputPosition(self, move = None): if move: @@ -1359,7 +1359,7 @@ if not isinstance(output_block, SFC_Divergence) or output_block.GetConnectors()["inputs"].index(output) == 0: output_block.Move(move[0], move[1], self.Parent.Wires) output_block.RefreshOutputPosition(move) - + # Method called when a LeftDown event have been generated def OnLeftDown(self, event, dc, scaling): self.RealConnectors = {"Inputs":[],"Outputs":[]} @@ -1370,12 +1370,12 @@ position = output.GetRelPosition() self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0])) Graphic_Element.OnLeftDown(self, event, dc, scaling) - + # Method called when a LeftUp event have been generated def OnLeftUp(self, event, dc, scaling): Graphic_Element.OnLeftUp(self, event, dc, scaling) self.RealConnectors = None - + # Method called when a RightDown event have been generated def OnRightDown(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -1389,7 +1389,7 @@ self.oldPos = GetScaledEventPosition(event, dc, scaling) else: Graphic_Element.OnRightDown(self, event, dc, scaling) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): pos = GetScaledEventPosition(event, dc, scaling) @@ -1414,7 +1414,7 @@ else: # Popup the divergence menu without delete branch self.Parent.PopupDivergenceMenu(False) - + # Refreshes the divergence state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): handle_type, handle = self.Handle @@ -1430,7 +1430,7 @@ elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) return 0, 0 - + # Refresh output element model def RefreshOutputModel(self, move=False): if move and self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -1442,7 +1442,7 @@ output_block.RefreshModel(False) if not isinstance(output_block, SFC_Divergence) or move: output_block.RefreshOutputModel(move) - + # Refreshes the divergence model def RefreshModel(self, move=True): self.Parent.RefreshDivergenceModel(self) @@ -1453,7 +1453,7 @@ else: for output in self.Outputs: output.RefreshWires() - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -1467,13 +1467,13 @@ if self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]: posx -= SFC_SIMULTANEOUS_SEQUENCE_EXTRA width += SFC_SIMULTANEOUS_SEQUENCE_EXTRA * 2 - dc.DrawRectangle(int(round((posx - 1) * scalex)) - 2, - int(round((self.Pos.y - 1) * scaley)) - 2, - int(round((width + 3) * scalex)) + 5, + dc.DrawRectangle(int(round((posx - 1) * scalex)) - 2, + int(round((self.Pos.y - 1) * scaley)) - 2, + int(round((width + 3) * scalex)) + 5, int(round((self.Size.height + 3) * scaley)) + 5) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Draws divergence def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -1487,16 +1487,16 @@ if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]: dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]: - dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, + dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y, self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y) - dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + self.Size[1], + dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + self.Size[1], self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y + self.Size[1]) # Draw inputs and outputs connectors for input in self.Inputs: input.Draw(dc) for output in self.Outputs: output.Draw(dc) - + #------------------------------------------------------------------------------- # Sequencial Function Chart Jump to Step @@ -1507,7 +1507,7 @@ """ class SFC_Jump(Graphic_Element): - + # Create a new jump def __init__(self, parent, target, id = None): Graphic_Element.__init__(self, parent) @@ -1519,19 +1519,19 @@ self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True) self.Value = None self.PreviousValue = None - + def Flush(self): if self.Input is not None: self.Input.Flush() self.Input = None - + def SpreadCurrent(self): if self.Parent.Debug: self.PreviousValue = self.Value self.Value = self.Input.ReceivingCurrent() if self.Value != self.PreviousValue and self.Visible: self.Parent.ElementNeedRefresh(self) - + # Make a clone of this SFC_Jump def Clone(self, parent, id = None, pos = None): jump = SFC_Jump(parent, self.Target, id) @@ -1542,10 +1542,10 @@ jump.SetPosition(self.Pos.x, self.Pos.y) jump.Input = self.Input.Clone(jump) return jump - + def GetConnectorTranslation(self, element): return {self.Input : element.Input} - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -1555,29 +1555,29 @@ if self.Input.IsConnected(): rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey)) return rect - + # Forbids to change the jump size def SetSize(self, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.SetSize(self, width, height) - + # Forbids to resize jump def Resize(self, x, y, width, height): if self.Parent.GetDrawingMode() == FREEDRAWING_MODE: Graphic_Element.Resize(self, x, y, width, height) - + # Delete this jump by calling the appropriate method def Delete(self): self.Parent.DeleteJump(self) - + # Unconnect input def Clean(self): self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the size of text for target def RefreshTargetSize(self): self.TargetSize = self.Parent.GetTextExtent(self.Target) - + # Returns if the point given is in the bounding box def HitTest(self, pt, connectors=True): # Calculate the bounding box of the condition outside the transition @@ -1587,22 +1587,22 @@ text_width, text_height) return text_bbx.InsideXY(pt.x, pt.y) or Graphic_Element.HitTest(self, pt, connectors) - + # Refresh the jump bounding box def RefreshBoundingBox(self): text_width, text_height = self.Parent.GetTextExtent(self.Target) # Calculate the bounding box size bbx_width = self.Size[0] + 2 + text_width - self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y - CONNECTOR_SIZE, + self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y - CONNECTOR_SIZE, bbx_width + 1, self.Size[1] + CONNECTOR_SIZE + 1) - + # Returns the connector connected to input def GetPreviousConnector(self): wires = self.Input.GetWires() if len(wires) == 1: return wires[0][0].GetOtherConnected(self.Input) return None - + # Refresh the element connectors position def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -1611,41 +1611,41 @@ horizontal_pos = round(float(self.Pos.x + horizontal_pos) / float(scaling[0])) * scaling[0] - self.Pos.x self.Input.SetPosition(wx.Point(horizontal_pos, 0)) self.RefreshConnected() - + # Refresh the position of wires connected to jump def RefreshConnected(self, exclude = []): if self.Input: self.Input.MoveConnected(exclude) - - # Returns input jump connector + + # Returns input jump connector def GetConnector(self, position = None, name = None): return self.Input - - # Returns all the jump connectors + + # Returns all the jump connectors def GetConnectors(self): return {"inputs": [self.Input], "outputs": []} - + # Test if point given is on jump input connector def TestConnector(self, pt, direction = None, exclude = True): # Test input connector if self.Input and self.Input.TestPoint(pt, direction, exclude): return self.Input return None - + # Changes the jump target def SetTarget(self, target): self.Target = target self.RefreshTargetSize() self.RefreshBoundingBox() - + # Returns the jump target def GetTarget(self): return self.Target - + # Returns the jump minimum size def GetMinSize(self): return SFC_JUMP_SIZE - + # Align input element with this jump def RefreshInputPosition(self): if self.Input: @@ -1662,21 +1662,21 @@ input_block.MoveActionBlock((diffx, 0)) input_block.Move(diffx, 0) input_block.RefreshInputPosition() - + # Can't align output element, because there is no output def RefreshOutputPosition(self, move = None): pass - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the jump properties self.Parent.EditJumpContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupDefaultMenu() - + # Refreshes the jump state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -1688,7 +1688,7 @@ return movex, 0 else: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac = 2) - + # Refresh input element model def RefreshInputModel(self): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -1698,32 +1698,32 @@ input_block.RefreshModel(False) if not isinstance(input_block, SFC_Divergence): input_block.RefreshInputModel() - + # Refresh output element model def RefreshOutputModel(self, move=False): pass - + # Refreshes the jump model def RefreshModel(self, move=True): self.Parent.RefreshJumpModel(self) if move: if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: self.RefreshInputModel() - + # Adds an highlight to the variable def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "target" and start[0] == 0 and end[0] == 0: AddHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes an highlight from the variable def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] == "target": RemoveHighlight(self.Highlights, (start, end, highlight_type)) - + # Removes all the highlights of one particular type from the variable def ClearHighlight(self, highlight_type=None): ClearHighlights(self.Highlights, highlight_type) - + # Draws the highlightment of this element if it is highlighted def DrawHighlightment(self, dc): scalex, scaley = dc.GetUserScale() @@ -1731,16 +1731,16 @@ dc.SetPen(MiterPen(HIGHLIGHTCOLOR)) dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR)) dc.SetLogicalFunction(wx.AND) - points = [wx.Point(int(round((self.Pos.x - 2) * scalex)) - 3, + points = [wx.Point(int(round((self.Pos.x - 2) * scalex)) - 3, int(round((self.Pos.y - 2) * scaley)) - 2), - wx.Point(int(round((self.Pos.x + self.Size[0] + 2) * scalex)) + 4, + wx.Point(int(round((self.Pos.x + self.Size[0] + 2) * scalex)) + 4, int(round((self.Pos.y - 2) * scaley)) - 2), - wx.Point(int(round((self.Pos.x + self.Size[0] / 2) * scalex)), + wx.Point(int(round((self.Pos.x + self.Size[0] / 2) * scalex)), int(round((self.Pos.y + self.Size[1] + 3) * scaley)) + 4)] dc.DrawPolygon(points) dc.SetLogicalFunction(wx.COPY) dc.SetUserScale(scalex, scaley) - + # Draws divergence def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -1750,12 +1750,12 @@ else: dc.SetPen(MiterPen(wx.BLACK)) dc.SetBrush(wx.BLACK_BRUSH) - + if getattr(dc, "printing", False): target_size = dc.GetTextExtent(self.Target) else: target_size = self.TargetSize - + # Draw plain rectangle for representing the divergence dc.DrawLine(self.Pos.x + self.Size[0] / 2, self.Pos.y, self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1]) points = [wx.Point(self.Pos.x, self.Pos.y), @@ -1769,10 +1769,10 @@ # Draw input connector if self.Input: self.Input.Draw(dc) - + if not getattr(dc, "printing", False): DrawHighlightedText(dc, self.Target, self.Highlights, target_pos[0], target_pos[1]) - + #------------------------------------------------------------------------------- # Sequencial Function Chart Action Block @@ -1783,7 +1783,7 @@ """ class SFC_ActionBlock(Graphic_Element): - + # Create a new action block def __init__(self, parent, actions = [], id = None): Graphic_Element.__init__(self, parent) @@ -1796,19 +1796,19 @@ self.SetActions(actions) self.Value = None self.PreviousValue = None - + def Flush(self): if self.Input is not None: self.Input.Flush() self.Input = None - + def SpreadCurrent(self): if self.Parent.Debug: self.PreviousValue = self.Value self.Value = self.Input.ReceivingCurrent() if self.Value != self.PreviousValue and self.Visible: self.Parent.ElementNeedRefresh(self) - + # Make a clone of this SFC_ActionBlock def Clone(self, parent, id = None, pos = None): actions = [action.copy() for action in self.Actions] @@ -1820,10 +1820,10 @@ action_block.SetPosition(self.Pos.x, self.Pos.y) action_block.Input = self.Input.Clone(action_block) return action_block - + def GetConnectorTranslation(self, element): return {self.Input : element.Input} - + # Returns the RedrawRect def GetRedrawRect(self, movex = 0, movey = 0): rect = Graphic_Element.GetRedrawRect(self, movex, movey) @@ -1833,17 +1833,17 @@ if self.Input.IsConnected(): rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey)) return rect - + # Returns the number of action lines def GetLineNumber(self): return len(self.Actions) - + def GetLineSize(self): if len(self.Actions) > 0: return self.Size[1] / len(self.Actions) else: return SFC_ACTION_MIN_SIZE[1] - + # Forbids to resize the action block def Resize(self, x, y, width, height): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -1851,38 +1851,38 @@ self.SetSize(width, self.Size[1]) else: Graphic_Element.Resize(self, x, y, width, height) - + # Delete this action block by calling the appropriate method def Delete(self): self.Parent.DeleteActionBlock(self) - + # Unconnect input and output def Clean(self): self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE) - + # Refresh the action block bounding box def RefreshBoundingBox(self): self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) - + # Refresh the position of wires connected to action block def RefreshConnected(self, exclude = []): self.Input.MoveConnected(exclude) - - # Returns input action block connector + + # Returns input action block connector def GetConnector(self, position = None, name = None): return self.Input - - # Returns all the action block connectors + + # Returns all the action block connectors def GetConnectors(self): return {"inputs": [self.Input], "outputs": []} - + # Test if point given is on action block input connector def TestConnector(self, pt, direction = None, exclude = True): # Test input connector if self.Input.TestPoint(pt, direction, exclude): return self.Input return None - + # Refresh the element connectors position def RefreshConnectors(self): scaling = self.Parent.GetScaling() @@ -1891,7 +1891,7 @@ vertical_pos = round(float(self.Pos.y + vertical_pos) / float(scaling[1])) * scaling[1] - self.Pos.y self.Input.SetPosition(wx.Point(0, vertical_pos)) self.RefreshConnected() - + # Changes the action block actions def SetActions(self, actions): self.Actions = actions @@ -1931,25 +1931,25 @@ input_block = wires[0][0].GetOtherConnected(self.Input).GetParentBlock() input_block.RefreshOutputPosition() input_block.RefreshOutputModel(True) - + # Returns the action block actions def GetActions(self): return self.Actions - + # Returns the action block minimum size def GetMinSize(self): return self.MinSize - + # Method called when a LeftDClick event have been generated def OnLeftDClick(self, event, dc, scaling): # Edit the action block properties self.Parent.EditActionBlockContent(self) - + # Method called when a RightUp event have been generated def OnRightUp(self, event, dc, scaling): # Popup the default menu self.Parent.PopupDefaultMenu() - + # Refreshes the action block state according to move defined and handle selected def ProcessDragging(self, movex, movey, event, scaling): if self.Parent.GetDrawingMode() != FREEDRAWING_MODE: @@ -1970,18 +1970,18 @@ else: return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling) - + # Refreshes the action block model def RefreshModel(self, move=True): self.Parent.RefreshActionBlockModel(self) - + # Adds an highlight to the variable def AddHighlight(self, infos, start, end, highlight_type): if infos[0] == "action" and infos[1] < len(self.Actions): action_highlights = self.Highlights.setdefault(infos[1], {}) attribute_highlights = action_highlights.setdefault(infos[2], []) AddHighlight(attribute_highlights, (start, end, highlight_type)) - + # Removes an highlight from the block def RemoveHighlight(self, infos, start, end, highlight_type): if infos[0] == "action" and infos[1] < len(self.Actions): @@ -1991,7 +1991,7 @@ action_highlights.pop(infos[2]) if len(action_highlights) == 0: self.Highlights.pop(infos[1]) - + # Removes all the highlights of one particular type from the block def ClearHighlight(self, highlight_type=None): if highlight_type is None: @@ -2006,7 +2006,7 @@ action_highlights.pop(name) if len(action_highlights) == 0: self.Highlights.pop(number) - + # Draws divergence def Draw(self, dc): Graphic_Element.Draw(self, dc) @@ -2018,14 +2018,14 @@ colsize = [self.ColSize[0], self.Size[0] - self.ColSize[0] - self.ColSize[2], self.ColSize[2]] # Draw plain rectangle for representing the action block dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1) - dc.DrawLine(self.Pos.x + colsize[0], self.Pos.y, + dc.DrawLine(self.Pos.x + colsize[0], self.Pos.y, self.Pos.x + colsize[0], self.Pos.y + self.Size[1]) - dc.DrawLine(self.Pos.x + colsize[0] + colsize[1], self.Pos.y, + dc.DrawLine(self.Pos.x + colsize[0] + colsize[1], self.Pos.y, self.Pos.x + colsize[0] + colsize[1], self.Pos.y + self.Size[1]) line_size = self.GetLineSize() for i, action in enumerate(self.Actions): if i != 0: - dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size, + dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size, self.Pos.x + self.Size[0], self.Pos.y + i * line_size) qualifier_size = dc.GetTextExtent(action.qualifier) if action.duration != "": @@ -2048,7 +2048,7 @@ indicator_pos = (self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - indicator_size[0]) / 2, self.Pos.y + i * line_size + (line_size - indicator_size[1]) / 2) dc.DrawText(action.indicator, indicator_pos[0], indicator_pos[1]) - + if not getattr(dc, "printing", False): action_highlights = self.Highlights.get(i, {}) for name, attribute_highlights in action_highlights.iteritems(): @@ -2060,7 +2060,6 @@ DrawHighlightedText(dc, action.value, attribute_highlights, content_pos[0], content_pos[1]) elif name == "indicator": DrawHighlightedText(dc, action.indicator, attribute_highlights, indicator_pos[0], indicator_pos[1]) - + # Draw input connector self.Input.Draw(dc) - diff -r d51af006fa6b -r 64d8f52bc8c8 graphics/ToolTipProducer.py --- a/graphics/ToolTipProducer.py Fri Aug 11 15:18:19 2017 +0300 +++ b/graphics/ToolTipProducer.py Mon Aug 14 19:13:01 2017 +0300 @@ -25,7 +25,7 @@ import wx from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD - + #------------------------------------------------------------------------------- # Tool Tip Producer class #------------------------------------------------------------------------------- @@ -35,29 +35,29 @@ """ class ToolTipProducer: - + def __init__(self, parent): """ Constructor @param parent: Parent Viewer """ self.Parent = parent - + self.ToolTip = None self.ToolTipPos = None - + # Timer for firing Tool tip display self.ToolTipTimer = wx.Timer(self.Parent, -1) - self.Parent.Bind(wx.EVT_TIMER, - self.OnToolTipTimer, + self.Parent.Bind(wx.EVT_TIMER, + self.OnToolTipTimer, self.ToolTipTimer) - + def __del__(self): """ Destructor """ self.DestroyToolTip() - + def OnToolTipTimer(self, event): """ Callback for Tool Tip firing timer Event @@ -65,21 +65,21 @@ """ # Get Tool Tip text value = self.GetToolTipValue() - + if value is not None and self.ToolTipPos is not None: # Create Tool Tip self.ToolTip = CustomToolTip(self.Parent, value) self.ToolTip.SetToolTipPosition(self.ToolTipPos) self.ToolTip.Show() - + def GetToolTipValue(self): """ Return tool tip text - Have to be overridden by inherited classes - @return: Tool tip text (None if not overridden) + Have to be overridden by inherited classes + @return: Tool tip text (None if not overridden) """ return None - + def DisplayToolTip(self, pos): """ Display Tool tip @@ -87,14 +87,14 @@ """ # Destroy current displayed Tool tip self.DestroyToolTip() - + # Save Tool Tip position self.ToolTipPos = pos # Start Tool tip firing timer self.ToolTipTimer.Start( - int(TOOLTIP_WAIT_PERIOD * 1000), + int(TOOLTIP_WAIT_PERIOD * 1000), oneShot=True) - + def SetToolTipText(self, text): """ Set current Tool tip text @@ -102,7 +102,7 @@ """ if self.ToolTip is not None: self.ToolTip.SetTip(text) - + def DestroyToolTip(self): """ Destroy current displayed Tool Tip @@ -110,7 +110,7 @@ # Stop Tool tip firing timer self.ToolTipTimer.Stop() self.ToolTipPos = None - + # Destroy Tool Tip if self.ToolTip is not None: self.ToolTip.Destroy() diff -r d51af006fa6b -r 64d8f52bc8c8 i18n/mki18n.py --- a/i18n/mki18n.py Fri Aug 11 15:18:19 2017 +0300 +++ b/i18n/mki18n.py Mon Aug 14 19:13:01 2017 +0300 @@ -1,21 +1,21 @@ #! /usr/bin/env python # -*- coding: iso-8859-1 -*- -# +# # PYTHON MODULE: MKI18N.PY # ========= -# +# # Abstract: Make Internationalization (i18n) files for an application. -# +# # Copyright Pierre Rouleau. 2003. Released to public domain. -# +# # Last update: Saturday, November 8, 2003. @ 15:55:18. -# +# # File: ROUP2003N01::C:/dev/python/mki18n.py -# +# # RCS $Header: //software/official/MKS/MKS_SI/TV_NT/dev/Python/rcs/mki18n.py 1.5 2003/11/05 19:40:04 PRouleau Exp $ -# +# # Update history: -# +# # - File created: Saturday, June 7, 2003. by Pierre Rouleau # - 10/06/03 rcs : RCS Revision 1.1 2003/06/10 10:06:12 PRouleau # - 10/06/03 rcs : RCS Initial revision @@ -27,22 +27,22 @@ # - 05/11/03 rcs : RCS Revision 1.4 2003/10/22 06:39:31 PRouleau # - 05/11/03 P.R.: [code:fix] : included the unixpath() in this file. # - 08/11/03 rcs : RCS Revision 1.5 2003/11/05 19:40:04 PRouleau -# +# # RCS $Log: $ -# -# -# ----------------------------------------------------------------------------- -""" -mki18n allows you to internationalize your software. You can use it to +# +# +# ----------------------------------------------------------------------------- +""" +mki18n allows you to internationalize your software. You can use it to create the GNU .po files (Portable Object) and the compiled .mo files (Machine Object). -mki18n module can be used from the command line or from within a script (see +mki18n module can be used from the command line or from within a script (see the Usage at the end of this page). Table of Contents ----------------- - + makePO() -- Build the Portable Object file for the application -- catPO() -- Concatenate one or several PO files with the application domain files. -- makeMO() -- Compile the Portable Object files into the Machine Object stored in the right location. -- @@ -60,24 +60,24 @@ libiconv ftp site`_ and get version 1.9.1 or later. Get the Windows .ZIP files and install the packages inside c:/gnu. All binaries will be stored inside c:/gnu/bin. Just put c:/gnu/bin inside your PATH. You will need - the following files: - - - `gettext-runtime-0.12.1.bin.woe32.zip`_ + the following files: + + - `gettext-runtime-0.12.1.bin.woe32.zip`_ - `gettext-tools-0.12.1.bin.woe32.zip`_ - - `libiconv-1.9.1.bin.woe32.zip`_ + - `libiconv-1.9.1.bin.woe32.zip`_ .. _GNU libiconv: http://www.gnu.org/software/libiconv/ .. _GNU libiconv ftp site: http://www.ibiblio.org/pub/gnu/libiconv/ -.. _gettext-runtime-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-runtime-0.12.1.bin.woe32.zip -.. _gettext-tools-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-tools-0.12.1.bin.woe32.zip +.. _gettext-runtime-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-runtime-0.12.1.bin.woe32.zip +.. _gettext-tools-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-tools-0.12.1.bin.woe32.zip .. _libiconv-1.9.1.bin.woe32.zip: http://www.ibiblio.org/pub/gnu/libiconv/libiconv-1.9.1.bin.woe32.zip """ # ----------------------------------------------------------------------------- # Module Import # ------------- -# +# import os import sys import wx @@ -143,24 +143,24 @@ def makePO(applicationDirectoryPath, applicationDomain=None, verbose=0) : """Build the Portable Object Template file for the application. - makePO builds the .pot file for the application stored inside - a specified directory by running xgettext for all application source - files. It finds the name of all files by looking for a file called 'app.fil'. + makePO builds the .pot file for the application stored inside + a specified directory by running xgettext for all application source + files. It finds the name of all files by looking for a file called 'app.fil'. If this file does not exists, makePo raises an IOError exception. By default the application domain (the application name) is the same as the directory name but it can be overridden by the 'applicationDomain' argument. - makePO always creates a new file called messages.pot. If it finds files - of the form app_xx.po where 'app' is the application name and 'xx' is one - of the ISO 639 two-letter language codes, makePO resynchronizes those - files with the latest extracted strings (now contained in messages.pot). + makePO always creates a new file called messages.pot. If it finds files + of the form app_xx.po where 'app' is the application name and 'xx' is one + of the ISO 639 two-letter language codes, makePO resynchronizes those + files with the latest extracted strings (now contained in messages.pot). This process updates all line location number in the language-specific - .po files and may also create new entries for translation (or comment out - some). The .po file is not changed, instead a new file is created with + .po files and may also create new entries for translation (or comment out + some). The .po file is not changed, instead a new file is created with the .new extension appended to the name of the .po file. - By default the function does not display what it is doing. Set the + By default the function does not display what it is doing. Set the verbose argument to 1 to force it to print its commands. """ @@ -175,10 +175,10 @@ raise IOError(2,'No module file: ' % filelist) fileout = 'messages.pot' - # Steps: + # Steps: # Use xgettext to parse all application modules # The following switches are used: - # + # # -s : sort output by string content (easier to use when we need to merge several .po files) # --files-from=app.fil : The list of files is taken from the file: app.fil # --output= : specifies the name of the output file (using a .pot extension) @@ -190,12 +190,12 @@ processCustomFiles(filelist, fileout, XSD_STRING_MODEL, 'Extra XSD strings') XML_TC6_STRING_MODEL = re.compile("\s*\s*", re.MULTILINE | re.DOTALL) - processCustomFiles(filelist, fileout, XML_TC6_STRING_MODEL, 'Extra TC6 documentation strings') + processCustomFiles(filelist, fileout, XML_TC6_STRING_MODEL, 'Extra TC6 documentation strings') # generate messages.po cmd = 'msginit --no-wrap --no-translator -i %s -l en_US.UTF-8 -o messages.po' % (fileout) if verbose: print cmd - os.system(cmd) + os.system(cmd) languageDict = getlanguageDict() @@ -251,18 +251,18 @@ # ----------------------------------------------------------------------------- # m a k e M O ( ) -- Compile the Portable Object files into the Machine Object stored in the right location. -- # ^^^^^^^^^^^^^^^ -# +# def makeMO(applicationDirectoryPath,targetDir='./locale',applicationDomain=None, verbose=0, forceEnglish=0) : """Compile the Portable Object files into the Machine Object stored in the right location. - makeMO converts all translated language-specific PO files located inside - the application directory into the binary .MO files stored inside the + makeMO converts all translated language-specific PO files located inside + the application directory into the binary .MO files stored inside the LC_MESSAGES sub-directory for the found locale files. - makeMO searches for all files that have a name of the form 'app_xx.po' - inside the application directory specified by the first argument. The - 'app' is the application domain name (that can be specified by the - applicationDomain argument or is taken from the directory name). The 'xx' + makeMO searches for all files that have a name of the form 'app_xx.po' + inside the application directory specified by the first argument. The + 'app' is the application domain name (that can be specified by the + applicationDomain argument or is taken from the directory name). The 'xx' corresponds to one of the ISO 639 two-letter language codes. makeMo stores the resulting files inside a sub-directory of `targetDir` @@ -296,7 +296,7 @@ if verbose: print cmd os.system(cmd) os.chdir(currentDir) - + # ----------------------------------------------------------------------------- # p r i n t U s a g e -- Displays how to use this script from the command line -- # ^^^^^^^^^^^^^^^^^^^ @@ -331,7 +331,7 @@ # # # You must specify one of the -p or -m option to perform the work. You can # # specify the path of the target application. If you leave it out mki18n # - # will use the current directory as the application main directory. # + # will use the current directory as the application main directory. # # # ##################################################################################""" if errorMsg: @@ -340,14 +340,14 @@ # ----------------------------------------------------------------------------- # f i l e B a s e O f ( ) -- Return base name of filename -- # ^^^^^^^^^^^^^^^^^^^^^^^ -# +# def fileBaseOf(filename,withPath=0) : """fileBaseOf(filename,withPath) ---> string Return base name of filename. The returned string never includes the extension. - Use os.path.basename() to return the basename with the extension. The - second argument is optional. If specified and if set to 'true' (non zero) - the string returned contains the full path of the file name. Otherwise the + Use os.path.basename() to return the basename with the extension. The + second argument is optional. If specified and if set to 'true' (non zero) + the string returned contains the full path of the file name. Otherwise the path is excluded. [Example] @@ -370,8 +370,8 @@ 'abcdef' >>> fileBaseOf(fn,1) 'abcdef' - """ - pos = filename.rfind('.') + """ + pos = filename.rfind('.') if pos > 0: filename = filename[:pos] if withPath: @@ -381,49 +381,49 @@ # ----------------------------------------------------------------------------- # m k d i r ( ) -- Create a directory (and possibly the entire tree) -- # ^^^^^^^^^^^^^ -# +# def mkdir(directory) : """Create a directory (and possibly the entire tree). The os.mkdir() will fail to create a directory if one of the directory in the specified path does not exist. mkdir() solves this problem. It creates every intermediate directory - required to create the final path. Under Unix, the function + required to create the final path. Under Unix, the function only supports forward slash separator, but under Windows and MacOS the function supports the forward slash and the OS separator (backslash under windows). - """ + """ # translate the path separators directory = unixpath(directory) # build a list of all directory elements aList = filter(lambda x: len(x)>0, directory.split('/')) - theLen = len(aList) + theLen = len(aList) # if the first element is a Windows-style disk drive # concatenate it with the first directory if aList[0].endswith(':'): if theLen > 1: aList[1] = aList[0] + '/' + aList[1] - del aList[0] - theLen -= 1 + del aList[0] + theLen -= 1 # if the original directory starts at root, - # make sure the first element of the list + # make sure the first element of the list # starts at root too - if directory[0] == '/': + if directory[0] == '/': aList[0] = '/' + aList[0] - # Now iterate through the list, check if the + # Now iterate through the list, check if the # directory exists and if not create it theDir = '' for i in range(theLen): theDir += aList[i] if not os.path.exists(theDir): os.mkdir(theDir) - theDir += '/' - + theDir += '/' + # ----------------------------------------------------------------------------- # u n i x p a t h ( ) -- Return a path name that contains Unix separator. -- # ^^^^^^^^^^^^^^^^^^^ -# +# def unixpath(thePath) : r"""Return a path name that contains Unix separator. @@ -432,7 +432,7 @@ 'd:/test' >>> unixpath("d:/test/file.txt") 'd:/test/file.txt' - >>> + >>> """ thePath = os.path.normpath(thePath) if os.sep == '/': @@ -440,11 +440,11 @@ else: return thePath.replace(os.sep,'/') -# ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- # S c r i p t e x e c u t i o n -- Runs when invoked from the command line -- # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# +# if __name__ == "__main__": import getopt # command line parsing argc = len(sys.argv) @@ -453,11 +453,11 @@ sys.exit(1) # If there is some arguments, parse the command line validOptions = "ehmpv" - validLongOptions = ['domain=', 'moTarget='] + validLongOptions = ['domain=', 'moTarget='] option = {} option['forceEnglish'] = 0 option['mo'] = 0 - option['po'] = 0 + option['po'] = 0 option['verbose'] = 0 option['domain'] = None option['moTarget'] = None @@ -465,11 +465,11 @@ optionList,pargs = getopt.getopt(sys.argv[1:],validOptions,validLongOptions) except getopt.GetoptError, e: printUsage(e[0]) - sys.exit(1) + sys.exit(1) for (opt,val) in optionList: - if (opt == '-h'): + if (opt == '-h'): printUsage() - sys.exit(0) + sys.exit(0) elif (opt == '-e'): option['forceEnglish'] = 1 elif (opt == '-m'): option['mo'] = 1 elif (opt == '-p'): option['po'] = 1 @@ -497,7 +497,7 @@ printUsage(e[1] + '\n You must write a file app.fil that contains the list of all files to parse.') if option['mo']: makeMO(appDirPath,option['moTarget'],option['domain'],option['verbose'],option['forceEnglish']) - sys.exit(1) - - -# ----------------------------------------------------------------------------- + sys.exit(1) + + +# ----------------------------------------------------------------------------- diff -r d51af006fa6b -r 64d8f52bc8c8 plcopen/plcopen.py --- a/plcopen/plcopen.py Fri Aug 11 15:18:19 2017 +0300 +++ b/plcopen/plcopen.py Mon Aug 14 19:13:01 2017 +0300 @@ -49,14 +49,14 @@ VarOrder = ["Local","Temp","Input","Output","InOut","External","Global","Access"] """ -Define which action qualifier must be associated with a duration +Define which action qualifier must be associated with a duration """ -QualifierList = OrderedDict([("N", False), ("R", False), ("S", False), - ("L", True), ("D", True), ("P", False), ("P0", False), +QualifierList = OrderedDict([("N", False), ("R", False), ("S", False), + ("L", True), ("D", True), ("P", False), ("P0", False), ("P1", False), ("SD", True), ("DS", True), ("SL", True)]) -FILTER_ADDRESS_MODEL = "(%%[IQM](?:[XBWDL])?)(%s)((?:\.[0-9]+)*)" +FILTER_ADDRESS_MODEL = "(%%[IQM](?:[XBWDL])?)(%s)((?:\.[0-9]+)*)" def update_address(address, address_model, new_leading): result = address_model.match(address) @@ -73,10 +73,10 @@ return v1 """ -Helper class for bounding_box calculation +Helper class for bounding_box calculation """ class rect: - + def __init__(self, x=None, y=None, width=None, height=None): self.x_min = x self.x_max = None @@ -86,19 +86,19 @@ self.x_max = x + width if height is not None and y is not None: self.y_max = y + height - + def update(self, x, y): self.x_min = _init_and_compare(min, self.x_min, x) self.x_max = _init_and_compare(max, self.x_max, x) self.y_min = _init_and_compare(min, self.y_min, y) self.y_max = _init_and_compare(max, self.y_max, y) - + def union(self, rect): self.x_min = _init_and_compare(min, self.x_min, rect.x_min) self.x_max = _init_and_compare(max, self.x_max, rect.x_max) self.y_min = _init_and_compare(min, self.y_min, rect.y_min) self.y_max = _init_and_compare(max, self.y_max, rect.y_max) - + def bounding_box(self): width = height = None if self.x_min is not None and self.x_max is not None: @@ -125,7 +125,7 @@ test_result = [] result = criteria["pattern"].search(text) while result is not None: - prev_pos=result.endpos + prev_pos=result.endpos start = TextLenInRowColumn(text[:result.start()]) end = TextLenInRowColumn(text[:result.end() - 1]) test_result.append((start, end, "\n".join(lines[start[0]:end[0] + 1]))) @@ -141,11 +141,11 @@ PLCOpen_XPath = lambda xpath: etree.XPath(xpath, namespaces=PLCOpenParser.NSMAP) LOAD_POU_PROJECT_TEMPLATE = """ - - @@ -176,8 +176,8 @@ PLCOpen_v1_xml = PLCOpen_v1_file.read() PLCOpen_v1_file.close() PLCOpen_v1_xml = PLCOpen_v1_xml.replace( - "http://www.plcopen.org/xml/tc6.xsd", - "http://www.plcopen.org/xml/tc6_0201") + "http://www.plcopen.org/xml/tc6.xsd", + "http://www.plcopen.org/xml/tc6_0201") PLCOpen_v1_xsd = etree.XMLSchema(etree.fromstring(PLCOpen_v1_xml)) # XPath for file compatibility process @@ -190,21 +190,21 @@ def LoadProjectXML(project_xml): project_xml = project_xml.replace( - "http://www.plcopen.org/xml/tc6.xsd", + "http://www.plcopen.org/xml/tc6.xsd", "http://www.plcopen.org/xml/tc6_0201") for cre, repl in [ (re.compile("(?)(?:)(?!)"), "]]>")]: project_xml = cre.sub(repl, project_xml) - + try: tree, error = PLCOpenParser.LoadXMLString(project_xml) if error is None: return tree, None - + if PLCOpen_v1_xsd.validate(tree): # Make file compatible with PLCOpen v2 - + # Update resource interval value for resource in ProjectResourcesXPath(tree): for task in resource.gettask(): @@ -229,13 +229,13 @@ else: text += "%dms"%(time_values[3] / 1000) task.set("interval", text) - + # Update resources pou instance attributes for pouInstance in ResourceInstancesXpath(resource): type_name = pouInstance.attrib.pop("type") if type_name is not None: pouInstance.set("typeName", type_name) - + # Update transitions condition for transition_condition in TransitionsConditionXPath(tree): connections = ConditionConnectionsXPath(transition_condition) @@ -245,23 +245,23 @@ connectionPointIn.setrelPositionXY(0, 0) for connection in connections: connectionPointIn.append(connection) - + # Update actionBlocks for actionBlock in ActionBlocksXPath(tree): for connectionPointOut in ActionBlocksConnectionPointOutXPath(actionBlock): actionBlock.remove(connectionPointOut) - + for action in actionBlock.getaction(): action.set("localId", "0") relPosition = PLCOpenParser.CreateElement("relPosition", "action") relPosition.set("x", "0") relPosition.set("y", "0") action.setrelPosition(relPosition) - + return tree, None - + return tree, error - + except Exception, e: return None, e.message @@ -288,9 +288,9 @@ def SaveProject(project, filepath): project_file = open(filepath, 'w') project_file.write(etree.tostring( - project, - pretty_print=True, - xml_declaration=True, + project, + pretty_print=True, + xml_declaration=True, encoding='utf-8')) project_file.close() @@ -302,7 +302,7 @@ text = pattern.sub(new_name, text) self.setanyText(text) setattr(cls, "updateElementName", updateElementName) - + def updateElementAddress(self, address_model, new_leading): text = self.getanyText() startpos = 0 @@ -315,28 +315,28 @@ result = address_model.search(text, startpos) self.setanyText(text) setattr(cls, "updateElementAddress", updateElementAddress) - + def hasblock(self, block_type): - text = self.getanyText() + text = self.getanyText() pattern = re.compile('\\b' + block_type + '\\b', re.IGNORECASE) return pattern.search(text) is not None setattr(cls, "hasblock", hasblock) - + def Search(self, criteria, parent_infos): return [(tuple(parent_infos),) + result for result in TestTextElement(self.getanyText(), criteria)] setattr(cls, "Search", Search) - + cls = PLCOpenParser.GetElementClass("project") if cls: - + def setname(self, name): self.contentHeader.setname(name) setattr(cls, "setname", setname) - + def getname(self): return self.contentHeader.getname() setattr(cls, "getname", getname) - + def getfileHeader(self): fileheader_obj = self.fileHeader return { @@ -351,7 +351,7 @@ ("contentDescription", fileheader_obj.getcontentDescription())] } setattr(cls, "getfileHeader", getfileHeader) - + def setfileHeader(self, fileheader): fileheader_obj = self.fileHeader for attr in ["companyName", "companyURL", "productName", @@ -361,7 +361,7 @@ if value is not None: setattr(fileheader_obj, attr, value) setattr(cls, "setfileHeader", setfileHeader) - + def getcontentHeader(self): contentheader_obj = self.contentHeader contentheader = { @@ -378,7 +378,7 @@ contentheader["scaling"] = self.contentHeader.getscaling() return contentheader setattr(cls, "getcontentHeader", getcontentHeader) - + def setcontentHeader(self, contentheader): contentheader_obj = self.contentHeader for attr, value in contentheader.iteritems(): @@ -392,7 +392,7 @@ elif attr in ["modificationDateTime", "organization", "language"]: setattr(contentheader_obj, attr, value) setattr(cls, "setcontentHeader", setcontentHeader) - + def gettypeElementFunc(element_type): elements_xpath = PLCOpen_XPath( "ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name=$name]" % locals()) @@ -402,7 +402,7 @@ return elements[0] return None return gettypeElement - + datatypes_xpath = PLCOpen_XPath("ppx:types/ppx:dataTypes/ppx:dataType") filtered_datatypes_xpath = PLCOpen_XPath( "ppx:types/ppx:dataTypes/ppx:dataType[@name!=$exclude]") @@ -411,43 +411,43 @@ return filtered_datatypes_xpath(self, exclude=exclude) return datatypes_xpath(self) setattr(cls, "getdataTypes", getdataTypes) - + setattr(cls, "getdataType", gettypeElementFunc("dataType")) - + def appenddataType(self, name): if self.getdataType(name) is not None: raise ValueError, "\"%s\" Data Type already exists !!!"%name self.types.appenddataTypeElement(name) setattr(cls, "appenddataType", appenddataType) - + def insertdataType(self, index, datatype): self.types.insertdataTypeElement(index, datatype) setattr(cls, "insertdataType", insertdataType) - + def removedataType(self, name): self.types.removedataTypeElement(name) setattr(cls, "removedataType", removedataType) - + def getpous(self, exclude=None, filter=[]): return self.xpath( - "ppx:types/ppx:pous/ppx:pou%s%s" % + "ppx:types/ppx:pous/ppx:pou%s%s" % (("[@name!='%s']" % exclude) if exclude is not None else '', ("[%s]" % " or ".join( map(lambda x: "@pouType='%s'" % x, filter))) if len(filter) > 0 else ""), namespaces=PLCOpenParser.NSMAP) setattr(cls, "getpous", getpous) - + setattr(cls, "getpou", gettypeElementFunc("pou")) - + def appendpou(self, name, pou_type, body_type): self.types.appendpouElement(name, pou_type, body_type) setattr(cls, "appendpou", appendpou) - + def insertpou(self, index, pou): self.types.insertpouElement(index, pou) setattr(cls, "insertpou", insertpou) - + def removepou(self, name): self.types.removepouElement(name) setattr(cls, "removepou", removepou) @@ -473,7 +473,7 @@ new_configuration = PLCOpenParser.CreateElement("configuration", "configurations") new_configuration.setname(name) self.instances.configurations.appendconfiguration(new_configuration) - setattr(cls, "addconfiguration", addconfiguration) + setattr(cls, "addconfiguration", addconfiguration) def removeconfiguration(self, name): configuration = self.getconfiguration(name) @@ -481,7 +481,7 @@ raise ValueError, ("\"%s\" configuration doesn't exist !!!") % name self.instances.configurations.remove(configuration) setattr(cls, "removeconfiguration", removeconfiguration) - + resources_xpath = PLCOpen_XPath( "ppx:instances/ppx:configurations/ppx:configuration[@name=$configname]/ppx:resource[@name=$name]") def getconfigurationResource(self, config_name, name): @@ -562,11 +562,11 @@ cls = PLCOpenParser.GetElementClass("contentHeader", "project") if cls: - + def setpageSize(self, width, height): self.coordinateInfo.setpageSize(width, height) setattr(cls, "setpageSize", setpageSize) - + def getpageSize(self): return self.coordinateInfo.getpageSize() setattr(cls, "getpageSize", getpageSize) @@ -575,7 +575,7 @@ for language, (x, y) in scaling.items(): self.coordinateInfo.setscaling(language, x, y) setattr(cls, "setscaling", setscaling) - + def getscaling(self): scaling = {} scaling["FBD"] = self.coordinateInfo.getscaling("FBD") @@ -595,7 +595,7 @@ self.pageSize.setx(width) self.pageSize.sety(height) setattr(cls, "setpageSize", setpageSize) - + def getpageSize(self): if self.pageSize is not None: return self.pageSize.getx(), self.pageSize.gety() @@ -613,7 +613,7 @@ self.sfc.scaling.setx(x) self.sfc.scaling.sety(y) setattr(cls, "setscaling", setscaling) - + def getscaling(self, language): if language == "FBD": return self.fbd.scaling.getx(), self.fbd.scaling.gety() @@ -685,7 +685,7 @@ cls = PLCOpenParser.GetElementClass("configuration", "configurations") if cls: - + def addglobalVar(self, var_type, name, location="", description=""): globalvars = self.getglobalVars() if len(globalvars) == 0: @@ -701,7 +701,7 @@ var.setdocumentation(ft) globalvars[-1].appendvariable(var) setattr(cls, "addglobalVar", addglobalVar) - + def updateElementName(self, old_name, new_name): _updateConfigurationResourceElementName(self, old_name, new_name) for resource in self.getresource(): @@ -727,7 +727,7 @@ search_result.extend(resource.Search(criteria, parent_infos)) return search_result setattr(cls, "Search", Search) - + cls = PLCOpenParser.GetElementClass("resource", "configuration") if cls: def updateElementName(self, old_name, new_name): @@ -788,7 +788,7 @@ setattr(cls, "updateElementAddress", updateElementAddress) def Search(self, criteria, parent_infos=[]): - return _Search([("single", self.getsingle()), + return _Search([("single", self.getsingle()), ("interval", self.getinterval()), ("priority", str(self.getpriority()))], criteria, parent_infos) @@ -802,7 +802,7 @@ setattr(cls, "updateElementName", updateElementName) def Search(self, criteria, parent_infos=[]): - return _Search([("name", self.getname()), + return _Search([("name", self.getname()), ("type", self.gettypeName())], criteria, parent_infos) setattr(cls, "Search", Search) @@ -822,22 +822,22 @@ elif vartype_content_name == "array": base_type = vartype_content.baseType.getcontent() base_type_name = base_type.getLocalTag() - # Array derived directly from a user defined type + # Array derived directly from a user defined type if base_type_name == "derived": basetype_name = base_type.getname() - # Array derived directly from a string type + # Array derived directly from a string type elif base_type_name in ["string", "wstring"]: basetype_name = base_type_name.upper() - # Array derived directly from an elementary type + # Array derived directly from an elementary type else: basetype_name = base_type_name return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (x.getlower(), x.getupper()), vartype_content.getdimension())), basetype_name) # Variable type is an elementary type return vartype_content_name setattr(cls, "gettypeAsText", gettypeAsText) - + def Search(self, criteria, parent_infos=[]): - search_result = _Search([("name", self.getname()), + search_result = _Search([("name", self.getname()), ("type", self.gettypeAsText()), ("location", self.getaddress())], criteria, parent_infos) @@ -855,7 +855,7 @@ def getdataTypeElements(self): return self.dataTypes.getdataType() setattr(cls, "getdataTypeElements", getdataTypeElements) - + def getdataTypeElement(self, name): elements = self.dataTypes.getdataType() for element in elements: @@ -870,11 +870,11 @@ new_datatype.setname(name) new_datatype.baseType.setcontent(PLCOpenParser.CreateElement("BOOL", "dataType")) setattr(cls, "appenddataTypeElement", appenddataTypeElement) - + def insertdataTypeElement(self, index, dataType): self.dataTypes.insertdataType(index, dataType) setattr(cls, "insertdataTypeElement", insertdataTypeElement) - + def removedataTypeElement(self, name): found = False for element in self.dataTypes.getdataType(): @@ -885,11 +885,11 @@ if not found: raise ValueError, _("\"%s\" Data Type doesn't exist !!!")%name setattr(cls, "removedataTypeElement", removedataTypeElement) - + def getpouElements(self): return self.pous.getpou() setattr(cls, "getpouElements", getpouElements) - + def getpouElement(self, name): elements = self.pous.getpou() for element in elements: @@ -909,11 +909,11 @@ new_pou.appendbody(PLCOpenParser.CreateElement("body", "pou")) new_pou.setbodyType(body_type) setattr(cls, "appendpouElement", appendpouElement) - + def insertpouElement(self, index, pou): self.pous.insertpou(index, pou) setattr(cls, "insertpouElement", insertpouElement) - + def removepouElement(self, name): found = False for element in self.pous.getpou(): @@ -941,7 +941,7 @@ cls = PLCOpenParser.GetElementClass("dataType", "dataTypes") if cls: setattr(cls, "updateElementName", _updateBaseTypeElementName) - + def Search(self, criteria, parent_infos=[]): search_result = [] filter = criteria["filter"] @@ -956,7 +956,7 @@ cls = PLCOpenParser.GetElementClass("dataType") if cls: - + def updateElementName(self, old_name, new_name): content_name = self.content.getLocalTag() if content_name in ["derived", "array", "subrangeSigned", "subrangeUnsigned"]: @@ -987,7 +987,7 @@ if TextMatched(self.name, old_name): self.name = new_name setattr(cls, "updateElementName", updateElementName) - + def Search(self, criteria, parent_infos=[]): return [(tuple(parent_infos),) + result for result in TestTextElement(self.name, criteria)] setattr(cls, "Search", Search) @@ -995,7 +995,7 @@ cls = PLCOpenParser.GetElementClass("array", "dataType") if cls: setattr(cls, "updateElementName", _updateBaseTypeElementName) - + def Search(self, criteria, parent_infos=[]): search_result = self.baseType.Search(criteria, parent_infos) for i, dimension in enumerate(self.getdimension()): @@ -1024,11 +1024,11 @@ cls = PLCOpenParser.GetElementClass("enum", "dataType") if cls: - + def updateElementName(self, old_name, new_name): pass setattr(cls, "updateElementName", updateElementName) - + enumerated_datatype_values_xpath = PLCOpen_XPath("ppx:values/ppx:value") def Search(self, criteria, parent_infos=[]): search_result = [] @@ -1044,21 +1044,21 @@ if type_content_type == "derived": return type_content.getname() return type_content_type.upper() - + cls = PLCOpenParser.GetElementClass("pou", "pous") if cls: - + block_inputs_xpath = PLCOpen_XPath( "ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable") block_outputs_xpath = PLCOpen_XPath( "ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable") - def getblockInfos(self): + def getblockInfos(self): block_infos = { - "name" : self.getname(), - "type" : self.getpouType(), + "name" : self.getname(), + "type" : self.getpouType(), "extensible" : False, - "inputs" : [], - "outputs" : [], + "inputs" : [], + "outputs" : [], "comment" : self.getdescription()} if self.interface is not None: return_type = self.interface.getreturnType() @@ -1071,15 +1071,15 @@ block_infos["outputs"].extend( [(var.getname(), _getvariableTypeinfos(var.type), "none") for var in block_outputs_xpath(self)]) - - block_infos["usage"] = ("\n (%s) => (%s)" % - (", ".join(["%s:%s" % (input[1], input[0]) + + block_infos["usage"] = ("\n (%s) => (%s)" % + (", ".join(["%s:%s" % (input[1], input[0]) for input in block_infos["inputs"]]), - ", ".join(["%s:%s" % (output[1], output[0]) + ", ".join(["%s:%s" % (output[1], output[0]) for output in block_infos["outputs"]]))) return block_infos setattr(cls, "getblockInfos", getblockInfos) - + def setdescription(self, description): doc = self.getdocumentation() if doc is None: @@ -1087,14 +1087,14 @@ self.setdocumentation(doc) doc.setanyText(description) setattr(cls, "setdescription", setdescription) - + def getdescription(self): doc = self.getdocumentation() if doc is not None: return doc.getanyText() return "" setattr(cls, "getdescription", getdescription) - + def setbodyType(self, body_type): if len(self.body) > 0: if body_type in ["IL", "ST", "LD", "FBD", "SFC"]: @@ -1102,66 +1102,66 @@ else: raise ValueError, "%s isn't a valid body type!"%type setattr(cls, "setbodyType", setbodyType) - + def getbodyType(self): if len(self.body) > 0: return self.body[0].getcontent().getLocalTag() setattr(cls, "getbodyType", getbodyType) - + def resetexecutionOrder(self): if len(self.body) > 0: self.body[0].resetexecutionOrder() setattr(cls, "resetexecutionOrder", resetexecutionOrder) - + def compileexecutionOrder(self): if len(self.body) > 0: self.body[0].compileexecutionOrder() setattr(cls, "compileexecutionOrder", compileexecutionOrder) - + def setelementExecutionOrder(self, instance, new_executionOrder): if len(self.body) > 0: self.body[0].setelementExecutionOrder(instance, new_executionOrder) setattr(cls, "setelementExecutionOrder", setelementExecutionOrder) - + def addinstance(self, instance): if len(self.body) > 0: self.body[0].appendcontentInstance(instance) setattr(cls, "addinstance", addinstance) - + def getinstances(self): if len(self.body) > 0: return self.body[0].getcontentInstances() return [] setattr(cls, "getinstances", getinstances) - + def getinstance(self, id): if len(self.body) > 0: return self.body[0].getcontentInstance(id) return None setattr(cls, "getinstance", getinstance) - + def getinstancesIds(self): if len(self.body) > 0: return self.body[0].getcontentInstancesIds() return [] setattr(cls, "getinstancesIds", getinstancesIds) - + def getinstanceByName(self, name): if len(self.body) > 0: return self.body[0].getcontentInstanceByName(name) return None setattr(cls, "getinstanceByName", getinstanceByName) - + def removeinstance(self, id): if len(self.body) > 0: self.body[0].removecontentInstance(id) setattr(cls, "removeinstance", removeinstance) - + def settext(self, text): if len(self.body) > 0: self.body[0].settext(text) setattr(cls, "settext", settext) - + def gettext(self): if len(self.body) > 0: return self.body[0].gettext() @@ -1178,17 +1178,17 @@ vars.append((reverse_types[varlist.getLocalTag()], varlist)) return vars setattr(cls, "getvars", getvars) - + def setvars(self, vars): if self.interface is None: self.interface = PLCOpenParser.CreateElement("interface", "pou") self.interface.setcontent(vars) setattr(cls, "setvars", setvars) - + def addpouExternalVar(self, var_type, name): self.addpouVar(var_type, name, "externalVars") setattr(cls, "addpouExternalVar", addpouExternalVar) - + def addpouVar(self, var_type, name, var_class="localVars", location="", description="", initval=""): if self.interface is None: self.interface = PLCOpenParser.CreateElement("interface", "pou") @@ -1218,11 +1218,11 @@ el = PLCOpenParser.CreateElement("initialValue", "variable") el.setvalue(initval) var.setinitialValue(el) - + varlist.appendvariable(var) setattr(cls, "addpouVar", addpouVar) setattr(cls, "addpouLocalVar", addpouVar) - + def changepouVar(self, old_type, old_name, new_type, new_name): if self.interface is not None: content = self.interface.getcontent() @@ -1236,7 +1236,7 @@ vartype_content.setname(new_type) return setattr(cls, "changepouVar", changepouVar) - + def removepouVar(self, var_type, name): if self.interface is not None: content = self.interface.getcontent() @@ -1255,14 +1255,14 @@ if self.getbodyType() in ["SFC"]: for instance in self.getinstances(): if isinstance(instance, PLCOpenParser.GetElementClass("step", "sfcObjects")) and TextMatched(instance.getname(), name): - return True + return True return False setattr(cls, "hasstep", hasstep) - + def hasblock(self, name=None, block_type=None): if self.getbodyType() in ["FBD", "LD", "SFC"]: for instance in self.getinstances(): - if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and + if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and (TextMatched(instance.getinstanceName(), name) or TextMatched(instance.gettypeName(), block_type))): return True if self.transitions: @@ -1279,7 +1279,7 @@ return self.body[0].hasblock(block_type) return False setattr(cls, "hasblock", hasblock) - + def addtransition(self, name, body_type): if self.transitions is None: self.addtransitions() @@ -1291,7 +1291,7 @@ if body_type == "ST": transition.settext(":= ;") setattr(cls, "addtransition", addtransition) - + def gettransition(self, name): if self.transitions is not None: for transition in self.transitions.gettransition(): @@ -1299,13 +1299,13 @@ return transition return None setattr(cls, "gettransition", gettransition) - + def gettransitionList(self): if self.transitions is not None: return self.transitions.gettransition() return [] setattr(cls, "gettransitionList", gettransitionList) - + def removetransition(self, name): if self.transitions is not None: removed = False @@ -1314,7 +1314,7 @@ if transition.getbodyType() in ["FBD", "LD", "SFC"]: for instance in transition.getinstances(): if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")): - self.removepouVar(instance.gettypeName(), + self.removepouVar(instance.gettypeName(), instance.getinstanceName()) self.transitions.remove(transition) removed = True @@ -1332,7 +1332,7 @@ action.setname(name) action.setbodyType(body_type) setattr(cls, "addaction", addaction) - + def getaction(self, name): if self.actions is not None: for action in self.actions.getaction(): @@ -1340,13 +1340,13 @@ return action return None setattr(cls, "getaction", getaction) - + def getactionList(self): if self.actions is not None: return self.actions.getaction() return [] setattr(cls, "getactionList", getactionList) - + def removeaction(self, name): if self.actions is not None: removed = False @@ -1355,7 +1355,7 @@ if action.getbodyType() in ["FBD", "LD", "SFC"]: for instance in action.getinstances(): if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")): - self.removepouVar(instance.gettypeName(), + self.removepouVar(instance.gettypeName(), instance.getinstanceName()) self.actions.remove(action) removed = True @@ -1417,7 +1417,7 @@ if result is not None: content.remove(variable) setattr(cls, "removeVariableByFilter", removeVariableByFilter) - + def Search(self, criteria, parent_infos=[]): search_result = [] filter = criteria["filter"] @@ -1494,7 +1494,7 @@ def hasblock(self, name=None, block_type=None): if self.getbodyType() in ["FBD", "LD", "SFC"]: for instance in self.getinstances(): - if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and + if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and (TextMatched(instance.getinstanceName(), name) or TextMatched(instance.gettypeName(), block_type))): return True elif block_type is not None: @@ -1506,7 +1506,7 @@ def updateElementAddress(self, address_model, new_leading): self.body.updateElementAddress(address_model, new_leading) - + cls = PLCOpenParser.GetElementClass("transition", "transitions") if cls: @@ -1526,7 +1526,7 @@ setattr(cls, "hasblock", hasblock) setattr(cls, "updateElementName", updateElementName) setattr(cls, "updateElementAddress", updateElementAddress) - + def Search(self, criteria, parent_infos): search_result = [] parent_infos = parent_infos[:-1] + ["T::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())] @@ -1554,7 +1554,7 @@ setattr(cls, "hasblock", hasblock) setattr(cls, "updateElementName", updateElementName) setattr(cls, "updateElementAddress", updateElementAddress) - + def Search(self, criteria, parent_infos): search_result = [] parent_infos = parent_infos[:-1] + ["A::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())] @@ -1571,24 +1571,24 @@ def resetcurrentExecutionOrderId(self): object.__setattr__(self, "currentExecutionOrderId", 0) setattr(cls, "resetcurrentExecutionOrderId", resetcurrentExecutionOrderId) - + def getnewExecutionOrderId(self): object.__setattr__(self, "currentExecutionOrderId", self.currentExecutionOrderId + 1) return self.currentExecutionOrderId setattr(cls, "getnewExecutionOrderId", getnewExecutionOrderId) - + def resetexecutionOrder(self): if self.content.getLocalTag() == "FBD": for element in self.content.getcontent(): - if not isinstance(element, (PLCOpenParser.GetElementClass("comment", "commonObjects"), - PLCOpenParser.GetElementClass("connector", "commonObjects"), + if not isinstance(element, (PLCOpenParser.GetElementClass("comment", "commonObjects"), + PLCOpenParser.GetElementClass("connector", "commonObjects"), PLCOpenParser.GetElementClass("continuation", "commonObjects"))): element.setexecutionOrderId(0) self.checkedBlocksDict.clear() else: raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "resetexecutionOrder", resetexecutionOrder) - + def compileexecutionOrder(self): if self.content.getLocalTag() == "FBD": self.resetexecutionOrder() @@ -1602,7 +1602,7 @@ else: raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "compileexecutionOrder", compileexecutionOrder) - + def compileelementExecutionOrder(self, link): if self.content.getLocalTag() == "FBD": localid = link.getrefLocalId() @@ -1626,7 +1626,7 @@ else: raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "compileelementExecutionOrder", compileelementExecutionOrder) - + def setelementExecutionOrder(self, instance, new_executionOrder): if self.content.getLocalTag() == "FBD": old_executionOrder = instance.getexecutionOrderId() @@ -1642,21 +1642,21 @@ else: raise TypeError, _("Can only generate execution order on FBD networks!") setattr(cls, "setelementExecutionOrder", setelementExecutionOrder) - + def appendcontentInstance(self, instance): if self.content.getLocalTag() in ["LD","FBD","SFC"]: self.content.appendcontent(instance) else: raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag() setattr(cls, "appendcontentInstance", appendcontentInstance) - + def getcontentInstances(self): if self.content.getLocalTag() in ["LD","FBD","SFC"]: return self.content.getcontent() else: raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag() setattr(cls, "getcontentInstances", getcontentInstances) - + instance_by_id_xpath = PLCOpen_XPath("*[@localId=$localId]") instance_by_name_xpath = PLCOpen_XPath("ppx:block[@instanceName=$name]") def getcontentInstance(self, local_id): @@ -1668,7 +1668,7 @@ else: raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag() setattr(cls, "getcontentInstance", getcontentInstance) - + def getcontentInstancesIds(self): if self.content.getLocalTag() in ["LD","FBD","SFC"]: return OrderedDict([(instance.getlocalId(), True) @@ -1676,7 +1676,7 @@ else: raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag() setattr(cls, "getcontentInstancesIds", getcontentInstancesIds) - + def getcontentInstanceByName(self, name): if self.content.getLocalTag() in ["LD","FBD","SFC"]: instance = instance_by_name_xpath(self.content) @@ -1686,7 +1686,7 @@ else: raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag() setattr(cls, "getcontentInstanceByName", getcontentInstanceByName) - + def removecontentInstance(self, local_id): if self.content.getLocalTag() in ["LD","FBD","SFC"]: instance = instance_by_id_xpath(self.content, localId=local_id) @@ -1697,7 +1697,7 @@ else: raise TypeError, "%s body don't have instances!"%self.content.getLocalTag() setattr(cls, "removecontentInstance", removecontentInstance) - + def settext(self, text): if self.content.getLocalTag() in ["IL","ST"]: self.content.setanyText(text) @@ -1711,14 +1711,14 @@ else: raise TypeError, _("%s body don't have text!")%self.content.getLocalTag() setattr(cls, "gettext", gettext) - + def hasblock(self, block_type): if self.content.getLocalTag() in ["IL","ST"]: return self.content.hasblock(block_type) else: raise TypeError, _("%s body don't have text!")%self.content.getLocalTag() setattr(cls, "hasblock", hasblock) - + def updateElementName(self, old_name, new_name): if self.content.getLocalTag() in ["IL", "ST"]: self.content.updateElementName(old_name, new_name) @@ -1753,7 +1753,7 @@ def setx(self, x): self.position.setx(x) - + def sety(self, y): self.position.sety(y) @@ -1828,7 +1828,7 @@ def _translate(self, dx, dy): self.setx(self.getx() + dx) self.sety(self.gety() + dy) - + def _translateConnections(connectionPointIn, dx, dy): connections = connectionPointIn.getconnections() if connections is not None: @@ -1892,11 +1892,11 @@ def setcontentText(self, text): self.content.setanyText(text) setattr(cls, "setcontentText", setcontentText) - + def getcontentText(self): return self.content.getanyText() setattr(cls, "getcontentText", getcontentText) - + def updateElementName(self, old_name, new_name): self.content.updateElementName(old_name, new_name) setattr(cls, "updateElementName", updateElementName) @@ -2004,7 +2004,7 @@ condition.setcontent(PLCOpenParser.CreateElement("ST", "inline")) condition.settext(value) setattr(cls, "setconditionContent", setconditionContent) - + def getconditionContent(self): if self.condition is not None: content = self.condition.getcontent() @@ -2035,21 +2035,21 @@ bbox.union(_getConnectionsBoundingBox(condition_connection)) return bbox setattr(cls, "getBoundingBox", getBoundingBox) - + def translate(self, dx, dy): _translateSingle(self, dx, dy) condition_connection = self.getconditionConnection() if condition_connection is not None: _translateConnections(condition_connection, dx, dy) setattr(cls, "translate", translate) - + def filterConnections(self, connections): _filterConnectionsSingle(self, connections) condition_connection = self.getconditionConnection() if condition_connection is not None: _filterConnections(condition_connection, self.localId, connections) setattr(cls, "filterConnections", filterConnections) - + def updateConnectionsId(self, translation): connections_end = [] if self.connectionPointIn is not None: @@ -2087,7 +2087,7 @@ return condition_connection.getconnections() return None setattr(cls, "getconnections", getconnections) - + def Search(self, criteria, parent_infos=[]): parent_infos = parent_infos + ["transition", self.getlocalId()] search_result = [] @@ -2104,7 +2104,7 @@ _initElementClass("selectionConvergence", "sfcObjects", "multiple") _initElementClass("simultaneousDivergence", "sfcObjects", "single") _initElementClass("simultaneousConvergence", "sfcObjects", "multiple") - + cls = _initElementClass("jumpStep", "sfcObjects", "single") if cls: def Search(self, criteria, parent_infos): @@ -2117,7 +2117,7 @@ if self.reference is not None: self.reference.setname(name) setattr(cls, "setreferenceName", setreferenceName) - + def getreferenceName(self): if self.reference is not None: return self.reference.getname() @@ -2129,7 +2129,7 @@ self.inline.setcontent(PLCOpenParser.CreateElement("ST", "inline")) self.inline.settext(content) setattr(cls, "setinlineContent", setinlineContent) - + def getinlineContent(self): if self.inline is not None: return self.inline.gettext() @@ -2155,7 +2155,7 @@ if qualifier is None: qualifier = "N" return _Search([("inline", self.getinlineContent()), - ("reference", self.getreferenceName()), + ("reference", self.getreferenceName()), ("qualifier", qualifier), ("duration", self.getduration()), ("indicator", self.getindicator())], @@ -2318,33 +2318,33 @@ def removeconnections(self): self.content = None setattr(cls, "removeconnections", removeconnections) - + connection_xpath = PLCOpen_XPath("ppx:connection") connection_by_position_xpath = PLCOpen_XPath("ppx:connection[position()=$pos]") def getconnections(self): return connection_xpath(self) setattr(cls, "getconnections", getconnections) - + def getconnection(self, idx): connection = connection_by_position_xpath(self, pos=idx+1) if len(connection) > 0: return connection[0] return None setattr(cls, "getconnection", getconnection) - + def setconnectionId(self, idx, local_id): connection = self.getconnection(idx) if connection is not None: connection.setrefLocalId(local_id) setattr(cls, "setconnectionId", setconnectionId) - + def getconnectionId(self, idx): connection = self.getconnection(idx) if connection is not None: return connection.getrefLocalId() return None setattr(cls, "getconnectionId", getconnectionId) - + def setconnectionPoints(self, idx, points): connection = self.getconnection(idx) if connection is not None: @@ -2363,7 +2363,7 @@ if connection is not None: connection.setformalParameter(parameter) setattr(cls, "setconnectionParameter", setconnectionParameter) - + def getconnectionParameter(self, idx): connection = self.getconnection(idx) if connection is not None: @@ -2398,7 +2398,7 @@ content.setvalue(value) self.setcontent(content) setattr(cls, "setvalue", setvalue) - + def getvalue(self): return self.content.getvalue() setattr(cls, "getvalue", getvalue) @@ -2420,7 +2420,7 @@ cls = PLCOpenParser.GetElementClass("arrayValue", "value") if cls: arrayValue_model = re.compile("([0-9]+)\((.*)\)$") - + def setvalue(self, value): elements = [] for item in extractValues(value[1:-1]): @@ -2436,7 +2436,7 @@ elements.append(element) self.value = elements setattr(cls, "setvalue", setvalue) - + def getvalue(self): values = [] for element in self.value: @@ -2457,7 +2457,7 @@ cls = PLCOpenParser.GetElementClass("structValue", "value") if cls: structValue_model = re.compile("(.*):=(.*)") - + def setvalue(self, value): elements = [] for item in extractValues(value[1:-1]): @@ -2470,11 +2470,10 @@ elements.append(element) self.value = elements setattr(cls, "setvalue", setvalue) - + def getvalue(self): values = [] for element in self.value: values.append("%s := %s"%(element.getmember(), element.getvalue())) return "(%s)"%", ".join(values) setattr(cls, "getvalue", getvalue) - diff -r d51af006fa6b -r 64d8f52bc8c8 plcopen/structures.py --- a/plcopen/structures.py Fri Aug 11 15:18:19 2017 +0300 +++ b/plcopen/structures.py Mon Aug 14 19:13:01 2017 +0300 @@ -92,7 +92,7 @@ """ take a .csv file and translate it it a "csv_table" -""" +""" def csv_file_to_table(file): return [ map(string.strip,line.split(';')) for line in file.xreadlines()] @@ -119,18 +119,18 @@ variable_from_csv = dict([(champ, val) for champ, val in zip(variables, fields[1:]) if champ!='']) standard_funtions_input_variables[variable_from_csv['name']] = variable_from_csv['type'] return standard_funtions_input_variables - + """ translate .csv file input declaration into PLCOpenEditor interessting values in : "(ANY_NUM, ANY_NUM)" and { ParameterName: Type, ...} -return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")] +return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")] """ def csv_input_translate(str_decl, variables, base): decl = str_decl.replace('(','').replace(')','').replace(' ','').split(',') params = [] - + len_of_not_predifined_variable = len([True for param_type in decl if param_type not in variables]) - + for param_type in decl: if param_type in variables.keys(): param_name = param_type @@ -147,7 +147,7 @@ """ Returns this kind of declaration for all standard functions - [{"name" : "Numerical", 'list': [ { + [{"name" : "Numerical", 'list': [ { 'baseinputnumber': 1, 'comment': 'Addition', 'extensible': True, @@ -158,19 +158,19 @@ 'type': 'function'}, ...... ] },.....] """ def get_standard_funtions(table): - + variables = get_standard_funtions_input_variables(table) - + fonctions = find_section("Standard_functions_type",table) Standard_Functions_Decl = [] Current_section = None - + translate = { "extensible" : lambda x: {"yes":True, "no":False}[x], "inputs" : lambda x:csv_input_translate(x,variables,baseinputnumber), "outputs":lambda x:[("OUT",x,"none")]} - + for fields in table: if fields[1]: # If function section name given @@ -191,14 +191,14 @@ if param in translate: Function_decl[param] = translate[param](value) Function_decl["type"] = "function" - + if Function_decl["name"].startswith('*') or Function_decl["name"].endswith('*') : input_ovrloading_types = GetSubTypes(Function_decl["inputs"][0][1]) output_types = GetSubTypes(Function_decl["outputs"][0][1]) else: input_ovrloading_types = [None] output_types = [None] - + funcdeclname_orig = Function_decl["name"] funcdeclname = Function_decl["name"].strip('*_') fdc = Function_decl["inputs"][:] @@ -210,14 +210,14 @@ Function_decl["inputs"] += [(decl_tpl[0], intype, decl_tpl[2])] else: Function_decl["inputs"] += [(decl_tpl)] - + if funcdeclname_orig.startswith('*'): - funcdeclin = intype + '_' + funcdeclname + funcdeclin = intype + '_' + funcdeclname else: funcdeclin = funcdeclname else: funcdeclin = funcdeclname - + for outype in output_types: if outype != None: decl_tpl = Function_decl["outputs"][0] @@ -234,7 +234,7 @@ filter_name = Function_decl["filter"] store = True for (InTypes, OutTypes) in ANY_TO_ANY_FILTERS.get(filter_name,[]): - outs = reduce(lambda a,b: a or b, + outs = reduce(lambda a,b: a or b, map(lambda testtype : IsOfType( Function_decl["outputs"][0][1], testtype), OutTypes)) @@ -253,7 +253,7 @@ Current_section["list"].append(Function_decl_copy) else: raise "First function must be in a category" - + return Standard_Functions_Decl StdBlckLst.extend(get_standard_funtions(csv_file_to_table(open(StdFuncsCSV)))) @@ -266,10 +266,10 @@ words = desc["comment"].split('"') if len(words) > 1: desc["comment"] = words[1] - desc["usage"] = ("\n (%s) => (%s)" % - (", ".join(["%s:%s" % (input[1], input[0]) + desc["usage"] = ("\n (%s) => (%s)" % + (", ".join(["%s:%s" % (input[1], input[0]) for input in desc["inputs"]]), - ", ".join(["%s:%s" % (output[1], output[0]) + ", ".join(["%s:%s" % (output[1], output[0]) for output in desc["outputs"]]))) BlkLst = StdBlckDct.setdefault(desc["name"],[]) BlkLst.append((section["name"], desc)) @@ -321,7 +321,7 @@ # Keywords for Structured Text ST_BLOCK_START_KEYWORDS = ["IF", "ELSIF", "ELSE", "CASE", "FOR", "WHILE", "REPEAT"] ST_BLOCK_END_KEYWORDS = ["END_IF", "END_CASE", "END_FOR", "END_WHILE", "END_REPEAT"] -ST_KEYWORDS = ["TRUE", "FALSE", "THEN", "OF", "TO", "BY", "DO", "DO", "UNTIL", "EXIT", +ST_KEYWORDS = ["TRUE", "FALSE", "THEN", "OF", "TO", "BY", "DO", "DO", "UNTIL", "EXIT", "RETURN", "NOT", "MOD", "AND", "XOR", "OR"] + ST_BLOCK_START_KEYWORDS + ST_BLOCK_END_KEYWORDS # All the keywords of IEC @@ -338,5 +338,3 @@ SFC_KEYWORDS, IL_KEYWORDS, ST_KEYWORDS])]: for keywords in keywords_list: all_keywords.extend([keyword for keyword in keywords if keyword not in all_keywords]) - - diff -r d51af006fa6b -r 64d8f52bc8c8 py_ext/PythonEditor.py --- a/py_ext/PythonEditor.py Fri Aug 11 15:18:19 2017 +0300 +++ b/py_ext/PythonEditor.py Mon Aug 14 19:13:01 2017 +0300 @@ -32,12 +32,12 @@ KEYWORDS = keyword.kwlist COMMENT_HEADER = "#" - + def SetCodeLexer(self): self.SetLexer(stc.STC_LEX_PYTHON) - + # Line numbers in margin - self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2,size:%(size)d' % faces) # Highlighted brace self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00,size:%(size)d' % faces) # Unmatched brace @@ -69,15 +69,14 @@ # Identifiers. I leave this as not bold because everything seems # to be an identifier if it doesn't match the above criterae self.StyleSetSpec(stc.STC_P_IDENTIFIER, 'fore:#000000,size:%(size)d' % faces) - + #------------------------------------------------------------------------------- # CFileEditor Main Frame Class #------------------------------------------------------------------------------- class PythonEditor(CodeFileEditor): - + CONFNODEEDITOR_TABS = [ (_("Python code"), "_create_CodePanel")] CODE_EDITOR = PythonCodeEditor - diff -r d51af006fa6b -r 64d8f52bc8c8 py_ext/py_ext.py --- a/py_ext/py_ext.py Fri Aug 11 15:18:19 2017 +0300 +++ b/py_ext/py_ext.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,10 +30,10 @@ class PythonLibrary(POULibrary): def GetLibraryPath(self): - return paths.AbsNeighbourFile(__file__, "pous.xml") + return paths.AbsNeighbourFile(__file__, "pous.xml") def Generate_C(self, buildpath, varlist, IECCFLAGS): - + plc_python_filepath = paths.AbsNeighbourFile(__file__, "plc_python.c") plc_python_file = open(plc_python_filepath, 'r') plc_python_code = plc_python_file.read() @@ -44,21 +44,19 @@ "PYTHON_POLL"]: python_eval_fb_list.append(v) python_eval_fb_count = max(1, len(python_eval_fb_list)) - + # prepare python code plc_python_code = plc_python_code % { "python_eval_fb_count": python_eval_fb_count } - + Gen_Pythonfile_path = os.path.join(buildpath, "py_ext.c") pythonfile = open(Gen_Pythonfile_path,'w') pythonfile.write(plc_python_code) pythonfile.close() - + return (["py_ext"], [(Gen_Pythonfile_path, IECCFLAGS)], True), "" class PythonFile(PythonFileCTNMixin): - + def GetIconName(self): return "Pyfile" - - diff -r d51af006fa6b -r 64d8f52bc8c8 runtime/PLCObject.py --- a/runtime/PLCObject.py Fri Aug 11 15:18:19 2017 +0300 +++ b/runtime/PLCObject.py Mon Aug 14 19:13:01 2017 +0300 @@ -143,8 +143,8 @@ self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle) self.PLC_ID = ctypes.c_char_p.in_dll(self.PLClibraryHandle, "PLC_ID") - if len(md5) == 32 : - self.PLC_ID.value = md5 + if len(md5) == 32 : + self.PLC_ID.value = md5 self._startPLC = self.PLClibraryHandle.startPLC self._startPLC.restype = ctypes.c_int @@ -556,5 +556,3 @@ return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" % (line_no, e_value, script.splitlines()[line_no - 1])) return (0, kwargs.get("returnVal", None)) - - diff -r d51af006fa6b -r 64d8f52bc8c8 runtime/ServicePublisher.py --- a/runtime/ServicePublisher.py Fri Aug 11 15:18:19 2017 +0300 +++ b/runtime/ServicePublisher.py Mon Aug 14 19:13:01 2017 +0300 @@ -30,20 +30,20 @@ def __init__(self): # type: fully qualified service type name self.serviceproperties = {'description':'Beremiz remote PLC'} - + self.name = None self.ip_32b = None self.port = None self.server = None self.service_name = None self.retrytimer = None - + def RegisterService(self, name, ip, port): try: self._RegisterService(name, ip, port) except Exception,e: self.retrytimer = threading.Timer(2,self.RegisterService,[name, ip, port]) - self.retrytimer.start() + self.retrytimer.start() def _RegisterService(self, name, ip, port): # name: fully qualified service name @@ -66,20 +66,20 @@ self.port, properties = self.serviceproperties)) self.retrytimer=None - + def UnRegisterService(self): if self.retrytimer is not None: self.retrytimer.cancel() self.server.unregisterService( - Zeroconf.ServiceInfo(service_type, - self.service_name, - self.ip_32b, - self.port, + Zeroconf.ServiceInfo(service_type, + self.service_name, + self.ip_32b, + self.port, properties = self.serviceproperties)) self.server.close() self.server = None - + def gethostaddr(self, dst = '224.0.1.41'): s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/build.py --- a/svgui/pyjs/build.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/build.py Mon Aug 14 19:13:01 2017 +0300 @@ -306,7 +306,7 @@ # Second, (dynamic only), post-analyse the places where modules # haven't changed # Third, write everything out. - + for platform in app_platforms: mod_code[platform] = {} @@ -337,11 +337,11 @@ print appcode #mod_code[platform][app_name] = appcode - # platform.Module.cache.js + # platform.Module.cache.js modules_done = ['pyjslib', 'sys', '_pyjs.js'] #modules_to_do = [app_name] + app_translator.library_modules - modules_to_do = [app_name] + app_translator.library_modules + modules_to_do = [app_name] + app_translator.library_modules dependencies = {} @@ -403,9 +403,9 @@ deps = uniquify(deps) #print "modname:", mod_name, deps dependencies[mod_name] = deps - + # work out the dependency ordering of the modules - + mod_levels[platform] = make_deps(None, dependencies, modules_done) # now write everything out @@ -473,7 +473,7 @@ app_libs_ += mod_cache_html_output.read() # write out the dependency ordering of the modules - + app_modnames = [] for md in mod_levels[platform]: @@ -512,7 +512,7 @@ file_name = "%s.%s.%s" % (platform.lower(), app_name, digest) else: file_name = "%s.%s" % (platform.lower(), app_name) - file_name += ".cache.html" + file_name += ".cache.html" out_path = join(output, file_name) out_file = open(out_path, 'w') out_file.write(file_contents) @@ -599,7 +599,7 @@ if has_nodeps(mod, deps): res.append(mod) return res - + # this function takes a dictionary of dependent modules and # creates a list of lists. the first list will be modules # that have no dependencies; the second list will be those @@ -721,4 +721,3 @@ if __name__ == "__main__": main() - diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/jsonrpc/django/jsonrpc.py --- a/svgui/pyjs/jsonrpc/django/jsonrpc.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon Aug 14 19:13:01 2017 +0300 @@ -19,13 +19,13 @@ # (r'^service1/$', 'djangoapp.views.jsonservice'), class JSONRPCService(JSONRPCServiceBase): - + def __call__(self, request, extra=None): return self.process(request.raw_post_data) def jsonremote(service): """Make JSONRPCService a decorator so that you can write : - + from jsonrpc import JSONRPCService chatservice = JSONRPCService() @@ -62,7 +62,7 @@ # part of the app: # (r'^formsservice/$', 'djangoapp.views.processor'), -from django import forms +from django import forms def builderrors(form): d = {} @@ -223,4 +223,3 @@ for item in serialize('python', l, fields=fields): res.append(dict_datetimeflatten(item)) return res - diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/jsonrpc/jsonrpc.py --- a/svgui/pyjs/jsonrpc/jsonrpc.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/jsonrpc/jsonrpc.py Mon Aug 14 19:13:01 2017 +0300 @@ -39,5 +39,4 @@ return self.error(id, 100, 'method "%s" does not exist' % method) def listmethods(self): - return self.methods.keys() - + return self.methods.keys() diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/lib/pyjslib.py --- a/svgui/pyjs/lib/pyjslib.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/lib/pyjslib.py Mon Aug 14 19:13:01 2017 +0300 @@ -20,7 +20,7 @@ # must declare import _before_ importing sys def import_module(path, parent_module, module_name, dynamic=1, async=False): - """ + """ """ JS(""" @@ -38,7 +38,7 @@ } var override_name = sys.platform + "." + module_name; - if (((sys.overrides != null) && + if (((sys.overrides != null) && (sys.overrides.has_key(override_name)))) { cache_file = sys.overrides.__getitem__(override_name) ; @@ -67,7 +67,7 @@ module_load_request[module_name] = 1; } - /* following a load, this first executes the script + /* following a load, this first executes the script * "preparation" function MODULENAME_loaded_fn() * and then sets up the loaded module in the namespace * of the parent. @@ -201,7 +201,7 @@ self.parent_mod = parent_mod def next(self): - + for i in range(len(self.app_modlist[self.idx])): app = self.app_modlist[self.idx][i] import_module(self.path, self.parent_mod, app, self.dynamic, True); @@ -1109,7 +1109,7 @@ if pyjslib.isUndefined(object_): return False if not pyjslib.isObject(object_): - + return False if _isinstance(classinfo, Tuple): for ci in classinfo: @@ -1362,4 +1362,3 @@ if bases: JS("bss = bases.l;") JS(" return pyjs_type(clsname, bss, mths); ") - diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/lib/sys.py --- a/svgui/pyjs/lib/sys.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/lib/sys.py Mon Aug 14 19:13:01 2017 +0300 @@ -5,11 +5,11 @@ overrides = None # to be updated by app, on compile # the remote path for loading modules -loadpath = None +loadpath = None -stacktrace = None +stacktrace = None -appname = None +appname = None def setloadpath(lp): global loadpath diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/pyjs/pyjs.py --- a/svgui/pyjs/pyjs.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/pyjs/pyjs.py Mon Aug 14 19:13:01 2017 +0300 @@ -345,7 +345,7 @@ # added to the dependencies, and it's half way up the # module import directory structure! child_name = name[-1] - self.imported_modules_as.append(child_name) + self.imported_modules_as.append(child_name) print >> self.output, gen_mod_import(self.raw_module_name, strip_py(importName), self.dynamic) @@ -427,7 +427,7 @@ print >>self.output, "%s = function%s {" % (function_name, function_args) self._default_args_handler(node, normal_arg_names, None) - local_arg_names = normal_arg_names + declared_arg_names + local_arg_names = normal_arg_names + declared_arg_names if node.varargs: self._varargs_handler(node, varargname, declared_arg_names, None) @@ -539,12 +539,12 @@ except ValueError: # Must be a function call ... return ("pyjs_kwargs_function_call("+call_name+", " - + star_arg_name + + star_arg_name + ", ["+fn_args+"]" + ")" ) else: return ("pyjs_kwargs_method_call("+call_this+", '"+method_name+"', " - + star_arg_name + + star_arg_name + ", ["+fn_args+"]" + ")") else: @@ -628,7 +628,7 @@ def modpfx(self): return strip_py(self.module_prefix) - + def _name(self, v, current_klass, top_level=False, return_none_for_module=False): @@ -904,7 +904,7 @@ # default arguments self._default_args_handler(node, normal_arg_names, current_klass) - local_arg_names = normal_arg_names + declared_arg_names + local_arg_names = normal_arg_names + declared_arg_names if node.varargs: self._varargs_handler(node, varargname, declared_arg_names, current_klass) @@ -1170,7 +1170,7 @@ def _discard(self, node, current_klass): - + if isinstance(node.expr, ast.CallFunc): debugStmt = self.debug and not self._isNativeFunc(node) if debugStmt and isinstance(node.expr.node, ast.Name) and \ @@ -1774,4 +1774,3 @@ if __name__ == "__main__": main() - diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/svgui.py --- a/svgui/svgui.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/svgui.py Mon Aug 14 19:13:01 2017 +0300 @@ -35,7 +35,7 @@ class SVGUILibrary(POULibrary): def GetLibraryPath(self): - return paths.AbsNeighbourFile(__file__, "pous.xml") + return paths.AbsNeighbourFile(__file__, "pous.xml") class SVGUI(PythonFileCTNMixin): @@ -70,18 +70,18 @@ def CTNGenerate_C(self, buildpath, locations): """ - Return C code generated by iec2c compiler + Return C code generated by iec2c compiler when _generate_softPLC have been called @param locations: ignored @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND """ - + current_location = self.GetCurrentLocation() # define a unique name for the generated C file location_str = "_".join(map(lambda x:str(x), current_location)) - + res = ([], "", False) - + svgfile=self._getSVGpath() if os.path.exists(svgfile): res += (("gui.svg", file(svgfile,"rb")),) @@ -103,25 +103,25 @@ svguilibfile.close() jsmodules = {"LiveSVGPage": "svguilib.js"} res += (("svguilib.js", file(svguilibpath,"rb")),) - + runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) runtimefile = open(runtimefile_path, 'w') runtimefile.write(svguiservercode % {"svgfile" : "gui.svg"}) runtimefile.write(""" def _runtime_%(location)s_start(): website.LoadHMI(%(svgui_class)s, %(jsmodules)s) - + def _runtime_%(location)s_stop(): website.UnLoadHMI() - + """ % {"location": location_str, "svgui_class": "SVGUI_HMI", "jsmodules" : str(jsmodules), }) runtimefile.close() - + res += (("runtime_%s.py"%location_str, file(runtimefile_path,"rb")),) - + return res def _ImportSVG(self): @@ -132,7 +132,7 @@ shutil.copy(svgpath, self._getSVGpath()) else: self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n")%svgpath) - dialog.Destroy() + dialog.Destroy() def _StartInkscape(self): svgfile = self._getSVGpath() diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/svgui_server.py --- a/svgui/svgui_server.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/svgui_server.py Mon Aug 14 19:13:01 2017 +0300 @@ -38,7 +38,7 @@ return currentId class SvguiWidget: - + def __init__(self, classname, id, **kwargs): self.classname = classname self.id = id @@ -50,7 +50,7 @@ def setinput(self, attrname, value): self.inputs[attrname] = value - + def getinput(self, attrname, default=None): if not self.inputs.has_key(attrname): self.inputs[attrname] = default @@ -61,14 +61,14 @@ self.outputs[attrname] = value self.changed = True self.RefreshInterface() - + def updateoutputs(self, **kwargs): for attrname, value in kwargs.iteritems(): if self.outputs.get(attrname) != value: self.outputs[attrname] = value self.changed = True self.RefreshInterface() - + def RefreshInterface(self): interface = website.getHMI() if isinstance(interface, SVGUI_HMI) and self.changed and not self.inhibit: @@ -77,7 +77,7 @@ if d is not None: self.inhibit = True d.addCallback(self.InterfaceRefreshed) - + def InterfaceRefreshed(self, result): self.inhibit = False if self.changed: @@ -103,23 +103,23 @@ class SVGUI_HMI(website.PLCHMI): jsClass = u"LiveSVGPage.LiveSVGWidget" - - docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ tags.xml(loaders.xmlfile(os.path.join(WorkingDir, svgfile))), ]) - + def HMIinitialisation(self): gadgets = [] for gadget in svguiWidgets.values(): gadgets.append(unicode(json.dumps(gadget, default=get_object_init_state, indent=2), 'ascii')) d = self.callRemote('init', gadgets) d.addCallback(self.HMIinitialised) - + def sendData(self,data): if self.initialised: return self.callRemote('receiveData',unicode(json.dumps(data, default=get_object_current_state, indent=2), 'ascii')) return None - + def setattr(self, id, attrname, value): svguiWidgets[id].setinput(attrname, value) @@ -148,4 +148,3 @@ if gad is not None: return gad.getinput(attrname, default) return default - diff -r d51af006fa6b -r 64d8f52bc8c8 svgui/svguilib.py --- a/svgui/svguilib.py Fri Aug 11 15:18:19 2017 +0300 +++ b/svgui/svguilib.py Mon Aug 14 19:13:01 2017 +0300 @@ -23,7 +23,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class button: - + def __init__(self, parent, id, args): self.parent = parent self.id = id @@ -40,19 +40,19 @@ self.up = not self.state else: self.up = True - + # Add event on each element of the button if self.active: self.back_elt.addEventListener("mouseup", self, False) self.back_elt.addEventListener("mousedown", self, False) self.back_elt.addEventListener("mouseover", self, False) self.back_elt.addEventListener("mouseout", self, False) - + self.sele_elt.addEventListener("mouseup", self, False) self.sele_elt.addEventListener("mousedown", self, False) self.sele_elt.addEventListener("mouseover", self, False) self.sele_elt.addEventListener("mouseout", self, False) - + blockSVGElementDrag(self.back_elt) blockSVGElementDrag(self.sele_elt) @@ -66,7 +66,7 @@ else: self.sele_elt.removeAttribute("display") self.back_elt.setAttribute("display", "none") - + def updateValues(self, values): if values.state != self.state: self.state = values.state @@ -80,9 +80,9 @@ if evt.type == "mousedown": evt.stopPropagation() setCurrentObject(self) - + self.dragging = True - + if self.toggle: self.up = self.state else: @@ -90,18 +90,18 @@ self.state = True updateAttr(self.id, 'state', self.state) self.updateElements() - + if isCurrentObject(self) and self.dragging: # Quand le bouton est survole if evt.type == "mouseover" and self.toggle: self.up = self.state self.updateElements() - + # Quand le curseur quitte la zone du bouton - elif evt.type == "mouseout" and self.toggle: + elif evt.type == "mouseout" and self.toggle: self.up = not self.state self.updateElements() - + # Quand le bouton de la souris est relache elif evt.type == "mouseup": evt.stopPropagation() @@ -116,7 +116,7 @@ self.dragging = False class textControl: - + def __init__(self, parent, id, args): self.parent = parent self.id = id @@ -126,17 +126,15 @@ else: self.text = "" self.updateElements() - + def updateValues(self, values): if values.text != self.value: self.text = values.text updateAttr(self.id, 'text', self.text) self.updateElements() - + def updateElements(self): self.back_elt.firstChild.firstChild.textContent = self.text - + def handleEvent(self, evt): pass - - diff -r d51af006fa6b -r 64d8f52bc8c8 targets/__init__.py --- a/targets/__init__.py Fri Aug 11 15:18:19 2017 +0300 +++ b/targets/__init__.py Mon Aug 14 19:13:01 2017 +0300 @@ -41,14 +41,14 @@ def _GetLocalTargetClassFactory(name): return lambda:getattr(__import__(name,globals(),locals()), name+"_target") -targets = dict([(name, {"xsd":path.join(_base_path, name, "XSD"), +targets = dict([(name, {"xsd":path.join(_base_path, name, "XSD"), "class":_GetLocalTargetClassFactory(name), - "code": { fname: path.join(_base_path, name, fname) + "code": { fname: path.join(_base_path, name, fname) for fname in listdir(path.join(_base_path, name)) if fname.startswith("plc_%s_main"%name) and fname.endswith(".c")}}) - for name in listdir(_base_path) - if path.isdir(path.join(_base_path, name)) + for name in listdir(_base_path) + if path.isdir(path.join(_base_path, name)) and not name.startswith("__")]) toolchains = {"gcc": path.join(_base_path, "XSD_toolchain_gcc"), @@ -67,7 +67,7 @@ DictXSD_toolchain["toolchain_"+toolchainname] = \ open(xsdfilename).read() - # Get all xsd targets + # Get all xsd targets for targetname,nfo in targets.iteritems(): xsd_string = open(nfo["xsd"]).read() targetchoices += xsd_string%DictXSD_toolchain @@ -86,4 +86,3 @@ def GetCode(name): filename = paths.AbsNeighbourFile(__file__,name) return open(filename).read() - diff -r d51af006fa6b -r 64d8f52bc8c8 targets/toolchain_makefile.py --- a/targets/toolchain_makefile.py Fri Aug 11 15:18:19 2017 +0300 +++ b/targets/toolchain_makefile.py Mon Aug 14 19:13:01 2017 +0300 @@ -33,7 +33,7 @@ class toolchain_makefile(): def __init__(self, CTRInstance): self.CTRInstance = CTRInstance - self.md5key = None + self.md5key = None self.buildpath = None self.SetBuildPath(self.CTRInstance._getBuildPath()) @@ -83,7 +83,7 @@ def build(self): srcfiles= [] cflags = [] - wholesrcdata = "" + wholesrcdata = "" for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS: # Get CFiles list to give it to makefile for CFile, CFLAGS in CFilesAndCFLAGS: @@ -92,7 +92,7 @@ srcfiles.append(CFileName) if CFLAGS not in cflags: cflags.append(CFLAGS) - + oldmd5 = self.md5key self.md5key = hashlib.md5(wholesrcdata).hexdigest() @@ -108,8 +108,8 @@ "md5": self.md5key, "buildpath": self.buildpath } - - # clean sequence of multiple whitespaces + + # clean sequence of multiple whitespaces cmd = re.sub(r"[ ]+", " ", target.getCommand().strip()) command = [ token % beremizcommand for token in cmd.split(' ')] @@ -125,4 +125,3 @@ else : self.CTRInstance.logger.write(_("Source didn't change, no build.\n")) return True - diff -r d51af006fa6b -r 64d8f52bc8c8 util/ProcessLogger.py --- a/util/ProcessLogger.py Fri Aug 11 15:18:19 2017 +0300 +++ b/util/ProcessLogger.py Mon Aug 14 19:13:01 2017 +0300 @@ -53,7 +53,7 @@ self.retval = self.Proc.poll() else: self.retval = self.Proc.returncode - + outchunk = self.fd.readline() if self.callback : self.callback(outchunk) while outchunk != '' and not self.killed : @@ -108,7 +108,7 @@ self.errdata = [] self.keyword = keyword self.kill_it = kill_it - self.startsem = Semaphore(0) + self.startsem = Semaphore(0) self.finishsem = Semaphore(0) self.endlock = Lock() @@ -130,7 +130,7 @@ self.timeout.start() else: self.timeout = None - + self.Proc = subprocess.Popen( self.Command, **popenargs ) self.outt = outputThread( @@ -169,7 +169,7 @@ self.logger.write_warning(_("exited with status {a1} (pid {a2})\n").format(a1 = str(ecode), a2 = str(pid))) def finish(self, pid,ecode): - # avoid running function before start is finished + # avoid running function before start is finished self.startsem.acquire() if self.timeout: self.timeout.cancel() @@ -185,7 +185,7 @@ # avoid running kill before start is finished self.startsem.acquire() self.startsem.release() - + self.outt.killed = True self.errt.killed = True if wx.Platform == '__WXMSW__': @@ -215,4 +215,3 @@ def spin(self): self.finishsem.acquire() return [self.exitcode, "".join(self.outdata), "".join(self.errdata)] - diff -r d51af006fa6b -r 64d8f52bc8c8 util/TranslationCatalogs.py --- a/util/TranslationCatalogs.py Fri Aug 11 15:18:19 2017 +0300 +++ b/util/TranslationCatalogs.py Mon Aug 14 19:13:01 2017 +0300 @@ -22,7 +22,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -import os +import os import wx diff -r d51af006fa6b -r 64d8f52bc8c8 util/Zeroconf.py --- a/util/Zeroconf.py Fri Aug 11 15:18:19 2017 +0300 +++ b/util/Zeroconf.py Mon Aug 14 19:13:01 2017 +0300 @@ -19,7 +19,7 @@ You should have received a copy of the GNU Lesser 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 - + """ """0.12 update - allow selection of binding interface @@ -101,7 +101,7 @@ _BROWSER_TIME = 500 # Some DNS constants - + _MDNS_ADDR = '224.0.0.251' _MDNS_PORT = 5353; _DNS_PORT = 53; @@ -208,7 +208,7 @@ class DNSEntry(object): """A DNS entry""" - + def __init__(self, name, type, clazz): self.key = string.lower(name) self.name = name @@ -256,7 +256,7 @@ class DNSQuestion(DNSEntry): """A DNS question entry""" - + def __init__(self, name, type, clazz): if not name.endswith(".local."): raise NonLocalNameException @@ -273,7 +273,7 @@ class DNSRecord(DNSEntry): """A DNS record - like a DNS entry, but has a TTL""" - + def __init__(self, name, type, clazz, ttl): DNSEntry.__init__(self, name, type, clazz) self.ttl = ttl @@ -334,7 +334,7 @@ class DNSAddress(DNSRecord): """A DNS address record""" - + def __init__(self, name, type, clazz, ttl, address): DNSRecord.__init__(self, name, type, clazz, ttl) self.address = address @@ -378,10 +378,10 @@ def __repr__(self): """String representation""" return self.cpu + " " + self.os - + class DNSPointer(DNSRecord): """A DNS pointer record""" - + def __init__(self, name, type, clazz, ttl, alias): DNSRecord.__init__(self, name, type, clazz, ttl) self.alias = alias @@ -402,7 +402,7 @@ class DNSText(DNSRecord): """A DNS text record""" - + def __init__(self, name, type, clazz, ttl, text): DNSRecord.__init__(self, name, type, clazz, ttl) self.text = text @@ -426,7 +426,7 @@ class DNSService(DNSRecord): """A DNS service record""" - + def __init__(self, name, type, clazz, ttl, priority, weight, port, server): DNSRecord.__init__(self, name, type, clazz, ttl) self.priority = priority @@ -453,7 +453,7 @@ class DNSIncoming(object): """Object representation of an incoming DNS packet""" - + def __init__(self, data): """Constructor from string holding bytes of packet""" self.offset = 0 @@ -464,7 +464,7 @@ self.numAnswers = 0 self.numAuthorities = 0 self.numAdditionals = 0 - + self.readHeader() self.readQuestions() self.readOthers() @@ -491,7 +491,7 @@ name = self.readName() info = struct.unpack(format, self.data[self.offset:self.offset+length]) self.offset += length - + question = DNSQuestion(name, info[0], info[1]) self.questions.append(question) @@ -561,7 +561,7 @@ if rec is not None: self.answers.append(rec) - + def isQuery(self): """Returns true if this is a query""" return (self.flags & _FLAGS_QR_MASK) == _FLAGS_QR_QUERY @@ -574,7 +574,7 @@ """Reads a UTF-8 string of a given length from the packet""" result = self.data[offset:offset+len].decode('utf-8') return result - + def readName(self): """Reads a domain name from the packet""" result = '' @@ -607,11 +607,11 @@ self.offset = off return result - - + + class DNSOutgoing(object): """Object representation of an outgoing packet""" - + def __init__(self, flags, multicast = 1): self.finished = 0 self.id = 0 @@ -620,7 +620,7 @@ self.names = {} self.data = [] self.size = 12 - + self.questions = [] self.answers = [] self.authorities = [] @@ -660,7 +660,7 @@ format = '!H' self.data.insert(index, struct.pack(format, value)) self.size += 2 - + def writeShort(self, value): """Writes an unsigned short to the packet""" format = '!H' @@ -739,7 +739,7 @@ self.size += 2 record.write(self) self.size -= 2 - + length = len(''.join(self.data[index:])) self.insertShort(index, length) # Here is the short we adjusted for @@ -758,7 +758,7 @@ self.writeRecord(authority, 0) for additional in self.additionals: self.writeRecord(additional, 0) - + self.insertShort(0, len(self.additionals)) self.insertShort(0, len(self.authorities)) self.insertShort(0, len(self.answers)) @@ -773,7 +773,7 @@ class DNSCache(object): """A cache of DNS entries""" - + def __init__(self): self.cache = {} @@ -872,7 +872,7 @@ result = self.readers.keys() self.condition.release() return result - + def addReader(self, reader, socket): self.condition.acquire() self.readers[socket] = reader @@ -897,7 +897,7 @@ It requires registration with an Engine object in order to have the read() method called when a socket is availble for reading.""" - + def __init__(self, zeroconf): self.zeroconf = zeroconf self.zeroconf.engine.addReader(self, self.zeroconf.socket) @@ -924,7 +924,7 @@ class Reaper(threading.Thread): """A Reaper is used by this module to remove cache entries that have expired.""" - + def __init__(self, zeroconf): threading.Thread.__init__(self) self.zeroconf = zeroconf @@ -948,7 +948,7 @@ The listener object will have its addService() and removeService() methods called when this browser discovers changes in the services availability.""" - + def __init__(self, zeroconf, type, listener): """Creates a browser for a specific type""" threading.Thread.__init__(self) @@ -959,7 +959,7 @@ self.nextTime = currentTimeMillis() self.delay = _BROWSER_TIME self.list = [] - + self.done = 0 self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN)) @@ -1019,11 +1019,11 @@ if event is not None: event(self.zeroconf) - + class ServiceInfo(object): """Service information""" - + def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None): """Create a service description. @@ -1089,7 +1089,7 @@ index += 1 strs.append(text[index:index+length]) index += length - + for s in strs: eindex = s.find('=') if eindex == -1: @@ -1112,7 +1112,7 @@ except: traceback.print_exc() self.properties = None - + def getType(self): """Type accessor""" return self.type @@ -1200,7 +1200,7 @@ result = 1 finally: zeroconf.removeListener(self) - + return result def __eq__(self, other): @@ -1225,7 +1225,7 @@ result += self.text[:17] + "..." result += "]" return result - + class Zeroconf(object): """Implementation of Zeroconf Multicast DNS Service Discovery @@ -1274,7 +1274,7 @@ self.cache = DNSCache() self.condition = threading.Condition() - + self.engine = Engine(self) self.listener = Listener(self) self.reaper = Reaper(self) @@ -1465,7 +1465,7 @@ record = entry else: self.cache.add(record) - + self.updateRecord(now, record) def handleQuery(self, msg, addr, port): @@ -1479,7 +1479,7 @@ out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, 0) for question in msg.questions: out.addQuestion(question) - + for question in msg.questions: if question.type == _TYPE_PTR: for service in self.services.values(): @@ -1491,16 +1491,16 @@ try: if out is None: out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA) - + # Answer A record queries for any service addresses we know if question.type == _TYPE_A or question.type == _TYPE_ANY: for service in self.services.values(): if service.server == question.name.lower(): out.addAnswer(msg, DNSAddress(question.name, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address)) - + service = self.services.get(question.name.lower(), None) if not service: continue - + if question.type == _TYPE_SRV or question.type == _TYPE_ANY: out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server)) if question.type == _TYPE_TXT or question.type == _TYPE_ANY: @@ -1509,7 +1509,7 @@ out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address)) except: traceback.print_exc() - + if out is not None and out.answers: out.id = msg.id self.send(out, addr, port) @@ -1534,11 +1534,11 @@ self.unregisterAllServices() self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0')) self.socket.close() - + # Test a few module features, including service registration, service # query (for Zoe), and service unregistration. -if __name__ == '__main__': +if __name__ == '__main__': print "Multicast DNS Service Discovery for Python, version", __version__ r = Zeroconf() print "1. Testing registration of a service..." diff -r d51af006fa6b -r 64d8f52bc8c8 wxglade_hmi/wxglade_hmi.py --- a/wxglade_hmi/wxglade_hmi.py Fri Aug 11 15:18:19 2017 +0300 +++ b/wxglade_hmi/wxglade_hmi.py Mon Aug 14 19:13:01 2017 +0300 @@ -56,7 +56,7 @@ path = None try: from wxglade import __file__ as fileName - path = os.path.dirname(fileName) + path = os.path.dirname(fileName) return path except ImportError: pass @@ -66,7 +66,7 @@ path = defLibDir return path - + def launch_wxglade(self, options, wait=False): path = self.GetWxGladePath() glade = os.path.join(path, 'wxglade.py') @@ -82,24 +82,24 @@ return PythonFileCTNMixin.OnCTNSave(self, from_project_path) def CTNGenerate_C(self, buildpath, locations): - + hmi_frames = [] - + wxgfile_path=self._getWXGLADEpath() if os.path.exists(wxgfile_path): wxgfile = open(wxgfile_path, 'r') wxgtree = minidom.parse(wxgfile) wxgfile.close() - + for node in wxgtree.childNodes[1].childNodes: if node.nodeType == wxgtree.ELEMENT_NODE: hmi_frames.append({ "name" : node.getAttribute("name"), "class" : node.getAttribute("class"), "handlers" : [ - hnode.firstChild.data for hnode in + hnode.firstChild.data for hnode in node.getElementsByTagName("handler")]}) - + hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py") if wx.Platform == '__WXMSW__': wxgfile_path = "\"%s\""%wxgfile_path @@ -107,20 +107,20 @@ else: wxghmipyfile_path = hmipyfile_path self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) - + hmipyfile = open(hmipyfile_path, 'r') define_hmi = hmipyfile.read().decode('utf-8') hmipyfile.close() - + else: define_hmi = "" - - declare_hmi = "\n".join(["%(name)s = None\n" % x + + + declare_hmi = "\n".join(["%(name)s = None\n" % x + "\n".join(["%(class)s.%(h)s = %(h)s"% dict(x,h=h) for h in x['handlers']]) for x in hmi_frames]) global_hmi = ("global %s\n"%",".join( - [x["name"] for x in hmi_frames]) + [x["name"] for x in hmi_frames]) if len(hmi_frames) > 0 else "") init_hmi = "\n".join(["""\ def OnCloseFrame(evt): @@ -131,9 +131,9 @@ %(name)s.Show() """ % x for x in hmi_frames]) cleanup_hmi = "\n".join( - ["if %(name)s is not None: %(name)s.Destroy()" % x + ["if %(name)s is not None: %(name)s.Destroy()" % x for x in hmi_frames]) - + self.PreSectionsTexts = { "globals":define_hmi, "start":global_hmi, @@ -174,4 +174,3 @@ if wx.Platform == '__WXMSW__': wxg_filename = "\"%s\""%wxg_filename self.launch_wxglade([wxg_filename]) - diff -r d51af006fa6b -r 64d8f52bc8c8 xmlclass/xmlclass.py --- a/xmlclass/xmlclass.py Fri Aug 11 15:18:19 2017 +0300 +++ b/xmlclass/xmlclass.py Mon Aug 14 19:13:01 2017 +0300 @@ -93,7 +93,7 @@ def dst(self, dt): return ZERO -[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, +[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE, ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT, ] = range(13) @@ -140,7 +140,7 @@ def GetNormalizedString(attr, extract=True): """ - Function that normalizes a string according to XML 1.0. Replace + Function that normalizes a string according to XML 1.0. Replace tabulations, line feed and carriage return by white space @param attr: tree node containing data to extract or data to normalize @param extract: attr is a tree node or not @@ -155,14 +155,14 @@ def GetToken(attr, extract=True): """ - Function that tokenizes a string according to XML 1.0. Remove any leading - and trailing white space and replace internal sequence of two or more + Function that tokenizes a string according to XML 1.0. Remove any leading + and trailing white space and replace internal sequence of two or more spaces by only one white space @param attr: tree node containing data to extract or data to tokenize @param extract: attr is a tree node or not @return: data tokenized as string """ - return " ".join([part for part in + return " ".join([part for part in GetNormalizedString(attr, extract).split(" ") if part]) @@ -186,7 +186,7 @@ raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value) -def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None, +def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None, minExclusive=None, maxExclusive=None): """ Function that generates an extraction function for integer defining min and @@ -517,7 +517,7 @@ check that all extracted items match the model @param attr: tree node containing data to extract or data as a string @param extract: attr is a tree node or not - @return: data as a list of string if matching + @return: data as a list of string if matching """ if extract: value = GetAttributeValue(attr) @@ -535,18 +535,18 @@ return GetModelNameList def GenerateAnyInfos(infos): - + def GetTextElement(tree): if infos["namespace"][0] == "##any": return tree.xpath("p")[0] return tree.xpath("ns:p", namespaces={"ns": infos["namespace"][0]})[0] - + def ExtractAny(tree): return GetTextElement(tree).text - + def GenerateAny(tree, value): GetTextElement(tree).text = etree.CDATA(value) - + def InitialAny(): if infos["namespace"][0] == "##any": element_name = "p" @@ -555,9 +555,9 @@ p = etree.Element(element_name) p.text = etree.CDATA("") return p - + return { - "type": COMPLEXTYPE, + "type": COMPLEXTYPE, "extract": ExtractAny, "generate": GenerateAny, "initial": InitialAny, @@ -574,16 +574,16 @@ return True else: return None - + def GenerateTag(value, name=None, indent=0): if name is not None and not (infos["minOccurs"] == 0 and value is None): ind1, ind2 = getIndent(indent, name) return ind1 + "<%s/>\n" % name else: return "" - + return { - "type": TAG, + "type": TAG, "extract": ExtractTag, "generate": GenerateTag, "initial": lambda: None, @@ -595,7 +595,7 @@ namespace, name = DecomposeQualifiedName(infos) return factory.GetQualifiedNameInfos(name, namespace) return infos - + def GetElementInitialValue(factory, infos): infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"]) if infos["minOccurs"] == 1: @@ -667,7 +667,7 @@ prefix = ("%s:" % factory.TargetNamespace if factory.TargetNamespace is not None else "") choices_xpath = "|".join(map(lambda x: prefix + x, choices_dict.keys())) - + def GetContentInitial(): content_name, infos = choices[0] if content_name == "sequence": @@ -678,7 +678,7 @@ else: content_value = GetElementInitialValue(factory, infos) return content_value - + return { "type": COMPLEXTYPE, "choices_xpath": etree.XPath(choices_xpath, namespaces=factory.NSMAP), @@ -693,13 +693,13 @@ def DecomposeQualifiedName(name): result = QName_model.match(name) if not result: - raise ValueError("\"%s\" isn't a valid QName value!" % name) + raise ValueError("\"%s\" isn't a valid QName value!" % name) parts = result.groups()[0].split(':') if len(parts) == 1: return None, parts[0] return parts - -def GenerateElement(element_name, attributes, elements_model, + +def GenerateElement(element_name, attributes, elements_model, accept_text=False): def ExtractElement(factory, node): attrs = factory.ExtractNodeAttrs(element_name, node, attributes) @@ -746,20 +746,20 @@ else: self.BaseFolder = self.FileName = None self.Debug = debug - + # Dictionary for stocking Classes and Types definitions created from # the XML tree self.XMLClassDefinitions = {} - + self.DefinedNamespaces = {} self.NSMAP = {} self.Namespaces = {} self.SchemaNamespace = None self.TargetNamespace = None self.etreeNamespaceFormat = "%s" - + self.CurrentCompilations = [] - + # Dictionaries for stocking Classes and Types generated self.ComputeAfter = [] if self.FileName is not None: @@ -920,15 +920,15 @@ def ParseSchema(self): pass - + def AddEquivalentClass(self, name, base): if name != base: equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {}) equivalences[self.etreeNamespaceFormat % name] = True - + def AddDistinctionBetweenParentsInLookupClass( self, lookup_classes, parent, typeinfos): - parent = (self.etreeNamespaceFormat % parent + parent = (self.etreeNamespaceFormat % parent if parent is not None else None) parent_class = lookup_classes.get(parent) if parent_class is not None: @@ -939,7 +939,7 @@ lookup_classes[parent] = [typeinfos, parent_class] else: lookup_classes[parent] = typeinfos - + def AddToLookupClass(self, name, parent, typeinfos): lookup_name = self.etreeNamespaceFormat % name if isinstance(typeinfos, (StringType, UnicodeType)): @@ -958,7 +958,7 @@ self.AddDistinctionBetweenParentsInLookupClass( lookup_classes, parent, typeinfos) self.ComputedClassesLookUp[lookup_name] = lookup_classes - + def ExtractTypeInfos(self, name, parent, typeinfos): if isinstance(typeinfos, (StringType, UnicodeType)): namespace, type_name = DecomposeQualifiedName(typeinfos) @@ -986,12 +986,12 @@ return self.CreateClass(name, parent, typeinfos) elif typeinfos["type"] == SIMPLETYPE: return typeinfos - + def GetEquivalentParents(self, parent): return reduce(lambda x, y: x + y, [[p] + self.GetEquivalentParents(p) for p in self.EquivalentClassesParent.get(parent, {}).keys()], []) - + """ Methods that generates the classes """ @@ -1028,7 +1028,7 @@ if result is not None and \ not isinstance(result, (UnicodeType, StringType)): self.Namespaces[self.TargetNamespace][result["name"]] = result - + for name, parents in self.ComputedClassesLookUp.iteritems(): if isinstance(parents, DictType): computed_classes = parents.items() @@ -1042,7 +1042,7 @@ parents = dict(computed_classes) self.ComputedClassesLookUp[name] = parents parents[equivalent_parent] = computed_class - + return self.ComputedClasses def CreateClass(self, name, parent, classinfos, baseclass = False): @@ -1050,11 +1050,11 @@ classname = "%s_%s" % (parent, name) else: classname = name - + # Checks that classe haven't been generated yet if self.AlreadyComputed.get(classname, False): return self.ComputedClassesInfos.get(classname, None) - + # If base classes haven't been generated bases = [] base_infos = classinfos.get("base", None) @@ -1088,12 +1088,12 @@ bases.append(DefaultElementClass) bases = tuple(bases) classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass} - + self.AlreadyComputed[classname] = True - + for attribute in classinfos["attributes"]: infos = self.ExtractTypeInfos(attribute["name"], name, attribute["attr_type"]) - if infos is not None: + if infos is not None: if infos["type"] != SIMPLETYPE: raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"]) attrname = attribute["name"] @@ -1105,7 +1105,7 @@ else: raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"]) attribute["attr_type"] = infos - + for element in classinfos["elements"]: if element["type"] == CHOICE: elmtname = element["name"] @@ -1141,13 +1141,13 @@ classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname) classmembers["set%s" % elmtname] = generateSetMethod(elmtname) classmembers["get%s" % elmtname] = generateGetMethod(elmtname) - + classmembers["_init_"] = generateInitMethod(self, classinfos) classmembers["StructurePattern"] = GetStructurePattern(classinfos) classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos) classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos) classmembers["setElementValue"] = generateSetElementValue(self, classinfos) - + class_definition = classobj(str(name), bases, classmembers) setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos)) setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) @@ -1155,16 +1155,16 @@ "name": classname, "initial": generateClassCreateFunction(class_definition), } - + if self.FileName is not None: self.ComputedClasses[self.FileName][classname] = class_definition else: self.ComputedClasses[classname] = class_definition self.ComputedClassesInfos[classname] = class_infos - + self.AddToLookupClass(name, parent, class_definition) self.AddToLookupClass(classname, None, class_definition) - + return class_infos """ @@ -1183,7 +1183,7 @@ else: for classname, xmlclass in items: print "%s: %s" % (classname, str(xmlclass)) - + def PrintClassNames(self): classnames = self.XMLClassDefinitions.keys() classnames.sort() @@ -1191,7 +1191,7 @@ print classname """ -Method that generate the method for generating the xml tree structure model by +Method that generate the method for generating the xml tree structure model by following the attributes list defined """ def ComputeMultiplicity(name, infos): @@ -1213,7 +1213,7 @@ if infos["maxOccurs"] == "unbounded": return "(?:%s){%d,}" % (name, infos["minOccurs"], name) else: - return "(?:%s){%d,%d}" % (name, infos["minOccurs"], + return "(?:%s){%d,%d}" % (name, infos["minOccurs"], infos["maxOccurs"]) def GetStructurePattern(classinfos): @@ -1256,7 +1256,7 @@ attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"]) elements = dict([(element["name"], element) for element in classinfos["elements"]]) - + def getattrMethod(self, name): if attributes.has_key(name): attribute_infos = attributes[name] @@ -1269,7 +1269,7 @@ elif attribute_infos.has_key("default"): return attribute_infos["attr_type"]["extract"](attribute_infos["default"], extract=False) return None - + elif elements.has_key(name): element_infos = elements[name] element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"]) @@ -1279,7 +1279,7 @@ return content elif len(content) > 0: return content[0] - return None + return None elif element_infos["type"] == ANY: return element_infos["elmt_type"]["extract"](self) elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE: @@ -1290,7 +1290,7 @@ values = self.findall(element_name) if element_infos["elmt_type"]["type"] == SIMPLETYPE: return map(lambda value: - element_infos["elmt_type"]["extract"](value.text, extract=False), + element_infos["elmt_type"]["extract"](value.text, extract=False), values) return values else: @@ -1298,19 +1298,19 @@ if element_infos["elmt_type"]["type"] == SIMPLETYPE: return element_infos["elmt_type"]["extract"](value.text, extract=False) return value - + elif classinfos.has_key("base"): return classinfos["base"].__getattr__(self, name) - + return DefaultElementClass.__getattribute__(self, name) - + return getattrMethod def generateSetattrMethod(factory, class_definition, classinfos): attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"]) elements = OrderedDict([(element["name"], element) for element in classinfos["elements"]]) - + def setattrMethod(self, name, value): if attributes.has_key(name): attribute_infos = attributes[name] @@ -1323,26 +1323,26 @@ elif attribute_infos.has_key("fixed"): return return self.set(name, attribute_infos["attr_type"]["generate"](value)) - + elif elements.has_key(name): element_infos = elements[name] element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"]) if element_infos["type"] == ANY: element_infos["elmt_type"]["generate"](self, value) - + elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE: self.text = element_infos["elmt_type"]["generate"](value) - + else: prefix = ("%s:" % factory.TargetNamespace if factory.TargetNamespace is not None else "") element_xpath = (prefix + name if name != "content" else elements["content"]["elmt_type"]["choices_xpath"].path) - + for element in self.xpath(element_xpath, namespaces=factory.NSMAP): self.remove(element) - + if value is not None: element_idx = elements.keys().index(name) if element_idx > 0: @@ -1351,27 +1351,27 @@ if x != "content" else elements["content"]["elmt_type"]["choices_xpath"].path, elements.keys()[:element_idx])) - + insertion_point = len(self.xpath(previous_elements_xpath, namespaces=factory.NSMAP)) else: insertion_point = 0 - + if not isinstance(value, ListType): value = [value] - + for element in reversed(value): if element_infos["elmt_type"]["type"] == SIMPLETYPE: tmp_element = etree.Element(factory.etreeNamespaceFormat % name) tmp_element.text = element_infos["elmt_type"]["generate"](element) element = tmp_element self.insert(insertion_point, element) - + elif classinfos.has_key("base"): return classinfos["base"].__setattr__(self, name, value) - + else: raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name)) - + return setattrMethod def gettypeinfos(name, facets): @@ -1398,7 +1398,7 @@ attr_list.extend(classinfos["base"].getElementAttributes(self)) for attr in classinfos["attributes"]: if attr["use"] != "prohibited": - attr_params = {"name" : attr["name"], "use" : attr["use"], + attr_params = {"name" : attr["name"], "use" : attr["use"], "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]), "value" : getattr(self, attr["name"], "")} attr_list.append(attr_params) @@ -1408,7 +1408,7 @@ def generateGetElementInfos(factory, classinfos): attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) elements = dict([(element["name"], element) for element in classinfos["elements"]]) - + def getElementInfos(self, name, path=None, derived=False): attr_type = "element" value = None @@ -1419,14 +1419,14 @@ if attributes.has_key(parts[0]): if len(parts) != 1: raise ValueError("Wrong path!") - attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"], + attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"], attributes[parts[0]]["attr_type"]["facets"]) value = getattr(self, parts[0], "") elif elements.has_key(parts[0]): if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE: if len(parts) != 1: raise ValueError("Wrong path!") - attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], + attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"], elements[parts[0]]["elmt_type"]["facets"]) value = getattr(self, parts[0], "") elif parts[0] == "content": @@ -1463,8 +1463,8 @@ if self.content is not None: children.extend(self.content.getElementInfos(value)["children"]) elif element["elmt_type"]["type"] == SIMPLETYPE: - children.append({"name": element_name, "require": element["minOccurs"] != 0, - "type": gettypeinfos(element["elmt_type"]["basename"], + children.append({"name": element_name, "require": element["minOccurs"] != 0, + "type": gettypeinfos(element["elmt_type"]["basename"], element["elmt_type"]["facets"]), "value": getattr(self, element_name, None)}) else: @@ -1478,7 +1478,7 @@ def generateSetElementValue(factory, classinfos): attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"]) elements = dict([(element["name"], element) for element in classinfos["elements"]]) - + def setElementValue(self, path, value): if path is not None: parts = path.split(".", 1) @@ -1489,7 +1489,7 @@ setattr(self, parts[0], value) elif attributes[parts[0]]["use"] == "optional" and value == "": if attributes[parts[0]].has_key("default"): - setattr(self, parts[0], + setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"]( attributes[parts[0]]["default"], False)) else: @@ -1680,39 +1680,39 @@ NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ") class DefaultElementClass(etree.ElementBase): - + StructurePattern = re.compile("$") - + def _init_(self): pass - + def getLocalTag(self): return etree.QName(self.tag).localname - + def tostring(self): return NAMESPACE_PATTERN.sub("", etree.tostring(self, pretty_print=True, encoding='utf-8')).decode('utf-8') class XMLElementClassLookUp(etree.PythonElementClassLookup): - + def __init__(self, classes, *args, **kwargs): etree.PythonElementClassLookup.__init__(self, *args, **kwargs) self.LookUpClasses = classes - + def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass): element_class = self.LookUpClasses.get(element_tag, (default, None)) if not isinstance(element_class, DictType): if isinstance(element_class[0], (StringType, UnicodeType)): return self.GetElementClass(element_class[0], default=default) return element_class[0] - + element_with_parent_class = element_class.get(parent_tag, default) if isinstance(element_with_parent_class, (StringType, UnicodeType)): return self.GetElementClass(element_with_parent_class, default=default) return element_with_parent_class - + def lookup(self, document, element): parent = element.getparent() - element_class = self.GetElementClass(element.tag, + element_class = self.GetElementClass(element.tag, parent.tag if parent is not None else None) if isinstance(element_class, ListType): children = "".join([ @@ -1741,24 +1741,24 @@ self.RootNSMAP = namespaces self.BaseClass = base_class self.XSDSchema = xsd_schema - + def set_element_class_lookup(self, class_lookup): etree.XMLParser.set_element_class_lookup(self, class_lookup) self.ClassLookup = class_lookup - + def LoadXMLString(self, xml_string): tree = etree.fromstring(xml_string, self) if not self.XSDSchema.validate(tree): error = self.XSDSchema.error_log.last_error return tree, (error.line, error.message) - return tree, None - + return tree, None + def Dumps(self, xml_obj): return etree.tostring(xml_obj, encoding='utf-8') - + def Loads(self, xml_string): return etree.fromstring(xml_string, self) - + def CreateRoot(self): if self.BaseClass is not None: root = self.makeelement( @@ -1767,14 +1767,14 @@ root._init_() return root return None - + def GetElementClass(self, element_tag, parent_tag=None): return self.ClassLookup.GetElementClass( - self.DefaultNamespaceFormat % element_tag, - self.DefaultNamespaceFormat % parent_tag - if parent_tag is not None else parent_tag, + self.DefaultNamespaceFormat % element_tag, + self.DefaultNamespaceFormat % parent_tag + if parent_tag is not None else parent_tag, None) - + def CreateElement(self, element_tag, parent_tag=None, class_idx=None): element_class = self.GetElementClass(element_tag, parent_tag) if isinstance(element_class, ListType): @@ -1787,14 +1787,14 @@ DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag) new_element._init_() return new_element - + def GenerateParser(factory, xsdstring): ComputedClasses = factory.CreateClasses() - + if factory.FileName is not None: ComputedClasses = ComputedClasses[factory.FileName] BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass] - + parser = XMLClassParser( factory.NSMAP, factory.etreeNamespaceFormat, @@ -1803,6 +1803,5 @@ strip_cdata = False, remove_blank_text=True) class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp) parser.set_element_class_lookup(class_lookup) - + return parser - diff -r d51af006fa6b -r 64d8f52bc8c8 xmlclass/xsdschema.py --- a/xmlclass/xsdschema.py Fri Aug 11 15:18:19 2017 +0300 +++ b/xmlclass/xsdschema.py Mon Aug 14 19:13:01 2017 +0300 @@ -62,14 +62,14 @@ text += "\n" % name return text return generateXMLTextMethod - + DEFAULT_FACETS = GenerateDictFacets(["pattern", "whiteSpace", "enumeration"]) NUMBER_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["maxInclusive", "maxExclusive", "minInclusive", "minExclusive"]) DECIMAL_FACETS = GenerateDictFacets(NUMBER_FACETS.keys() + ["totalDigits", "fractionDigits"]) STRING_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["length", "minLength", "maxLength"]) -ALL_FACETS = ["pattern", "whiteSpace", "enumeration", "maxInclusive", - "maxExclusive", "minInclusive", "minExclusive", "totalDigits", +ALL_FACETS = ["pattern", "whiteSpace", "enumeration", "maxInclusive", + "maxExclusive", "minInclusive", "minExclusive", "totalDigits", "fractionDigits", "length", "minLength", "maxLength"] @@ -81,12 +81,12 @@ # Documentation elements def ReduceAppInfo(factory, attributes, elements): - return {"type": "appinfo", "source": attributes.get("source", None), + return {"type": "appinfo", "source": attributes.get("source", None), "content": "\n".join(elements)} def ReduceDocumentation(factory, attributes, elements): - return {"type": "documentation", "source": attributes.get("source", None), + return {"type": "documentation", "source": attributes.get("source", None), "language": attributes.get("lang", "any"), "content": "\n".join(elements)} @@ -124,7 +124,7 @@ def ReduceList(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) list = {"type": "list", "itemType": attributes.get("itemType", None), "doc": annotations} - + if len(children) > 0 and children[0]["type"] == SIMPLETYPE: if list["itemType"] is None: list["itemType"] = children[0] @@ -138,7 +138,7 @@ def ReduceUnion(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) union = {"type": "union", "memberTypes": attributes.get("memberTypes", []), "doc": annotations} - + for child in children: if child["type"] == SIMPLETYPE: union["memberTypes"].appendchild @@ -153,29 +153,29 @@ simpleType = {"type": SIMPLETYPE, "final": attributes.get("final", [])} if attributes.has_key("name"): simpleType["name"] = attributes["name"] - + if typeinfos["type"] in ["restriction", "extension"]: # Search for base type definition if isinstance(typeinfos["base"], (StringType, UnicodeType)): basetypeinfos = factory.FindSchemaElement(typeinfos["base"], SIMPLETYPE) if basetypeinfos is None: - raise "\"%s\" isn't defined!" % typeinfos["base"] + raise "\"%s\" isn't defined!" % typeinfos["base"] else: basetypeinfos = typeinfos["base"] - + # Check that base type is a simple type if basetypeinfos["type"] != SIMPLETYPE: raise ValueError("Base type given isn't a simpleType!") - + simpleType["basename"] = basetypeinfos["basename"] - + # Check that derivation is allowed if basetypeinfos.has_key("final"): if "#all" in basetypeinfos["final"]: raise ValueError("Base type can't be derivated!") if "restriction" in basetypeinfos["final"] and typeinfos["type"] == "restriction": raise ValueError("Base type can't be derivated by restriction!") - + # Extract simple type facets for facet in typeinfos.get("facets", []): facettype = facet["type"] @@ -286,12 +286,12 @@ elif basevalue is not None and value > basevalue: raise ValueError("\"totalDigits\" can't be greater than \"totalDigits\" defined in base type!") facets[facettype] = (value, facet.get("fixed", False)) - - # Report not redefined facet from base type to new created type + + # Report not redefined facet from base type to new created type for facettype, facetvalue in basetypeinfos["facets"].items(): if not facets.has_key(facettype): facets[facettype] = facetvalue - + # Generate extract value for new created type def ExtractSimpleTypeValue(attr, extract=True): value = basetypeinfos["extract"](attr, extract) @@ -317,7 +317,7 @@ model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue))) result = model.match(value) if result is None: - if len(facetvalue) > 1: + if len(facetvalue) > 1: raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue)) else: raise ValueError("value doesn't follow the pattern %s" % facetvalue[0]) @@ -327,7 +327,7 @@ elif facetvalue == "collapse": value = GetToken(value, False) return value - + def CheckSimpleTypeValue(value): for facetname, (facetvalue, facetfixed) in facets.items(): if facetvalue is not None: @@ -351,12 +351,12 @@ model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue))) result = model.match(value) if result is None: - if len(facetvalue) > 1: + if len(facetvalue) > 1: raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue)) else: raise ValueError("value doesn't follow the pattern %s" % facetvalue[0]) return True - + def SimpleTypeInitialValue(): for facetname, (facetvalue, facetfixed) in facets.items(): if facetvalue is not None: @@ -375,9 +375,9 @@ elif facetname == "maxExclusive" and facetvalue <= 0: return facetvalue - 1 return basetypeinfos["initial"]() - + GenerateSimpleType = basetypeinfos["generate"] - + elif typeinfos["type"] == "list": # Search for item type definition if isinstance(typeinfos["itemType"], (StringType, UnicodeType)): @@ -386,41 +386,41 @@ raise "\"%s\" isn't defined!" % typeinfos["itemType"] else: itemtypeinfos = typeinfos["itemType"] - + # Check that item type is a simple type if itemtypeinfos["type"] != SIMPLETYPE: raise ValueError, "Item type given isn't a simpleType!" - + simpleType["basename"] = "list" - + # Check that derivation is allowed if itemtypeinfos.has_key("final"): if itemtypeinfos["final"].has_key("#all"): raise ValueError("Item type can't be derivated!") if itemtypeinfos["final"].has_key("list"): raise ValueError("Item type can't be derivated by list!") - + # Generate extract value for new created type def ExtractSimpleTypeValue(attr, extract = True): values = [] for value in GetToken(attr, extract).split(" "): values.append(itemtypeinfos["extract"](value, False)) return values - + def CheckSimpleTypeValue(value): for item in value: result = itemtypeinfos["check"](item) if not result: return result return True - + SimpleTypeInitialValue = lambda: [] - + GenerateSimpleType = GenerateSimpleTypeXMLText(lambda x: " ".join(map(itemtypeinfos["generate"], x))) - + facets = GenerateDictFacets(["length", "maxLength", "minLength", "enumeration", "pattern"]) facets["whiteSpace"] = ("collapse", False) - + elif typeinfos["type"] == "union": # Search for member types definition membertypesinfos = [] @@ -431,22 +431,22 @@ raise ValueError("\"%s\" isn't defined!" % membertype) else: infos = membertype - + # Check that member type is a simple type if infos["type"] != SIMPLETYPE: raise ValueError("Member type given isn't a simpleType!") - + # Check that derivation is allowed if infos.has_key("final"): if infos["final"].has_key("#all"): raise ValueError("Item type can't be derivated!") if infos["final"].has_key("union"): raise ValueError("Member type can't be derivated by union!") - + membertypesinfos.append(infos) - + simpleType["basename"] = "union" - + # Generate extract value for new created type def ExtractSimpleTypeValue(attr, extract = True): if extract: @@ -459,25 +459,25 @@ except: pass raise ValueError("\"%s\" isn't valid for type defined for union!") - + def CheckSimpleTypeValue(value): for infos in membertypesinfos: result = infos["check"](value) if result: return result return False - + SimpleTypeInitialValue = membertypesinfos[0]["initial"] - + def GenerateSimpleTypeFunction(value): if isinstance(value, BooleanType): return {True: "true", False: "false"}[value] else: return str(value) GenerateSimpleType = GenerateSimpleTypeXMLText(GenerateSimpleTypeFunction) - + facets = GenerateDictFacets(["pattern", "enumeration"]) - + simpleType["facets"] = facets simpleType["extract"] = ExtractSimpleTypeValue simpleType["initial"] = SimpleTypeInitialValue @@ -488,10 +488,10 @@ def ReduceSimpleType(factory, attributes, elements): # Reduce all the simple type children annotations, children = factory.ReduceElements(elements) - + simpleType = CreateSimpleType(factory, attributes, children[0]) simpleType["doc"] = annotations - + return simpleType # Complex type @@ -503,7 +503,7 @@ basetypeinfos = factory.FindSchemaElement(base) if not isinstance(basetypeinfos, (UnicodeType, StringType)) and basetypeinfos["type"] == COMPLEXTYPE: attrnames = dict(map(lambda x:(x["name"], True), basetypeinfos["attributes"])) - + for element in elements: if element["type"] == ATTRIBUTE: if attrnames.get(element["name"], False): @@ -534,7 +534,7 @@ raise ValueError("Only one base type can be defined for restriction!") if restriction["base"] is None: raise ValueError("No base type has been defined for restriction!") - + while len(children) > 0 and children[0]["type"] in ALL_FACETS: restriction["facets"].append(children.pop(0)) restriction["attributes"] = ExtractAttributes(factory, children, restriction["base"]) @@ -571,9 +571,9 @@ def ReduceSimpleContent(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + simpleContent = children[0].copy() - + basetypeinfos = factory.FindSchemaElement(simpleContent["base"]) if basetypeinfos["type"] == SIMPLETYPE: contenttypeinfos = simpleContent.copy() @@ -588,7 +588,7 @@ else: raise ValueError("No compatible base type defined for simpleContent!") contenttypeinfos = CreateSimpleType(factory, attributes, contenttypeinfos) - + simpleContent["elements"] = [{"name": "content", "type": ELEMENT, "elmt_type": contenttypeinfos, "doc": annotations, "minOccurs": 1, "maxOccurs": 1}] @@ -605,7 +605,7 @@ def ReduceComplexType(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + if len(children) > 0: if children[0]["type"] in ["simpleContent", "complexContent"]: complexType = children[0].copy() @@ -666,20 +666,20 @@ def ReduceAttribute(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + if attributes.has_key("default"): if attributes.has_key("fixed"): raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!") elif attributes.get("use", "optional") != "optional": raise ValueError("if \"default\" present, \"use\" can only have the value \"optional\"!") - + attribute = {"type": ATTRIBUTE, "attr_type": attributes.get("type", None), "doc": annotations} if len(children) > 0: if attribute["attr_type"] is None: attribute["attr_type"] = children[0] else: raise ValueError("Only one type can be defined for attribute!") - + if attributes.has_key("ref"): if attributes.has_key("name"): raise ValueError("\"ref\" and \"name\" can't be defined at the same time!") @@ -689,7 +689,7 @@ raise ValueError("if \"ref\" is present, no type can be defined!") elif attribute["attr_type"] is None: raise ValueError("No type has been defined for attribute \"%s\"!" % attributes["name"]) - + if attributes.has_key("type"): tmp_attrs = attributes.copy() tmp_attrs.pop("type") @@ -711,14 +711,14 @@ def ReduceAny(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + any = {"type": ANY, "doc": annotations} any.update(attributes) return any def ReduceElement(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + types = [] constraints = [] for child in children: @@ -726,10 +726,10 @@ constraints.append(child) else: types.append(child) - + if attributes.has_key("default") and attributes.has_key("fixed"): raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!") - + if attributes.has_key("ref"): for attr in ["name", "default", "fixed", "form", "block", "type"]: if attributes.has_key(attr): @@ -738,7 +738,7 @@ raise ValueError("\"ref\" and \"nillable\" can't be defined at the same time!") if len(types) > 0: raise ValueError("No type and no constraints can be defined where \"ref\" is defined!") - + infos = factory.FindSchemaElement(attributes["ref"], ELEMENT) if infos is not None: element = infos.copy() @@ -748,7 +748,7 @@ return element else: raise ValueError("\"%s\" base type isn't defined or circular referenced!" % name) - + elif attributes.has_key("name"): element = {"type": ELEMENT, "elmt_type": attributes.get("type", None), "constraints": constraints, "doc": annotations} if len(types) > 0: @@ -759,7 +759,7 @@ elif element["elmt_type"] is None: element["elmt_type"] = "tag" element["type"] = TAG - + if attributes.has_key("type"): tmp_attrs = attributes.copy() tmp_attrs.pop("type") @@ -772,18 +772,18 @@ def ReduceAll(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + for child in children: if children["maxOccurs"] == "unbounded" or children["maxOccurs"] > 1: raise ValueError("\"all\" item can't have \"maxOccurs\" attribute greater than 1!") - + return {"type": "all", "elements": children, "minOccurs": attributes["minOccurs"], "maxOccurs": attributes["maxOccurs"], "order": False, "doc": annotations} def ReduceChoice(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + choices = [] for child in children: if child["type"] in [ELEMENT, ANY, TAG]: @@ -795,7 +795,7 @@ elif child["type"] == CHOICE: choices.extend(child["choices"]) elif child["type"] == "group": - elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP) + elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP) if not elmtgroup.has_key("choices"): raise ValueError("Only group composed of \"choice\" can be referenced in \"choice\" element!") choices_tmp = [] @@ -810,18 +810,18 @@ else: choices_tmp.append(choice) choices.extend(choices_tmp) - + for choice in choices: attributes["minOccurs"] = min(attributes["minOccurs"], choice["minOccurs"]) choice["minOccurs"] = 1 - + return {"type": CHOICE, "choices": choices, "minOccurs": attributes["minOccurs"], "maxOccurs": attributes["maxOccurs"], "doc": annotations} def ReduceSequence(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + sequence = [] for child in children: if child["type"] in [ELEMENT, ANY, TAG, CHOICE]: @@ -844,14 +844,14 @@ else: elements_tmp.append(element) sequence.extend(elements_tmp) - + return {"type": "sequence", "elements": sequence, "minOccurs": attributes["minOccurs"], "maxOccurs": attributes["maxOccurs"], "order": True, "doc": annotations} - - + + def ReduceGroup(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + if attributes.has_key("ref"): return {"type": "group", "ref": attributes["ref"], "doc": annotations} else: @@ -868,39 +868,39 @@ def ReduceUnique(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + unique = {"type": CONSTRAINT, "const_type": "unique", "selector": children[0], "fields": children[1:]} unique.update(attributes) return unique - + def ReduceKey(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + key = {"type": CONSTRAINT, "const_type": "key", "selector": children[0], "fields": children[1:]} key.update(attributes) return key def ReduceKeyRef(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + keyref = {"type": CONSTRAINT, "const_type": "keyref", "selector": children[0], "fields": children[1:]} keyref.update(attributes) return keyref - + def ReduceSelector(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + selector = {"type": CONSTRAINT, "const_type": "selector"} selector.update(attributes) return selector def ReduceField(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + field = {"type": CONSTRAINT, "const_type": "field"} field.update(attributes) return field - + # Inclusion elements @@ -910,7 +910,7 @@ def ReduceInclude(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) - + if factory.FileName is None: raise ValueError("Include in XSD string not yet supported") filepath = attributes["schemaLocation"] @@ -922,7 +922,7 @@ include_factory = XSDClassFactory(minidom.parse(xsdfile), filepath) xsdfile.close() include_factory.CreateClasses() - + if factory.TargetNamespace == include_factory.TargetNamespace: factory.Namespaces[factory.TargetNamespace].update(include_factory.Namespaces[include_factory.TargetNamespace]) else: @@ -931,7 +931,7 @@ factory.ComputedClassesLookUp.update(include_factory.ComputedClassesLookUp) factory.EquivalentClassesParent.update(include_factory.EquivalentClassesParent) return None - + def ReduceRedefine(factory, attributes, elements): annotations, children = factory.ReduceElements(elements) raise ValueError("\"redefine\" element isn't supported yet!") @@ -944,15 +944,15 @@ factory.ElementFormDefault = attributes["elementFormDefault"] factory.BlockDefault = attributes["blockDefault"] factory.FinalDefault = attributes["finalDefault"] - + targetNamespace = attributes.get("targetNamespace", None) factory.TargetNamespace = factory.DefinedNamespaces.get(targetNamespace, None) if factory.TargetNamespace is not None: factory.etreeNamespaceFormat = "{%s}%%s" % targetNamespace factory.Namespaces[factory.TargetNamespace] = {} - + annotations, children = factory.ReduceElements(elements, True) - + for child in children: if child.has_key("name"): infos = factory.GetQualifiedNameInfos(child["name"], factory.TargetNamespace, True) @@ -987,7 +987,7 @@ else: return True return schema == reference - + #------------------------------------------------------------------------------- # Base class for XSD schema extraction #------------------------------------------------------------------------------- @@ -999,7 +999,7 @@ ClassFactory.__init__(self, document, filepath, debug) self.Namespaces["xml"] = { "lang": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("lang", LANGUAGE_model) } @@ -1007,31 +1007,31 @@ } self.Namespaces["xsi"] = { "noNamespaceSchemaLocation": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": NotSupportedYet("noNamespaceSchemaLocation") } }, "nil": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": NotSupportedYet("nil") } }, "schemaLocation": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": NotSupportedYet("schemaLocation") } }, "type": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": NotSupportedYet("type") } } } - + def ParseSchema(self): for child in self.Document.childNodes: if child.nodeType == self.Document.ELEMENT_NODE: @@ -1067,7 +1067,7 @@ if element_type is not None and element["type"] != element_type: raise ValueError("\"%s\" isn't of the expected type!" % element_name) return element - + def CreateSchemaElement(self, element_name, element_type): for type, attributes, elements in self.Schema[2]: namespace, name = DecomposeQualifiedName(type) @@ -1091,7 +1091,7 @@ return None """ -This function opens the xsd file and generate a xml parser with class lookup from +This function opens the xsd file and generate a xml parser with class lookup from the xml tree """ def GenerateParserFromXSD(filepath): @@ -1129,9 +1129,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, element*) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("all", ["id", "maxOccurs", "minOccurs"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("all", ["id", "maxOccurs", "minOccurs"], re.compile("((?:annotation )?(?:element )*)")) }, "reduce": ReduceAll @@ -1143,9 +1143,9 @@ {any attributes with non-schema namespace . . .}> Content: (appinfo | documentation)* """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("annotation", ["id"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("annotation", ["id"], re.compile("((?:app_info |documentation )*)")) }, "reduce": ReduceAnnotation @@ -1161,10 +1161,10 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("any", - ["id", "maxOccurs", "minOccurs", "namespace", "processContents"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("any", + ["id", "maxOccurs", "minOccurs", "namespace", "processContents"], re.compile("((?:annotation )?(?:simpleType )*)")) }, "reduce": ReduceAny @@ -1178,7 +1178,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("anyAttribute", ["id", "namespace", "processContents"], ONLY_ANNOTATION) @@ -1192,7 +1192,7 @@ {any attributes with non-schema namespace . . .}> Content: ({any})* """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("appinfo", ["source"], re.compile("(.*)"), True) }, @@ -1212,13 +1212,13 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, simpleType?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("attribute", - ["default", "fixed", "form", "id", "name", "ref", "type", "use"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("attribute", + ["default", "fixed", "form", "id", "name", "ref", "type", "use"], re.compile("((?:annotation )?(?:simpleType )?)")), - "schema": GenerateElement("attribute", - ["default", "fixed", "form", "id", "name", "type"], + "schema": GenerateElement("attribute", + ["default", "fixed", "form", "id", "name", "type"], re.compile("((?:annotation )?(?:simpleType )?)")) }, "reduce": ReduceAttribute @@ -1232,12 +1232,12 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("attributeGroup", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("attributeGroup", ["id", "ref"], ONLY_ANNOTATION), "schema": GenerateElement("attributeGroup", - ["id", "name"], + ["id", "name"], re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))")) }, "reduce": ReduceAttributeGroup @@ -1251,9 +1251,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (element | group | choice | sequence | any)*) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("choice", ["id", "maxOccurs", "minOccurs"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("choice", ["id", "maxOccurs", "minOccurs"], re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)")) }, "reduce": ReduceChoice @@ -1266,9 +1266,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (restriction | extension)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("complexContent", ["id", "mixed"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("complexContent", ["id", "mixed"], re.compile("((?:annotation )?(?:restriction |extension ))")) }, "reduce": ReduceComplexContent @@ -1285,10 +1285,10 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("complexType", - ["abstract", "block", "final", "id", "mixed", "name"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("complexType", + ["abstract", "block", "final", "id", "mixed", "name"], re.compile("((?:annotation )?(?:simpleContent |complexContent |(?:(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))))")) }, "reduce": ReduceComplexType @@ -1301,9 +1301,9 @@ {any attributes with non-schema namespace . . .}> Content: ({any})* """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("documentation", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("documentation", ["source", "lang"], re.compile("(.*)"), True) }, "reduce": ReduceDocumentation @@ -1328,13 +1328,13 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("element", - ["abstract", "block", "default", "final", "fixed", "form", "id", "maxOccurs", "minOccurs", "name", "nillable", "ref", "substitutionGroup", "type"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("element", + ["abstract", "block", "default", "final", "fixed", "form", "id", "maxOccurs", "minOccurs", "name", "nillable", "ref", "substitutionGroup", "type"], re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)")), - "schema": GenerateElement("element", - ["abstract", "block", "default", "final", "fixed", "form", "id", "name", "nillable", "substitutionGroup", "type"], + "schema": GenerateElement("element", + ["abstract", "block", "default", "final", "fixed", "form", "id", "name", "nillable", "substitutionGroup", "type"], re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)")) }, "reduce": ReduceElement @@ -1347,7 +1347,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("enumeration", ["id", "value"], ONLY_ANNOTATION) }, @@ -1361,11 +1361,11 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("extension", ["base", "id"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("extension", ["base", "id"], re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))")), - "complexContent": GenerateElement("extension", ["base", "id"], + "complexContent": GenerateElement("extension", ["base", "id"], re.compile("((?:annotation )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))")) }, "reduce": ReduceExtension @@ -1378,7 +1378,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("field", ["id", "xpath"], ONLY_ANNOTATION) }, @@ -1393,9 +1393,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("fractionDigits", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("fractionDigits", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("fractionDigits", True) @@ -1411,13 +1411,13 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (all | choice | sequence)?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("group", - ["id", "maxOccurs", "minOccurs", "ref"], + ["id", "maxOccurs", "minOccurs", "ref"], re.compile("((?:annotation )?(?:all |choice |sequence )?)")), "schema": GenerateElement("group", - ["id", "name"], + ["id", "name"], re.compile("((?:annotation )?(?:all |choice |sequence )?)")) }, "reduce": ReduceGroup @@ -1431,7 +1431,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("import", ["id", "namespace", "schemaLocation"], ONLY_ANNOTATION) @@ -1446,7 +1446,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("include", ["id", "schemaLocation"], ONLY_ANNOTATION) @@ -1461,9 +1461,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (selector, field+)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("key", ["id", "name"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("key", ["id", "name"], re.compile("((?:annotation )?(?:selector (?:field )+))")) }, "reduce": ReduceKey @@ -1477,9 +1477,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (selector, field+)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("keyref", ["id", "name", "refer"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("keyref", ["id", "name", "refer"], re.compile("((?:annotation )?(?:selector (?:field )+))")) }, "reduce": ReduceKeyRef @@ -1493,9 +1493,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("length", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("length", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("length", True) @@ -1508,9 +1508,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, simpleType?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("list", ["id", "itemType"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("list", ["id", "itemType"], re.compile("((?:annotation )?(?:simpleType )?)$")) }, "reduce": ReduceList @@ -1524,7 +1524,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("maxExclusive", ["fixed", "id", "value"], ONLY_ANNOTATION) @@ -1540,9 +1540,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("maxInclusive", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("maxInclusive", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("maxInclusive", True) @@ -1556,9 +1556,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("maxLength", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("maxLength", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("maxLength", True) @@ -1572,9 +1572,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("minExclusive", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("minExclusive", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("minExclusive", True) @@ -1588,9 +1588,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("minInclusive", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("minInclusive", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("minInclusive", True) @@ -1604,7 +1604,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("minLength", ["fixed", "id", "value"], ONLY_ANNOTATION) @@ -1619,7 +1619,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("pattern", ["id", "value"], ONLY_ANNOTATION) }, @@ -1633,9 +1633,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation | (simpleType | complexType | group | attributeGroup))* """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("refine", ["id", "schemaLocation"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("refine", ["id", "schemaLocation"], re.compile("((?:annotation |(?:simpleType |complexType |group |attributeGroup ))*)")) }, "reduce": ReduceRedefine @@ -1648,13 +1648,13 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("restriction", ["base", "id"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("restriction", ["base", "id"], re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)))")), - "simpleContent": GenerateElement("restriction", ["base", "id"], + "simpleContent": GenerateElement("restriction", ["base", "id"], re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")), - "complexContent": GenerateElement("restriction", ["base", "id"], + "complexContent": GenerateElement("restriction", ["base", "id"], re.compile("((?:annotation )?(?:(?:simpleType )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")), }, "reduce": ReduceRestriction @@ -1673,10 +1673,10 @@ {any attributes with non-schema namespace . . .}> Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("schema", - ["attributeFormDefault", "blockDefault", "elementFormDefault", "finalDefault", "id", "targetNamespace", "version", "lang"], + ["attributeFormDefault", "blockDefault", "elementFormDefault", "finalDefault", "id", "targetNamespace", "version", "lang"], re.compile("((?:include |import |redefine |annotation )*(?:(?:(?:simpleType |complexType |group |attributeGroup )|element |attribute |annotation )(?:annotation )*)*)")) } }, @@ -1688,7 +1688,7 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, + "type": SYNTAXELEMENT, "extract": { "default": GenerateElement("selector", ["id", "xpath"], ONLY_ANNOTATION) }, @@ -1703,9 +1703,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (element | group | choice | sequence | any)*) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("sequence", ["id", "maxOccurs", "minOccurs"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("sequence", ["id", "maxOccurs", "minOccurs"], re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)")) }, "reduce": ReduceSequence @@ -1717,9 +1717,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (restriction | extension)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("simpleContent", ["id"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("simpleContent", ["id"], re.compile("((?:annotation )?(?:restriction |extension ))")) }, "reduce": ReduceSimpleContent @@ -1733,9 +1733,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (restriction | list | union)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("simpleType", ["final", "id", "name"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("simpleType", ["final", "id", "name"], re.compile("((?:annotation )?(?:restriction |list |union ))")) }, "reduce": ReduceSimpleType @@ -1749,9 +1749,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("totalDigits", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("totalDigits", ["fixed", "id", "value"], ONLY_ANNOTATION), }, "reduce": GenerateFacetReducing("totalDigits", True) @@ -1764,9 +1764,9 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, simpleType*) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("union", ["id", "memberTypes"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("union", ["id", "memberTypes"], re.compile("((?:annotation )?(?:simpleType )*)")) }, "reduce": ReduceUnion @@ -1779,14 +1779,14 @@ {any attributes with non-schema namespace . . .}> Content: (annotation?, (selector, field+)) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("unique", ["id", "name"], + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("unique", ["id", "name"], re.compile("((?:annotation )?(?:selector |(?:field )+))")) }, "reduce": ReduceUnique }, - + "whiteSpace": {"struct" : """ Content: (annotation?) """, - "type": SYNTAXELEMENT, - "extract": { - "default": GenerateElement("whiteSpace", + "type": SYNTAXELEMENT, + "extract": { + "default": GenerateElement("whiteSpace", ["fixed", "id", "value"], ONLY_ANNOTATION) }, "reduce": GenerateFacetReducing("whiteSpace", True) @@ -1808,7 +1808,7 @@ #------------------------------------------------------------------------------- "abstract": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetBoolean }, @@ -1818,7 +1818,7 @@ }, "attributeFormDefault": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateEnumeratedExtraction("member attributeFormDefault", ["qualified", "unqualified"]) }, @@ -1826,23 +1826,23 @@ "default": "unqualified" } }, - + "base": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member base", QName_model) } }, - + "block": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateGetList("block", ["restriction", "extension", "substitution"]) } }, - + "blockDefault": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateGetList("block", ["restriction", "extension", "substitution"]) }, @@ -1850,16 +1850,16 @@ "default": "" } }, - + "default": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetAttributeValue } }, "elementFormDefault": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateEnumeratedExtraction("member elementFormDefault", ["qualified", "unqualified"]) }, @@ -1867,9 +1867,9 @@ "default": "unqualified" } }, - + "final": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateGetList("final", ["restriction", "extension", "substitution"]), "simpleType": GenerateGetList("final", ["list", "union", "restriction"]) @@ -1877,7 +1877,7 @@ }, "finalDefault": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateGetList("finalDefault", ["restriction", "extension", "list", "union"]) }, @@ -1885,9 +1885,9 @@ "default": "" } }, - + "fixed": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetBoolean, "attribute": GetAttributeValue, @@ -1901,35 +1901,35 @@ }, "form": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateEnumeratedExtraction("member form", ["qualified", "unqualified"]) } }, "id": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member id", NCName_model) } }, - + "itemType": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member itemType", QName_model) } }, "memberTypes": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameListExtraction("member memberTypes", QNames_model) }, }, - + "maxOccurs": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateLimitExtraction(), "all": GenerateLimitExtraction(1, 1, False) @@ -1940,7 +1940,7 @@ }, "minOccurs": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateLimitExtraction(unbounded = False), "all": GenerateLimitExtraction(0, 1, False) @@ -1951,7 +1951,7 @@ }, "mixed": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetBoolean }, @@ -1960,16 +1960,16 @@ "complexType": False } }, - + "name": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member name", NCName_model) } }, - + "namespace": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member namespace", URI_model), "any": GetNamespaces @@ -1981,14 +1981,14 @@ }, "nillable": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetBoolean }, }, - + "processContents": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateEnumeratedExtraction("member processContents", ["lax", "skip", "strict"]) }, @@ -1996,9 +1996,9 @@ "default": "strict" } }, - + "ref": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member ref", QName_model) } @@ -2010,44 +2010,44 @@ "default": GenerateModelNameExtraction("member refer", QName_model) } }, - + "schemaLocation": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member schemaLocation", URI_model) } }, - + "source": { "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member source", URI_model) } }, - + "substitutionGroup": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member substitutionGroup", QName_model) } }, "targetNamespace": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member targetNamespace", URI_model) } }, - + "type": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateModelNameExtraction("member type", QName_model) } }, "use": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GenerateEnumeratedExtraction("member usage", ["required", "optional", "prohibited"]) }, @@ -2057,7 +2057,7 @@ }, "value": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { "default": GetAttributeValue, "fractionDigits": GenerateIntegerExtraction(minInclusive=0), @@ -2077,13 +2077,13 @@ }, "xpath": { - "type": SYNTAXATTRIBUTE, + "type": SYNTAXATTRIBUTE, "extract": { # "default": NotSupportedYet("xpath") "default": GetAttributeValue } }, - + #------------------------------------------------------------------------------- # Simple types definition #------------------------------------------------------------------------------- @@ -2110,27 +2110,27 @@ "token": { "type": SIMPLETYPE, - "basename": "token", + "basename": "token", "extract": GetToken, "facets": STRING_FACETS, "generate": GenerateSimpleTypeXMLText(lambda x : x), "initial": lambda: "", "check": lambda x: isinstance(x, (StringType, UnicodeType)) }, - + "base64Binary": { - "type": SIMPLETYPE, - "basename": "base64Binary", + "type": SIMPLETYPE, + "basename": "base64Binary", "extract": NotSupportedYet("base64Binary"), "facets": STRING_FACETS, "generate": GenerateSimpleTypeXMLText(str), "initial": lambda: 0, "check": lambda x: isinstance(x, (IntType, LongType)) }, - + "hexBinary": { "type": SIMPLETYPE, - "basename": "hexBinary", + "basename": "hexBinary", "extract": GetHexInteger, "facets": STRING_FACETS, "generate": GenerateSimpleTypeXMLText(lambda x: ("%."+str(int(round(len("%X"%x)/2.)*2))+"X")%x), @@ -2140,24 +2140,24 @@ "integer": { "type": SIMPLETYPE, - "basename": "integer", + "basename": "integer", "extract": GenerateIntegerExtraction(), "facets": DECIMAL_FACETS, "generate": GenerateSimpleTypeXMLText(str), "initial": lambda: 0, "check": lambda x: isinstance(x, IntType) }, - + "positiveInteger": { "type": SIMPLETYPE, - "basename": "positiveInteger", + "basename": "positiveInteger", "extract": GenerateIntegerExtraction(minExclusive=0), "facets": DECIMAL_FACETS, "generate": GenerateSimpleTypeXMLText(str), "initial": lambda: 1, "check": lambda x: isinstance(x, IntType) }, - + "negativeInteger": { "type": SIMPLETYPE, "basename": "negativeInteger", @@ -2167,27 +2167,27 @@ "initial": lambda: -1, "check": lambda x: isinstance(x, IntType) }, - + "nonNegativeInteger": { - "type": SIMPLETYPE, - "basename": "nonNegativeInteger", + "type": SIMPLETYPE, + "basename": "nonNegativeInteger", "extract": GenerateIntegerExtraction(minInclusive=0), "facets": DECIMAL_FACETS, "generate": GenerateSimpleTypeXMLText(str), "initial": lambda: 0, "check": lambda x: isinstance(x, IntType) }, - + "nonPositiveInteger": { "type": SIMPLETYPE, - "basename": "nonPositiveInteger", + "basename": "nonPositiveInteger", "extract": GenerateIntegerExtraction(maxInclusive=0), "facets": DECIMAL_FACETS, "generate": GenerateSimpleTypeXMLText(str), "initial": lambda: 0, "check": lambda x: isinstance(x, IntType) }, - + "long": { "type": SIMPLETYPE, "basename": "long", @@ -2197,7 +2197,7 @@ "initial": lambda: 0, "check": lambda x: isinstance(x, IntType) }, - + "unsignedLong": { "type": SIMPLETYPE, "basename": "unsignedLong", @@ -2240,7 +2240,7 @@ "unsignedShort": { "type": SIMPLETYPE, - "basename": "unsignedShort", + "basename": "unsignedShort", "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**16), "facets": DECIMAL_FACETS, "generate": GenerateSimpleTypeXMLText(str), @@ -2306,7 +2306,7 @@ "generate": GenerateSimpleTypeXMLText(lambda x:{True : "true", False : "false"}[x]), "initial": lambda: False, "check": lambda x: isinstance(x, BooleanType) - }, + }, "duration": { "type": SIMPLETYPE, @@ -2337,7 +2337,7 @@ "initial": lambda: datetime.date(1,1,1), "check": lambda x: isinstance(x, datetime.date) }, - + "time": { "type": SIMPLETYPE, "basename": "time", @@ -2407,7 +2407,7 @@ "initial": lambda: "", "check": lambda x: isinstance(x, (StringType, UnicodeType)) }, - + "QName": { "type": SIMPLETYPE, "basename": "QName", @@ -2531,4 +2531,3 @@ # Complex Types "anyType": {"type": COMPLEXTYPE, "extract": lambda x:None}, } -