# HG changeset patch # User laurent # Date 1337587374 -7200 # Node ID ce605c1a6d049c2892c59544a7854eab5ff01a3c # Parent 629680fb05824a0d7a5371562479c2781538d032# Parent 188906a7368c9707dab9f1c97229b6d75235654e Merged diff -r 188906a7368c -r ce605c1a6d04 GraphicViewer.py --- a/GraphicViewer.py Tue May 15 05:19:13 2012 +0900 +++ b/GraphicViewer.py Mon May 21 10:02:54 2012 +0200 @@ -507,14 +507,15 @@ ## Refresh the variable cursor. # @param dc The draw canvas def RefreshCursor(self, dc=None): - if dc is None: - dc = wx.BufferedDC(wx.ClientDC(self.Canvas.canvas), self.Canvas._Buffer) - - # Erase previous time cursor if drawn - if self.LastCursor is not None: - self.DrawCursor(dc, *self.LastCursor) - - # Draw new time cursor - if self.CursorIdx is not None: - self.LastCursor = self.Datas[self.CursorIdx] - self.DrawCursor(dc, *self.LastCursor) + if self: + if dc is None: + dc = wx.BufferedDC(wx.ClientDC(self.Canvas.canvas), self.Canvas._Buffer) + + # Erase previous time cursor if drawn + if self.LastCursor is not None: + self.DrawCursor(dc, *self.LastCursor) + + # Draw new time cursor + if self.CursorIdx is not None: + self.LastCursor = self.Datas[self.CursorIdx] + self.DrawCursor(dc, *self.LastCursor) diff -r 188906a7368c -r ce605c1a6d04 Images/custom_tree_background.png Binary file Images/custom_tree_background.png has changed diff -r 188906a7368c -r ce605c1a6d04 Images/debug.png Binary file Images/debug.png has changed diff -r 188906a7368c -r ce605c1a6d04 Images/edit.png Binary file Images/edit.png has changed diff -r 188906a7368c -r ce605c1a6d04 Images/graph.png Binary file Images/graph.png has changed diff -r 188906a7368c -r ce605c1a6d04 Images/icons.svg --- a/Images/icons.svg Tue May 15 05:19:13 2012 +0900 +++ b/Images/icons.svg Mon May 21 10:02:54 2012 +0200 @@ -23,2498 +23,6524 @@ sodipodi:docname="icons.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + id="defs4"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %%custom_tree_background%% + + + + + + + + + + + %%up%% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %%edit%% + + + + + + + + + + + + + + + + + + + + %%debug%% + + + + + + + + + + + + + + + + + + + + + + + + + %%graph%% diff -r 188906a7368c -r ce605c1a6d04 Images/up.png Binary file Images/up.png has changed diff -r 188906a7368c -r ce605c1a6d04 PLCControler.py --- a/PLCControler.py Tue May 15 05:19:13 2012 +0900 +++ b/PLCControler.py Mon May 21 10:02:54 2012 +0200 @@ -75,7 +75,12 @@ "InOut" : (plcopen.interface_inOutVars, ITEM_VAR_INOUT) } -LOCATIONS_ITEMS = [LOCATION_PLUGIN, +POU_TYPES = {"program": ITEM_PROGRAM, + "functionBlock": ITEM_FUNCTIONBLOCK, + "function": ITEM_FUNCTION, + } + +LOCATIONS_ITEMS = [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, @@ -204,7 +209,7 @@ self.ProgramOffset = 0 self.NextCompiledProject = None self.CurrentCompiledProject = None - self.PluginTypes = [] + self.ConfNodeTypes = [] self.ProgramFilePath = "" def GetQualifierTypes(self): @@ -376,135 +381,259 @@ resources["values"].append(resource_infos) config_infos["values"] = [resources] configurations["values"].append(config_infos) - infos["values"] = [{"name": PROPERTIES, "type": ITEM_PROPERTIES, "values": []}, - datatypes, pou_types["function"], pou_types["functionBlock"], + infos["values"] = [datatypes, pou_types["function"], pou_types["functionBlock"], pou_types["program"], configurations] return infos return None - # Return project topology informations - def GetProjectTopology(self, debug = False): - project = self.GetProject(debug) - if project is not None: - infos = {"name": project.getname(), "type": ITEM_PROJECT, "values" : []} - for config in project.getconfigurations(): - config_infos = {"name" : config.getname(), "type": ITEM_CONFIGURATION, "values" : []} - for resource in config.getresource(): - resource_infos = {"name" : resource.getname(), "type": ITEM_RESOURCE, "values": []} - for task in resource.gettask(): - for pou in task.getpouInstance(): - instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug) - if instance_infos is not None: - resource_infos["values"].append(instance_infos) - for pou in resource.getpouInstance(): - instance_infos = self.GetPouTopology(pou.getname(), pou.gettypeName(), debug=debug) - if instance_infos is not None: - resource_infos["values"].append(instance_infos) - for varlist in resource.getglobalVars(): - for variable in varlist.getvariable(): - vartype_content = variable.gettype().getcontent() - if vartype_content["name"] == "derived": - var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname(), True, debug) - if var_infos is not None: - resource_infos["values"].append(var_infos) - elif vartype_content["name"] in ["string", "wstring"]: - resource_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"].upper(), - "type" : ITEM_VAR_GLOBAL, "values" : []}) - else: - resource_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"], - "type" : ITEM_VAR_GLOBAL, "values" : []}) - config_infos["values"].append(resource_infos) - for varlist in config.getglobalVars(): - for variable in varlist.getvariable(): - vartype_content = variable.gettype().getcontent() - if vartype_content["name"] == "derived": - var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname(), True, debug) - if var_infos is not None: - config_infos["values"].append(var_infos) - elif vartype_content["name"] in ["string", "wstring"]: - config_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"].upper(), - "type" : ITEM_VAR_GLOBAL, "values" : []}) - else: - config_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"], - "type" : ITEM_VAR_GLOBAL, "values" : []}) - infos["values"].append(config_infos) - return infos - return None - - # Return pou topology informations - def GetPouTopology(self, name, type, global_var = False, debug = False): - project = self.GetProject(debug) - if project is not None: - pou = project.getpou(type) + def GetPouVariableInfos(self, project, variable, var_class, debug=False): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + var_type = vartype_content["value"].getname() + pou_type = None + pou = project.getpou(var_type) if pou is not None: pou_type = pou.getpouType() - if pou_type == "function": - return None - elif pou_type == "program": - pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_PROGRAM, - "tagname" : self.ComputePouName(pou.getname()), "values" : []} + edit = debug = pou_type is not None + if pou_type is None: + block_infos = self.GetBlockType(var_type, debug = debug) + pou_type = block_infos["type"] + if pou_type is not None: + var_class = None + if pou_type == "program": + var_class = ITEM_PROGRAM + elif pou_type != "function": + var_class = ITEM_FUNCTIONBLOCK + if var_class is not None: + return {"name": variable.getname(), + "type": var_type, + "class": var_class, + "edit": edit, + "debug": debug} + elif var_type in self.GetDataTypes(debug = debug): + return {"name": variable.getname(), + "type": var_type, + "class": var_class, + "edit": False, + "debug": False} + elif vartype_content["name"] in ["string", "wstring"]: + return {"name": variable.getname(), + "type": vartype_content["name"].upper(), + "class": var_class, + "edit": False, + "debug": True} + else: + return {"name": variable.getname(), + "type": vartype_content["name"], + "class": var_class, + "edit": False, + "debug": True} + return None + + def GetPouVariables(self, tagname, debug = False): + vars = [] + pou_type = None + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "P": + pou = project.getpou(words[1]) + if pou is not None: + pou_type = pou.getpouType() + if (pou_type in ["program", "functionBlock"] and + pou.interface is not None): + # Extract variables from every varLists + for varlist_type, varlist in pou.getvars(): + var_infos = VAR_CLASS_INFOS.get(varlist_type, None) + if var_infos is not None: + var_class = var_infos[1] + else: + var_class = ITEM_VAR_LOCAL + for variable in varlist.getvariable(): + var_infos = self.GetPouVariableInfos(project, variable, var_class, debug) + if var_infos is not None: + vars.append(var_infos) + return {"class": POU_TYPES[pou_type], + "type": words[1], + "variables": vars, + "edit": True, + "debug": True} else: - pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_FUNCTIONBLOCK, - "tagname" : self.ComputePouName(pou.getname()), "values" : []} - if pou.getbodyType() == "SFC": - for transition in pou.gettransitionList(): - pou_infos["values"].append({"name" : transition.getname(), - "elmt_type" : "TRANSITION", "type" : ITEM_TRANSITION, - "tagname" : self.ComputePouActionName(pou.getname(), transition.getname()), - "values" : []}) - for action in pou.getactionList(): - pou_infos["values"].append({"name": action.getname(), - "elmt_type" : "ACTION", "type": ITEM_ACTION, - "tagname" : self.ComputePouActionName(pou.getname(), action.getname()), - "values" : []}) - if pou.interface: - # Extract variables from every varLists - for type, varlist in pou.getvars(): - infos = VAR_CLASS_INFOS.get(type, None) - if infos is not None: - current_var_class = infos[1] - else: - current_var_class = ITEM_VAR_LOCAL - for variable in varlist.getvariable(): - vartype_content = variable.gettype().getcontent() - if vartype_content["name"] == "derived": - var_infos = self.GetPouTopology(variable.getname(), vartype_content["value"].getname()) - if var_infos is not None: - pou_infos["values"].append(var_infos) - elif vartype_content["name"] in ["string", "wstring"]: - pou_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"].upper(), - "type" : current_var_class, "values" : []}) - else: - pou_infos["values"].append({"name" : variable.getname(), - "elmt_type" : vartype_content["name"], - "type" : current_var_class, "values" : []}) - return pou_infos - block_infos = self.GetBlockType(type, debug = debug) - if block_infos is not None: - if block_infos["type"] == "function": - return None - elif block_infos["type"] == "program": - pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_PROGRAM, "values" : []} - else: - pou_infos = {"name" : name, "elmt_type" : type, "type" : ITEM_FUNCTIONBLOCK, "values" : []} - for varname, vartype, varmodifier in block_infos["inputs"]: - pou_infos["values"].append({"name" : varname, "elmt_type" : vartype, "type" : ITEM_VAR_INPUT, "values" : []}) - for varname, vartype, varmodifier in block_infos["outputs"]: - pou_infos["values"].append({"name" : varname, "elmt_type" : vartype, "type" : ITEM_VAR_INPUT, "values" : []}) - return pou_infos + block_infos = self.GetBlockType(words[1], debug = debug) + if (block_infos is not None and + block_infos["type"] in ["program", "functionBlock"]): + for varname, vartype, varmodifier in block_infos["inputs"]: + vars.append({"name" : varname, + "type" : vartype, + "class" : ITEM_VAR_INPUT, + "edit": False, + "debug": True}) + for varname, vartype, varmodifier in block_infos["outputs"]: + vars.append({"name" : varname, + "type" : vartype, + "class" : ITEM_VAR_OUTPUT, + "edit": False, + "debug": True}) + return {"class": POU_TYPES[block_infos["type"]], + "type": None, + "variables": vars, + "edit": False, + "debug": False} + elif words[0] in ['C', 'R']: + if words[0] == 'C': + pou_type = ITEM_CONFIGURATION + element = project.getconfiguration(words[1]) + for resource in element.getresource(): + vars.append({"name": resource.getname(), + "type": None, + "class": ITEM_RESOURCE, + "edit": True, + "debug": False}) + elif words[0] == 'R': + pou_type = ITEM_RESOURCE + element = project.getconfigurationResource(words[1], words[2]) + for task in element.gettask(): + for pou in task.getpouInstance(): + vars.append({"name": pou.getname(), + "type": pou.gettypeName(), + "class": ITEM_PROGRAM, + "edit": True, + "debug": True}) + for pou in element.getpouInstance(): + vars.append({"name": pou.getname(), + "type": pou.gettypeName(), + "class": ITEM_PROGRAM, + "edit": True, + "debug": True}) + for varlist in element.getglobalVars(): + for variable in varlist.getvariable(): + var_infos = self.GetPouVariableInfos(project, variable, ITEM_VAR_GLOBAL, debug) + if var_infos is not None: + vars.append(var_infos) + return {"class": pou_type, + "type": None, + "variables": vars, + "edit": True, + "debug": False} + return None + + def RecursiveSearchPouInstances(self, project, pou_type, parent_path, varlists, debug = False): + instances = [] + for varlist in varlists: + for variable in varlist.getvariable(): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + var_path = "%s.%s" % (parent_path, variable.getname()) + var_type = vartype_content["value"].getname() + if var_type == pou_type: + instances.append(var_path) + else: + pou = project.getpou(var_type) + if pou is not None: + instances.extend( + self.RecursiveSearchPouInstances( + project, pou_type, var_path, + [varlist for type, varlist in pou.getvars()], + debug)) + return instances + + def SearchPouInstances(self, tagname, debug = False): + project = self.GetProject(debug) + if project is not None: + words = tagname.split("::") + if words[0] == "P": + instances = [] + for config in project.getconfigurations(): + config_name = config.getname() + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], config_name, + config.getglobalVars(), debug)) + for resource in config.getresource(): + res_path = "%s.%s" % (config_name, resource.getname()) + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], res_path, + resource.getglobalVars(), debug)) + pou_instances = resource.getpouInstance()[:] + for task in resource.gettask(): + pou_instances.extend(task.getpouInstance()) + for pou_instance in pou_instances: + pou_path = "%s.%s" % (res_path, pou_instance.getname()) + pou_type = pou_instance.gettypeName() + if pou_type == words[1]: + instances.append(pou_path) + pou = project.getpou(pou_type) + if pou is not None: + instances.extend( + self.RecursiveSearchPouInstances( + project, words[1], pou_path, + [varlist for type, varlist in pou.getvars()], + debug)) + return instances + elif words[0] == 'C': + return [words[1]] + elif words[0] == 'R': + return ["%s.%s" % (words[1], words[2])] + return [] + + def RecursiveGetPouInstanceTagName(self, project, pou_type, parts): + pou = project.getpou(pou_type) + if pou is not None: + if len(parts) == 0: + return self.ComputePouName(pou_type) - if type in self.GetDataTypes(debug = debug): - if global_var: - return {"name" : name, "elmt_type" : type, "type" : ITEM_VAR_GLOBAL, "values" : []} - else: - return {"name" : name, "elmt_type" : type, "type" : ITEM_VAR_LOCAL, "values" : []} - return None - + for varlist_type, varlist in pou.getvars(): + for variable in varlist.getvariable(): + vartype_content = variable.gettype().getcontent() + if vartype_content["name"] == "derived": + return self.RecursiveGetPouInstanceTagName( + project, + vartype_content["value"].getname(), + parts[1:]) + return None + + def GetPouInstanceTagName(self, instance_path, debug = False): + parts = instance_path.split(".") + if len(parts) == 1: + return self.ComputeConfigurationName(parts[0]) + elif len(parts) == 2: + return self.ComputeConfigurationResourceName(parts[0], parts[1]) + else: + project = self.GetProject(debug) + for config in project.getconfigurations(): + if config.getname() == parts[0]: + for resource in config.getresource(): + if resource.getname() == parts[1]: + pou_instances = resource.getpouInstance()[:] + for task in resource.gettask(): + pou_instances.extend(task.getpouInstance()) + for pou_instance in pou_instances: + if pou_instance.getname() == parts[2]: + if len(parts) == 3: + return self.ComputePouName( + pou_instance.gettypeName()) + else: + return self.RecursiveGetPouInstanceTagName( + project, + pou_instance.gettypeName(), + parts[3:]) + return None + + def GetInstanceInfos(self, instance_path, debug = False): + tagname = self.GetPouInstanceTagName(instance_path) + if tagname is not None: + return self.GetPouVariables(tagname, debug) + else: + pou_path, var_name = instance_path.rsplit(".", 1) + tagname = self.GetPouInstanceTagName(pou_path) + if tagname is not None: + pou_infos = self.GetPouVariables(tagname, debug) + for var_infos in pou_infos["variables"]: + if var_infos["name"] == var_name: + return var_infos + return None + # Return if data type given by name is used by another data type or pou def DataTypeIsUsed(self, name, debug = False): project = self.GetProject(debug) @@ -667,6 +796,15 @@ self.Project.removepou(pou_name) self.BufferProject() + # Return the name of the configuration if only one exist + def GetProjectMainConfigurationName(self): + if self.Project is not None: + # Found the configuration corresponding to old name and change its name to new name + configurations = self.Project.getconfigurations() + if len(configurations) == 1: + return configurations[0].getname() + return None + # Add a configuration to Project def ProjectAddConfiguration(self, config_name): if self.Project is not None: @@ -1129,7 +1267,7 @@ return tree, [] datatype = project.getdataType(typename) if datatype is None: - datatype = self.GetPluginDataType(typename) + datatype = self.GetConfNodeDataType(typename) if datatype is not None: tree = [] basetype_content = datatype.baseType.getcontent() @@ -1251,28 +1389,28 @@ return returntype_content["name"] return None - # Function that add a new plugin to the plugin list - def AddPluginTypesList(self, typeslist): - self.PluginTypes.extend(typeslist) + # Function that add a new confnode to the confnode list + def AddConfNodeTypesList(self, typeslist): + self.ConfNodeTypes.extend(typeslist) - # Function that clear the plugin list - def ClearPluginTypes(self): - for i in xrange(len(self.PluginTypes)): - self.PluginTypes.pop(0) - - def GetPluginBlockTypes(self): - return [{"name": _("%s POUs") % plugintypes["name"], - "list": plugintypes["types"].GetCustomBlockTypes()} - for plugintypes in self.PluginTypes] + # Function that clear the confnode list + def ClearConfNodeTypes(self): + for i in xrange(len(self.ConfNodeTypes)): + self.ConfNodeTypes.pop(0) + + def GetConfNodeBlockTypes(self): + return [{"name": _("%s POUs") % confnodetypes["name"], + "list": confnodetypes["types"].GetCustomBlockTypes()} + for confnodetypes in self.ConfNodeTypes] - def GetPluginDataTypes(self, exclude = ""): - return [{"name": _("%s Data Types") % plugintypes["name"], - "list": [datatype["name"] for datatype in plugintypes["types"].GetCustomDataTypes(exclude)]} - for plugintypes in self.PluginTypes] - - def GetPluginDataType(self, type): - for plugintype in self.PluginTypes: - datatype = plugintype["types"].getdataType(type) + def GetConfNodeDataTypes(self, exclude = ""): + return [{"name": _("%s Data Types") % confnodetypes["name"], + "list": [datatype["name"] for datatype in confnodetypes["types"].GetCustomDataTypes(exclude)]} + for confnodetypes in self.ConfNodeTypes] + + def GetConfNodeDataType(self, type): + for confnodetype in self.ConfNodeTypes: + datatype = confnodetype["types"].getdataType(type) if datatype is not None: return datatype return None @@ -1283,7 +1421,7 @@ # Function that returns the block definition associated to the block type given def GetBlockType(self, type, inputs = None, debug = False): result_blocktype = None - for category in BlockTypes + self.GetPluginBlockTypes(): + for category in BlockTypes + self.GetConfNodeBlockTypes(): for blocktype in category["list"]: if blocktype["name"] == type: if inputs is not None and inputs != "undefined": @@ -1317,7 +1455,7 @@ type = self.GetPouType(name, debug) if type == "function" or words[0] == "T": blocktypes = [] - for category in BlockTypes + self.GetPluginBlockTypes(): + for category in BlockTypes + self.GetConfNodeBlockTypes(): cat = {"name" : category["name"], "list" : []} for block in category["list"]: if block["type"] == "function": @@ -1325,7 +1463,7 @@ if len(cat["list"]) > 0: blocktypes.append(cat) else: - blocktypes = [category for category in BlockTypes + self.GetPluginBlockTypes()] + blocktypes = [category for category in BlockTypes + self.GetConfNodeBlockTypes()] project = self.GetProject(debug) if project is not None: blocktypes.append({"name" : USER_DEFINED_POUS, "list": project.GetCustomBlockTypes(name, type == "function" or words[0] == "T")}) @@ -1334,7 +1472,7 @@ # Return Function Block types checking for recursion def GetFunctionBlockTypes(self, tagname = "", debug = False): blocktypes = [] - for category in BlockTypes + self.GetPluginBlockTypes(): + for category in BlockTypes + self.GetConfNodeBlockTypes(): for block in category["list"]: if block["type"] == "functionBlock": blocktypes.append(block["name"]) @@ -1381,8 +1519,8 @@ result = project.GetBaseType(type) if result is not None: return result - for plugintype in self.PluginTypes: - result = plugintype["types"].GetBaseType(type) + for confnodetype in self.ConfNodeTypes: + result = confnodetype["types"].GetBaseType(type) if result is not None: return result return None @@ -1406,8 +1544,8 @@ project = self.GetProject(debug) if project is not None and project.IsOfType(type, reference): return True - for plugintype in self.PluginTypes: - if plugintype["types"].IsOfType(type, reference): + for confnodetype in self.ConfNodeTypes: + if confnodetype["types"].IsOfType(type, reference): return True return False @@ -1423,7 +1561,7 @@ if project is not None: datatype = project.getdataType(type) if datatype is None: - datatype = self.GetPluginDataType(type) + datatype = self.GetConfNodeDataType(type) if datatype is not None: return project.IsLocatableType(datatype) return True @@ -1433,7 +1571,7 @@ if project is not None: datatype = project.getdataType(type) if datatype is None: - datatype = self.GetPluginDataType(type) + datatype = self.GetConfNodeDataType(type) if datatype is not None: basetype_content = datatype.baseType.getcontent() return basetype_content["name"] == "enum" @@ -1448,8 +1586,8 @@ result = project.GetDataTypeRange(type) if result is not None: return result - for plugintype in self.PluginTypes: - result = plugintype["types"].GetDataTypeRange(type) + for confnodetype in self.ConfNodeTypes: + result = confnodetype["types"].GetDataTypeRange(type) if result is not None: return result return None @@ -1460,8 +1598,8 @@ project = self.GetProject(debug) if project is not None: subrange_basetypes.extend(project.GetSubrangeBaseTypes(exclude)) - for plugintype in self.PluginTypes: - subrange_basetypes.extend(plugintype["types"].GetSubrangeBaseTypes(exclude)) + for confnodetype in self.ConfNodeTypes: + subrange_basetypes.extend(confnodetype["types"].GetSubrangeBaseTypes(exclude)) return DataTypeRange.keys() + subrange_basetypes # Return Enumerated Values @@ -1472,8 +1610,8 @@ values.extend(project.GetEnumeratedDataTypeValues(type)) if type is None and len(values) > 0: return values - for plugintype in self.PluginTypes: - values.extend(plugintype["types"].GetEnumeratedDataTypeValues(type)) + for confnodetype in self.ConfNodeTypes: + values.extend(confnodetype["types"].GetEnumeratedDataTypeValues(type)) if type is None and len(values) > 0: return values return values @@ -2739,7 +2877,7 @@ for child in tree.childNodes: if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "project": try: - result = self.Project.loadXMLTree(child, ["xmlns", "xmlns:xhtml", "xmlns:xsi", "xsi:schemaLocation"]) + result = self.Project.loadXMLTree(child) except ValueError, e: return _("Project file syntax error:\n\n") + str(e) self.SetFilePath(filepath) diff -r 188906a7368c -r ce605c1a6d04 PLCGenerator.py --- a/PLCGenerator.py Tue May 15 05:19:13 2012 +0900 +++ b/PLCGenerator.py Mon May 21 10:02:54 2012 +0200 @@ -821,6 +821,7 @@ otherInstances["outVariables&coils"].append(instance) orderedInstances.sort() otherInstances["outVariables&coils"].sort(SortInstances) + otherInstances["blocks"].sort(SortInstances) instances = [instance for (executionOrderId, instance) in orderedInstances] instances.extend(otherInstances["connectors"] + otherInstances["outVariables&coils"] + otherInstances["blocks"]) for instance in instances: diff -r 188906a7368c -r ce605c1a6d04 PLCOpenEditor.py --- a/PLCOpenEditor.py Tue May 15 05:19:13 2012 +0900 +++ b/PLCOpenEditor.py Mon May 21 10:02:54 2012 +0200 @@ -24,20 +24,14 @@ from datetime import datetime import wx, wx.grid - -if wx.VERSION >= (2, 8, 0): - import wx.aui - USE_AUI = True -else: - USE_AUI = False - +import wx.aui import os, re, platform, sys, time, traceback, getopt import cPickle CWD = os.path.split(os.path.realpath(__file__))[0] base_folder = os.path.split(CWD)[0] sys.path.append(base_folder) -from docutils import * +from docutil import * from types import TupleType @@ -114,18 +108,18 @@ from DataTypeEditor import * from PLCControler import * from SearchResultPanel import SearchResultPanel -from controls import CustomGrid, CustomTable, LibraryPanel +from controls import CustomGrid, CustomTable, CustomTree, LibraryPanel, PouInstanceVariablesPanel # Define PLCOpenEditor controls id [ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK, - ID_PLCOPENEDITORTYPESTREE, ID_PLCOPENEDITORINSTANCESTREE, - ID_PLCOPENEDITORMAINSPLITTER, ID_PLCOPENEDITORSECONDSPLITTER, - ID_PLCOPENEDITORTHIRDSPLITTER, ID_PLCOPENEDITORLIBRARYPANEL, - ID_PLCOPENEDITORLIBRARYSEARCHCTRL, ID_PLCOPENEDITORLIBRARYTREE, - ID_PLCOPENEDITORLIBRARYCOMMENT, ID_PLCOPENEDITORTABSOPENED, - ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITOREDITORMENUTOOLBAR, - ID_PLCOPENEDITOREDITORTOOLBAR, + ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORMAINSPLITTER, + ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER, + ID_PLCOPENEDITORLIBRARYPANEL, ID_PLCOPENEDITORLIBRARYSEARCHCTRL, + ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT, + ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED, + ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR, + ID_PLCOPENEDITORPROJECTPANEL, ] = [wx.NewId() for _init_ctrls in range(17)] # Define PLCOpenEditor FileMenu extra items id @@ -270,8 +264,8 @@ else: parent.Append(helpString=help, id=id, kind=kind, item=text) -[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, - INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES +[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, + POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES ] = range(10) def GetShortcutKeyCallbackFunction(viewer_function): @@ -285,20 +279,13 @@ control.ProcessEvent(event) return ShortcutKeyFunction -def GetParentName(tree, item, parent_type): - parent_item = tree.GetItemParent(item) - parent_item_type = tree.GetPyData(parent_item) - while parent_item_type != parent_type: - parent_item = tree.GetItemParent(parent_item) - parent_item_type = tree.GetPyData(parent_item) - return tree.GetItemText(parent_item) - def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None): def DeleteElementFunction(self, selected): - name = self.TypesTree.GetItemText(selected) + name = self.ProjectTree.GetItemText(selected) if check_function is None or not check_function(self.Controler, name): if parent_type is not None: - parent_name = GetParentName(self.TypesTree, selected, parent_type) + item_infos = self.ProjectTree.GetPyData(selected) + parent_name = item_infos["tagname"].split("::")[1] remove_function(self.Controler, parent_name, name) else: remove_function(self.Controler, name) @@ -412,6 +399,19 @@ def _init_coll_FileMenu_Items(self, parent): pass + def _init_coll_AddMenu_Items(self, parent, add_config=True): + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE, + kind=wx.ITEM_NORMAL, text=_(u'&Data Type')) + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION, + kind=wx.ITEM_NORMAL, text=_(u'&Function')) + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, + kind=wx.ITEM_NORMAL, text=_(u'Function &Block')) + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM, + kind=wx.ITEM_NORMAL, text=_(u'&Program')) + if add_config: + AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, + kind=wx.ITEM_NORMAL, text=_(u'&Configuration')) + def _init_coll_EditMenu_Items(self, parent): AppendMenu(parent, help='', id=wx.ID_UNDO, kind=wx.ITEM_NORMAL, text=_(u'Undo\tCTRL+Z')) @@ -431,18 +431,9 @@ AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, kind=wx.ITEM_NORMAL, text=_(u'Search in Project\tCTRL+F')) parent.AppendSeparator() - addmenu = wx.Menu(title='') - parent.AppendMenu(wx.ID_ADD, _(u"&Add Element"), addmenu) - AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE, - kind=wx.ITEM_NORMAL, text=_(u'&Data Type')) - AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION, - kind=wx.ITEM_NORMAL, text=_(u'&Function')) - AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK, - kind=wx.ITEM_NORMAL, text=_(u'Function &Block')) - AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM, - kind=wx.ITEM_NORMAL, text=_(u'&Program')) - AppendMenu(addmenu, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION, - kind=wx.ITEM_NORMAL, text=_(u'&Configuration')) + add_menu = wx.Menu(title='') + self._init_coll_AddMenu_Items(add_menu) + parent.AppendMenu(wx.ID_ADD, _(u"&Add Element"), add_menu) AppendMenu(parent, help='', id=wx.ID_SELECTALL, kind=wx.ITEM_NORMAL, text=_(u'Select All\tCTRL+A')) AppendMenu(parent, help='', id=wx.ID_DELETE, @@ -492,11 +483,10 @@ kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%") self.Bind(wx.EVT_MENU, self.GenerateZoomFunction(idx), id=new_id) - if USE_AUI: - parent.AppendSeparator() - AppendMenu(parent, help='', id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, - kind=wx.ITEM_NORMAL, text=_(u'Reset Perspective')) - self.Bind(wx.EVT_MENU, self.OnResetPerspective, id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE) + parent.AppendSeparator() + AppendMenu(parent, help='', id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE, + kind=wx.ITEM_NORMAL, text=_(u'Reset Perspective')) + self.Bind(wx.EVT_MENU, self.OnResetPerspective, id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE) self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH) if self.EnableDebug: @@ -534,103 +524,52 @@ # Creating main structure #----------------------------------------------------------------------- - if USE_AUI: - self.AUIManager = wx.aui.AuiManager(self) - self.AUIManager.SetDockSizeConstraint(0.5, 0.5) - self.Panes = {} - - self.LeftNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORLEFTNOTEBOOK, - style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| - wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.LeftNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, - self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.LeftNoteBook, - wx.aui.AuiPaneInfo().Name("ProjectPane"). - Caption(_("Project")).Left().Layer(1). - BestSize(wx.Size(300, 500)).CloseButton(False)) - - self.BottomNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORBOTTOMNOTEBOOK, - style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| - wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.BottomNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, - self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.BottomNoteBook, - wx.aui.AuiPaneInfo().Name("ResultPane"). - Bottom().Layer(0). - BestSize(wx.Size(800, 300)).CloseButton(False)) - - self.RightNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORRIGHTNOTEBOOK, - style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| - wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) - self.RightNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, - self.OnAllowNotebookDnD) - self.AUIManager.AddPane(self.RightNoteBook, - wx.aui.AuiPaneInfo().Name("LibraryPane"). - Right().Layer(0). - BestSize(wx.Size(250, 400)).CloseButton(False)) - - self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, - style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING, - self.OnPouSelectedChanging) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, - self.OnPouSelectedChanged) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, - self.OnPageClose) - self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG, - self.OnPageDragged) - self.AUIManager.AddPane(self.TabsOpened, - wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane")) - - else: - self.MainSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORMAINSPLITTER, - name='MainSplitter', parent=self, point=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.SP_3D) - self.MainSplitter.SetNeedUpdating(True) - self.MainSplitter.SetMinimumPaneSize(1) - - self.LeftNoteBook = wx.Notebook(id=ID_PLCOPENEDITORLEFTNOTEBOOK, - name='LeftNoteBook', parent=self.MainSplitter, pos=wx.Point(0, - 0), size=wx.Size(0, 0), style=0) - - self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER, - name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.SP_3D) - self.SecondSplitter.SetMinimumPaneSize(1) - - self.MainSplitter.SplitVertically(self.LeftNoteBook, self.SecondSplitter, 200) - - self.ThirdSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORTHIRDSPLITTER, - name='ThirdSplitter', parent=self.SecondSplitter, point=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.SP_3D) - self.ThirdSplitter.SetMinimumPaneSize(1) - - self.BottomNoteBook = wx.Notebook(id=ID_PLCOPENEDITORBOTTOMNOTEBOOK, - name='BottomNoteBook', parent=self.SecondSplitter, pos=wx.Point(0, - 0), size=wx.Size(0, 0), style=0) - - self.SecondSplitter.SplitHorizontally(self.ThirdSplitter, self.BottomNoteBook, -200) - - self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED, - name='TabsOpened', parent=self.ThirdSplitter, pos=wx.Point(0, - 0), size=wx.Size(0, 0), style=0) - self.TabsOpened.SetImageList(self.TabsImageList) - if wx.VERSION >= (2, 6, 0): - self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, - self.OnPouSelectedChanging, id=ID_PLCOPENEDITORTABSOPENED) - self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, - self.OnPouSelectedChanged, id=ID_PLCOPENEDITORTABSOPENED) - else: - wx.EVT_NOTEBOOK_PAGE_CHANGING(self.TabsOpened, ID_PLCOPENEDITORTABSOPENED, - self.OnPouSelectedChanging) - wx.EVT_NOTEBOOK_PAGE_CHANGED(self.TabsOpened, ID_PLCOPENEDITORTABSOPENED, - self.OnPouSelectedChanged) - - self.RightNoteBook = wx.Notebook(id=ID_PLCOPENEDITORRIGHTNOTEBOOK, - name='RightNoteBook', parent=self.ThirdSplitter, pos=wx.Point(0, - 0), size=wx.Size(0, 0), style=0) - - self.ThirdSplitter.SplitVertically(self.TabsOpened, self.RightNoteBook, -250) + self.AUIManager = wx.aui.AuiManager(self) + self.AUIManager.SetDockSizeConstraint(0.5, 0.5) + self.Panes = {} + + self.LeftNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORLEFTNOTEBOOK, + style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| + wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) + self.LeftNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.OnAllowNotebookDnD) + self.AUIManager.AddPane(self.LeftNoteBook, + wx.aui.AuiPaneInfo().Name("ProjectPane"). + Left().Layer(1). + BestSize(wx.Size(300, 500)).CloseButton(False)) + + self.BottomNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORBOTTOMNOTEBOOK, + style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| + wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) + self.BottomNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.OnAllowNotebookDnD) + self.AUIManager.AddPane(self.BottomNoteBook, + wx.aui.AuiPaneInfo().Name("ResultPane"). + Bottom().Layer(0). + BestSize(wx.Size(800, 300)).CloseButton(False)) + + self.RightNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORRIGHTNOTEBOOK, + style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE| + wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE) + self.RightNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND, + self.OnAllowNotebookDnD) + self.AUIManager.AddPane(self.RightNoteBook, + wx.aui.AuiPaneInfo().Name("LibraryPane"). + Right().Layer(0). + BestSize(wx.Size(250, 400)).CloseButton(False)) + + self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, + style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON) + self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING, + self.OnPouSelectedChanging) + self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, + self.OnPouSelectedChanged) + self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE, + self.OnPageClose) + self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG, + self.OnPageDragged) + self.AUIManager.AddPane(self.TabsOpened, + wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane")) #----------------------------------------------------------------------- # Creating PLCopen Project Types Tree @@ -638,91 +577,78 @@ self.MainTabs = {} - self.TypesTree = wx.TreeCtrl(id=ID_PLCOPENEDITORTYPESTREE, - name='TypesTree', parent=self.LeftNoteBook, + self.ProjectPanel = wx.SplitterWindow(id=ID_PLCOPENEDITORPROJECTPANEL, + name='ProjectPanel', parent=self.LeftNoteBook, point=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.SP_3D) + + self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE, + name='ProjectTree', parent=self.ProjectPanel, pos=wx.Point(0, 0), size=wx.Size(0, 0), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_EDIT_LABELS) + self.ProjectTree.SetBackgroundBitmap(wx.Bitmap(os.path.join(CWD, 'Images', 'custom_tree_background.png')), + wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM) + add_menu = wx.Menu() + self._init_coll_AddMenu_Items(add_menu) + self.ProjectTree.SetAddMenu(add_menu) if wx.Platform == '__WXMSW__': - self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnTypesTreeRightUp, - id=ID_PLCOPENEDITORTYPESTREE) - self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTypesTreeItemSelected, - id=ID_PLCOPENEDITORTYPESTREE) + self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp, + id=ID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected, + id=ID_PLCOPENEDITORPROJECTTREE) else: if wx.VERSION >= (2, 6, 0): - self.TypesTree.Bind(wx.EVT_RIGHT_UP, self.OnTypesTreeRightUp) - self.TypesTree.Bind(wx.EVT_LEFT_UP, self.OnTypesTreeLeftUp) + self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp) + self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp) else: - wx.EVT_RIGHT_UP(self.TypesTree, self.OnTypesTreeRightUp) - wx.EVT_LEFT_UP(self.TypesTree, self.OnTypesTreeLeftUp) - self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnTypesTreeItemChanging, - id=ID_PLCOPENEDITORTYPESTREE) - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTypesTreeBeginDrag, - id=ID_PLCOPENEDITORTYPESTREE) - self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTypesTreeItemBeginEdit, - id=ID_PLCOPENEDITORTYPESTREE) - self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTypesTreeItemEndEdit, - id=ID_PLCOPENEDITORTYPESTREE) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnTypesTreeItemActivated, - id=ID_PLCOPENEDITORTYPESTREE) - - self.MainTabs["TypesTree"] = (self.TypesTree, _("Types")) - self.LeftNoteBook.AddPage(*self.MainTabs["TypesTree"]) + wx.EVT_RIGHT_UP(self.ProjectTree, self.OnProjectTreeRightUp) + wx.EVT_LEFT_UP(self.ProjectTree, self.OnProjectTreeLeftUp) + self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging, + id=ID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag, + id=ID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit, + id=ID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnProjectTreeItemEndEdit, + id=ID_PLCOPENEDITORPROJECTTREE) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated, + id=ID_PLCOPENEDITORPROJECTTREE) #----------------------------------------------------------------------- - # Creating PLCopen Project Instances Tree + # Creating PLCopen Project POU Instance Variables Panel #----------------------------------------------------------------------- - self.InstancesTree = wx.TreeCtrl(id=ID_PLCOPENEDITORINSTANCESTREE, - name='InstancesTree', parent=self.LeftNoteBook, - pos=wx.Point(0, 0), size=wx.Size(0, 0), - style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER) - if self.EnableDebug: - if wx.VERSION >= (2, 6, 0): - self.InstancesTree.Bind(wx.EVT_RIGHT_UP, self.OnInstancesTreeRightUp) - else: - wx.EVT_RIGHT_UP(self.InstancesTree, self.OnInstancesTreeRightUp) - self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnInstancesTreeBeginDrag, - id=ID_PLCOPENEDITORINSTANCESTREE) - self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnInstancesTreeItemActivated, - id=ID_PLCOPENEDITORINSTANCESTREE) - - self.MainTabs["InstancesTree"] = (self.InstancesTree, _("Instances")) - self.LeftNoteBook.AddPage(*self.MainTabs["InstancesTree"]) + self.PouInstanceVariablesPanel = PouInstanceVariablesPanel(self.ProjectPanel, self, self.Controler, self.EnableDebug) + + self.MainTabs["ProjectPanel"] = (self.ProjectPanel, _("Project")) + self.LeftNoteBook.AddPage(*self.MainTabs["ProjectPanel"]) + + self.ProjectPanel.SplitHorizontally(self.ProjectTree, self.PouInstanceVariablesPanel, 300) #----------------------------------------------------------------------- # Creating Tool Bar #----------------------------------------------------------------------- - if USE_AUI: - MenuToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORMENUTOOLBAR, wx.DefaultPosition, wx.DefaultSize, - wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) - MenuToolBar.SetToolBitmapSize(wx.Size(25, 25)) - MenuToolBar.Realize() - self.Panes["MenuToolBar"] = MenuToolBar - self.AUIManager.AddPane(MenuToolBar, wx.aui.AuiPaneInfo(). - Name("MenuToolBar").Caption(_("Menu ToolBar")). - ToolbarPane().Top(). - LeftDockable(False).RightDockable(False)) - - EditorToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize, - wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) - EditorToolBar.SetToolBitmapSize(wx.Size(25, 25)) - EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, - wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object")) - EditorToolBar.Realize() - self.Panes["EditorToolBar"] = EditorToolBar - self.AUIManager.AddPane(EditorToolBar, wx.aui.AuiPaneInfo(). - Name("EditorToolBar").Caption(_("Editor ToolBar")). - ToolbarPane().Top().Position(1). - LeftDockable(False).RightDockable(False)) - - else: - self.EditorToolBar = self.CreateToolBar(wx.TB_HORIZONTAL|wx.TB_FLAT|wx.NO_BORDER, - ID_PLCOPENEDITOREDITORTOOLBAR, 'EditorToolBar') - self.EditorToolBar.SetToolBitmapSize(wx.Size(25, 25)) - self.EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, - wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object")) - self.EditorToolBar.Realize() + MenuToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORMENUTOOLBAR, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) + MenuToolBar.SetToolBitmapSize(wx.Size(25, 25)) + MenuToolBar.Realize() + self.Panes["MenuToolBar"] = MenuToolBar + self.AUIManager.AddPane(MenuToolBar, wx.aui.AuiPaneInfo(). + Name("MenuToolBar").Caption(_("Menu ToolBar")). + ToolbarPane().Top(). + LeftDockable(False).RightDockable(False)) + + EditorToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER) + EditorToolBar.SetToolBitmapSize(wx.Size(25, 25)) + EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, + wx.Bitmap(os.path.join(CWD, 'Images', 'select.png')), wx.NullBitmap, _("Select an object")) + EditorToolBar.Realize() + self.Panes["EditorToolBar"] = EditorToolBar + self.AUIManager.AddPane(EditorToolBar, wx.aui.AuiPaneInfo(). + Name("EditorToolBar").Caption(_("Editor ToolBar")). + ToolbarPane().Top().Position(1). + LeftDockable(False).RightDockable(False)) self.Bind(wx.EVT_MENU, self.OnSelectionTool, id=ID_PLCOPENEDITOREDITORTOOLBARSELECTION) @@ -751,8 +677,7 @@ self.MainTabs["DebugVariablePanel"] = (self.DebugVariablePanel, _("Debugger")) self.RightNoteBook.AddPage(*self.MainTabs["DebugVariablePanel"]) - if USE_AUI: - self.AUIManager.Update() + self.AUIManager.Update() ## Constructor of the PLCOpenEditor class. # @param parent The parent window. @@ -805,8 +730,8 @@ self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) # Assign icon list to TreeCtrls - self.TypesTree.SetImageList(self.TreeImageList) - self.InstancesTree.SetImageList(self.TreeImageList) + self.ProjectTree.SetImageList(self.TreeImageList) + self.PouInstanceVariablesPanel.SetTreeImageList(self.TreeImageList) self.CurrentEditorToolBar = [] self.CurrentMenu = None @@ -814,8 +739,7 @@ self.Highlights = {} self.DrawingMode = FREEDRAWING_MODE #self.DrawingMode = DRIVENDRAWING_MODE - if USE_AUI: - self.AuiTabCtrl = [] + self.AuiTabCtrl = [] self.DefaultPerspective = None # Initialize Printing configuring elements @@ -924,17 +848,14 @@ elif page_infos[0] == "editor": tagname = page_infos[1] page_ref = self.EditProjectElement(self.Controler.GetElementType(tagname), tagname) - page_ref.RefreshView() - return notebook.GetPageIndex(page_ref) + if page_ref is not None: + page_ref.RefreshView() + return notebook.GetPageIndex(page_ref) elif page_infos[0] == "debug": instance_path = page_infos[1] - item = self.GetInstancesTreeItem(self.InstancesTree.GetRootItem(), instance_path) - item_infos = self.InstancesTree.GetPyData(item) - if item_infos[1] is not None: - instance_type = item_infos[1] - else: - instance_type = self.InstancesTree.GetItemText(item).split(" (")[1].split(")")[0] - return notebook.GetPageIndex(self.OpenDebugViewer(item_infos[0], instance_path, instance_type)) + instance_infos = self.Controler.GetInstanceInfos(instance_path, self.EnableDebug) + if instance_infos is not None: + return notebook.GetPageIndex(self.OpenDebugViewer(instance_infos["class"], instance_path, instance_infos["type"])) return None def LoadTabOrganization(self, notebook, tabs, mode="all", first_index=None): @@ -967,7 +888,7 @@ wx.CallAfter(notebook.SetSelection, selected) def ResetPerspective(self): - if USE_AUI and self.DefaultPerspective is not None: + if self.DefaultPerspective is not None: self.AUIManager.LoadPerspective(self.DefaultPerspective["perspective"]) for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: @@ -992,36 +913,35 @@ self.SetClientSize(frame_size) def RestoreLastOrganization(self): - if USE_AUI: - notebooks = {} - for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), - (self.BottomNoteBook, "bottomnotebook"), - (self.RightNoteBook, "rightnotebook")]: - notebooks[entry_name] = self.SaveTabOrganization(notebook) - self.DefaultPerspective = { - "perspective": self.AUIManager.SavePerspective(), - "notebooks": notebooks, - } - - try: - if self.Config.HasEntry("perspective"): - self.AUIManager.LoadPerspective(str(self.Config.Read("perspective"))) - - if self.Config.HasEntry("notebooks"): - notebooks = cPickle.loads(str(self.Config.Read("notebooks"))) - - for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: - for idx in xrange(notebook.GetPageCount()): - notebook.RemovePage(0) - - for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), - (self.BottomNoteBook, "bottomnotebook"), - (self.RightNoteBook, "rightnotebook")]: - self.LoadTabOrganization(notebook, notebooks.get(entry_name)) - except: - self.ResetPerspective() - - self.LoadProjectOrganization() + notebooks = {} + for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), + (self.BottomNoteBook, "bottomnotebook"), + (self.RightNoteBook, "rightnotebook")]: + notebooks[entry_name] = self.SaveTabOrganization(notebook) + self.DefaultPerspective = { + "perspective": self.AUIManager.SavePerspective(), + "notebooks": notebooks, + } + + try: + if self.Config.HasEntry("perspective"): + self.AUIManager.LoadPerspective(str(self.Config.Read("perspective"))) + + if self.Config.HasEntry("notebooks"): + notebooks = cPickle.loads(str(self.Config.Read("notebooks"))) + + for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: + for idx in xrange(notebook.GetPageCount()): + notebook.RemovePage(0) + + for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), + (self.BottomNoteBook, "bottomnotebook"), + (self.RightNoteBook, "rightnotebook")]: + self.LoadTabOrganization(notebook, notebooks.get(entry_name)) + except: + self.ResetPerspective() + + self.LoadProjectOrganization() def SaveLastState(self): if not self.IsMaximized(): @@ -1029,17 +949,16 @@ elif self.Config.HasEntry("framesize"): self.Config.DeleteEntry("framesize") - if USE_AUI: - notebooks = {} - for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), - (self.BottomNoteBook, "bottomnotebook"), - (self.RightNoteBook, "rightnotebook")]: - notebooks[entry_name] = self.SaveTabOrganization(notebook) - self.Config.Write("notebooks", cPickle.dumps(notebooks)) - - self.Config.Write("perspective", self.AUIManager.SavePerspective()) - - self.SaveProjectOrganization() + notebooks = {} + for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), + (self.BottomNoteBook, "bottomnotebook"), + (self.RightNoteBook, "rightnotebook")]: + notebooks[entry_name] = self.SaveTabOrganization(notebook) + self.Config.Write("notebooks", cPickle.dumps(notebooks)) + + self.Config.Write("perspective", self.AUIManager.SavePerspective()) + + self.SaveProjectOrganization() for i in xrange(self.TabsOpened.GetPageCount()): self.SavePageState(self.TabsOpened.GetPage(i)) @@ -1047,7 +966,7 @@ self.Config.Flush() def SaveProjectOrganization(self): - if USE_AUI and self.Controler is not None: + if self.Controler is not None: tabs = [] projects = {} @@ -1066,7 +985,7 @@ self.Config.Flush() def LoadProjectOrganization(self): - if USE_AUI and self.Controler is not None: + if self.Controler is not None: project = self.GetProjectConfiguration() try: @@ -1093,8 +1012,8 @@ FILEMENU : self.RefreshFileMenu, EDITMENU : self.RefreshEditMenu, DISPLAYMENU : self.RefreshDisplayMenu, - TYPESTREE : self.RefreshTypesTree, - INSTANCESTREE : self.RefreshInstancesTree, + PROJECTTREE : self.RefreshProjectTree, + POUINSTANCEVARIABLESPANEL : self.RefreshPouInstanceVariablesPanel, LIBRARYTREE : self.RefreshLibraryPanel, SCALING : self.RefreshScaling, PAGETITLES: self.RefreshPageTitles} @@ -1102,8 +1021,12 @@ ## Call PLCOpenEditor refresh functions. # @param elements List of elements to refresh. def _Refresh(self, *elements): - for element in elements: - self.RefreshFunctions[element]() + try: + for element in elements: + self.RefreshFunctions[element]() + except wx.PyDeadObjectError: + # ignore exceptions caused by refresh while quitting + pass ## Callback function when AUINotebook Page closed with CloseButton # @param event AUINotebook Event. @@ -1145,7 +1068,7 @@ editor = self.TabsOpened.GetPage(i) editor.RefreshScaling() - def ShowProperties(self): + def EditProjectSettings(self): old_values = self.Controler.GetProjectProperties() dialog = ProjectDialog(self) dialog.SetValues(old_values) @@ -1155,7 +1078,7 @@ if new_values != old_values: self.Controler.SetProjectProperties(None, new_values) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, - TYPESTREE, INSTANCESTREE, SCALING) + PROJECTTREE, POUINSTANCEVARIABLESPANEL, SCALING) dialog.Destroy() #------------------------------------------------------------------------------- @@ -1171,10 +1094,7 @@ index = self.TabsImageListIndexes.get((icon1_name, icon2_name), None) # Return index or bitmap if found if index is not None: - if USE_AUI: - return self.TabsImageList.GetBitmap(index) - else: - return index + return self.TabsImageList.GetBitmap(index) if icon2_name is None: # Bitmap with only one icon bitmap = wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%icon1_name)) @@ -1199,10 +1119,7 @@ index = self.TabsImageList.Add(bitmap) # Save bitmap index in ImageList in dictionary self.TabsImageListIndexes[(icon1_name, icon2_name)] = index - if USE_AUI: - return bitmap - else: - return index + return bitmap ## Function that add a tab in Notebook, calling refresh for tab DClick event # for wx.aui.AUINotebook. @@ -1226,11 +1143,8 @@ ## Function that fix difference in deleting all tabs between # wx.Notebook and wx.aui.AUINotebook. def DeleteAllPages(self): - if USE_AUI: - for idx in xrange(self.TabsOpened.GetPageCount()): - self.TabsOpened.DeletePage(0) - else: - self.TabsOpened.DeleteAllPages() + for idx in xrange(self.TabsOpened.GetPageCount()): + self.TabsOpened.DeletePage(0) self.RefreshTabCtrlEvent() ## Function that fix difference in setting picture on tab between @@ -1239,10 +1153,7 @@ # @param bitmap wx.Bitmap to define on tab. # @return True if operation succeeded def SetPageBitmap(self, idx, bitmap): - if USE_AUI: - return self.TabsOpened.SetPageBitmap(idx, bitmap) - else: - return self.TabsOpened.SetPageImage(idx, bitmap) + return self.TabsOpened.SetPageBitmap(idx, bitmap) #------------------------------------------------------------------------------- # Dialog Message Functions @@ -1277,8 +1188,9 @@ def ResetView(self): self.DeleteAllPages() - self.TypesTree.DeleteAllItems() - self.InstancesTree.DeleteAllItems() + self.ProjectTree.DeleteAllItems() + self.ProjectTree.Enable(False) + self.PouInstanceVariablesPanel.ResetView() self.LibraryPanel.ResetTree() self.LibraryPanel.SetControler(None) self.Controler = None @@ -1425,7 +1337,7 @@ window.Undo() else: self.Controler.LoadPrevious() - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES) def OnRedoMenu(self, event): @@ -1435,7 +1347,7 @@ window.Redo() else: self.Controler.LoadNext() - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES) def OnEnableUndoRedoMenu(self, event): @@ -1468,16 +1380,15 @@ def OnDeleteMenu(self, event): window = self.FindFocus() - if window == self.TypesTree or window is None: - selected = self.TypesTree.GetSelection() + if window == self.ProjectTree or window is None: + selected = self.ProjectTree.GetSelection() if selected.IsOk(): - type = self.TypesTree.GetPyData(selected) - function = self.DeleteFunctions.get(type, None) + function = self.DeleteFunctions.get(self.ProjectTree.GetPyData(selected)["type"], None) if function is not None: function(self, selected) self.CloseTabsWithoutModel() - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, TYPESTREE, - INSTANCESTREE, LIBRARYTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, + POUINSTANCEVARIABLESPANEL, LIBRARYTREE) elif isinstance(window, (Viewer, TextViewer)): event = wx.KeyEvent(wx.EVT_CHAR._getEvtType()) event.m_keyCode = wx.WXK_DELETE @@ -1555,19 +1466,22 @@ event.Allow() def RefreshTabCtrlEvent(self): - if USE_AUI: - auitabctrl = [] - for child in self.TabsOpened.GetChildren(): - if isinstance(child, wx.aui.AuiTabCtrl): - auitabctrl.append(child) - if child not in self.AuiTabCtrl: - child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child)) - self.AuiTabCtrl = auitabctrl - if self.TabsOpened.GetPageCount() == 0: - pane = self.AUIManager.GetPane(self.TabsOpened) - if pane.IsMaximized(): - self.AUIManager.RestorePane(pane) - self.AUIManager.Update() + auitabctrl = [] + for child in self.TabsOpened.GetChildren(): + if isinstance(child, wx.aui.AuiTabCtrl): + auitabctrl.append(child) + if child not in self.AuiTabCtrl: + child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child)) + self.AuiTabCtrl = auitabctrl + if self.TabsOpened.GetPageCount() == 0: + pane = self.AUIManager.GetPane(self.TabsOpened) + if pane.IsMaximized(): + self.AUIManager.RestorePane(pane) + self.AUIManager.Update() + + def EnsureTabVisible(self, tab): + notebook = tab.GetParent() + notebook.SetSelection(notebook.GetPageIndex(tab)) def OnPouSelectedChanging(self, event): if not self.Starting: @@ -1583,11 +1497,19 @@ selected = self.TabsOpened.GetSelection() if selected >= 0: window = self.TabsOpened.GetPage(selected) + tagname = window.GetTagName() if not window.IsDebugging(): - wx.CallAfter(self.SelectTypesTreeItem, window.GetTagName()) + wx.CallAfter(self.SelectProjectTreeItem, tagname) + wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname) window.RefreshView() + self.EnsureTabVisible(self.LibraryPanel) else: - wx.CallAfter(self.SelectInstancesTreeItem, window.GetInstancePath()) + instance_path = window.GetInstancePath() + if tagname == "": + instance_path = instance_path.rsplit(".", 1)[0] + tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug) + self.EnsureTabVisible(self.DebugVariablePanel) + wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path) wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR) event.Skip() @@ -1596,18 +1518,15 @@ if selected >= 0: window = self.TabsOpened.GetPage(selected) if not window.IsDebugging(): - self.SelectTypesTreeItem(window.GetTagName()) + self.SelectProjectTreeItem(window.GetTagName()) else: - self.SelectInstancesTreeItem(window.GetInstancePath()) - if USE_AUI: - for child in self.TabsOpened.GetChildren(): - if isinstance(child, wx.aui.AuiTabCtrl): - active_page = child.GetActivePage() - if active_page >= 0: - window = child.GetWindowFromIdx(active_page) - window.RefreshView() - else: - window.RefreshView() + self.PouInstanceVariablesPanel.SetPouType(window.GetTagName(), window.GetInstancePath()) + for child in self.TabsOpened.GetChildren(): + if isinstance(child, wx.aui.AuiTabCtrl): + active_page = child.GetActivePage() + if active_page >= 0: + window = child.GetWindowFromIdx(active_page) + window.RefreshView() self._Refresh(FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR) def RefreshEditorNames(self, old_tagname, new_tagname): @@ -1647,109 +1566,118 @@ # Types Tree Management Functions #------------------------------------------------------------------------------- - def RefreshTypesTree(self): + def RefreshProjectTree(self): infos = self.Controler.GetProjectInfos() - root = self.TypesTree.GetRootItem() + root = self.ProjectTree.GetRootItem() if not root.IsOk(): - root = self.TypesTree.AddRoot(infos["name"]) - self.GenerateTypesTreeBranch(root, infos) - self.TypesTree.Expand(root) + root = self.ProjectTree.AddRoot(infos["name"]) + self.GenerateProjectTreeBranch(root, infos) + self.ProjectTree.Expand(root) def ResetSelectedItem(self): self.SelectedItem = None - def GenerateTypesTreeBranch(self, root, infos, topology=False): + def GenerateProjectTreeBranch(self, root, infos): to_delete = [] item_name = infos["name"] if infos["type"] in ITEMS_UNEDITABLE: - item_name = _(item_name) - self.TypesTree.SetItemText(root, item_name) - self.TypesTree.SetPyData(root, infos["type"]) + if len(infos["values"]) == 1: + return self.GenerateProjectTreeBranch(root, infos["values"][0]) + item_name = _(item_name) + self.ProjectTree.SetItemText(root, item_name) + self.ProjectTree.SetPyData(root, infos) highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK)) - self.TypesTree.SetItemBackgroundColour(root, highlight_colours[0]) - self.TypesTree.SetItemTextColour(root, highlight_colours[1]) + self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0]) + self.ProjectTree.SetItemTextColour(root, highlight_colours[1]) if infos["type"] == ITEM_POU: - self.TypesTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])]) + self.ProjectTree.SetItemImage(root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])]) + elif infos.has_key("icon") and infos["icon"] is not None: + icon_path = infos["icon"] + if not self.TreeImageDict.has_key(icon_path): + self.TreeImageDict[icon_path] = self.TreeImageList.Add(wx.Bitmap(icon_path)) + self.ProjectTree.SetItemImage(root, self.TreeImageDict[icon_path]) + elif self.TreeImageDict.has_key(infos["type"]): + self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) + + if wx.VERSION >= (2, 6, 0): + item, root_cookie = self.ProjectTree.GetFirstChild(root) else: - self.TypesTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) - - if wx.VERSION >= (2, 6, 0): - item, root_cookie = self.TypesTree.GetFirstChild(root) - else: - item, root_cookie = self.TypesTree.GetFirstChild(root, 0) + item, root_cookie = self.ProjectTree.GetFirstChild(root, 0) for values in infos["values"]: - if not item.IsOk(): - item = self.TypesTree.AppendItem(root, "") - if wx.Platform != '__WXMSW__': - item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie) - self.GenerateTypesTreeBranch(item, values) - item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie) + if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0: + if not item.IsOk(): + item = self.ProjectTree.AppendItem(root, "") + if wx.Platform != '__WXMSW__': + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) + self.GenerateProjectTreeBranch(item, values) + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) while item.IsOk(): to_delete.append(item) - item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie) + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) for item in to_delete: - self.TypesTree.Delete(item) - - def SelectTypesTreeItem(self, tagname): - if self.TypesTree is not None: - root = self.TypesTree.GetRootItem() + self.ProjectTree.Delete(item) + + def SelectProjectTreeItem(self, tagname): + if self.ProjectTree is not None: + root = self.ProjectTree.GetRootItem() if root.IsOk(): words = tagname.split("::") if words[0] == "D": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_DATATYPE)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_DATATYPE)]) elif words[0] == "P": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU)]) elif words[0] == "T": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)]) elif words[0] == "A": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)]) elif words[0] == "C": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)]) elif words[0] == "R": - return self.RecursiveTypesTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)]) + return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)]) return False - def RecursiveTypesTreeItemSelection(self, root, items): + def RecursiveProjectTreeItemSelection(self, root, items): found = False if wx.VERSION >= (2, 6, 0): - item, root_cookie = self.TypesTree.GetFirstChild(root) + item, root_cookie = self.ProjectTree.GetFirstChild(root) else: - item, root_cookie = self.TypesTree.GetFirstChild(root, 0) + item, root_cookie = self.ProjectTree.GetFirstChild(root, 0) while item.IsOk() and not found: - if (self.TypesTree.GetItemText(item), self.TypesTree.GetPyData(item)) == items[0]: + item_infos = self.ProjectTree.GetPyData(item) + if (item_infos["name"].split(":")[-1].strip(), item_infos["type"]) == items[0]: if len(items) == 1: self.SelectedItem = item - self.TypesTree.SelectItem(item) + self.ProjectTree.SelectItem(item) wx.CallAfter(self.ResetSelectedItem) return True else: - found = self.RecursiveTypesTreeItemSelection(item, items[1:]) + found = self.RecursiveProjectTreeItemSelection(item, items[1:]) else: - found = self.RecursiveTypesTreeItemSelection(item, items) - item, root_cookie = self.TypesTree.GetNextChild(root, root_cookie) + found = self.RecursiveProjectTreeItemSelection(item, items) + item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) return found - def OnTypesTreeBeginDrag(self, event): + def OnProjectTreeBeginDrag(self, event): if wx.Platform == '__WXMSW__': self.SelectedItem = event.GetItem() - if self.SelectedItem is not None and self.TypesTree.GetPyData(self.SelectedItem) == ITEM_POU: - block_name = self.TypesTree.GetItemText(self.SelectedItem) + if self.SelectedItem is not None and self.ProjectTree.GetPyData(self.SelectedItem)["type"] == ITEM_POU: + block_name = self.ProjectTree.GetItemText(self.SelectedItem) block_type = self.Controler.GetPouType(block_name) if block_type != "program": data = wx.TextDataObject(str((block_name, block_type, ""))) - dragSource = wx.DropSource(self.TypesTree) + dragSource = wx.DropSource(self.ProjectTree) dragSource.SetData(data) dragSource.DoDragDrop() self.ResetSelectedItem() - def OnTypesTreeItemBeginEdit(self, event): + def OnProjectTreeItemBeginEdit(self, event): selected = event.GetItem() - if self.TypesTree.GetPyData(selected) in ITEMS_UNEDITABLE: + if self.ProjectTree.GetPyData(selected)["type"] in ITEMS_UNEDITABLE: event.Veto() else: event.Skip() - def OnTypesTreeItemEndEdit(self, event): + def OnProjectTreeItemEndEdit(self, event): message = None abort = False new_name = event.GetLabel() @@ -1760,11 +1688,11 @@ message = _("\"%s\" is a keyword. It can't be used!")%new_name else: item = event.GetItem() - old_name = self.TypesTree.GetItemText(item) - itemtype = self.TypesTree.GetPyData(item) - if itemtype == ITEM_PROJECT: + old_name = self.ProjectTree.GetItemText(item) + item_infos = self.ProjectTree.GetPyData(item) + if item_infos["type"] == ITEM_PROJECT: self.Controler.SetProjectProperties(name = new_name) - elif itemtype == ITEM_DATATYPE: + elif item_infos["type"] == ITEM_DATATYPE: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames() if name != old_name]: message = _("\"%s\" data type already exists!")%new_name abort = True @@ -1773,7 +1701,7 @@ self.RefreshEditorNames(self.Controler.ComputeDataTypeName(old_name), self.Controler.ComputeDataTypeName(new_name)) self.RefreshPageTitles() - elif itemtype == ITEM_POU: + elif item_infos["type"] == ITEM_POU: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]: message = _("\"%s\" pou already exists!")%new_name abort = True @@ -1788,29 +1716,29 @@ self.Controler.ComputePouName(new_name)) self.RefreshLibraryPanel() self.RefreshPageTitles() - elif itemtype == ITEM_TRANSITION: - pou_name = GetParentName(self.TypesTree, item, ITEM_POU) + elif item_infos["type"] == ITEM_TRANSITION: 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.GetProjectPouVariables(pou_name) if name != old_name]: message = _("A variable with \"%s\" as name already exists in this pou!")%new_name else: - self.Controler.ChangePouTransitionName(pou_name, old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputePouTransitionName(pou_name, old_name), - self.Controler.ComputePouTransitionName(pou_name, new_name)) + words = item_infos["tagname"].split("::") + self.Controler.ChangePouTransitionName(words[1], old_name, new_name) + self.RefreshEditorNames(self.Controler.ComputePouTransitionName(words[1], old_name), + self.Controler.ComputePouTransitionName(words[1], new_name)) self.RefreshPageTitles() - elif itemtype == ITEM_ACTION: - pou_name = GetParentName(self.TypesTree, item, ITEM_POU) + elif item_infos["type"] == ITEM_ACTION: 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.GetProjectPouVariables(pou_name) if name != old_name]: message = _("A variable with \"%s\" as name already exists in this pou!")%new_name else: - self.Controler.ChangePouActionName(pou_name, old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputePouActionName(pou_name, old_name), - self.Controler.ComputePouActionName(pou_name, new_name)) + words = item_infos["tagname"].split("::") + self.Controler.ChangePouActionName(words[1], old_name, new_name) + self.RefreshEditorNames(self.Controler.ComputePouActionName(words[1], old_name), + self.Controler.ComputePouActionName(words[1], new_name)) self.RefreshPageTitles() - elif itemtype == ITEM_CONFIGURATION: + elif item_infos["type"] == ITEM_CONFIGURATION: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]: message = _("\"%s\" config already exists!")%new_name abort = True @@ -1829,8 +1757,7 @@ self.RefreshEditorNames(self.Controler.ComputeConfigurationName(old_name), self.Controler.ComputeConfigurationName(new_name)) self.RefreshPageTitles() - elif itemtype == ITEM_RESOURCE: - config_name = GetParentName(self.TypesTree, item, ITEM_CONFIGURATION) + elif item_infos["type"] == ITEM_RESOURCE: if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames()]: message = _("\"%s\" config already exists!")%new_name abort = True @@ -1845,79 +1772,57 @@ abort = True messageDialog.Destroy() if not abort: - self.Controler.ChangeConfigurationResourceName(config_name, old_name, new_name) - self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(config_name, old_name), - self.Controler.ComputeConfigurationResourceName(config_name, new_name)) + words = item_infos["tagname"].split("::") + self.Controler.ChangeConfigurationResourceName(words[1], old_name, new_name) + self.RefreshEditorNames(self.Controler.ComputeConfigurationResourceName(words[1], old_name), + self.Controler.ComputeConfigurationResourceName(words[1], new_name)) self.RefreshPageTitles() if message or abort: if message: self.ShowErrorMessage(message) item = event.GetItem() - wx.CallAfter(self.TypesTree.EditLabel, item) + wx.CallAfter(self.ProjectTree.EditLabel, item) event.Veto() else: - wx.CallAfter(self.RefreshTypesTree) + wx.CallAfter(self.RefreshProjectTree) self.RefreshEditor() self._Refresh(TITLE, FILEMENU, EDITMENU) event.Skip() - def OnTypesTreeItemActivated(self, event): + def OnProjectTreeItemActivated(self, event): selected = event.GetItem() - name = self.TypesTree.GetItemText(selected) - data = self.TypesTree.GetPyData(selected) - if UNEDITABLE_NAMES_DICT.get(name, name) == "Properties": - self.ShowProperties() - if data == ITEM_DATATYPE: - self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name)) - elif data == ITEM_POU: - self.EditProjectElement(data, self.Controler.ComputePouName(name)) - elif data == ITEM_CONFIGURATION: - self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name)) - elif data == ITEM_RESOURCE: - config_name = GetParentName(self.TypesTree, selected, ITEM_CONFIGURATION) - self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name)) - elif data in [ITEM_TRANSITION, ITEM_ACTION]: - pou_name = GetParentName(self.TypesTree, selected, ITEM_POU) - if data == ITEM_TRANSITION: - tagname = self.Controler.ComputePouTransitionName(pou_name, name) - elif data == ITEM_ACTION: - tagname = self.Controler.ComputePouActionName(pou_name, name) - self.EditProjectElement(data, tagname) + name = self.ProjectTree.GetItemText(selected) + item_infos = self.ProjectTree.GetPyData(selected) + if item_infos["type"] == ITEM_PROJECT: + self.EditProjectSettings() + elif item_infos["type"] in [ITEM_DATATYPE, ITEM_POU, + ITEM_CONFIGURATION, ITEM_RESOURCE, + ITEM_TRANSITION, ITEM_ACTION]: + self.EditProjectElement(item_infos["type"], item_infos["tagname"]) event.Skip() - def TypesTreeItemSelect(self, select_item): - name = self.TypesTree.GetItemText(select_item) - data = self.TypesTree.GetPyData(select_item) - if data == ITEM_DATATYPE: - self.EditProjectElement(data, self.Controler.ComputeDataTypeName(name), True) - elif data == ITEM_POU: - self.EditProjectElement(data, self.Controler.ComputePouName(name), True) - elif data == ITEM_CONFIGURATION: - self.EditProjectElement(data, self.Controler.ComputeConfigurationName(name), True) - elif data == ITEM_RESOURCE: - config_name = GetParentName(self.TypesTree, select_item, ITEM_CONFIGURATION) - self.EditProjectElement(data, self.Controler.ComputeConfigurationResourceName(config_name, name), True) - elif data in [ITEM_TRANSITION, ITEM_ACTION]: - pou_name = GetParentName(self.TypesTree, select_item, ITEM_POU) - if data == ITEM_TRANSITION: - tagname = self.Controler.ComputePouTransitionName(pou_name, name) - elif data == ITEM_ACTION: - tagname = self.Controler.ComputePouActionName(pou_name, name) - self.EditProjectElement(data, tagname, True) - - def OnTypesTreeLeftUp(self, event): + def ProjectTreeItemSelect(self, select_item): + name = self.ProjectTree.GetItemText(select_item) + item_infos = self.ProjectTree.GetPyData(select_item) + if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU, + ITEM_CONFIGURATION, ITEM_RESOURCE, + ITEM_TRANSITION, ITEM_ACTION]: + self.EditProjectElement(item_infos["type"], item_infos["tagname"], True) + self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"]) + + def OnProjectTreeLeftUp(self, event): if self.SelectedItem is not None: - self.TypesTree.SelectItem(self.SelectedItem) - self.TypesTreeItemSelect(self.SelectedItem) + self.ProjectTree.SelectItem(self.SelectedItem) + self.ProjectTreeItemSelect(self.SelectedItem) wx.CallAfter(self.ResetSelectedItem) event.Skip() - def OnTypesTreeItemSelected(self, event): - self.TypesTreeItemSelect(event.GetItem()) + def OnProjectTreeItemSelected(self, event): + self.ProjectTreeItemSelect(event.GetItem()) event.Skip() - def OnTypesTreeItemChanging(self, event): - if self.TypesTree.GetPyData(event.GetItem()) not in ITEMS_UNEDITABLE and self.SelectedItem is None: + def OnProjectTreeItemChanging(self, event): + if self.ProjectTree.GetPyData(event.GetItem())["type"] not in ITEMS_UNEDITABLE and self.SelectedItem is None: self.SelectedItem = event.GetItem() event.Veto() else: @@ -1996,18 +1901,18 @@ self.RefreshPageTitles() return new_window - def OnTypesTreeRightUp(self, event): + def OnProjectTreeRightUp(self, event): if wx.Platform == '__WXMSW__': item = event.GetItem() else: - item, flags = self.TypesTree.HitTest(wx.Point(event.GetX(), event.GetY())) - self.TypesTree.SelectItem(item) - self.TypesTreeItemSelect(item) - name = self.TypesTree.GetItemText(item) - type = self.TypesTree.GetPyData(item) + item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY())) + self.ProjectTree.SelectItem(item) + self.ProjectTreeItemSelect(item) + name = self.ProjectTree.GetItemText(item) + item_infos = self.ProjectTree.GetPyData(item) menu = None - if type in ITEMS_UNEDITABLE: + if item_infos["type"] in ITEMS_UNEDITABLE: name = UNEDITABLE_NAMES_DICT[name] if name == "Data Types": @@ -2039,37 +1944,41 @@ menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition")) - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) + parent = self.ProjectTree.GetItemParent(item)["type"] + parent_type = self.ProjectTree.GetPyData(parent) while parent_type != ITEM_POU: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(self.TypesTree.GetItemText(parent)), id=new_id) + parent = self.ProjectTree.GetItemParent(parent) + parent_type = self.ProjectTree.GetPyData(parent)["type"] + self.Bind(wx.EVT_MENU, self.GenerateAddTransitionFunction(self.ProjectTree.GetItemText(parent)), id=new_id) elif name == "Actions": menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Action")) - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) + parent = self.ProjectTree.GetItemParent(item) + parent_type = self.ProjectTree.GetPyData(parent)["type"] while parent_type != ITEM_POU: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(self.TypesTree.GetItemText(parent)), id=new_id) + parent = self.ProjectTree.GetItemParent(parent) + parent_type = self.ProjectTree.GetPyData(parent)["type"] + self.Bind(wx.EVT_MENU, self.GenerateAddActionFunction(self.ProjectTree.GetItemText(parent)), id=new_id) elif name == "Resources": menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource")) - parent = self.TypesTree.GetItemParent(item) - parent_type = self.TypesTree.GetPyData(parent) - while parent_type != ITEM_CONFIGURATION: - parent = self.TypesTree.GetItemParent(parent) - parent_type = self.TypesTree.GetPyData(parent) - self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(self.TypesTree.GetItemText(parent)), id=new_id) + parent = self.ProjectTree.GetItemParent(item) + parent_type = self.ProjectTree.GetPyData(parent)["type"] + while parent_type not in [ITEM_CONFIGURATION, ITEM_PROJECT]: + parent = self.ProjectTree.GetItemParent(parent) + parent_type = self.ProjectTree.GetPyData(parent)["type"] + if parent_type == ITEM_PROJECT: + parent_name = None + else: + parent_name = self.ProjectTree.GetItemText(parent) + self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id) else: - if type == ITEM_POU: + if item_infos["type"] == ITEM_POU: menu = wx.Menu(title='') if self.Controler.GetPouBodyType(name) == "SFC": new_id = wx.NewId() @@ -2099,13 +2008,13 @@ AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Rename")) self.Bind(wx.EVT_MENU, self.OnRenamePouMenu, id=new_id) - elif type == ITEM_CONFIGURATION: + elif item_infos["type"] == ITEM_CONFIGURATION: menu = wx.Menu(title='') new_id = wx.NewId() AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Resource")) self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(name), id=new_id) - elif type in [ITEM_DATATYPE, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE]: + elif item_infos["type"] in [ITEM_DATATYPE, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE]: menu = wx.Menu(title='') if menu is not None: @@ -2124,83 +2033,11 @@ # Instances Tree Management Functions #------------------------------------------------------------------------------- - def RefreshInstancesTree(self): - infos = self.Controler.GetProjectTopology(self.EnableDebug) - root = self.InstancesTree.GetRootItem() - if not root.IsOk(): - root = self.InstancesTree.AddRoot(infos["name"]) - self.GenerateInstancesTreeBranch(root, infos) - self.InstancesTree.Expand(root) - - def GenerateInstancesTreeBranch(self, root, infos): - to_delete = [] - if infos.get("elmt_type", None) is not None: - self.InstancesTree.SetItemText(root, "%s (%s)"%(infos["name"], infos["elmt_type"])) - else: - self.InstancesTree.SetItemText(root, infos["name"]) - self.InstancesTree.SetPyData(root, (infos["type"], infos.get("tagname", None))) - self.InstancesTree.SetItemImage(root, self.TreeImageDict[infos["type"]]) - - if wx.VERSION >= (2, 6, 0): - item, root_cookie = self.InstancesTree.GetFirstChild(root) - else: - item, root_cookie = self.InstancesTree.GetFirstChild(root, 0) - for values in infos["values"]: - if not item.IsOk(): - item = self.InstancesTree.AppendItem(root, "") - if wx.Platform != '__WXMSW__': - item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie) - self.GenerateInstancesTreeBranch(item, values) - item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie) - while item.IsOk(): - to_delete.append(item) - item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie) - for item in to_delete: - self.InstancesTree.Delete(item) - if infos["type"] in [ITEM_CONFIGURATION, ITEM_RESOURCE]: - self.InstancesTree.Expand(root) - - def OnInstancesTreeBeginDrag(self, event): - if self.Controler.DebugAvailable(): - selected_item = event.GetItem() - selected_infos = self.InstancesTree.GetPyData(selected_item) - if selected_item is not None and selected_infos[0] in ITEMS_VARIABLE: - var_path = self.InstancesTree.GetItemText(selected_item).split(" (")[0] - parent_item = self.InstancesTree.GetItemParent(selected_item) - while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT: - parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0] - var_path = "%s.%s"%(parent_name, var_path) - parent_item = self.InstancesTree.GetItemParent(parent_item) - data = wx.TextDataObject(str((var_path, "debug"))) - dragSource = wx.DropSource(self.InstancesTree) - dragSource.SetData(data) - dragSource.DoDragDrop() - event.Skip() - else: - event.Veto() - - def OnInstancesTreeItemActivated(self, event): - if self.Controler.DebugAvailable(): - selected_item = event.GetItem() - selected_infos = self.InstancesTree.GetPyData(selected_item) - if selected_item is not None and ( - selected_infos[0] in [ITEM_FUNCTIONBLOCK, ITEM_PROGRAM, ITEM_TRANSITION, ITEM_ACTION] or - selected_infos[0] in ITEMS_VARIABLE): - - instance_path, var_type = self.InstancesTree.GetItemText(selected_item).split(" (") - if selected_infos[1] is not None: - instance_type = selected_infos[1] - else: - instance_type = var_type.split(")")[0] - parent_item = self.InstancesTree.GetItemParent(selected_item) - while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT: - parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0] - instance_path = "%s.%s"%(parent_name, instance_path) - parent_item = self.InstancesTree.GetItemParent(parent_item) - - self.OpenDebugViewer(selected_infos[0], instance_path, instance_type) - - event.Skip() + def GetTreeImage(self, var_class): + return self.TreeImageDict[var_class] + + def RefreshPouInstanceVariablesPanel(self): + self.PouInstanceVariablesPanel.RefreshView() def OpenDebugViewer(self, instance_category, instance_path, instance_type): openedidx = self.IsOpened(instance_path) @@ -2267,66 +2104,6 @@ self.RefreshPageTitles() return new_window - def OnInstancesTreeRightUp(self, event): - if self.Controler.DebugAvailable(): - if wx.Platform == '__WXMSW__': - selected_item = event.GetItem() - else: - selected_item = self.InstancesTree.GetSelection() - selected_infos = self.InstancesTree.GetPyData(selected_item) - if selected_item is not None and selected_infos[0] in ITEMS_VARIABLE: - var_path, var_type = self.InstancesTree.GetItemText(selected_item).split(" (") - var_type = var_type.split(")")[0] - - if self.Controler.IsOfType(var_type, "ANY_NUM", True) or\ - self.Controler.IsOfType(var_type, "ANY_BIT", True): - parent_item = self.InstancesTree.GetItemParent(selected_item) - while self.InstancesTree.GetPyData(parent_item)[0] != ITEM_PROJECT: - parent_name = self.InstancesTree.GetItemText(parent_item).split(" (")[0] - var_path = "%s.%s"%(parent_name, var_path) - parent_item = self.InstancesTree.GetItemParent(parent_item) - - menu = wx.Menu(title='') - new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Graphic Panel")) - self.Bind(wx.EVT_MENU, self.AddVariableGraphicFunction(var_path), id=new_id) - new_id = wx.NewId() - AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("CSV Log")) - self.PopupMenu(menu) - event.Skip() - - def AddVariableGraphicFunction(self, iec_path): - def AddVariableGraphic(event): - self.OpenGraphicViewer(iec_path) - event.Skip() - return AddVariableGraphic - - def GetInstancesTreeItem(self, root, instancepath): - paths = instancepath.split(".", 1) - if wx.VERSION >= (2, 6, 0): - item, root_cookie = self.InstancesTree.GetFirstChild(root) - else: - item, root_cookie = self.InstancesTree.GetFirstChild(root, 0) - while item.IsOk(): - name = self.InstancesTree.GetItemText(item).split(" (")[0] - if name == paths[0]: - if len(paths) == 1: - return item - else: - return self.GetInstancesTreeItem(item, paths[1]) - item, root_cookie = self.InstancesTree.GetNextChild(root, root_cookie) - return None - - def SelectInstancesTreeItem(self, instancepath): - if self.InstancesTree is not None: - root = self.InstancesTree.GetRootItem() - if root.IsOk(): - item = self.GetInstancesTreeItem(root, instancepath) - if item is not None: - self.InstancesTree.SelectItem(item) - return True - return False - def ResetGraphicViewers(self): for i in xrange(self.TabsOpened.GetPageCount()): editor = self.TabsOpened.GetPage(i) @@ -2337,18 +2114,11 @@ if self.EnableDebug: idxs = range(self.TabsOpened.GetPageCount()) idxs.reverse() - root = None - if self.InstancesTree is not None: - root = self.InstancesTree.GetRootItem() - if not root.IsOk(): - root = None for idx in idxs: editor = self.TabsOpened.GetPage(idx) if editor.IsDebugging(): - item = None - if root is not None: - item = self.GetInstancesTreeItem(root, editor.GetInstancePath()) - if item is None: + instance_infos = self.Controler.GetInstanceInfos(editor.GetInstancePath(), self.EnableDebug) + if instance_infos is None: self.TabsOpened.DeletePage(idx) elif isinstance(editor, GraphicViewer): editor.ResetView(True) @@ -2356,9 +2126,10 @@ editor.RefreshView() self.DebugVariablePanel.UnregisterObsoleteData() - def AddDebugVariable(self, iec_path): + def AddDebugVariable(self, iec_path, force=False): if self.EnableDebug: - self.DebugVariablePanel.InsertValue(iec_path) + self.DebugVariablePanel.InsertValue(iec_path, force=force) + self.EnsureTabVisible(self.DebugVariablePanel) #------------------------------------------------------------------------------- # Library Panel Management Function @@ -2384,14 +2155,10 @@ if callback is not None: self.Bind(wx.EVT_TOOL, callback, id=id) MenuToolBar.Realize() - if USE_AUI: - self.AUIManager.GetPane("MenuToolBar").BestSize(MenuToolBar.GetBestSize()) + self.AUIManager.GetPane("MenuToolBar").BestSize(MenuToolBar.GetBestSize()) def ResetEditorToolBar(self): - if USE_AUI: - EditorToolBar = self.Panes["EditorToolBar"] - else: - EditorToolBar = self.EditorToolBar + EditorToolBar = self.Panes["EditorToolBar"] for item in self.CurrentEditorToolBar: if wx.VERSION >= (2, 6, 0): @@ -2404,9 +2171,8 @@ if EditorToolBar: EditorToolBar.Realize() - if USE_AUI: - self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize()) - self.AUIManager.Update() + self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize()) + self.AUIManager.Update() def RefreshEditorToolBar(self): selected = self.TabsOpened.GetSelection() @@ -2421,10 +2187,7 @@ self.ResetEditorToolBar() self.CurrentMenu = menu self.CurrentEditorToolBar = [] - if USE_AUI: - EditorToolBar = self.Panes["EditorToolBar"] - else: - EditorToolBar = self.EditorToolBar + EditorToolBar = self.Panes["EditorToolBar"] if EditorToolBar: for radio, modes, id, method, picture, help in EditorToolBarItems[menu]: if modes & self.DrawingMode: @@ -2435,9 +2198,8 @@ self.Bind(wx.EVT_MENU, getattr(self, method), id=id) self.CurrentEditorToolBar.append(id) EditorToolBar.Realize() - if USE_AUI: - self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize()) - self.AUIManager.Update() + self.AUIManager.GetPane("EditorToolBar").BestSize(EditorToolBar.GetBestSize()) + self.AUIManager.Update() elif not menu: self.ResetEditorToolBar() self.CurrentMenu = menu @@ -2453,19 +2215,13 @@ if selected != -1: window = self.TabsOpened.GetPage(selected) window.SetMode(MODE_SELECTION) - if USE_AUI: - EditorToolBar = self.Panes["EditorToolBar"] - else: - EditorToolBar = self.EditorToolBar + EditorToolBar = self.Panes["EditorToolBar"] if EditorToolBar: EditorToolBar.ToggleTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, False) EditorToolBar.ToggleTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION, True) def ResetToolToggle(self, id): - if USE_AUI: - tool = self.Panes["EditorToolBar"].FindById(id) - else: - tool = self.EditorToolBar.FindById(id) + tool = self.Panes["EditorToolBar"].FindById(id) tool.SetToggle(False) def OnSelectionTool(self, event): @@ -2599,7 +2355,7 @@ if dialog.ShowModal() == wx.ID_OK: tagname = self.Controler.ProjectAddDataType(dialog.GetValue()) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) self.EditProjectElement(ITEM_DATATYPE, tagname) dialog.Destroy() @@ -2612,7 +2368,7 @@ values = dialog.GetValues() tagname = self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"]) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE) self.EditProjectElement(ITEM_POU, tagname) dialog.Destroy() return OnAddPouMenu @@ -2626,7 +2382,7 @@ values = dialog.GetValues() tagname = self.Controler.ProjectAddPouTransition(pou_name, values["transitionName"], values["language"]) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) self.EditProjectElement(ITEM_TRANSITION, tagname) dialog.Destroy() return OnAddTransitionMenu @@ -2640,7 +2396,7 @@ values = dialog.GetValues() tagname = self.Controler.ProjectAddPouAction(pou_name, values["actionName"], values["language"]) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) self.EditProjectElement(ITEM_ACTION, tagname) dialog.Destroy() return OnAddActionMenu @@ -2653,7 +2409,7 @@ value = dialog.GetValue() tagname = self.Controler.ProjectAddConfiguration(value) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) self.EditProjectElement(ITEM_CONFIGURATION, tagname) dialog.Destroy() @@ -2666,22 +2422,22 @@ value = dialog.GetValue() tagname = self.Controler.ProjectAddConfigurationResource(config_name, value) if tagname is not None: - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) self.EditProjectElement(ITEM_RESOURCE, tagname) dialog.Destroy() return OnAddResourceMenu def GenerateChangePouTypeFunction(self, name, new_type): def OnChangePouTypeMenu(event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_POU: + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: self.Controler.ProjectChangePouType(name, new_type) - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE) return OnChangePouTypeMenu def OnCopyPou(self, event): - selected = self.TypesTree.GetSelection() - pou_name = self.TypesTree.GetItemText(selected) + selected = self.ProjectTree.GetSelection() + pou_name = self.ProjectTree.GetItemText(selected) pou_xml = self.Controler.GetPouXml(pou_name) if pou_xml is not None: @@ -2689,9 +2445,9 @@ self._Refresh(EDITMENU) def OnPastePou(self, event): - selected = self.TypesTree.GetSelection() - - pou_type = self.TypesTree.GetItemText(selected) + selected = self.ProjectTree.GetSelection() + + pou_type = self.ProjectTree.GetItemText(selected) pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs' pou_type = {'Functions': 'function', 'Function Blocks': 'functionBlock', 'Programs': 'program'}[pou_type] @@ -2704,106 +2460,94 @@ message.ShowModal() message.Destroy() else: - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, TYPESTREE, LIBRARYTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE) #------------------------------------------------------------------------------- # Remove Project Elements Functions #------------------------------------------------------------------------------- def OnRemoveDataTypeMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_DATATYPE: - name = self.TypesTree.GetItemText(selected) + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_DATATYPE: + name = self.ProjectTree.GetItemText(selected) if not self.Controler.DataTypeIsUsed(name): self.Controler.ProjectRemoveDataType(name) tagname = self.Controler.ComputeDataTypeName(name) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE) else: self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")) def OnRenamePouMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_POU: - wx.CallAfter(self.TypesTree.EditLabel, selected) + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: + wx.CallAfter(self.ProjectTree.EditLabel, selected) def OnRemovePouMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_POU: - name = self.TypesTree.GetItemText(selected) + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU: + name = self.ProjectTree.GetItemText(selected) if not self.Controler.PouIsUsed(name): self.Controler.ProjectRemovePou(name) tagname = self.Controler.ComputePouName(name) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE) + self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) else: self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")) def OnRemoveTransitionMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_TRANSITION: - transition = self.TypesTree.GetItemText(selected) - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_POU: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - pou_name = self.TypesTree.GetItemText(item) + selected = self.ProjectTree.GetSelection() + item_infos = self.ProjectTree.GetPyData(selected) + if item_infos["type"] == ITEM_TRANSITION: + transition = self.ProjectTree.GetItemText(selected) + pou_name = item_infos["tagname"].split("::")[1] self.Controler.ProjectRemovePouTransition(pou_name, transition) tagname = self.Controler.ComputePouTransitionName(pou_name, transition) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) def OnRemoveActionMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_ACTION: - action = self.TypesTree.GetItemText(selected) - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_POU: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - pou_name = self.TypesTree.GetItemText(item) + selected = self.ProjectTree.GetSelection() + item_infos = self.ProjectTree.GetPyData(selected) + if item_infos["type"] == ITEM_ACTION: + action = self.ProjectTree.GetItemText(selected) + pou_name = item_infos["tagname"].split("::")[1] self.Controler.ProjectRemovePouAction(pou_name, action) tagname = self.Controler.ComputePouActionName(pou_name, action) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE) def OnRemoveConfigurationMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_CONFIGURATION: - name = self.TypesTree.GetItemText(selected) + selected = self.ProjectTree.GetSelection() + if self.ProjectTree.GetPyData(selected)["type"] == ITEM_CONFIGURATION: + name = self.ProjectTree.GetItemText(selected) self.Controler.ProjectRemoveConfiguration(name) tagname = self.Controler.ComputeConfigurationName(name) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) def OnRemoveResourceMenu(self, event): - selected = self.TypesTree.GetSelection() - if self.TypesTree.GetPyData(selected) == ITEM_RESOURCE: - resource = self.TypesTree.GetItemText(selected) - item = self.TypesTree.GetItemParent(selected) - item_type = self.TypesTree.GetPyData(item) - while item_type != ITEM_CONFIGURATION: - item = self.TypesTree.GetItemParent(item) - item_type = self.TypesTree.GetPyData(item) - config_name = self.TypesTree.GetItemText(item) + selected = self.ProjectTree.GetSelection() + item_infos = self.ProjectTree.GetPyData(selected) + if item_infos["type"] == ITEM_RESOURCE: + resource = self.ProjectTree.GetItemText(selected) + config_name = item_infos["tagname"].split("::")[1] self.Controler.ProjectRemoveConfigurationResource(config_name, resource) tagname = self.Controler.ComputeConfigurationResourceName(config_name, selected) idx = self.IsOpened(tagname) if idx is not None: self.TabsOpened.DeletePage(idx) - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE) + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL) def OnPLCOpenEditorMenu(self, event): wx.MessageBox(_("No documentation available.\nComing soon.")) @@ -2820,11 +2564,11 @@ #------------------------------------------------------------------------------- def ShowHighlight(self, infos, start, end, highlight_type): - self.SelectTypesTreeItem(infos[0]) + self.SelectProjectTreeItem(infos[0]) if infos[1] == "name": self.Highlights[infos[0]] = highlight_type - self.RefreshTypesTree() - self.TypesTree.Unselect() + self.RefreshProjectTree() + self.ProjectTree.Unselect() else: self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0]) selected = self.TabsOpened.GetSelection() @@ -2843,7 +2587,7 @@ self.Highlights = {} else: self.Highlights = dict([(name, highlight) for name, highlight in self.Highlights.iteritems() if highlight != highlight_type]) - self.RefreshTypesTree() + self.RefreshProjectTree() for i in xrange(self.TabsOpened.GetPageCount()): viewer = self.TabsOpened.GetPage(i) viewer.ClearHighlights(highlight_type) @@ -2944,11 +2688,14 @@ # Open the filepath if defined if fileOpen is not None and os.path.isfile(fileOpen): # Create a new controller - self.Controler = PLCControler() - result = self.Controler.OpenXMLFile(fileOpen) + controler = PLCControler() + result = controler.OpenXMLFile(fileOpen) if result is None: - self.LibraryPanel.SetControler(self.Controler) - self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) + self.Controler = controler + self.LibraryPanel.SetControler(controler) + self.ProjectTree.Enable(True) + self.PouInstanceVariablesPanel.SetController(controler) + self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) # Define PLCOpenEditor icon self.SetIcon(wx.Icon(os.path.join(CWD,"Images", "poe.ico"),wx.BITMAP_TYPE_ICO)) @@ -2962,8 +2709,7 @@ def OnCloseFrame(self, event): if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")): - if USE_AUI: - self.AUIManager.UnInit() + self.AUIManager.UnInit() self.SaveLastState() @@ -3038,7 +2784,7 @@ self.Controler = PLCControler() self.Controler.CreateNewProject(properties) self.LibraryPanel.SetControler(self.Controler) - self._Refresh(TITLE, FILEMENU, EDITMENU, TYPESTREE, INSTANCESTREE, + self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) def OnOpenProjectMenu(self, event): @@ -3059,12 +2805,15 @@ filepath = dialog.GetPath() if os.path.isfile(filepath): self.ResetView() - self.Controler = PLCControler() - result = self.Controler.OpenXMLFile(filepath) + controler = PLCControler() + result = controler.OpenXMLFile(filepath) if result is None: - self.LibraryPanel.SetControler(self.Controler) + self.Controler = controler + self.LibraryPanel.SetControler(controler) + self.ProjectTree.Enable(True) + self.PouInstanceVariablesPanel.SetController(controler) self.LoadProjectOrganization() - self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) + self._Refresh(PROJECTTREE, LIBRARYTREE) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) dialog.Destroy() diff -r 188906a7368c -r ce605c1a6d04 RessourceEditor.py --- a/RessourceEditor.py Tue May 15 05:19:13 2012 +0900 +++ b/RessourceEditor.py Mon May 21 10:02:54 2012 +0200 @@ -502,7 +502,7 @@ def OnInstancesGridCellChange(self, event): self.RefreshModel() - self.ParentWindow.RefreshInstancesTree() + self.ParentWindow.RefreshPouInstanceVariablesPanel() self.InstancesGrid.RefreshButtons() event.Skip() diff -r 188906a7368c -r ce605c1a6d04 TextViewer.py --- a/TextViewer.py Tue May 15 05:19:13 2012 +0900 +++ b/TextViewer.py Mon May 21 10:02:54 2012 +0200 @@ -247,7 +247,8 @@ return {"cursor_pos": self.Editor.GetCurrentPos()} def SetState(self, state): - self.Editor.GotoPos(state["cursor_pos"]) + if self: + self.Editor.GotoPos(state.get("cursor_pos", 0)) def OnModification(self, event): if not self.DisableEvents: diff -r 188906a7368c -r ce605c1a6d04 Viewer.py --- a/Viewer.py Tue May 15 05:19:13 2012 +0900 +++ b/Viewer.py Mon May 21 10:02:54 2012 +0200 @@ -691,9 +691,10 @@ "zoom": self.CurrentScale} def SetState(self, state): - self.SetScale(state["zoom"]) - self.Scroll(*state["position"]) - self.RefreshVisibleElements() + if self: + self.SetScale(state["zoom"]) + self.Scroll(*state["position"]) + self.RefreshVisibleElements() def GetLogicalDC(self, buffered=False): if buffered: @@ -1966,7 +1967,7 @@ self.RefreshScrollBars() self.RefreshVisibleElements() self.RefreshVariablePanel() - self.ParentWindow.RefreshInstancesTree() + self.ParentWindow.RefreshPouInstanceVariablesPanel() block.Refresh() dialog.Destroy() @@ -2277,7 +2278,7 @@ self.RefreshScrollBars() self.RefreshVisibleElements() self.RefreshVariablePanel() - self.ParentWindow.RefreshInstancesTree() + self.ParentWindow.RefreshPouInstanceVariablesPanel() if old_values["executionOrder"] != new_values["executionOrder"]: self.RefreshView() else: @@ -2690,7 +2691,7 @@ for element in elements: element.RefreshModel() wx.CallAfter(self.RefreshVariablePanel) - wx.CallAfter(self.ParentWindow.RefreshInstancesTree) + wx.CallAfter(self.ParentWindow.RefreshPouInstanceVariablesPanel) def DeleteVariable(self, variable): connectors = variable.GetConnectors() @@ -2828,7 +2829,7 @@ self.RefreshBuffer() self.RefreshScrollBars() self.RefreshVariablePanel() - self.ParentWindow.RefreshInstancesTree() + self.ParentWindow.RefreshPouInstanceVariablesPanel() self.RefreshRect(self.GetScrolledRect(rect), False) def Copy(self): @@ -2856,7 +2857,7 @@ self.RefreshBuffer() self.RefreshView(selection=result) self.RefreshVariablePanel() - self.ParentWindow.RefreshInstancesTree() + self.ParentWindow.RefreshPouInstanceVariablesPanel() else: message = wx.MessageDialog(self.Editor, result, "Error", wx.OK|wx.ICON_ERROR) message.ShowModal() diff -r 188906a7368c -r ce605c1a6d04 controls/CustomTable.py --- a/controls/CustomTable.py Tue May 15 05:19:13 2012 +0900 +++ b/controls/CustomTable.py Mon May 21 10:02:54 2012 +0200 @@ -1,3 +1,6 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + #This library is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public #License as published by the Free Software Foundation; either diff -r 188906a7368c -r ce605c1a6d04 controls/CustomTree.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/CustomTree.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx + +class CustomTree(wx.TreeCtrl): + + def __init__(self, *args, **kwargs): + wx.TreeCtrl.__init__(self, *args, **kwargs) + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + self.BackgroundBitmap = None + self.BackgroundAlign = wx.ALIGN_LEFT|wx.ALIGN_TOP + + self.AddMenu = None + self.Enabled = False + + if wx.Platform == '__WXMSW__': + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + else: + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnResize) + self.Bind(wx.EVT_SCROLL, self.OnScroll) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + + def SetBackgroundBitmap(self, bitmap, align): + self.BackgroundBitmap = bitmap + self.BackgroundAlign = align + + 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 RefreshBackground(self, refresh_base=False): + dc = wx.ClientDC(self) + dc.Clear() + + bitmap_rect = self.GetBitmapRect() + dc.DrawBitmap(self.BackgroundBitmap, bitmap_rect.x, bitmap_rect.y) + + if refresh_base: + self.Refresh(False) + + def OnEraseBackground(self, event): + self.RefreshBackground(True) + + 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 + flags & wx.TREE_HITTEST_NOWHERE) and self.AddMenu is not None: + self.PopupMenuXY(self.AddMenu, pos.x, pos.y) + event.Skip() + + def OnScroll(self, event): + print "scroll event" + self.RefreshBackground(True) + event.Skip() + + def OnResize(self, event): + self.RefreshBackground(True) + event.Skip() + + def OnPaint(self, event): + self.RefreshBackground() + event.Skip() \ No newline at end of file diff -r 188906a7368c -r ce605c1a6d04 controls/EditorPanel.py --- a/controls/EditorPanel.py Tue May 15 05:19:13 2012 +0900 +++ b/controls/EditorPanel.py Mon May 21 10:02:54 2012 +0200 @@ -65,7 +65,7 @@ elif self.VariableEditor is not None: self.Initialize(self.VariableEditor) elif self.Editor is not None: - self.Initialize(self.Editor) + self.Initialize(self.Editor) def __init__(self, parent, tagname, window, controler, debug=False): self.ParentWindow = window @@ -137,10 +137,10 @@ if self.VariableEditor is not None: self.VariableEditor.RefreshView() - def GetPluginMenuItems(self): + def GetConfNodeMenuItems(self): return self.MenuItems - def RefreshPluginMenu(self, plugin_menu): + def RefreshConfNodeMenu(self, confnode_menu): pass def _Refresh(self, *args): diff -r 188906a7368c -r ce605c1a6d04 controls/PouInstanceVariablesPanel.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/controls/PouInstanceVariablesPanel.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,318 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2012: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx +import wx.lib.buttons +import wx.lib.agw.customtreectrl as CT + +from PLCControler import ITEMS_VARIABLE, ITEM_CONFIGURATION, ITEM_RESOURCE, ITEM_POU + +class PouInstanceVariablesPanel(wx.Panel): + + def __init__(self, parent, window, controller, debug): + 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( + name='ParentButton', parent=self, + bitmap=window.GenerateBitmap("up"), + pos=wx.Point(0, 0), size=wx.Size(28, 28), + style=wx.NO_BORDER) + self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick, + self.ParentButton) + + self.InstanceChoice = wx.ComboBox(name='InstanceChoice', + parent=self, pos=wx.Point(0, 0), + size=wx.Size(0, 28), style=wx.CB_READONLY) + self.Bind(wx.EVT_COMBOBOX, self.OnInstanceChoiceChanged, + self.InstanceChoice) + self.InstanceChoice.Bind(wx.EVT_LEFT_DOWN, self.OnInstanceChoiceLeftDown) + + self.DebugButton = wx.lib.buttons.GenBitmapButton( + name='DebugButton', parent=self, + bitmap=window.GenerateBitmap("debug"), + pos=wx.Point(0, 0), size=wx.Size(28, 28), + style=wx.NO_BORDER) + self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick, + self.DebugButton) + + self.VariablesList = CT.CustomTreeCtrl( + name='VariablesList', parent=self, + pos=wx.Point(0, 0), size=wx.Size(0, 0), + style=wx.SUNKEN_BORDER, + agwStyle=CT.TR_NO_BUTTONS| + CT.TR_SINGLE| + CT.TR_HAS_VARIABLE_ROW_HEIGHT| + CT.TR_HIDE_ROOT| + CT.TR_NO_LINES| + getattr(CT, "TR_ALIGN_WINDOWS_RIGHT", CT.TR_ALIGN_WINDOWS)) + self.VariablesList.SetIndent(0) + self.VariablesList.SetSpacing(5) + self.VariablesList.DoSelectItem = lambda *x,**y:True + self.VariablesList.Bind(CT.EVT_TREE_ITEM_ACTIVATED, + self.OnVariablesListItemActivated) + self.VariablesList.Bind(wx.EVT_LEFT_DOWN, self.OnVariablesListLeftDown) + + buttons_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0) + buttons_sizer.AddWindow(self.ParentButton, 0, border=0, flag=0) + buttons_sizer.AddWindow(self.InstanceChoice, 0, border=0, flag=wx.GROW) + buttons_sizer.AddWindow(self.DebugButton, 0, border=0, flag=0) + 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, 0, border=0, flag=wx.GROW) + main_sizer.AddWindow(self.VariablesList, 0, border=0, 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): + self.PouTagName = tagname + if pou_instance is not None: + self.PouInstance = pou_instance + + self.RefreshView() + + def ResetView(self): + self.Controller = None + + self.PouTagName = None + self.PouInfos = None + self.PouInstance = None + + self.RefreshView() + + def RefreshView(self): + self.VariablesList.DeleteAllItems() + self.InstanceChoice.Clear() + self.InstanceChoice.SetValue("") + + if self.PouTagName is not None: + self.PouInfos = self.Controller.GetPouVariables(self.PouTagName, self.Debug) + else: + self.PouInfos = None + if self.PouInfos is not None: + root = self.VariablesList.AddRoot("") + for var_infos in self.PouInfos["variables"]: + if var_infos.get("type", None) is not None: + text = "%(name)s (%(type)s)" % var_infos + else: + text = var_infos["name"] + + panel = wx.Panel(self.VariablesList) + + buttons = [] + if var_infos["class"] in ITEMS_VARIABLE: + if (var_infos["debug"] and self.Debug and + (self.Controller.IsOfType(var_infos["type"], "ANY_NUM", True) or + self.Controller.IsOfType(var_infos["type"], "ANY_BIT", True))): + graph_button = wx.lib.buttons.GenBitmapButton(name="graph", + parent=panel, bitmap=self.ParentWindow.GenerateBitmap("graph"), + pos=wx.Point(0, 0), size=wx.Size(28, 28), style=wx.NO_BORDER) + self.Bind(wx.EVT_BUTTON, self.GenGraphButtonCallback(var_infos), graph_button) + buttons.append(graph_button) + elif var_infos["edit"]: + edit_button = wx.lib.buttons.GenBitmapButton(name="edit", + parent=panel, bitmap=self.ParentWindow.GenerateBitmap("edit"), + pos=wx.Point(0, 0), size=wx.Size(28, 28), style=wx.NO_BORDER) + self.Bind(wx.EVT_BUTTON, self.GenEditButtonCallback(var_infos), edit_button) + buttons.append(edit_button) + + if var_infos["debug"] and self.Debug: + debug_button = wx.lib.buttons.GenBitmapButton(name="debug", + parent=panel, bitmap=self.ParentWindow.GenerateBitmap("debug"), + pos=wx.Point(0, 0), size=wx.Size(28, 28), style=wx.NO_BORDER) + self.Bind(wx.EVT_BUTTON, self.GenDebugButtonCallback(var_infos), debug_button) + buttons.append(debug_button) + + button_num = len(buttons) + if button_num > 0: + panel.SetSize(wx.Size(button_num * 32, 28)) + panel.SetBackgroundColour(self.VariablesList.GetBackgroundColour()) + panel_sizer = wx.BoxSizer(wx.HORIZONTAL) + panel.SetSizer(panel_sizer) + + for button in buttons: + panel_sizer.AddWindow(button, 0, border=4, flag=wx.LEFT) + else: + panel.Destroy() + panel = None + + item = self.VariablesList.AppendItem(root, text, wnd=panel) + self.VariablesList.SetItemImage(item, self.ParentWindow.GetTreeImage(var_infos["class"])) + self.VariablesList.SetPyData(item, var_infos) + + instances = self.Controller.SearchPouInstances(self.PouTagName, self.Debug) + for instance in instances: + self.InstanceChoice.Append(instance) + if len(instances) == 1: + self.PouInstance = instances[0] + if self.PouInfos["class"] in [ITEM_CONFIGURATION, ITEM_RESOURCE]: + self.PouInstance = None + self.InstanceChoice.SetSelection(0) + elif self.PouInstance in instances: + self.InstanceChoice.SetStringSelection(self.PouInstance) + else: + self.PouInstance = None + self.InstanceChoice.SetValue(_("Select an instance")) + + self.RefreshButtons() + + def RefreshButtons(self): + enabled = self.InstanceChoice.GetSelection() != -1 + self.ParentButton.Enable(enabled and self.PouInfos["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) + while item is not None and item.IsOk(): + panel = self.VariablesList.GetItemWindow(item) + if panel is not None: + for child in panel.GetChildren(): + if child.GetName() != "edit": + child.Enable(enabled) + item, item_cookie = self.VariablesList.GetNextChild(root, item_cookie) + + def GenEditButtonCallback(self, infos): + def EditButtonCallback(event): + var_class = infos["class"] + if var_class == ITEM_RESOURCE: + tagname = self.Controller.ComputeConfigurationResourceName( + self.InstanceChoice.GetStringSelection(), + infos["name"]) + else: + var_class = ITEM_POU + tagname = self.Controller.ComputePouName(infos["type"]) + self.ParentWindow.EditProjectElement(var_class, tagname) + event.Skip() + return EditButtonCallback + + def GenDebugButtonCallback(self, infos): + def DebugButtonCallback(event): + if self.InstanceChoice.GetSelection() != -1: + var_class = infos["class"] + var_path = "%s.%s" % (self.InstanceChoice.GetStringSelection(), + infos["name"]) + if var_class in ITEMS_VARIABLE: + self.ParentWindow.AddDebugVariable(var_path, force=True) + else: + self.ParentWindow.OpenDebugViewer( + infos["class"], + var_path, + self.Controller.ComputePouName(infos["type"])) + event.Skip() + return DebugButtonCallback + + def GenGraphButtonCallback(self, infos): + def GraphButtonCallback(event): + if self.InstanceChoice.GetSelection() != -1: + if infos["class"] in ITEMS_VARIABLE: + var_path = "%s.%s" % (self.InstanceChoice.GetStringSelection(), + infos["name"]) + self.ParentWindow.OpenGraphicViewer(var_path) + event.Skip() + return GraphButtonCallback + + def ShowInstanceChoicePopup(self): + self.InstanceChoice.SetFocusFromKbd() + size = self.InstanceChoice.GetSize() + event = wx.MouseEvent(wx.EVT_LEFT_DOWN._getEvtType()) + event.m_x = size.width / 2 + event.m_y = size.height / 2 + event.SetEventObject(self.InstanceChoice) + #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] + tagname = self.Controller.GetPouInstanceTagName(parent_path, self.Debug) + if tagname is not None: + 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( + self.PouInfos["class"], + self.InstanceChoice.GetStringSelection(), + self.PouTagName) + event.Skip() + + def OnVariablesListItemActivated(self, event): + if self.InstanceChoice.GetSelection() != -1: + instance_path = self.InstanceChoice.GetStringSelection() + 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 and item_infos["class"] not in ITEMS_VARIABLE: + if item_infos["class"] == ITEM_RESOURCE: + tagname = self.Controller.ComputeConfigurationResourceName( + instance_path, + item_infos["name"]) + else: + tagname = self.Controller.ComputePouName(item_infos["type"]) + item_path = "%s.%s" % (instance_path, item_infos["name"]) + wx.CallAfter(self.SetPouType, tagname, item_path) + wx.CallAfter(self.ParentWindow.SelectProjectTreeItem, tagname) + event.Skip() + + def OnVariablesListLeftDown(self, event): + if self.InstanceChoice.GetSelection() == -1: + wx.CallAfter(self.ShowInstanceChoicePopup) + event.Skip() + + def OnInstanceChoiceLeftDown(self, event): + event.Skip() diff -r 188906a7368c -r ce605c1a6d04 controls/VariablePanel.py --- a/controls/VariablePanel.py Tue May 15 05:19:13 2012 +0900 +++ b/controls/VariablePanel.py Mon May 21 10:02:54 2012 +0200 @@ -43,7 +43,7 @@ parent.Append(helpString=help, id=id, kind=kind, item=text) [TITLE, TOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, - INSTANCESTREE, LIBRARYTREE, SCALING + POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING ] = range(9) #------------------------------------------------------------------------------- @@ -644,7 +644,7 @@ self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection()) self.Controler.BufferProject() self.ParentWindow.RefreshView(variablepanel = False) - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) event.Skip() def OnDescriptionChanged(self, event): @@ -653,7 +653,7 @@ new_description = self.Description.GetValue() if new_description != old_description: self.Controler.SetPouDescription(words[1], new_description) - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) event.Skip() def OnClassFilter(self, event): @@ -695,7 +695,7 @@ self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value) self.Controler.BufferProject() self.ParentWindow.RefreshView(variablepanel = False) - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) event.Skip() else: self.SaveValues() @@ -738,17 +738,17 @@ type_menu.AppendMenu(wx.NewId(), _("User Data Types"), datatype_menu) - for category in self.Controler.GetPluginDataTypes(): + for category in self.Controler.GetConfNodeDataTypes(): if len(category["list"]) > 0: - # build a submenu containing plugin types - plugin_datatype_menu = wx.Menu(title='') + # build a submenu containing confnode types + confnode_datatype_menu = wx.Menu(title='') for datatype in category["list"]: new_id = wx.NewId() - AppendMenu(plugin_datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) + AppendMenu(confnode_datatype_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype) self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id) - type_menu.AppendMenu(wx.NewId(), category["name"], plugin_datatype_menu) + type_menu.AppendMenu(wx.NewId(), category["name"], confnode_datatype_menu) # build a submenu containing function block types bodytype = self.Controler.GetEditedElementBodyType(self.TagName) @@ -789,7 +789,7 @@ self.SaveValues(False) self.ParentWindow.RefreshView(variablepanel = False) self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) return VariableTypeFunction def VariableArrayTypeFunction(self, event): @@ -803,7 +803,7 @@ self.SaveValues(False) self.ParentWindow.RefreshView(variablepanel = False) self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) dialog.Destroy() def OnVariablesGridCellLeftClick(self, event): @@ -840,7 +840,7 @@ self.Controler.SetPouInterfaceVars(words[1], self.Values) if buffer: self.Controler.BufferProject() - self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, INSTANCESTREE, LIBRARYTREE) + self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE) #------------------------------------------------------------------------------- # Highlights showing functions diff -r 188906a7368c -r ce605c1a6d04 controls/__init__.py --- a/controls/__init__.py Tue May 15 05:19:13 2012 +0900 +++ b/controls/__init__.py Mon May 21 10:02:54 2012 +0200 @@ -32,3 +32,5 @@ from LocationCellEditor import LocationCellEditor from VariablePanel import VariablePanel from LibraryPanel import LibraryPanel +from PouInstanceVariablesPanel import PouInstanceVariablesPanel +from CustomTree import CustomTree diff -r 188906a7368c -r ce605c1a6d04 dialogs/BrowseLocationsDialog.py --- a/dialogs/BrowseLocationsDialog.py Tue May 15 05:19:13 2012 +0900 +++ b/dialogs/BrowseLocationsDialog.py Mon May 21 10:02:54 2012 +0200 @@ -22,7 +22,7 @@ import wx from plcopen.structures import LOCATIONDATATYPES -from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY +from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY CWD = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0] @@ -131,7 +131,7 @@ # Icons for items for imgname, itemtype in [ - ("CONFIGURATION", LOCATION_PLUGIN), + ("CONFIGURATION", LOCATION_CONFNODE), ("RESOURCE", LOCATION_MODULE), ("PROGRAM", LOCATION_GROUP), ("VAR_INPUT", LOCATION_VAR_INPUT), @@ -157,7 +157,7 @@ root = self.LocationsTree.GetRootItem() if not root.IsOk(): if wx.Platform == '__WXMSW__': - root = self.LocationsTree.AddRoot(_('Plugins')) + root = self.LocationsTree.AddRoot(_('ConfNodes')) else: root = self.LocationsTree.AddRoot("") self.GenerateLocationsTreeBranch(root, self.Locations) @@ -171,7 +171,7 @@ item, root_cookie = self.LocationsTree.GetFirstChild(root, 0) for loc_infos in locations: infos = loc_infos.copy() - if infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP] or\ + if infos["type"] in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP] or\ infos["type"] in self.Filter and (infos["IEC_type"] == self.VarType or infos["IEC_type"] is None and LOCATION_SIZES[self.VarType] == infos["size"]): children = [child for child in infos.pop("children")] @@ -193,7 +193,7 @@ def OnLocationsTreeItemActivated(self, event): infos = self.LocationsTree.GetPyData(event.GetItem()) - if infos["type"] not in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: + if infos["type"] not in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]: wx.CallAfter(self.EndModal, wx.ID_OK) event.Skip() @@ -210,7 +210,7 @@ var_infos = None if selected.IsOk(): var_infos = self.LocationsTree.GetPyData(selected) - if var_infos is None or var_infos["type"] in [LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP]: + if var_infos is None or var_infos["type"] in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]: message = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) message.ShowModal() message.Destroy() diff -r 188906a7368c -r ce605c1a6d04 docutil/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docutil/__init__.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +from dochtml import * +from docpdf import * +from docsvg import * \ No newline at end of file diff -r 188906a7368c -r ce605c1a6d04 docutil/dochtml.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docutil/dochtml.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx, os, wx.html, subprocess + +HtmlFrameOpened = [] + +def OpenHtmlFrame(self, title, file, size): + if title not in HtmlFrameOpened: + HtmlFrameOpened.append(title) + window = HtmlFrame(self, HtmlFrameOpened) + window.SetTitle(title) + window.SetHtmlPage(file) + window.SetClientSize(size) + window.Show() + +[ID_HTMLFRAME, ID_HTMLFRAMEHTMLCONTENT] = [wx.NewId() for _init_ctrls in range(2)] +EVT_HTML_URL_CLICK = wx.NewId() + +class HtmlWindowUrlClick(wx.PyEvent): + def __init__(self, linkinfo): + wx.PyEvent.__init__(self) + self.SetEventType(EVT_HTML_URL_CLICK) + self.linkinfo = (linkinfo.GetHref(), linkinfo.GetTarget()) + +class UrlClickHtmlWindow(wx.html.HtmlWindow): + """ HTML window that generates and OnLinkClicked event. + + Use this to avoid having to override HTMLWindow + """ + def OnLinkClicked(self, linkinfo): + wx.PostEvent(self, HtmlWindowUrlClick(linkinfo)) + + def Bind(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY): + if event == HtmlWindowUrlClick: + self.Connect(-1, -1, EVT_HTML_URL_CLICK, handler) + else: + wx.html.HtmlWindow.Bind(event, handler, source=source, id=id, id2=id2) + +class HtmlFrame(wx.Frame): + def _init_ctrls(self, prnt): + wx.Frame.__init__(self, id=ID_HTMLFRAME, name='HtmlFrame', + parent=prnt, pos=wx.Point(320, 231), size=wx.Size(853, 616), + style=wx.DEFAULT_FRAME_STYLE, title='') + self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + self.HtmlContent = UrlClickHtmlWindow(id=ID_HTMLFRAMEHTMLCONTENT, + name='HtmlContent', parent=self, pos=wx.Point(0, 0), + size=wx.Size(-1, -1), style=wx.html.HW_SCROLLBAR_AUTO|wx.html.HW_NO_SELECTION) + self.HtmlContent.Bind(HtmlWindowUrlClick, self.OnLinkClick) + + def __init__(self, parent, opened): + self._init_ctrls(parent) + self.HtmlFrameOpened = opened + + def SetHtmlCode(self, htmlcode): + self.HtmlContent.SetPage(htmlcode) + + def SetHtmlPage(self, htmlpage): + self.HtmlContent.LoadPage(htmlpage) + + def OnCloseFrame(self, event): + self.HtmlFrameOpened.remove(self.GetTitle()) + event.Skip() + + def OnLinkClick(self, event): + url = event.linkinfo[0] + try: + if wx.Platform == '__WXMSW__': + import webbrowser + webbrowser.open(url) + elif subprocess.call("firefox %s"%url, shell=True) != 0: + wx.MessageBox("""Firefox browser not found.\nPlease point your browser at :\n%s""" % url) + except ImportError: + wx.MessageBox('Please point your browser at: %s' % url) \ No newline at end of file diff -r 188906a7368c -r ce605c1a6d04 docutil/docpdf.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docutil/docpdf.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx, os + +readerexepath = None + +def get_acroversion(): + " Return version of Adobe Acrobat executable or None" + import _winreg + adobesoft = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\Adobe') + for index in range(_winreg.QueryInfoKey(adobesoft)[0]): + key = _winreg.EnumKey(adobesoft, index) + if "acrobat" in key.lower(): + acrokey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s' % key) + for index in range(_winreg.QueryInfoKey(acrokey)[0]): + numver = _winreg.EnumKey(acrokey, index) + try: + res = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s\\%s\\InstallPath' % (key, numver)) + return res + except: + pass + return None + +def open_win_pdf(readerexepath, pdffile, pagenum = None): + if pagenum != None : + os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", "/A", "page=%d=OpenActions" % pagenum, '"%s"'%pdffile) + else: + os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", '"%s"'%pdffile) + +def open_lin_pdf(readerexepath, pdffile, pagenum = None): + if pagenum == None : + os.system("%s -remote DS301 %s &"%(readerexepath, pdffile)) + else: + print "Open pdf %s at page %d"%(pdffile, pagenum) + os.system("%s -remote DS301 %s %d &"%(readerexepath, pdffile, pagenum)) + +def open_pdf(pdffile, pagenum = None): + if wx.Platform == '__WXMSW__' : + try: + readerpath = get_acroversion() + except: + wx.MessageBox("Acrobat Reader is not found or installed !") + return None + + readerexepath = os.path.join(readerpath, "AcroRd32.exe") + if(os.path.isfile(readerexepath)): + open_win_pdf(readerexepath, pdffile, pagenum) + else: + return None + else: + readerexepath = os.path.join("/usr/bin","xpdf") + if(os.path.isfile(readerexepath)): + open_lin_pdf(readerexepath, pdffile, pagenum) + else: + wx.MessageBox("xpdf is not found or installed !") + return None diff -r 188906a7368c -r ce605c1a6d04 docutil/docsvg.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docutil/docsvg.py Mon May 21 10:02:54 2012 +0200 @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor +#based on the plcopen standard. +# +#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD +# +#See COPYING file for copyrights details. +# +#This library is free software; you can redistribute it and/or +#modify it under the terms of the GNU General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This library is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#General Public License for more details. +# +#You should have received a copy of the GNU General Public +#License along with this library; if not, write to the Free Software +#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +import wx, os, subprocess + +def get_inkscape_path(): + """ Return the Inkscape path """ + import _winreg + svgexepath = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, + 'Software\\Classes\\svgfile\\shell\\Inkscape\\command') + svgexepath = svgexepath.replace('"%1"', '') + return svgexepath.replace('"', '') + +def open_win_svg(svgexepath, svgfile): + """ Open Inkscape on Windows platform """ + popenargs = [svgexepath] + if svgfile is not None : + popenargs.append(svgfile) + subprocess.Popen(popenargs).pid + +def open_lin_svg(svgexepath, svgfile): + """ Open Inkscape on Linux platform """ + if os.path.isfile("/usr/bin/inkscape"): + os.system("%s %s &"%(svgexepath , svgfile)) + +def open_svg(svgfile): + """ Generic function to open SVG file """ + if wx.Platform == '__WXMSW__' : + svgexepath = get_inkscape_path() + try: + open_win_svg(svgexepath , svgfile) + except: + wx.MessageBox("Inkscape is not found or installed !") + return None + else: + svgexepath = os.path.join("/usr/bin","inkscape") + if(os.path.isfile(svgexepath)): + open_lin_svg(svgexepath, svgfile) + else: + wx.MessageBox("Inkscape is not found or installed !") + return None + diff -r 188906a7368c -r ce605c1a6d04 docutils/__init__.py --- a/docutils/__init__.py Tue May 15 05:19:13 2012 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. -# -#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# -#See COPYING file for copyrights details. -# -#This library is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public -#License as published by the Free Software Foundation; either -#version 2.1 of the License, or (at your option) any later version. -# -#This library is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -#General Public License for more details. -# -#You should have received a copy of the GNU General Public -#License along with this library; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -from dochtml import * -from docpdf import * -from docsvg import * \ No newline at end of file diff -r 188906a7368c -r ce605c1a6d04 docutils/dochtml.py --- a/docutils/dochtml.py Tue May 15 05:19:13 2012 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. -# -#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# -#See COPYING file for copyrights details. -# -#This library is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public -#License as published by the Free Software Foundation; either -#version 2.1 of the License, or (at your option) any later version. -# -#This library is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -#General Public License for more details. -# -#You should have received a copy of the GNU General Public -#License along with this library; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import wx, os, wx.html, subprocess - -HtmlFrameOpened = [] - -def OpenHtmlFrame(self, title, file, size): - if title not in HtmlFrameOpened: - HtmlFrameOpened.append(title) - window = HtmlFrame(self, HtmlFrameOpened) - window.SetTitle(title) - window.SetHtmlPage(file) - window.SetClientSize(size) - window.Show() - -[ID_HTMLFRAME, ID_HTMLFRAMEHTMLCONTENT] = [wx.NewId() for _init_ctrls in range(2)] -EVT_HTML_URL_CLICK = wx.NewId() - -class HtmlWindowUrlClick(wx.PyEvent): - def __init__(self, linkinfo): - wx.PyEvent.__init__(self) - self.SetEventType(EVT_HTML_URL_CLICK) - self.linkinfo = (linkinfo.GetHref(), linkinfo.GetTarget()) - -class UrlClickHtmlWindow(wx.html.HtmlWindow): - """ HTML window that generates and OnLinkClicked event. - - Use this to avoid having to override HTMLWindow - """ - def OnLinkClicked(self, linkinfo): - wx.PostEvent(self, HtmlWindowUrlClick(linkinfo)) - - def Bind(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY): - if event == HtmlWindowUrlClick: - self.Connect(-1, -1, EVT_HTML_URL_CLICK, handler) - else: - wx.html.HtmlWindow.Bind(event, handler, source=source, id=id, id2=id2) - -class HtmlFrame(wx.Frame): - def _init_ctrls(self, prnt): - wx.Frame.__init__(self, id=ID_HTMLFRAME, name='HtmlFrame', - parent=prnt, pos=wx.Point(320, 231), size=wx.Size(853, 616), - style=wx.DEFAULT_FRAME_STYLE, title='') - self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) - - self.HtmlContent = UrlClickHtmlWindow(id=ID_HTMLFRAMEHTMLCONTENT, - name='HtmlContent', parent=self, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.html.HW_SCROLLBAR_AUTO|wx.html.HW_NO_SELECTION) - self.HtmlContent.Bind(HtmlWindowUrlClick, self.OnLinkClick) - - def __init__(self, parent, opened): - self._init_ctrls(parent) - self.HtmlFrameOpened = opened - - def SetHtmlCode(self, htmlcode): - self.HtmlContent.SetPage(htmlcode) - - def SetHtmlPage(self, htmlpage): - self.HtmlContent.LoadPage(htmlpage) - - def OnCloseFrame(self, event): - self.HtmlFrameOpened.remove(self.GetTitle()) - event.Skip() - - def OnLinkClick(self, event): - url = event.linkinfo[0] - try: - if wx.Platform == '__WXMSW__': - import webbrowser - webbrowser.open(url) - elif subprocess.call("firefox %s"%url, shell=True) != 0: - wx.MessageBox("""Firefox browser not found.\nPlease point your browser at :\n%s""" % url) - except ImportError: - wx.MessageBox('Please point your browser at: %s' % url) \ No newline at end of file diff -r 188906a7368c -r ce605c1a6d04 docutils/docpdf.py --- a/docutils/docpdf.py Tue May 15 05:19:13 2012 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. -# -#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# -#See COPYING file for copyrights details. -# -#This library is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public -#License as published by the Free Software Foundation; either -#version 2.1 of the License, or (at your option) any later version. -# -#This library is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -#General Public License for more details. -# -#You should have received a copy of the GNU General Public -#License along with this library; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import wx, os - -readerexepath = None - -def get_acroversion(): - " Return version of Adobe Acrobat executable or None" - import _winreg - adobesoft = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, r'Software\Adobe') - for index in range(_winreg.QueryInfoKey(adobesoft)[0]): - key = _winreg.EnumKey(adobesoft, index) - if "acrobat" in key.lower(): - acrokey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s' % key) - for index in range(_winreg.QueryInfoKey(acrokey)[0]): - numver = _winreg.EnumKey(acrokey, index) - try: - res = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s\\%s\\InstallPath' % (key, numver)) - return res - except: - pass - return None - -def open_win_pdf(readerexepath, pdffile, pagenum = None): - if pagenum != None : - os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", "/A", "page=%d=OpenActions" % pagenum, '"%s"'%pdffile) - else: - os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", '"%s"'%pdffile) - -def open_lin_pdf(readerexepath, pdffile, pagenum = None): - if pagenum == None : - os.system("%s -remote DS301 %s &"%(readerexepath, pdffile)) - else: - print "Open pdf %s at page %d"%(pdffile, pagenum) - os.system("%s -remote DS301 %s %d &"%(readerexepath, pdffile, pagenum)) - -def open_pdf(pdffile, pagenum = None): - if wx.Platform == '__WXMSW__' : - try: - readerpath = get_acroversion() - except: - wx.MessageBox("Acrobat Reader is not found or installed !") - return None - - readerexepath = os.path.join(readerpath, "AcroRd32.exe") - if(os.path.isfile(readerexepath)): - open_win_pdf(readerexepath, pdffile, pagenum) - else: - return None - else: - readerexepath = os.path.join("/usr/bin","xpdf") - if(os.path.isfile(readerexepath)): - open_lin_pdf(readerexepath, pdffile, pagenum) - else: - wx.MessageBox("xpdf is not found or installed !") - return None diff -r 188906a7368c -r ce605c1a6d04 docutils/docsvg.py --- a/docutils/docsvg.py Tue May 15 05:19:13 2012 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor -#based on the plcopen standard. -# -#Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD -# -#See COPYING file for copyrights details. -# -#This library is free software; you can redistribute it and/or -#modify it under the terms of the GNU General Public -#License as published by the Free Software Foundation; either -#version 2.1 of the License, or (at your option) any later version. -# -#This library is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -#General Public License for more details. -# -#You should have received a copy of the GNU General Public -#License along with this library; if not, write to the Free Software -#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -import wx, os, subprocess - -def get_inkscape_path(): - """ Return the Inkscape path """ - import _winreg - svgexepath = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, - 'Software\\Classes\\svgfile\\shell\\Inkscape\\command') - svgexepath = svgexepath.replace('"%1"', '') - return svgexepath.replace('"', '') - -def open_win_svg(svgexepath, svgfile): - """ Open Inkscape on Windows platform """ - popenargs = [svgexepath] - if svgfile is not None : - popenargs.append(svgfile) - subprocess.Popen(popenargs).pid - -def open_lin_svg(svgexepath, svgfile): - """ Open Inkscape on Linux platform """ - if os.path.isfile("/usr/bin/inkscape"): - os.system("%s %s &"%(svgexepath , svgfile)) - -def open_svg(svgfile): - """ Generic function to open SVG file """ - if wx.Platform == '__WXMSW__' : - svgexepath = get_inkscape_path() - try: - open_win_svg(svgexepath , svgfile) - except: - wx.MessageBox("Inkscape is not found or installed !") - return None - else: - svgexepath = os.path.join("/usr/bin","inkscape") - if(os.path.isfile(svgexepath)): - open_lin_svg(svgexepath, svgfile) - else: - wx.MessageBox("Inkscape is not found or installed !") - return None - diff -r 188906a7368c -r ce605c1a6d04 graphics/FBD_Objects.py --- a/graphics/FBD_Objects.py Tue May 15 05:19:13 2012 +0900 +++ b/graphics/FBD_Objects.py Mon May 21 10:02:54 2012 +0200 @@ -263,6 +263,7 @@ self.Pen = MiterPen(self.Colour) # Extract the inputs properties and create or modify the corresponding connector + idx = 0 for idx, (input_name, input_type, input_modifier) in enumerate(inputs): if idx < len(self.Inputs): connector = self.Inputs[idx] @@ -280,6 +281,7 @@ self.Inputs = self.Inputs[:idx + 1] # Extract the outputs properties and create or modify the corresponding connector + idx = 0 for idx, (output_name, output_type, output_modifier) in enumerate(outputs): if idx < len(self.Outputs): connector = self.Outputs[idx] diff -r 188906a7368c -r ce605c1a6d04 plcopen/plcopen.py --- a/plcopen/plcopen.py Tue May 15 05:19:13 2012 +0900 +++ b/plcopen/plcopen.py Mon May 21 10:02:54 2012 +0200 @@ -234,8 +234,10 @@ self.contentHeader.setauthor(contentheader["authorName"]) if contentheader.has_key("language"): self.contentHeader.setlanguage(contentheader["language"]) - self.contentHeader.setpageSize(*contentheader["pageSize"]) - self.contentHeader.setscaling(contentheader["scaling"]) + if contentheader.has_key("pageSize"): + self.contentHeader.setpageSize(*contentheader["pageSize"]) + if contentheader.has_key("scaling"): + self.contentHeader.setscaling(contentheader["scaling"]) setattr(cls, "setcontentHeader", setcontentHeader) def getdataTypes(self): diff -r 188906a7368c -r ce605c1a6d04 xmlclass/xmlclass.py --- a/xmlclass/xmlclass.py Tue May 15 05:19:13 2012 +0900 +++ b/xmlclass/xmlclass.py Mon May 21 10:02:54 2012 +0200 @@ -1238,15 +1238,16 @@ classmembers["setElementValue"] = generateSetElementValue(self, classinfos) classmembers["singleLineAttributes"] = True classmembers["compatibility"] = lambda x, y: None + classmembers["extraAttrs"] = {} class_definition = classobj(str(classname), bases, classmembers) setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos)) class_infos = {"type": COMPILEDCOMPLEXTYPE, - "name": classname, - "check": generateClassCheckFunction(class_definition), - "initial": generateClassCreateFunction(class_definition), - "extract": generateClassExtractFunction(class_definition), - "generate": class_definition.generateXMLText} + "name": classname, + "check": generateClassCheckFunction(class_definition), + "initial": generateClassCreateFunction(class_definition), + "extract": generateClassExtractFunction(class_definition), + "generate": class_definition.generateXMLText} if self.FileName is not None: self.ComputedClasses[self.FileName][classname] = class_definition @@ -1410,6 +1411,7 @@ elements = dict([(element["name"], element) for element in classinfos["elements"]]) def loadXMLTreeMethod(self, tree, extras=[], derived=False): + self.extraAttrs = {} self.compatibility(tree) if not derived: children_structure = "" @@ -1430,8 +1432,8 @@ if attributes.has_key(attrname): attributes[attrname]["attr_type"] = FindTypeInfos(factory, attributes[attrname]["attr_type"]) object.__setattr__(self, attrname, attributes[attrname]["attr_type"]["extract"](attr)) - elif not classinfos.has_key("base") and attrname not in extras: - raise ValueError("Invalid attribute \"%s\" for \"%s\" element!" % (attrname, tree.nodeName)) + elif not classinfos.has_key("base") and not attrname in extras and not self.extraAttrs.has_key(attrname): + self.extraAttrs[attrname] = GetAttributeValue(attr) required_attributes.pop(attrname, None) if len(required_attributes) > 0: raise ValueError("Required attributes %s missing for \"%s\" element!" % (", ".join(["\"%s\""%name for name in required_attributes]), tree.nodeName)) @@ -1489,8 +1491,10 @@ text = u'' first = True + if not classinfos.has_key("base"): - for attr, value in extras.items(): + extras.update(self.extraAttrs) + for attr, value in extras.iteritems(): if not first and not self.singleLineAttributes: text += u'\n%s' % (ind2) text += u' %s=%s' % (attr, quoteattr(value)) @@ -1643,7 +1647,7 @@ elif element["elmt_type"]["type"] == SIMPLETYPE: children.append({"name": element_name, "require": element["minOccurs"] != 0, "type": gettypeinfos(element["elmt_type"]["basename"], - element["elmt_type"]["facets"]), + element["elmt_type"]["facets"]), "value": getattr(self, element_name, None)}) else: instance = getattr(self, element_name, None) @@ -1677,6 +1681,9 @@ setattr(self, parts[0], elements[parts[0]]["elmt_type"]["extract"](value, False)) else: instance = getattr(self, parts[0], None) + if instance is None and elements[parts[0]]["minOccurs"] == 0: + instance = elements[parts[0]]["elmt_type"]["initial"]() + setattr(self, parts[0], instance) if instance != None: if len(parts) > 1: instance.setElementValue(parts[1], value) @@ -1702,6 +1709,7 @@ """ def generateInitMethod(factory, classinfos): def initMethod(self): + self.extraAttrs = {} if classinfos.has_key("base"): classinfos["base"].__init__(self) for attribute in classinfos["attributes"]: @@ -1837,14 +1845,8 @@ """ This function generate the classes from a class factory """ -def GenerateClasses(factory, declare=False): +def GenerateClasses(factory): ComputedClasses = factory.CreateClasses() - #factory.PrintClasses() - if declare: - for ClassName, Class in pluginClasses.items(): - sys._getframe(1).f_locals[ClassName] = Class - for TypeName, Type in pluginTypes.items(): - sys._getframe(1).f_locals[TypeName] = Type if factory.FileName is not None and len(ComputedClasses) == 1: globals().update(ComputedClasses[factory.FileName]) return ComputedClasses[factory.FileName] diff -r 188906a7368c -r ce605c1a6d04 xmlclass/xsdschema.py --- a/xmlclass/xsdschema.py Tue May 15 05:19:13 2012 +0900 +++ b/xmlclass/xsdschema.py Mon May 21 10:02:54 2012 +0200 @@ -1086,17 +1086,17 @@ """ This function opens the xsd file and generate the classes from the xml tree """ -def GenerateClassesFromXSD(filepath, declare=False): +def GenerateClassesFromXSD(filepath): xsdfile = open(filepath, 'r') factory = XSDClassFactory(minidom.parse(xsdfile), filepath) xsdfile.close() - return GenerateClasses(factory, declare) + return GenerateClasses(factory) """ This function generate the classes from the xsd given as a string """ -def GenerateClassesFromXSDstring(xsdstring, declare=False): - return GenerateClasses(XSDClassFactory(minidom.parseString(xsdstring)), declare) +def GenerateClassesFromXSDstring(xsdstring): + return GenerateClasses(XSDClassFactory(minidom.parseString(xsdstring))) #-------------------------------------------------------------------------------