# HG changeset patch # User Edouard Tisserant # Date 1336409249 -7200 # Node ID 1c23952dbde1d9f366432c4253f593e15a4234c7 # Parent 180e4a7d945ce442f31394959521c1adb878d9f4 refactoring diff -r 180e4a7d945c -r 1c23952dbde1 Beremiz.py --- a/Beremiz.py Thu May 03 19:02:34 2012 +0200 +++ b/Beremiz.py Mon May 07 18:47:29 2012 +0200 @@ -146,13 +146,13 @@ import TextCtrlAutoComplete, cPickle from BrowseValuesLibraryDialog import BrowseValuesLibraryDialog import types, time, re, platform, time, traceback, commands -from plugger import PluginsRoot, MiniTextControler, MATIEC_ERROR_MODEL +from ConfigTree import ConfigTreeRoot, MiniTextControler, MATIEC_ERROR_MODEL from wxPopen import ProcessLogger from docutils import * from PLCOpenEditor import IDEFrame, AppendMenu, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, TYPESTREE, INSTANCESTREE, LIBRARYTREE, SCALING, PAGETITLES, USE_AUI from PLCOpenEditor import EditorPanel, Viewer, TextViewer, GraphicViewer, ResourceEditor, ConfigurationEditor, DataTypeEditor -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 SCROLLBAR_UNIT = 10 WINDOW_COLOUR = wx.Colour(240,240,240) @@ -378,18 +378,18 @@ [ID_FILEMENURECENTPROJECTS, ] = [wx.NewId() for _init_ctrls in range(1)] -PLUGINMENU_POSITION = 3 +CONFNODEMENU_POSITION = 3 class Beremiz(IDEFrame): def _init_coll_MenuBar_Menus(self, parent): IDEFrame._init_coll_MenuBar_Menus(self, parent) - parent.Insert(pos=PLUGINMENU_POSITION, - menu=self.PluginMenu, title=_(u'&Plugin')) + parent.Insert(pos=CONFNODEMENU_POSITION, + menu=self.ConfNodeMenu, title=_(u'&ConfNode')) def _init_utils(self): - self.PluginMenu = wx.Menu(title='') + self.ConfNodeMenu = wx.Menu(title='') self.RecentProjectsMenu = wx.Menu(title='') IDEFrame._init_utils(self) @@ -451,25 +451,25 @@ def _init_coll_PLCConfigMainSizer_Items(self, parent): parent.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT) - parent.AddSizer(self.PluginTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT) + parent.AddSizer(self.ConfNodeTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT) def _init_coll_PLCConfigMainSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableRow(1) - def _init_coll_PluginTreeSizer_Growables(self, parent): + def _init_coll_ConfNodeTreeSizer_Growables(self, parent): parent.AddGrowableCol(0) parent.AddGrowableCol(1) def _init_beremiz_sizers(self): self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2) self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL) - #self.PluginTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2) - self.PluginTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2) + #self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=3, hgap=0, rows=0, vgap=2) + self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2) self._init_coll_PLCConfigMainSizer_Items(self.PLCConfigMainSizer) self._init_coll_PLCConfigMainSizer_Growables(self.PLCConfigMainSizer) - self._init_coll_PluginTreeSizer_Growables(self.PluginTreeSizer) + self._init_coll_ConfNodeTreeSizer_Growables(self.ConfNodeTreeSizer) self.PLCConfig.SetSizer(self.PLCConfigMainSizer) @@ -485,8 +485,8 @@ ("Build", wx.WXK_F11)]: def OnMethodGen(obj,meth): def OnMethod(evt): - if obj.PluginRoot is not None: - obj.PluginRoot.CallMethod('_'+meth) + if obj.CTR is not None: + obj.CTR.CallMethod('_'+meth) wx.CallAfter(self.RefreshAll) return OnMethod newid = wx.NewId() @@ -516,7 +516,7 @@ self._init_beremiz_sizers() - def __init__(self, parent, projectOpen=None, buildpath=None, plugin_root=None, debug=True): + def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True): IDEFrame.__init__(self, parent, debug) self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole) @@ -530,7 +530,7 @@ self.LastPanelSelected = None - self.PluginInfos = {} + self.ConfNodeInfos = {} # Define Tree item icon list self.LocationImageList = wx.ImageList(16, 16) @@ -538,7 +538,7 @@ # Icons for location items for imgname, itemtype in [ - ("CONFIGURATION", LOCATION_PLUGIN), + ("CONFIGURATION", LOCATION_CONFNODE), ("RESOURCE", LOCATION_MODULE), ("PROGRAM", LOCATION_GROUP), ("VAR_INPUT", LOCATION_VAR_INPUT), @@ -555,9 +555,9 @@ projectOpen = None if projectOpen is not None and os.path.isdir(projectOpen): - self.PluginRoot = PluginsRoot(self, self.Log) - self.Controler = self.PluginRoot - result = self.PluginRoot.LoadProject(projectOpen, buildpath) + self.CTR = ConfigTreeRoot(self, self.Log) + self.Controler = self.CTR + result = self.CTR.LoadProject(projectOpen, buildpath) if not result: self.LibraryPanel.SetControler(self.Controler) self.RefreshConfigRecentProjects(os.path.abspath(projectOpen)) @@ -567,19 +567,19 @@ self.ResetView() self.ShowErrorMessage(result) else: - self.PluginRoot = plugin_root - self.Controler = plugin_root - if plugin_root is not None: + self.CTR = ctr + self.Controler = ctr + if ctr is not None: self.LibraryPanel.SetControler(self.Controler) self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() if self.EnableDebug: - self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self.DebugVariablePanel.SetDataProducer(self.CTR) self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU) - self.RefreshPluginMenu() + self.RefreshConfNodeMenu() self.LogConsole.SetFocus() def RiseLogConsole(self): @@ -587,9 +587,9 @@ def RefreshTitle(self): name = _("Beremiz") - if self.PluginRoot is not None: - projectname = self.PluginRoot.GetProjectName() - if self.PluginRoot.ProjectTestModified(): + if self.CTR is not None: + projectname = self.CTR.GetProjectName() + if self.CTR.ProjectTestModified(): projectname = "~%s~" % projectname self.SetTitle("%s - %s" % (name, projectname)) else: @@ -640,20 +640,20 @@ event.Skip() def SearchLineForError(self): - if self.PluginRoot is not None: + if self.CTR is not None: text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint()) line = self.LogConsole.GetLineText(len(text.splitlines()) - 1) result = MATIEC_ERROR_MODEL.match(line) if result is not None: first_line, first_column, last_line, last_column, error = result.groups() - infos = self.PluginRoot.ShowError(self.Log, + infos = self.CTR.ShowError(self.Log, (int(first_line), int(first_column)), (int(last_line), int(last_column))) ## Function displaying an Error dialog in PLCOpenEditor. # @return False if closing cancelled. def CheckSaveBeforeClosing(self, title=_("Close Project")): - if self.PluginRoot.ProjectTestModified(): + if self.CTR.ProjectTestModified(): dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), title, @@ -661,7 +661,7 @@ answer = dialog.ShowModal() dialog.Destroy() if answer == wx.ID_YES: - self.PluginRoot.SaveProject() + self.CTR.SaveProject() elif answer == wx.ID_CANCEL: return False return True @@ -674,33 +674,33 @@ ResourceEditor, ConfigurationEditor, DataTypeEditor))): - return ("plugin", tab.Controler.PlugFullName()) + return ("confnode", tab.Controler.PlugFullName()) elif (isinstance(tab, TextViewer) and (tab.Controler is None or isinstance(tab.Controler, MiniTextControler))): - return ("plugin", None, tab.GetInstancePath()) + return ("confnode", None, tab.GetInstancePath()) else: return IDEFrame.GetTabInfos(self, tab) def LoadTab(self, notebook, page_infos): - if page_infos[0] == "plugin": + if page_infos[0] == "confnode": if page_infos[1] is None: - plugin = self.PluginRoot + confnode = self.CTR else: - plugin = self.PluginRoot.GetChildByName(page_infos[1]) - return notebook.GetPageIndex(plugin._OpenView(*page_infos[2:])) + confnode = self.CTR.GetChildByName(page_infos[1]) + return notebook.GetPageIndex(confnode._OpenView(*page_infos[2:])) else: return IDEFrame.LoadTab(self, notebook, page_infos) def OnCloseFrame(self, event): - if self.PluginRoot is None or self.CheckSaveBeforeClosing(_("Close Application")): - if self.PluginRoot is not None: - self.PluginRoot.KillDebugThread() + if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")): + if self.CTR is not None: + self.CTR.KillDebugThread() self.KillLocalRuntime() self.SaveLastState() - if self.PluginRoot is not None: - project_path = os.path.realpath(self.PluginRoot.GetProjectPath()) + if self.CTR is not None: + project_path = os.path.realpath(self.CTR.GetProjectPath()) else: project_path = "" self.Config.Write("currenteditedproject", project_path) @@ -732,7 +732,7 @@ self.RefreshRecentProjectsMenu() MenuToolBar = self.Panes["MenuToolBar"] - if self.PluginRoot is not None: + if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) @@ -754,7 +754,7 @@ self.FileMenu.Enable(wx.ID_PRINT, False) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) - project_modified = self.PluginRoot.ProjectTestModified() + project_modified = self.CTR.ProjectTestModified() self.FileMenu.Enable(wx.ID_SAVE, project_modified) MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) self.FileMenu.Enable(wx.ID_SAVEAS, True) @@ -789,7 +789,7 @@ def GenerateOpenRecentProjectFunction(self, projectpath): def OpenRecentProject(event): - if self.PluginRoot is not None and not self.CheckSaveBeforeClosing(): + if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.OpenProject(projectpath) @@ -810,28 +810,28 @@ if callback is not None: self.Bind(wx.EVT_MENU, callback, id=id) - def RefreshPluginMenu(self): - if self.PluginRoot is not None: + def RefreshConfNodeMenu(self): + if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: panel = self.TabsOpened.GetPage(selected) else: panel = None if panel != self.LastPanelSelected: - for i in xrange(self.PluginMenu.GetMenuItemCount()): - item = self.PluginMenu.FindItemByPosition(0) - self.PluginMenu.Delete(item.GetId()) + for i in xrange(self.ConfNodeMenu.GetMenuItemCount()): + item = self.ConfNodeMenu.FindItemByPosition(0) + self.ConfNodeMenu.Delete(item.GetId()) self.LastPanelSelected = panel if panel is not None: - items = panel.GetPluginMenuItems() + items = panel.GetConfNodeMenuItems() else: items = [] - self.MenuBar.EnableTop(PLUGINMENU_POSITION, len(items) > 0) - self.GenerateMenuRecursive(items, self.PluginMenu) + self.MenuBar.EnableTop(CONFNODEMENU_POSITION, len(items) > 0) + self.GenerateMenuRecursive(items, self.ConfNodeMenu) if panel is not None: - panel.RefreshPluginMenu(self.PluginMenu) - else: - self.MenuBar.EnableTop(PLUGINMENU_POSITION, False) + panel.RefreshConfNodeMenu(self.ConfNodeMenu) + else: + self.MenuBar.EnableTop(CONFNODEMENU_POSITION, False) self.MenuBar.UpdateMenus() def RefreshScrollBars(self): @@ -850,15 +850,15 @@ self.Freeze() self.ClearSizer(self.PLCParamsSizer) - if self.PluginRoot is not None: + if self.CTR is not None: plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) - if self.PluginRoot.PlugTestModified(): + if self.CTR.PlugTestModified(): bkgdclr = CHANGED_TITLE_COLOUR else: bkgdclr = TITLE_COLOUR - if self.PluginRoot not in self.PluginInfos: - self.PluginInfos[self.PluginRoot] = {"right_visible" : False} + if self.CTR not in self.ConfNodeInfos: + self.ConfNodeInfos[self.CTR] = {"right_visible" : False} plcwindow.SetBackgroundColour(TITLE_COLOUR) plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown) @@ -869,15 +869,15 @@ st = wx.StaticText(plcwindow, -1) st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - st.SetLabel(self.PluginRoot.GetProjectName()) + st.SetLabel(self.CTR.GetProjectName()) plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER) addbutton_id = wx.NewId() addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')), - name='AddPluginButton', parent=plcwindow, pos=wx.Point(0, 0), + name='AddConfNodeButton', parent=plcwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) - addbutton.SetToolTipString(_("Add a sub plugin")) - addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddPluginMenu(self.PluginRoot), id=addbutton_id) + addbutton.SetToolTipString(_("Add a sub confnode")) + addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(self.CTR), id=addbutton_id) plcwindowsizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER) plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL) @@ -886,7 +886,7 @@ plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL) plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER) - msizer = self.GenerateMethodButtonSizer(self.PluginRoot, plcwindow, not self.PluginInfos[self.PluginRoot]["right_visible"]) + msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"]) plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW) paramswindow = wx.Panel(plcwindow, -1, size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL) @@ -897,10 +897,10 @@ psizer = wx.BoxSizer(wx.HORIZONTAL) paramswindow.SetSizer(psizer) - plugin_infos = self.PluginRoot.GetParamsAttributes() - self.RefreshSizerElement(paramswindow, psizer, self.PluginRoot, plugin_infos, None, False) - - if not self.PluginInfos[self.PluginRoot]["right_visible"]: + confnode_infos = self.CTR.GetParamsAttributes() + self.RefreshSizerElement(paramswindow, psizer, self.CTR, confnode_infos, None, False) + + if not self.ConfNodeInfos[self.CTR]["right_visible"]: paramswindow.Hide() minimizebutton_id = wx.NewId() @@ -909,7 +909,7 @@ size=wx.Size(24, 24), style=wx.NO_BORDER) make_genbitmaptogglebutton_flat(minimizebutton) minimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png'))) - minimizebutton.SetToggle(self.PluginInfos[self.PluginRoot]["right_visible"]) + minimizebutton.SetToggle(self.ConfNodeInfos[self.CTR]["right_visible"]) plcwindowbuttonsizer.AddWindow(minimizebutton, 0, border=5, flag=wx.ALL) def togglewindow(event): @@ -918,32 +918,32 @@ msizer.SetCols(1) else: paramswindow.Hide() - msizer.SetCols(len(self.PluginRoot.PluginMethods)) - self.PluginInfos[self.PluginRoot]["right_visible"] = minimizebutton.GetToggle() + msizer.SetCols(len(self.CTR.ConfNodeMethods)) + self.ConfNodeInfos[self.CTR]["right_visible"] = minimizebutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() event.Skip() minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id) - self.PluginInfos[self.PluginRoot]["main"] = plcwindow - self.PluginInfos[self.PluginRoot]["params"] = paramswindow + self.ConfNodeInfos[self.CTR]["main"] = plcwindow + self.ConfNodeInfos[self.CTR]["params"] = paramswindow self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() self.Thaw() - def GenerateEnableButton(self, parent, sizer, plugin): - enabled = plugin.PlugEnabled() + def GenerateEnableButton(self, parent, sizer, confnode): + enabled = confnode.PlugEnabled() if enabled is not None: enablebutton_id = wx.NewId() enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')), name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER) - enablebutton.SetToolTipString(_("Enable/Disable this plugin")) + enablebutton.SetToolTipString(_("Enable/Disable this confnode")) make_genbitmaptogglebutton_flat(enablebutton) enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png'))) enablebutton.SetToggle(enabled) def toggleenablebutton(event): - res = self.SetPluginParamsAttribute(plugin, "BaseParams.Enabled", enablebutton.GetToggle()) + res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.Enabled", enablebutton.GetToggle()) enablebutton.SetToggle(res) event.Skip() enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id) @@ -951,23 +951,23 @@ else: sizer.AddSpacer(wx.Size(16, 16)) - def GenerateMethodButtonSizer(self, plugin, parent, horizontal = True): + def GenerateMethodButtonSizer(self, confnode, parent, horizontal = True): normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"]) mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"]) if horizontal: - msizer = wx.FlexGridSizer(cols=len(plugin.PluginMethods)) + msizer = wx.FlexGridSizer(cols=len(confnode.ConfNodeMethods)) else: msizer = wx.FlexGridSizer(cols=1) - for plugin_method in plugin.PluginMethods: - if "method" in plugin_method and plugin_method.get("shown",True): + for confnode_method in confnode.ConfNodeMethods: + if "method" in confnode_method and confnode_method.get("shown",True): id = wx.NewId() - label = plugin_method["name"] + label = confnode_method["name"] button = GenBitmapTextButton(id=id, parent=parent, - bitmap=wx.Bitmap(Bpath( "%s.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=label, + bitmap=wx.Bitmap(Bpath( "%s.png"%confnode_method.get("bitmap", os.path.join("images", "Unknown")))), label=label, name=label, pos=wx.DefaultPosition, style=wx.NO_BORDER) button.SetFont(normal_bt_font) - button.SetToolTipString(plugin_method["tooltip"]) - button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(plugin, plugin_method["method"]), id=id) + button.SetToolTipString(confnode_method["tooltip"]) + button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode, confnode_method["method"]), id=id) # a fancy underline on mouseover def setFontStyle(b, s): def fn(event): @@ -978,12 +978,12 @@ button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font)) button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font)) #hack to force size to mini - if not plugin_method.get("enabled",True): + if not confnode_method.get("enabled",True): button.Disable() msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER) return msizer - def GenerateParamsPanel(self, plugin, bkgdclr, top_offset=0): + def GenerateParamsPanel(self, confnode, bkgdclr, top_offset=0): rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) rightwindow.SetBackgroundColour(bkgdclr) @@ -995,7 +995,7 @@ rightwindowsizer.AddGrowableRow(0) rightwindowmainsizer.AddSizer(rightwindowsizer, 0, border=0, flag=wx.GROW) - msizer = self.GenerateMethodButtonSizer(plugin, rightwindow, not self.PluginInfos[plugin]["right_visible"]) + msizer = self.GenerateMethodButtonSizer(confnode, rightwindow, not self.ConfNodeInfos[confnode]["right_visible"]) rightwindowsizer.AddSizer(msizer, 0, border=top_offset, flag=wx.TOP|wx.GROW) rightparamssizer = wx.BoxSizer(wx.HORIZONTAL) @@ -1006,15 +1006,15 @@ psizer = wx.BoxSizer(wx.VERTICAL) paramswindow.SetSizer(psizer) - self.PluginInfos[plugin]["params"] = paramswindow + self.ConfNodeInfos[confnode]["params"] = paramswindow rightparamssizer.AddWindow(paramswindow, 0, border=5, flag=wx.ALL) - plugin_infos = plugin.GetParamsAttributes() - if len(plugin_infos) > 0: - self.RefreshSizerElement(paramswindow, psizer, plugin, plugin_infos, None, False) - - if not self.PluginInfos[plugin]["right_visible"]: + confnode_infos = confnode.GetParamsAttributes() + if len(confnode_infos) > 0: + self.RefreshSizerElement(paramswindow, psizer, confnode, confnode_infos, None, False) + + if not self.ConfNodeInfos[confnode]["right_visible"]: paramswindow.Hide() rightminimizebutton_id = wx.NewId() @@ -1023,7 +1023,7 @@ size=wx.Size(24, 24), style=wx.NO_BORDER) make_genbitmaptogglebutton_flat(rightminimizebutton) rightminimizebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Minimize.png'))) - rightminimizebutton.SetToggle(self.PluginInfos[plugin]["right_visible"]) + rightminimizebutton.SetToggle(self.ConfNodeInfos[confnode]["right_visible"]) rightparamssizer.AddWindow(rightminimizebutton, 0, border=5, flag=wx.ALL) def togglerightwindow(event): @@ -1032,8 +1032,8 @@ msizer.SetCols(1) else: rightparamssizer.Hide(0) - msizer.SetCols(len(plugin.PluginMethods)) - self.PluginInfos[plugin]["right_visible"] = rightminimizebutton.GetToggle() + msizer.SetCols(len(confnode.ConfNodeMethods)) + self.ConfNodeInfos[confnode]["right_visible"] = rightminimizebutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() event.Skip() @@ -1042,58 +1042,58 @@ return rightwindow - def RefreshPluginTree(self): + def RefreshConfNodeTree(self): self.Freeze() - self.ClearSizer(self.PluginTreeSizer) - if self.PluginRoot is not None: - for child in self.PluginRoot.IECSortedChilds(): + self.ClearSizer(self.ConfNodeTreeSizer) + if self.CTR is not None: + for child in self.CTR.IECSortedChilds(): self.GenerateTreeBranch(child) - if not self.PluginInfos[child]["expanded"]: - self.CollapsePlugin(child) + if not self.ConfNodeInfos[child]["expanded"]: + self.CollapseConfNode(child) self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() self.Thaw() - def SetPluginParamsAttribute(self, plugin, *args, **kwargs): - res, StructChanged = plugin.SetParamsAttribute(*args, **kwargs) + def SetConfNodeParamsAttribute(self, confnode, *args, **kwargs): + res, StructChanged = confnode.SetParamsAttribute(*args, **kwargs) if StructChanged: - wx.CallAfter(self.RefreshPluginTree) - else: - if plugin == self.PluginRoot: + wx.CallAfter(self.RefreshConfNodeTree) + else: + if confnode == self.CTR: bkgdclr = CHANGED_TITLE_COLOUR items = ["main", "params"] else: bkgdclr = CHANGED_WINDOW_COLOUR items = ["left", "right", "params"] for i in items: - self.PluginInfos[plugin][i].SetBackgroundColour(bkgdclr) - self.PluginInfos[plugin][i].Refresh() + self.ConfNodeInfos[confnode][i].SetBackgroundColour(bkgdclr) + self.ConfNodeInfos[confnode][i].Refresh() self._Refresh(TITLE, FILEMENU) return res - def ExpandPlugin(self, plugin, force = False): - for child in self.PluginInfos[plugin]["children"]: - self.PluginInfos[child]["left"].Show() - self.PluginInfos[child]["right"].Show() - if force or self.PluginInfos[child]["expanded"]: - self.ExpandPlugin(child, force) + def ExpandConfNode(self, confnode, force = False): + for child in self.ConfNodeInfos[confnode]["children"]: + self.ConfNodeInfos[child]["left"].Show() + self.ConfNodeInfos[child]["right"].Show() + if force or self.ConfNodeInfos[child]["expanded"]: + self.ExpandConfNode(child, force) if force: - self.PluginInfos[child]["expanded"] = True - locations_infos = self.PluginInfos[plugin].get("locations_infos", None) + self.ConfNodeInfos[child]["expanded"] = True + locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None) if locations_infos is not None: if force or locations_infos["root"]["expanded"]: self.ExpandLocation(locations_infos, "root", force) if force: locations_infos["root"]["expanded"] = True - def CollapsePlugin(self, plugin, force = False): - for child in self.PluginInfos[plugin]["children"]: - self.PluginInfos[child]["left"].Hide() - self.PluginInfos[child]["right"].Hide() - self.CollapsePlugin(child, force) + def CollapseConfNode(self, confnode, force = False): + for child in self.ConfNodeInfos[confnode]["children"]: + self.ConfNodeInfos[child]["left"].Hide() + self.ConfNodeInfos[child]["right"].Hide() + self.CollapseConfNode(child, force) if force: - self.PluginInfos[child]["expanded"] = False - locations_infos = self.PluginInfos[plugin].get("locations_infos", None) + self.ConfNodeInfos[child]["expanded"] = False + locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None) if locations_infos is not None: self.CollapseLocation(locations_infos, "root", force) if force: @@ -1129,30 +1129,30 @@ if locations_infos["root"]["left"] is not None and refresh_size: self.RefreshTreeCtrlSize(locations_infos["root"]["left"]) - def GenerateTreeBranch(self, plugin): + def GenerateTreeBranch(self, confnode): leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) - if plugin.PlugTestModified(): + if confnode.PlugTestModified(): bkgdclr=CHANGED_WINDOW_COLOUR else: bkgdclr=WINDOW_COLOUR leftwindow.SetBackgroundColour(bkgdclr) - if not self.PluginInfos.has_key(plugin): - self.PluginInfos[plugin] = {"expanded" : False, "right_visible" : False} - - self.PluginInfos[plugin]["children"] = plugin.IECSortedChilds() - plugin_locations = [] - if len(self.PluginInfos[plugin]["children"]) == 0: - plugin_locations = plugin.GetVariableLocationTree()["children"] - if not self.PluginInfos[plugin].has_key("locations_infos"): - self.PluginInfos[plugin]["locations_infos"] = {"root": {"expanded" : False}} - - self.PluginInfos[plugin]["locations_infos"]["root"]["left"] = None - self.PluginInfos[plugin]["locations_infos"]["root"]["right"] = None - self.PluginInfos[plugin]["locations_infos"]["root"]["children"] = [] - - self.PluginTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW) + if not self.ConfNodeInfos.has_key(confnode): + self.ConfNodeInfos[confnode] = {"expanded" : False, "right_visible" : False} + + self.ConfNodeInfos[confnode]["children"] = confnode.IECSortedChilds() + confnode_locations = [] + if len(self.ConfNodeInfos[confnode]["children"]) == 0: + confnode_locations = confnode.GetVariableLocationTree()["children"] + if not self.ConfNodeInfos[confnode].has_key("locations_infos"): + self.ConfNodeInfos[confnode]["locations_infos"] = {"root": {"expanded" : False}} + + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["left"] = None + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["right"] = None + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["children"] = [] + + self.ConfNodeTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW) leftwindowsizer = wx.FlexGridSizer(cols=1, rows=2) leftwindowsizer.AddGrowableCol(0) @@ -1171,38 +1171,38 @@ rolesizer = wx.BoxSizer(wx.HORIZONTAL) leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT) - #self.GenerateEnableButton(leftwindow, rolesizer, plugin) + #self.GenerateEnableButton(leftwindow, rolesizer, confnode) roletext = wx.StaticText(leftwindow, -1) - roletext.SetLabel(plugin.PlugHelp) + roletext.SetLabel(confnode.PlugHelp) rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT) - plugin_IECChannel = plugin.BaseParams.getIEC_Channel() + confnode_IECChannel = confnode.BaseParams.getIEC_Channel() iecsizer = wx.BoxSizer(wx.HORIZONTAL) leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) st = wx.StaticText(leftwindow, -1) st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - st.SetLabel(plugin.GetFullIEC_Channel()) + st.SetLabel(confnode.GetFullIEC_Channel()) iecsizer.AddWindow(st, 0, border=0, flag=0) updownsizer = wx.BoxSizer(wx.VERTICAL) iecsizer.AddSizer(updownsizer, 0, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL) - if plugin_IECChannel > 0: + if confnode_IECChannel > 0: ieccdownbutton_id = wx.NewId() ieccdownbutton = wx.lib.buttons.GenBitmapButton(id=ieccdownbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCDown.png')), name='IECCDownButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) - ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel - 1), id=ieccdownbutton_id) + ieccdownbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel - 1), id=ieccdownbutton_id) updownsizer.AddWindow(ieccdownbutton, 0, border=0, flag=wx.ALIGN_LEFT) ieccupbutton_id = wx.NewId() ieccupbutton = wx.lib.buttons.GenBitmapTextButton(id=ieccupbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'IECCUp.png')), name='IECCUpButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) - ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(plugin, plugin_IECChannel + 1), id=ieccupbutton_id) + ieccupbutton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(confnode, confnode_IECChannel + 1), id=ieccupbutton_id) updownsizer.AddWindow(ieccupbutton, 0, border=0, flag=wx.ALIGN_LEFT) adddeletesizer = wx.BoxSizer(wx.VERTICAL) @@ -1210,19 +1210,19 @@ deletebutton_id = wx.NewId() deletebutton = wx.lib.buttons.GenBitmapButton(id=deletebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Delete.png')), - name='DeletePluginButton', parent=leftwindow, pos=wx.Point(0, 0), + name='DeleteConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) - deletebutton.SetToolTipString(_("Delete this plugin")) - deletebutton.Bind(wx.EVT_BUTTON, self.GetDeleteButtonFunction(plugin), id=deletebutton_id) + deletebutton.SetToolTipString(_("Delete this confnode")) + deletebutton.Bind(wx.EVT_BUTTON, self.GetDeleteButtonFunction(confnode), id=deletebutton_id) adddeletesizer.AddWindow(deletebutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER) - if len(plugin.PlugChildsTypes) > 0: + if len(confnode.PlugChildsTypes) > 0: addbutton_id = wx.NewId() addbutton = wx.lib.buttons.GenBitmapButton(id=addbutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Add.png')), - name='AddPluginButton', parent=leftwindow, pos=wx.Point(0, 0), + name='AddConfNodeButton', parent=leftwindow, pos=wx.Point(0, 0), size=wx.Size(16, 16), style=wx.NO_BORDER) - addbutton.SetToolTipString(_("Add a sub plugin")) - addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddPluginMenu(plugin), id=addbutton_id) + addbutton.SetToolTipString(_("Add a sub confnode")) + addbutton.Bind(wx.EVT_BUTTON, self.Gen_AddConfNodeMenu(confnode), id=addbutton_id) adddeletesizer.AddWindow(addbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER) expandbutton_id = wx.NewId() @@ -1234,27 +1234,27 @@ expandbutton.SetUseFocusIndicator(False) expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png'))) - if len(self.PluginInfos[plugin]["children"]) > 0: - expandbutton.SetToggle(self.PluginInfos[plugin]["expanded"]) + if len(self.ConfNodeInfos[confnode]["children"]) > 0: + expandbutton.SetToggle(self.ConfNodeInfos[confnode]["expanded"]) def togglebutton(event): if expandbutton.GetToggle(): - self.ExpandPlugin(plugin) + self.ExpandConfNode(confnode) else: - self.CollapsePlugin(plugin) - self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle() + self.CollapseConfNode(confnode) + self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() event.Skip() expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id) - elif len(plugin_locations) > 0: - locations_infos = self.PluginInfos[plugin]["locations_infos"] + elif len(confnode_locations) > 0: + locations_infos = self.ConfNodeInfos[confnode]["locations_infos"] expandbutton.SetToggle(locations_infos["root"]["expanded"]) def togglebutton(event): if expandbutton.GetToggle(): self.ExpandLocation(locations_infos, "root") else: self.CollapseLocation(locations_infos, "root") - self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle() + self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle() locations_infos["root"]["expanded"] = expandbutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() @@ -1267,22 +1267,22 @@ tc_id = wx.NewId() tc = wx.TextCtrl(leftwindow, tc_id, size=wx.Size(150, 25), style=wx.NO_BORDER) tc.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - tc.ChangeValue(plugin.MandatoryParams[1].getName()) - tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, plugin, "BaseParams.Name"), id=tc_id) + tc.ChangeValue(confnode.MandatoryParams[1].getName()) + tc.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(tc, confnode, "BaseParams.Name"), id=tc_id) iecsizer.AddWindow(tc, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) - rightwindow = self.GenerateParamsPanel(plugin, bkgdclr, 8) - self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) - - self.PluginInfos[plugin]["left"] = leftwindow - self.PluginInfos[plugin]["right"] = rightwindow - for child in self.PluginInfos[plugin]["children"]: + rightwindow = self.GenerateParamsPanel(confnode, bkgdclr, 8) + self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) + + self.ConfNodeInfos[confnode]["left"] = leftwindow + self.ConfNodeInfos[confnode]["right"] = rightwindow + for child in self.ConfNodeInfos[confnode]["children"]: self.GenerateTreeBranch(child) - if not self.PluginInfos[child]["expanded"]: - self.CollapsePlugin(child) - - if len(plugin_locations) > 0: - locations_infos = self.PluginInfos[plugin]["locations_infos"] + if not self.ConfNodeInfos[child]["expanded"]: + self.CollapseConfNode(child) + + if len(confnode_locations) > 0: + locations_infos = self.ConfNodeInfos[confnode]["locations_infos"] treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT) treectrl.SetImageList(self.LocationImageList) @@ -1292,19 +1292,19 @@ treectrl.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheelTreeCtrl) treectrl.AddRoot("") - self.PluginTreeSizer.AddWindow(treectrl, 0, border=0, flag=0) + self.ConfNodeTreeSizer.AddWindow(treectrl, 0, border=0, flag=0) rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) rightwindow.SetBackgroundColour(wx.WHITE) - self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) + self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) locations_infos["root"]["left"] = treectrl locations_infos["root"]["right"] = rightwindow - for location in plugin_locations: + for location in confnode_locations: locations_infos["root"]["children"].append("root.%s" % location["name"]) self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location) if locations_infos["root"]["expanded"]: - self.PluginTreeSizer.Layout() + self.ConfNodeTreeSizer.Layout() self.ExpandLocation(locations_infos, "root") else: self.RefreshTreeCtrlSize(treectrl) @@ -1399,38 +1399,38 @@ def RefreshAll(self): self.RefreshPLCParams() - self.RefreshPluginTree() - - def GetItemChannelChangedFunction(self, plugin, value): - def OnPluginTreeItemChannelChanged(event): - res = self.SetPluginParamsAttribute(plugin, "BaseParams.IEC_Channel", value) + self.RefreshConfNodeTree() + + def GetItemChannelChangedFunction(self, confnode, value): + def OnConfNodeTreeItemChannelChanged(event): + res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.IEC_Channel", value) event.Skip() - return OnPluginTreeItemChannelChanged - - def _GetAddPluginFunction(self, name, plugin): - def OnPluginMenu(event): - wx.CallAfter(self.AddPlugin, name, plugin) - return OnPluginMenu - - def Gen_AddPluginMenu(self, plugin): - def AddPluginMenu(event): + return OnConfNodeTreeItemChannelChanged + + def _GetAddConfNodeFunction(self, name, confnode): + def OnConfNodeMenu(event): + wx.CallAfter(self.AddConfNode, name, confnode) + return OnConfNodeMenu + + def Gen_AddConfNodeMenu(self, confnode): + def AddConfNodeMenu(event): main_menu = wx.Menu(title='') - if len(plugin.PlugChildsTypes) > 0: - for name, XSDClass, help in plugin.PlugChildsTypes: + if len(confnode.PlugChildsTypes) > 0: + for name, XSDClass, help in confnode.PlugChildsTypes: new_id = wx.NewId() main_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=_("Append ")+help) - self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name, plugin), id=new_id) + self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id) self.PopupMenuXY(main_menu) main_menu.Destroy() - return AddPluginMenu - - def GetButtonCallBackFunction(self, plugin, method): - """ Generate the callbackfunc for a given plugin method""" + return AddConfNodeMenu + + def GetButtonCallBackFunction(self, confnode, method): + """ Generate the callbackfunc for a given confnode method""" def OnButtonClick(event): # Disable button to prevent re-entrant call event.GetEventObject().Disable() # Call - getattr(plugin,method)() + getattr(confnode,method)() # Re-enable button event.GetEventObject().Enable() # Trigger refresh on Idle @@ -1438,20 +1438,20 @@ event.Skip() return OnButtonClick - def GetChoiceCallBackFunction(self, choicectrl, plugin, path): + def GetChoiceCallBackFunction(self, choicectrl, confnode, path): def OnChoiceChanged(event): - res = self.SetPluginParamsAttribute(plugin, path, choicectrl.GetStringSelection()) + res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection()) choicectrl.SetStringSelection(res) event.Skip() return OnChoiceChanged - def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, plugin, path): + def GetChoiceContentCallBackFunction(self, choicectrl, staticboxsizer, confnode, path): def OnChoiceContentChanged(event): - res = self.SetPluginParamsAttribute(plugin, path, choicectrl.GetStringSelection()) + res = self.SetConfNodeParamsAttribute(confnode, path, choicectrl.GetStringSelection()) if wx.VERSION < (2, 8, 0): self.ParamsPanel.Freeze() choicectrl.SetStringSelection(res) - infos = self.PluginRoot.GetParamsAttributes(path) + infos = self.CTR.GetParamsAttributes(path) staticbox = staticboxsizer.GetStaticBox() staticbox.SetLabel("%(name)s - %(value)s"%infos) self.RefreshSizerElement(self.ParamsPanel, staticboxsizer, infos["children"], "%s.%s"%(path, infos["name"]), selected=selected) @@ -1463,27 +1463,27 @@ event.Skip() return OnChoiceContentChanged - def GetTextCtrlCallBackFunction(self, textctrl, plugin, path): + def GetTextCtrlCallBackFunction(self, textctrl, confnode, path): def OnTextCtrlChanged(event): - res = self.SetPluginParamsAttribute(plugin, path, textctrl.GetValue()) + res = self.SetConfNodeParamsAttribute(confnode, path, textctrl.GetValue()) if res != textctrl.GetValue(): textctrl.ChangeValue(res) event.Skip() return OnTextCtrlChanged - def GetCheckBoxCallBackFunction(self, chkbx, plugin, path): + def GetCheckBoxCallBackFunction(self, chkbx, confnode, path): def OnCheckBoxChanged(event): - res = self.SetPluginParamsAttribute(plugin, path, chkbx.IsChecked()) + res = self.SetConfNodeParamsAttribute(confnode, path, chkbx.IsChecked()) chkbx.SetValue(res) event.Skip() return OnCheckBoxChanged - def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, plugin, path): + def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, confnode, path): infos = [value_infos] def OnBrowseButton(event): dialog = BrowseValuesLibraryDialog(self, name, library, infos[0]) if dialog.ShowModal() == wx.ID_OK: - value, value_infos = self.SetPluginParamsAttribute(plugin, path, dialog.GetValueInfos()) + value, value_infos = self.SetConfNodeParamsAttribute(confnode, path, dialog.GetValueInfos()) textctrl.ChangeValue(value) infos[0] = value_infos dialog.Destroy() @@ -1502,7 +1502,7 @@ for staticbox in staticboxes: staticbox.Destroy() - def RefreshSizerElement(self, parent, sizer, plugin, elements, path, clean = True): + def RefreshSizerElement(self, parent, sizer, confnode, elements, path, clean = True): if clean: if wx.VERSION < (2, 8, 0): self.ClearSizer(sizer) @@ -1524,7 +1524,7 @@ sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW|wx.TOP) else: sizer.AddSizer(staticboxsizer, 0, border=0, flag=wx.GROW) - self.RefreshSizerElement(parent, staticboxsizer, plugin, element_infos["children"], element_path) + self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path) else: boxsizer = wx.FlexGridSizer(cols=3, rows=1) boxsizer.AddGrowableCol(1) @@ -1561,7 +1561,7 @@ browse_boxsizer.AddWindow(button, 0, border=0, flag=0) button.Bind(wx.EVT_BUTTON, self.GetBrowseCallBackFunction(element_infos["name"], textctrl, element_infos["type"], - value_infos, plugin, element_path), + value_infos, confnode, element_path), id=button_id) else: combobox = wx.ComboBox(id=id, name=element_infos["name"], parent=parent, @@ -1579,12 +1579,12 @@ pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0) staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL) sizer.AddSizer(staticboxsizer, 0, border=5, flag=wx.GROW|wx.BOTTOM) - self.RefreshSizerElement(parent, staticboxsizer, plugin, element_infos["children"], element_path) - callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, plugin, element_path) + self.RefreshSizerElement(parent, staticboxsizer, confnode, element_infos["children"], element_path) + callback = self.GetChoiceContentCallBackFunction(combobox, staticboxsizer, confnode, element_path) else: for choice in element_infos["type"]: combobox.Append(choice) - callback = self.GetChoiceCallBackFunction(combobox, plugin, element_path) + callback = self.GetChoiceCallBackFunction(combobox, confnode, element_path) if element_infos["value"] is None: combobox.SetStringSelection("") else: @@ -1603,7 +1603,7 @@ boxsizer.AddWindow(spinctrl, 0, border=0, flag=0) if element_infos["value"] is not None: spinctrl.SetValue(element_infos["value"]) - spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id) + spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id) else: if element_infos["type"] == "boolean": checkbox = wx.CheckBox(id=id, name=element_infos["name"], parent=parent, @@ -1611,7 +1611,7 @@ boxsizer.AddWindow(checkbox, 0, border=0, flag=0) if element_infos["value"] is not None: checkbox.SetValue(element_infos["value"]) - checkbox.Bind(wx.EVT_CHECKBOX, self.GetCheckBoxCallBackFunction(checkbox, plugin, element_path), id=id) + checkbox.Bind(wx.EVT_CHECKBOX, self.GetCheckBoxCallBackFunction(checkbox, confnode, element_path), id=id) elif element_infos["type"] in ["unsignedLong", "long","integer"]: if element_infos["type"].startswith("unsigned"): scmin = 0 @@ -1624,7 +1624,7 @@ boxsizer.AddWindow(spinctrl, 0, border=0, flag=0) if element_infos["value"] is not None: spinctrl.SetValue(element_infos["value"]) - spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, plugin, element_path), id=id) + spinctrl.Bind(wx.EVT_SPINCTRL, self.GetTextCtrlCallBackFunction(spinctrl, confnode, element_path), id=id) else: choices = cPickle.loads(str(self.Config.Read(element_path, cPickle.dumps([""])))) textctrl = TextCtrlAutoComplete.TextCtrlAutoComplete(id=id, @@ -1640,15 +1640,15 @@ boxsizer.AddWindow(textctrl, 0, border=0, flag=0) if element_infos["value"] is not None: textctrl.ChangeValue(str(element_infos["value"])) - textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, plugin, element_path)) + textctrl.Bind(wx.EVT_TEXT, self.GetTextCtrlCallBackFunction(textctrl, confnode, element_path)) first = False def ResetView(self): IDEFrame.ResetView(self) - self.PluginInfos = {} - if self.PluginRoot is not None: - self.PluginRoot.CloseProject() - self.PluginRoot = None + self.ConfNodeInfos = {} + if self.CTR is not None: + self.CTR.CloseProject() + self.CTR = None self.Log.flush() if self.EnableDebug: self.DebugVariablePanel.SetDataProducer(None) @@ -1662,7 +1662,7 @@ self.Config.Flush() def OnNewProjectMenu(self, event): - if self.PluginRoot is not None and not self.CheckSaveBeforeClosing(): + if self.CTR is not None and not self.CheckSaveBeforeClosing(): return if not self.Config.HasEntry("lastopenedfolder"): @@ -1676,15 +1676,15 @@ self.Config.Write("lastopenedfolder", os.path.dirname(projectpath)) self.Config.Flush() self.ResetView() - plugin_root = PluginsRoot(self, self.Log) - result = plugin_root.NewProject(projectpath) + ctr = ConfigTreeRoot(self, self.Log) + result = ctr.NewProject(projectpath) if not result: - self.PluginRoot = plugin_root - self.Controler = self.PluginRoot + self.CTR = ctr + self.Controler = self.CTR self.LibraryPanel.SetControler(self.Controler) self.RefreshConfigRecentProjects(projectpath) if self.EnableDebug: - self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self.DebugVariablePanel.SetDataProducer(self.CTR) self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() else: @@ -1694,7 +1694,7 @@ dialog.Destroy() def OnOpenProjectMenu(self, event): - if self.PluginRoot is not None and not self.CheckSaveBeforeClosing(): + if self.CTR is not None and not self.CheckSaveBeforeClosing(): return if not self.Config.HasEntry("lastopenedfolder"): @@ -1712,14 +1712,14 @@ self.Config.Write("lastopenedfolder", os.path.dirname(projectpath)) self.Config.Flush() self.ResetView() - self.PluginRoot = PluginsRoot(self, self.Log) - self.Controler = self.PluginRoot - result = self.PluginRoot.LoadProject(projectpath) + self.CTR = ConfigTreeRoot(self, self.Log) + self.Controler = self.CTR + result = self.CTR.LoadProject(projectpath) if not result: self.LibraryPanel.SetControler(self.Controler) self.RefreshConfigRecentProjects(projectpath) if self.EnableDebug: - self.DebugVariablePanel.SetDataProducer(self.PluginRoot) + self.DebugVariablePanel.SetDataProducer(self.CTR) self.LoadProjectOrganization() self._Refresh(TYPESTREE, INSTANCESTREE, LIBRARYTREE) self.RefreshAll() @@ -1731,7 +1731,7 @@ self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU) def OnCloseProjectMenu(self, event): - if self.PluginRoot is not None and not self.CheckSaveBeforeClosing(): + if self.CTR is not None and not self.CheckSaveBeforeClosing(): return self.SaveProjectOrganization() @@ -1740,14 +1740,14 @@ self.RefreshAll() def OnSaveProjectMenu(self, event): - if self.PluginRoot is not None: - self.PluginRoot.SaveProject() + if self.CTR is not None: + self.CTR.SaveProject() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) def OnSaveProjectAsMenu(self, event): - if self.PluginRoot is not None: - self.PluginRoot.SaveProjectAs() + if self.CTR is not None: + self.CTR.SaveProjectAs() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) event.Skip() @@ -1765,53 +1765,53 @@ OpenHtmlFrame(self,_("About Beremiz"), Bpath("doc","about.html"), wx.Size(550, 500)) def OnPouSelectedChanged(self, event): - wx.CallAfter(self.RefreshPluginMenu) + wx.CallAfter(self.RefreshConfNodeMenu) IDEFrame.OnPouSelectedChanged(self, event) def OnPageClose(self, event): - wx.CallAfter(self.RefreshPluginMenu) + wx.CallAfter(self.RefreshConfNodeMenu) IDEFrame.OnPageClose(self, event) - def GetAddButtonFunction(self, plugin, window): + def GetAddButtonFunction(self, confnode, window): def AddButtonFunction(event): - if plugin and len(plugin.PlugChildsTypes) > 0: - plugin_menu = wx.Menu(title='') - for name, XSDClass, help in plugin.PlugChildsTypes: + if confnode and len(confnode.PlugChildsTypes) > 0: + confnode_menu = wx.Menu(title='') + for name, XSDClass, help in confnode.PlugChildsTypes: new_id = wx.NewId() - plugin_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name) - self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name, plugin), id=new_id) + confnode_menu.Append(help=help, id=new_id, kind=wx.ITEM_NORMAL, text=name) + self.Bind(wx.EVT_MENU, self._GetAddConfNodeFunction(name, confnode), id=new_id) window_pos = window.GetPosition() - wx.CallAfter(self.PLCConfig.PopupMenu, plugin_menu) + wx.CallAfter(self.PLCConfig.PopupMenu, confnode_menu) event.Skip() return AddButtonFunction - def GetDeleteButtonFunction(self, plugin): + def GetDeleteButtonFunction(self, confnode): def DeleteButtonFunction(event): - wx.CallAfter(self.DeletePlugin, plugin) + wx.CallAfter(self.DeleteConfNode, confnode) event.Skip() return DeleteButtonFunction - def AddPlugin(self, PluginType, plugin): - if self.PluginRoot.CheckProjectPathPerm(): - dialog = wx.TextEntryDialog(self, _("Please enter a name for plugin:"), _("Add Plugin"), "", wx.OK|wx.CANCEL) + def AddConfNode(self, ConfNodeType, confnode): + if self.CTR.CheckProjectPathPerm(): + dialog = wx.TextEntryDialog(self, _("Please enter a name for confnode:"), _("Add ConfNode"), "", wx.OK|wx.CANCEL) if dialog.ShowModal() == wx.ID_OK: - PluginName = dialog.GetValue() - plugin.PlugAddChild(PluginName, PluginType) - self.PluginRoot.RefreshPluginsBlockLists() + ConfNodeName = dialog.GetValue() + confnode.PlugAddChild(ConfNodeName, ConfNodeType) + self.CTR.RefreshConfNodesBlockLists() self._Refresh(TITLE, FILEMENU) - self.RefreshPluginTree() + self.RefreshConfNodeTree() dialog.Destroy() - def DeletePlugin(self, plugin): - if self.PluginRoot.CheckProjectPathPerm(): - dialog = wx.MessageDialog(self, _("Really delete plugin ?"), _("Remove plugin"), wx.YES_NO|wx.NO_DEFAULT) + def DeleteConfNode(self, confnode): + if self.CTR.CheckProjectPathPerm(): + dialog = wx.MessageDialog(self, _("Really delete confnode ?"), _("Remove confnode"), wx.YES_NO|wx.NO_DEFAULT) if dialog.ShowModal() == wx.ID_YES: - self.PluginInfos.pop(plugin) - plugin.PlugRemove() - del plugin - self.PluginRoot.RefreshPluginsBlockLists() + self.ConfNodeInfos.pop(confnode) + confnode.PlugRemove() + del confnode + self.CTR.RefreshConfNodesBlockLists() self._Refresh(TITLE, FILEMENU) - self.RefreshPluginTree() + self.RefreshConfNodeTree() dialog.Destroy() #------------------------------------------------------------------------------- diff -r 180e4a7d945c -r 1c23952dbde1 ConfigTree.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ConfigTree.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2063 @@ +""" +Base definitions for beremiz confnodes +""" + +import os,sys,traceback +import time +import confnodes +import types +import shutil +from xml.dom import minidom +import wx + +#Quick hack to be able to find Beremiz IEC tools. Should be config params. +base_folder = os.path.split(sys.path[0])[0] + +from xmlclass import GenerateClassesFromXSDstring +from wxPopen import ProcessLogger + +from PLCControler import PLCControler, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY + +_BaseParamsClass = GenerateClassesFromXSDstring(""" + + + + + + + + + """)["BaseParams"] + +NameTypeSeparator = '@' + +class MiniTextControler: + + def __init__(self, filepath): + self.FilePath = filepath + + def PlugFullName(self): + return "" + + def SetEditedElementText(self, tagname, text): + file = open(self.FilePath, "w") + file.write(text) + file.close() + + def GetEditedElementText(self, tagname, debug = False): + if os.path.isfile(self.FilePath): + file = open(self.FilePath, "r") + text = file.read() + file.close() + return text + return "" + + def GetEditedElementInterfaceVars(self, tagname, debug = False): + return [] + + def GetEditedElementType(self, tagname, debug = False): + return "program" + + def GetBlockTypes(self, tagname = "", debug = False): + return [] + + def GetDataTypes(self, tagname = "", basetypes = True, only_locatables = False, debug = False): + return [] + + def GetEnumeratedDataValues(self, debug = False): + return [] + + def StartBuffering(self): + pass + + def EndBuffering(self): + pass + + def BufferProject(self): + pass + +# helper func to get path to images +def opjimg(imgname): + return os.path.join(base_folder, "beremiz", "images",imgname) + +# helper func to check path write permission +def CheckPathPerm(path): + if path is None or not os.path.isdir(path): + return False + for root, dirs, files in os.walk(path): + for name in files: + if os.access(root, os.W_OK) is not True or os.access(os.path.join(root, name), os.W_OK) is not True: + return False + return True + +class ConfigTreeNode: + """ + This class is the one that define confnodes. + """ + + XSD = None + PlugChildsTypes = [] + PlugMaxCount = None + ConfNodeMethods = [] + LibraryControler = None + EditorType = None + + def _AddParamsMembers(self): + self.PlugParams = None + if self.XSD: + self.Classes = GenerateClassesFromXSDstring(self.XSD) + Classes = [(name, XSDclass) for name, XSDclass in self.Classes.items() if XSDclass.IsBaseClass] + if len(Classes) == 1: + name, XSDclass = Classes[0] + obj = XSDclass() + self.PlugParams = (name, obj) + setattr(self, name, obj) + + def __init__(self): + # Create BaseParam + self.BaseParams = _BaseParamsClass() + self.MandatoryParams = ("BaseParams", self.BaseParams) + self._AddParamsMembers() + self.PluggedChilds = {} + self._View = None + # copy ConfNodeMethods so that it can be later customized + self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods] + self.LoadSTLibrary() + + def ConfNodeBaseXmlFilePath(self, PlugName=None): + return os.path.join(self.PlugPath(PlugName), "baseconfnode.xml") + + def ConfNodeXmlFilePath(self, PlugName=None): + return os.path.join(self.PlugPath(PlugName), "confnode.xml") + + def ConfNodeLibraryFilePath(self): + return os.path.join(self.ConfNodePath(), "pous.xml") + + def ConfNodePath(self): + return os.path.join(self.PlugParent.ConfNodePath(), self.PlugType) + + def PlugPath(self,PlugName=None): + if not PlugName: + PlugName = self.PlugName() + return os.path.join(self.PlugParent.PlugPath(), + PlugName + NameTypeSeparator + self.PlugType) + + def PlugName(self): + return self.BaseParams.getName() + + def PlugEnabled(self): + return self.BaseParams.getEnabled() + + def PlugFullName(self): + parent = self.PlugParent.PlugFullName() + if parent != "": + return parent + "." + self.PlugName() + return self.BaseParams.getName() + + def GetIconPath(self, name): + return opjimg(name) + + def PlugTestModified(self): + return self.ChangesToSave + + def ProjectTestModified(self): + """ + recursively check modified status + """ + if self.PlugTestModified(): + return True + + for PlugChild in self.IterChilds(): + if PlugChild.ProjectTestModified(): + return True + + return False + + def RemoteExec(self, script, **kwargs): + return self.PlugParent.RemoteExec(script, **kwargs) + + def OnPlugSave(self): + #Default, do nothing and return success + return True + + def GetParamsAttributes(self, path = None): + if path: + parts = path.split(".", 1) + if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: + return self.MandatoryParams[1].getElementInfos(parts[0], parts[1]) + elif self.PlugParams and parts[0] == self.PlugParams[0]: + return self.PlugParams[1].getElementInfos(parts[0], parts[1]) + else: + params = [] + if wx.VERSION < (2, 8, 0) and self.MandatoryParams: + params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0])) + if self.PlugParams: + params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0])) + return params + + def SetParamsAttribute(self, path, value): + self.ChangesToSave = True + # Filter IEC_Channel and Name, that have specific behavior + if path == "BaseParams.IEC_Channel": + old_leading = ".".join(map(str, self.GetCurrentLocation())) + new_value = self.FindNewIEC_Channel(value) + new_leading = ".".join(map(str, self.PlugParent.GetCurrentLocation() + (new_value,))) + self.GetPlugRoot().UpdateProjectVariableLocation(old_leading, new_leading) + return new_value, True + elif path == "BaseParams.Name": + res = self.FindNewName(value) + self.PlugRequestSave() + return res, True + + parts = path.split(".", 1) + if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: + self.MandatoryParams[1].setElementValue(parts[1], value) + elif self.PlugParams and parts[0] == self.PlugParams[0]: + self.PlugParams[1].setElementValue(parts[1], value) + return value, False + + def PlugMakeDir(self): + os.mkdir(self.PlugPath()) + + def PlugRequestSave(self): + if self.GetPlugRoot().CheckProjectPathPerm(False): + # If confnode do not have corresponding directory + plugpath = self.PlugPath() + if not os.path.isdir(plugpath): + # Create it + os.mkdir(plugpath) + + # generate XML for base XML parameters controller of the confnode + if self.MandatoryParams: + BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(),'w') + BaseXMLFile.write("\n") + BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0).encode("utf-8")) + BaseXMLFile.close() + + # generate XML for XML parameters controller of the confnode + if self.PlugParams: + XMLFile = open(self.ConfNodeXmlFilePath(),'w') + XMLFile.write("\n") + XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0).encode("utf-8")) + XMLFile.close() + + # Call the confnode specific OnPlugSave method + result = self.OnPlugSave() + if not result: + return _("Error while saving \"%s\"\n")%self.PlugPath() + + # mark confnode as saved + self.ChangesToSave = False + # go through all childs and do the same + for PlugChild in self.IterChilds(): + result = PlugChild.PlugRequestSave() + if result: + return result + return None + + def PlugImport(self, src_PlugPath): + shutil.copytree(src_PlugPath, self.PlugPath) + return True + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + self.GetPlugRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n") + return [],"",False + + def _Generate_C(self, buildpath, locations): + # Generate confnodes [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files + # extra_files = [(fname,fobject), ...] + gen_result = self.PlugGenerate_C(buildpath, locations) + PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3] + extra_files = gen_result[3:] + # if some files have been generated put them in the list with their location + if PlugCFilesAndCFLAGS: + LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)] + else: + LocationCFilesAndCFLAGS = [] + + # confnode asks for some LDFLAGS + if PlugLDFLAGS: + # LDFLAGS can be either string + if type(PlugLDFLAGS)==type(str()): + LDFLAGS=[PlugLDFLAGS] + #or list of strings + elif type(PlugLDFLAGS)==type(list()): + LDFLAGS=PlugLDFLAGS[:] + else: + LDFLAGS=[] + + # recurse through all childs, and stack their results + for PlugChild in self.IECSortedChilds(): + new_location = PlugChild.GetCurrentLocation() + # How deep are we in the tree ? + depth=len(new_location) + _LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \ + PlugChild._Generate_C( + #keep the same path + buildpath, + # filter locations that start with current IEC location + [loc for loc in locations if loc["LOC"][0:depth] == new_location ]) + # stack the result + LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS + LDFLAGS += _LDFLAGS + extra_files += _extra_files + + return LocationCFilesAndCFLAGS, LDFLAGS, extra_files + + def ConfNodeTypesFactory(self): + if self.LibraryControler is not None: + return [{"name" : self.PlugType, "types": self.LibraryControler.Project}] + return [] + + def ParentsTypesFactory(self): + return self.PlugParent.ParentsTypesFactory() + self.ConfNodeTypesFactory() + + def ConfNodesTypesFactory(self): + list = self.ConfNodeTypesFactory() + for PlugChild in self.IterChilds(): + list += PlugChild.ConfNodesTypesFactory() + return list + + def STLibraryFactory(self): + if self.LibraryControler is not None: + program, errors, warnings = self.LibraryControler.GenerateProgram() + return program + "\n" + return "" + + def ConfNodesSTLibraryFactory(self): + program = self.STLibraryFactory() + for PlugChild in self.IECSortedChilds(): + program += PlugChild.ConfNodesSTLibraryFactory() + return program + + def IterChilds(self): + for PlugType, PluggedChilds in self.PluggedChilds.items(): + for PlugInstance in PluggedChilds: + yield PlugInstance + + def IECSortedChilds(self): + # reorder childs by IEC_channels + ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChilds()] + if ordered: + ordered.sort() + return zip(*ordered)[1] + else: + return [] + + def _GetChildBySomething(self, something, toks): + for PlugInstance in self.IterChilds(): + # if match component of the name + if getattr(PlugInstance.BaseParams, something) == toks[0]: + # if Name have other components + if len(toks) >= 2: + # Recurse in order to find the latest object + return PlugInstance._GetChildBySomething( something, toks[1:]) + # No sub name -> found + return PlugInstance + # Not found + return None + + def GetChildByName(self, Name): + if Name: + toks = Name.split('.') + return self._GetChildBySomething("Name", toks) + else: + return self + + def GetChildByIECLocation(self, Location): + if Location: + return self._GetChildBySomething("IEC_Channel", Location) + else: + return self + + def GetCurrentLocation(self): + """ + @return: Tupple containing confnode IEC location of current confnode : %I0.0.4.5 => (0,0,4,5) + """ + return self.PlugParent.GetCurrentLocation() + (self.BaseParams.getIEC_Channel(),) + + def GetCurrentName(self): + """ + @return: String "ParentParentName.ParentName.Name" + """ + return self.PlugParent._GetCurrentName() + self.BaseParams.getName() + + def _GetCurrentName(self): + """ + @return: String "ParentParentName.ParentName.Name." + """ + return self.PlugParent._GetCurrentName() + self.BaseParams.getName() + "." + + def GetPlugRoot(self): + return self.PlugParent.GetPlugRoot() + + def GetFullIEC_Channel(self): + return ".".join([str(i) for i in self.GetCurrentLocation()]) + ".x" + + def GetLocations(self): + location = self.GetCurrentLocation() + return [loc for loc in self.PlugParent.GetLocations() if loc["LOC"][0:len(location)] == location] + + def GetVariableLocationTree(self): + ''' + This function is meant to be overridden by confnodes. + + It should returns an list of dictionaries + + - IEC_type is an IEC type like BOOL/BYTE/SINT/... + - location is a string of this variable's location, like "%IX0.0.0" + ''' + children = [] + for child in self.IECSortedChilds(): + children.append(child.GetVariableLocationTree()) + return {"name": self.BaseParams.getName(), + "type": LOCATION_CONFNODE, + "location": self.GetFullIEC_Channel(), + "children": children} + + def FindNewName(self, DesiredName): + """ + Changes Name to DesiredName if available, Name-N if not. + @param DesiredName: The desired Name (string) + """ + # Get Current Name + CurrentName = self.BaseParams.getName() + # Do nothing if no change + #if CurrentName == DesiredName: return CurrentName + # Build a list of used Name out of parent's PluggedChilds + AllNames=[] + for PlugInstance in self.PlugParent.IterChilds(): + if PlugInstance != self: + AllNames.append(PlugInstance.BaseParams.getName()) + + # Find a free name, eventually appending digit + res = DesiredName + suffix = 1 + while res in AllNames: + res = "%s-%d"%(DesiredName, suffix) + suffix += 1 + + # Get old path + oldname = self.PlugPath() + # Check previous confnode existance + dontexist = self.BaseParams.getName() == "__unnamed__" + # Set the new name + self.BaseParams.setName(res) + # Rename confnode dir if exist + if not dontexist: + shutil.move(oldname, self.PlugPath()) + # warn user he has two left hands + if DesiredName != res: + self.GetPlugRoot().logger.write_warning(_("A child names \"%s\" already exist -> \"%s\"\n")%(DesiredName,res)) + return res + + def GetAllChannels(self): + AllChannels=[] + for PlugInstance in self.PlugParent.IterChilds(): + if PlugInstance != self: + AllChannels.append(PlugInstance.BaseParams.getIEC_Channel()) + AllChannels.sort() + return AllChannels + + def FindNewIEC_Channel(self, DesiredChannel): + """ + Changes IEC Channel number to DesiredChannel if available, nearest available if not. + @param DesiredChannel: The desired IEC channel (int) + """ + # Get Current IEC channel + CurrentChannel = self.BaseParams.getIEC_Channel() + # Do nothing if no change + #if CurrentChannel == DesiredChannel: return CurrentChannel + # Build a list of used Channels out of parent's PluggedChilds + AllChannels = self.GetAllChannels() + + # Now, try to guess the nearest available channel + res = DesiredChannel + while res in AllChannels: # While channel not free + if res < CurrentChannel: # Want to go down ? + res -= 1 # Test for n-1 + if res < 0 : + self.GetPlugRoot().logger.write_warning(_("Cannot find lower free IEC channel than %d\n")%CurrentChannel) + return CurrentChannel # Can't go bellow 0, do nothing + else : # Want to go up ? + res += 1 # Test for n-1 + # Finally set IEC Channel + self.BaseParams.setIEC_Channel(res) + return res + + def _OpenView(self, name=None): + if self.EditorType is not None and self._View is None: + app_frame = self.GetPlugRoot().AppFrame + + self._View = self.EditorType(app_frame.TabsOpened, self, app_frame) + + app_frame.EditProjectElement(self._View, self.PlugName()) + + return self._View + return None + + def OnCloseEditor(self, view): + if self._View == view: + self._View = None + + def OnPlugClose(self): + if self._View is not None: + app_frame = self.GetPlugRoot().AppFrame + if app_frame is not None: + app_frame.DeletePage(self._View) + return True + + def _doRemoveChild(self, PlugInstance): + # Remove all childs of child + for SubPlugInstance in PlugInstance.IterChilds(): + PlugInstance._doRemoveChild(SubPlugInstance) + # Call the OnCloseMethod + PlugInstance.OnPlugClose() + # Delete confnode dir + shutil.rmtree(PlugInstance.PlugPath()) + # Remove child of PluggedChilds + self.PluggedChilds[PlugInstance.PlugType].remove(PlugInstance) + # Forget it... (View have to refresh) + + def PlugRemove(self): + # Fetch the confnode + #PlugInstance = self.GetChildByName(PlugName) + # Ask to his parent to remove it + self.PlugParent._doRemoveChild(self) + + def PlugAddChild(self, PlugName, PlugType, IEC_Channel=0): + """ + Create the confnodes that may be added as child to this node self + @param PlugType: string desining the confnode class name (get name from PlugChildsTypes) + @param PlugName: string for the name of the confnode instance + """ + # reorgabize self.PlugChildsTypes tuples from (name, PlugClass, Help) + # to ( name, (PlugClass, Help)), an make a dict + transpose = zip(*self.PlugChildsTypes) + PlugChildsTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2]))) + # Check that adding this confnode is allowed + try: + PlugClass, PlugHelp = PlugChildsTypes[PlugType] + except KeyError: + raise Exception, _("Cannot create child %s of type %s ")%(PlugName, PlugType) + + # if PlugClass is a class factory, call it. (prevent unneeded imports) + if type(PlugClass) == types.FunctionType: + PlugClass = PlugClass() + + # Eventualy Initialize child instance list for this class of confnode + PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType, list()) + # Check count + if getattr(PlugClass, "PlugMaxCount", None) and len(PluggedChildsWithSameClass) >= PlugClass.PlugMaxCount: + raise Exception, _("Max count (%d) reached for this confnode of type %s ")%(PlugClass.PlugMaxCount, PlugType) + + # create the final class, derived of provided confnode and template + class FinalPlugClass(PlugClass, ConfigTreeNode): + """ + ConfNode class is derivated into FinalPlugClass before being instanciated + This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called + before PlugClass.__init__, and to do the file related stuff. + """ + def __init__(_self): + # self is the parent + _self.PlugParent = self + # Keep track of the confnode type name + _self.PlugType = PlugType + # remind the help string, for more fancy display + _self.PlugHelp = PlugHelp + # Call the base confnode template init - change XSD into class members + ConfigTreeNode.__init__(_self) + # check name is unique + NewPlugName = _self.FindNewName(PlugName) + # If dir have already be made, and file exist + if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.ConfNodeXmlFilePath(PlugName)): + #Load the confnode.xml file into parameters members + _self.LoadXMLParams(NewPlugName) + # Basic check. Better to fail immediately. + if (_self.BaseParams.getName() != NewPlugName): + raise Exception, _("Project tree layout do not match confnode.xml %s!=%s ")%(NewPlugName, _self.BaseParams.getName()) + + # Now, self.PlugPath() should be OK + + # Check that IEC_Channel is not already in use. + _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel()) + # Call the confnode real __init__ + if getattr(PlugClass, "__init__", None): + PlugClass.__init__(_self) + #Load and init all the childs + _self.LoadChilds() + #just loaded, nothing to saved + _self.ChangesToSave = False + else: + # If confnode do not have corresponding file/dirs - they will be created on Save + _self.PlugMakeDir() + # Find an IEC number + _self.FindNewIEC_Channel(IEC_Channel) + # Call the confnode real __init__ + if getattr(PlugClass, "__init__", None): + PlugClass.__init__(_self) + _self.PlugRequestSave() + #just created, must be saved + _self.ChangesToSave = True + + def _getBuildPath(_self): + return self._getBuildPath() + + # Create the object out of the resulting class + newConfNodeOpj = FinalPlugClass() + # Store it in PluggedChils + PluggedChildsWithSameClass.append(newConfNodeOpj) + + return newConfNodeOpj + + def ClearPluggedChilds(self): + for child in self.IterChilds(): + child.ClearPluggedChilds() + self.PluggedChilds = {} + + def LoadSTLibrary(self): + # Get library blocks if plcopen library exist + library_path = self.ConfNodeLibraryFilePath() + if os.path.isfile(library_path): + self.LibraryControler = PLCControler() + self.LibraryControler.OpenXMLFile(library_path) + self.LibraryControler.ClearConfNodeTypes() + self.LibraryControler.AddConfNodeTypesList(self.ParentsTypesFactory()) + + def LoadXMLParams(self, PlugName = None): + methode_name = os.path.join(self.PlugPath(PlugName), "methods.py") + if os.path.isfile(methode_name): + execfile(methode_name) + + # Get the base xml tree + if self.MandatoryParams: + try: + basexmlfile = open(self.ConfNodeBaseXmlFilePath(PlugName), 'r') + basetree = minidom.parse(basexmlfile) + self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0]) + basexmlfile.close() + except Exception, exc: + self.GetPlugRoot().logger.write_error(_("Couldn't load confnode base parameters %s :\n %s") % (PlugName, str(exc))) + self.GetPlugRoot().logger.write_error(traceback.format_exc()) + + # Get the xml tree + if self.PlugParams: + try: + xmlfile = open(self.ConfNodeXmlFilePath(PlugName), 'r') + tree = minidom.parse(xmlfile) + self.PlugParams[1].loadXMLTree(tree.childNodes[0]) + xmlfile.close() + except Exception, exc: + self.GetPlugRoot().logger.write_error(_("Couldn't load confnode parameters %s :\n %s") % (PlugName, str(exc))) + self.GetPlugRoot().logger.write_error(traceback.format_exc()) + + def LoadChilds(self): + # Iterate over all PlugName@PlugType in confnode directory, and try to open them + for PlugDir in os.listdir(self.PlugPath()): + if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \ + PlugDir.count(NameTypeSeparator) == 1: + pname, ptype = PlugDir.split(NameTypeSeparator) + try: + self.PlugAddChild(pname, ptype) + except Exception, exc: + self.GetPlugRoot().logger.write_error(_("Could not add child \"%s\", type %s :\n%s\n")%(pname, ptype, str(exc))) + self.GetPlugRoot().logger.write_error(traceback.format_exc()) + + def EnableMethod(self, method, value): + for d in self.ConfNodeMethods: + if d["method"]==method: + d["enabled"]=value + return True + return False + + def ShowMethod(self, method, value): + for d in self.ConfNodeMethods: + if d["method"]==method: + d["shown"]=value + return True + return False + + def CallMethod(self, method): + for d in self.ConfNodeMethods: + if d["method"]==method and d.get("enabled", True) and d.get("shown", True): + getattr(self, method)() + +def _GetClassFunction(name): + def GetRootClass(): + return getattr(__import__("confnodes." + name), name).RootClass + return GetRootClass + + +#################################################################################### +#################################################################################### +#################################################################################### +################################### ROOT ###################################### +#################################################################################### +#################################################################################### +#################################################################################### + +if wx.Platform == '__WXMSW__': + exe_ext=".exe" +else: + exe_ext="" + +# import for project creation timestamping +from threading import Timer, Lock, Thread, Semaphore +from time import localtime +from datetime import datetime +# import necessary stuff from PLCOpenEditor +from PLCOpenEditor import PLCOpenEditor, ProjectDialog +from TextViewer import TextViewer +from plcopen.structures import IEC_KEYWORDS, TypeHierarchy_list + + +import re, tempfile +import targets +from targets.typemapping import DebugTypesSize + +import connectors +from discovery import DiscoveryDialog +from weakref import WeakKeyDictionary + +MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): error : (.*)$") + +DEBUG_RETRIES_WARN = 3 +DEBUG_RETRIES_REREGISTER = 4 + +class ConfigTreeRoot(ConfigTreeNode, PLCControler): + """ + This class define Root object of the confnode tree. + It is responsible of : + - Managing project directory + - Building project + - Handling PLCOpenEditor controler and view + - Loading user confnodes and instanciante them as childs + - ... + + """ + + # For root object, available Childs Types are modules of the confnode packages. + PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(confnodes.__all__,confnodes.helps)] + + XSD = """ + + + + + + + + """+targets.targetchoices+""" + + + + + + + + + + """ + + def __init__(self, frame, logger): + PLCControler.__init__(self) + + self.MandatoryParams = None + self.SetAppFrame(frame, logger) + self._builder = None + self._connector = None + + self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext) + self.ieclib_path = os.path.join(base_folder, "matiec", "lib") + + # Setup debug information + self.IECdebug_datas = {} + self.IECdebug_lock = Lock() + + self.DebugTimer=None + self.ResetIECProgramsAndVariables() + + #This method are not called here... but in NewProject and OpenProject + #self._AddParamsMembers() + #self.PluggedChilds = {} + + # In both new or load scenario, no need to save + self.ChangesToSave = False + # root have no parent + self.PlugParent = None + # Keep track of the confnode type name + self.PlugType = "Beremiz" + self.PluggedChilds = {} + # After __init__ root confnode is not valid + self.ProjectPath = None + self._setBuildPath(None) + self.DebugThread = None + self.debug_break = False + self.previous_plcstate = None + # copy ConfNodeMethods so that it can be later customized + self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods] + self.LoadSTLibrary() + + def __del__(self): + if self.DebugTimer: + self.DebugTimer.cancel() + self.KillDebugThread() + + def SetAppFrame(self, frame, logger): + self.AppFrame = frame + self.logger = logger + self.StatusTimer = None + + if frame is not None: + # Timer to pull PLC status + ID_STATUSTIMER = wx.NewId() + self.StatusTimer = wx.Timer(self.AppFrame, ID_STATUSTIMER) + self.AppFrame.Bind(wx.EVT_TIMER, self.PullPLCStatusProc, self.StatusTimer) + + self.RefreshConfNodesBlockLists() + + def ResetAppFrame(self, logger): + if self.AppFrame is not None: + self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer) + self.StatusTimer = None + self.AppFrame = None + + self.logger = logger + + def ConfNodeLibraryFilePath(self): + return os.path.join(os.path.split(__file__)[0], "pous.xml") + + def PlugTestModified(self): + return self.ChangesToSave or not self.ProjectIsSaved() + + def PlugFullName(self): + return "" + + def GetPlugRoot(self): + return self + + def GetIECLibPath(self): + return self.ieclib_path + + def GetIEC2cPath(self): + return self.iec2c_path + + def GetCurrentLocation(self): + return () + + def GetCurrentName(self): + return "" + + def _GetCurrentName(self): + return "" + + def GetProjectPath(self): + return self.ProjectPath + + def GetProjectName(self): + return os.path.split(self.ProjectPath)[1] + + def GetDefaultTargetName(self): + if wx.Platform == '__WXMSW__': + return "Win32" + else: + return "Linux" + + def GetTarget(self): + target = self.BeremizRoot.getTargetType() + if target.getcontent() is None: + target = self.Classes["BeremizRoot_TargetType"]() + target_name = self.GetDefaultTargetName() + target.setcontent({"name": target_name, "value": self.Classes["TargetType_%s"%target_name]()}) + return target + + def GetParamsAttributes(self, path = None): + params = ConfigTreeNode.GetParamsAttributes(self, path) + if params[0]["name"] == "BeremizRoot": + for child in params[0]["children"]: + if child["name"] == "TargetType" and child["value"] == '': + child.update(self.GetTarget().getElementInfos("TargetType")) + return params + + def SetParamsAttribute(self, path, value): + if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None: + self.BeremizRoot.setTargetType(self.GetTarget()) + return ConfigTreeNode.SetParamsAttribute(self, path, value) + + # helper func to check project path write permission + def CheckProjectPathPerm(self, dosave=True): + if CheckPathPerm(self.ProjectPath): + return True + dialog = wx.MessageDialog(self.AppFrame, + _('You must have permission to work on the project\nWork on a project copy ?'), + _('Error'), + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + answer = dialog.ShowModal() + dialog.Destroy() + if answer == wx.ID_YES: + if self.SaveProjectAs(): + self.AppFrame.RefreshAll() + self.AppFrame.RefreshTitle() + self.AppFrame.RefreshFileMenu() + return True + return False + + def NewProject(self, ProjectPath, BuildPath=None): + """ + Create a new project in an empty folder + @param ProjectPath: path of the folder where project have to be created + @param PLCParams: properties of the PLCOpen program created + """ + # Verify that chosen folder is empty + if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0: + return _("Chosen folder isn't empty. You can't use it for a new project!") + + dialog = ProjectDialog(self.AppFrame) + if dialog.ShowModal() == wx.ID_OK: + values = dialog.GetValues() + values["creationDateTime"] = datetime(*localtime()[:6]) + dialog.Destroy() + else: + dialog.Destroy() + return _("Project not created") + + # Create PLCOpen program + self.CreateNewProject(values) + # Change XSD into class members + self._AddParamsMembers() + self.PluggedChilds = {} + # Keep track of the root confnode (i.e. project path) + self.ProjectPath = ProjectPath + self._setBuildPath(BuildPath) + # get confnodes bloclist (is that usefull at project creation?) + self.RefreshConfNodesBlockLists() + # this will create files base XML files + self.SaveProject() + return None + + def LoadProject(self, ProjectPath, BuildPath=None): + """ + Load a project contained in a folder + @param ProjectPath: path of the project folder + """ + if os.path.basename(ProjectPath) == "": + ProjectPath = os.path.dirname(ProjectPath) + # Verify that project contains a PLCOpen program + plc_file = os.path.join(ProjectPath, "plc.xml") + if not os.path.isfile(plc_file): + return _("Chosen folder doesn't contain a program. It's not a valid project!") + # Load PLCOpen file + result = self.OpenXMLFile(plc_file) + if result: + return result + # Change XSD into class members + self._AddParamsMembers() + self.PluggedChilds = {} + # Keep track of the root confnode (i.e. project path) + self.ProjectPath = ProjectPath + self._setBuildPath(BuildPath) + # If dir have already be made, and file exist + if os.path.isdir(self.PlugPath()) and os.path.isfile(self.ConfNodeXmlFilePath()): + #Load the confnode.xml file into parameters members + result = self.LoadXMLParams() + if result: + return result + #Load and init all the childs + self.LoadChilds() + self.RefreshConfNodesBlockLists() + + if os.path.exists(self._getBuildPath()): + self.EnableMethod("_Clean", True) + + if os.path.isfile(self._getIECrawcodepath()): + self.ShowMethod("_showIECcode", True) + + return None + + def CloseProject(self): + self.ClearPluggedChilds() + self.ResetAppFrame(None) + + def SaveProject(self): + if self.CheckProjectPathPerm(False): + self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) + result = self.PlugRequestSave() + if result: + self.logger.write_error(result) + + def SaveProjectAs(self, dosave=True): + # Ask user to choose a path with write permissions + if wx.Platform == '__WXMSW__': + path = os.getenv("USERPROFILE") + else: + path = os.getenv("HOME") + dirdialog = wx.DirDialog(self.AppFrame , _("Choose a directory to save project"), path, wx.DD_NEW_DIR_BUTTON) + answer = dirdialog.ShowModal() + dirdialog.Destroy() + if answer == wx.ID_OK: + newprojectpath = dirdialog.GetPath() + if os.path.isdir(newprojectpath): + self.ProjectPath = newprojectpath + if dosave: + self.SaveProject() + self._setBuildPath(self.BuildPath) + return True + return False + + # Update PLCOpenEditor ConfNode Block types from loaded confnodes + def RefreshConfNodesBlockLists(self): + if getattr(self, "PluggedChilds", None) is not None: + self.ClearConfNodeTypes() + self.AddConfNodeTypesList(self.ConfNodesTypesFactory()) + if self.AppFrame is not None: + self.AppFrame.RefreshLibraryPanel() + self.AppFrame.RefreshEditor() + + # Update a PLCOpenEditor Pou variable location + def UpdateProjectVariableLocation(self, old_leading, new_leading): + self.Project.updateElementAddress(old_leading, new_leading) + self.BufferProject() + if self.AppFrame is not None: + self.AppFrame.RefreshTitle() + self.AppFrame.RefreshInstancesTree() + self.AppFrame.RefreshFileMenu() + self.AppFrame.RefreshEditMenu() + self.AppFrame.RefreshEditor() + + def GetVariableLocationTree(self): + ''' + This function is meant to be overridden by confnodes. + + It should returns an list of dictionaries + + - IEC_type is an IEC type like BOOL/BYTE/SINT/... + - location is a string of this variable's location, like "%IX0.0.0" + ''' + children = [] + for child in self.IECSortedChilds(): + children.append(child.GetVariableLocationTree()) + return children + + def ConfNodePath(self): + return os.path.join(os.path.split(__file__)[0], "confnodes") + + def PlugPath(self, PlugName=None): + return self.ProjectPath + + def ConfNodeXmlFilePath(self, PlugName=None): + return os.path.join(self.PlugPath(PlugName), "beremiz.xml") + + def ParentsTypesFactory(self): + return self.ConfNodeTypesFactory() + + def _setBuildPath(self, buildpath): + if CheckPathPerm(buildpath): + self.BuildPath = buildpath + else: + self.BuildPath = None + self.BuildPath = buildpath + self.DefaultBuildPath = None + if self._builder is not None: + self._builder.SetBuildPath(self._getBuildPath()) + + def _getBuildPath(self): + # BuildPath is defined by user + if self.BuildPath is not None: + return self.BuildPath + # BuildPath isn't defined by user but already created by default + if self.DefaultBuildPath is not None: + return self.DefaultBuildPath + # Create a build path in project folder if user has permissions + if CheckPathPerm(self.ProjectPath): + self.DefaultBuildPath = os.path.join(self.ProjectPath, "build") + # Create a build path in temp folder + else: + self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build") + + if not os.path.exists(self.DefaultBuildPath): + os.makedirs(self.DefaultBuildPath) + return self.DefaultBuildPath + + def _getExtraFilesPath(self): + return os.path.join(self._getBuildPath(), "extra_files") + + def _getIECcodepath(self): + # define name for IEC code file + return os.path.join(self._getBuildPath(), "plc.st") + + def _getIECgeneratedcodepath(self): + # define name for IEC generated code file + return os.path.join(self._getBuildPath(), "generated_plc.st") + + def _getIECrawcodepath(self): + # define name for IEC raw code file + return os.path.join(self.PlugPath(), "raw_plc.st") + + def GetLocations(self): + locations = [] + filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h") + if os.path.isfile(filepath): + # IEC2C compiler generate a list of located variables : LOCATED_VARIABLES.h + location_file = open(os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")) + # each line of LOCATED_VARIABLES.h declares a located variable + lines = [line.strip() for line in location_file.readlines()] + # This regular expression parses the lines genereated by IEC2C + LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P[A-Z]*),(?P[_A-Za-z0-9]*),(?P[QMI])(?:,(?P[XBWDL]))?,(?P[,0-9]*)\)") + for line in lines: + # If line match RE, + result = LOCATED_MODEL.match(line) + if result: + # Get the resulting dict + resdict = result.groupdict() + # rewrite string for variadic location as a tuple of integers + resdict['LOC'] = tuple(map(int,resdict['LOC'].split(','))) + # set located size to 'X' if not given + if not resdict['SIZE']: + resdict['SIZE'] = 'X' + # finally store into located variable list + locations.append(resdict) + return locations + + def _Generate_SoftPLC(self): + """ + Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C + @param buildpath: path where files should be created + """ + + # Update PLCOpenEditor ConfNode Block types before generate ST code + self.RefreshConfNodesBlockLists() + + self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")) + buildpath = self._getBuildPath() + # ask PLCOpenEditor controller to write ST/IL/SFC code file + program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath()) + if len(warnings) > 0: + self.logger.write_warning(_("Warnings in ST/IL/SFC code generator :\n")) + for warning in warnings: + self.logger.write_warning("%s\n"%warning) + if len(errors) > 0: + # Failed ! + self.logger.write_error(_("Error in ST/IL/SFC code generator :\n%s\n")%errors[0]) + return False + plc_file = open(self._getIECcodepath(), "w") + # Add ST Library from confnodes + plc_file.write(self.ConfNodesSTLibraryFactory()) + if os.path.isfile(self._getIECrawcodepath()): + plc_file.write(open(self._getIECrawcodepath(), "r").read()) + plc_file.write("\n") + plc_file.close() + plc_file = open(self._getIECcodepath(), "r") + self.ProgramOffset = 0 + for line in plc_file.xreadlines(): + self.ProgramOffset += 1 + plc_file.close() + plc_file = open(self._getIECcodepath(), "a") + plc_file.write(open(self._getIECgeneratedcodepath(), "r").read()) + plc_file.close() + + self.logger.write(_("Compiling IEC Program into C code...\n")) + + # Now compile IEC code into many C files + # files are listed to stdout, and errors to stderr. + status, result, err_result = ProcessLogger( + self.logger, + "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%( + self.iec2c_path, + self.ieclib_path, + buildpath, + self._getIECcodepath()), + no_stdout=True, no_stderr=True).spin() + if status: + # Failed ! + + # parse iec2c's error message. if it contains a line number, + # then print those lines from the generated IEC file. + for err_line in err_result.split('\n'): + self.logger.write_warning(err_line + "\n") + + m_result = MATIEC_ERROR_MODEL.match(err_line) + if m_result is not None: + first_line, first_column, last_line, last_column, error = m_result.groups() + first_line, last_line = int(first_line), int(last_line) + + last_section = None + f = open(self._getIECcodepath()) + + for i, line in enumerate(f.readlines()): + i = i + 1 + if line[0] not in '\t \r\n': + last_section = line + + if first_line <= i <= last_line: + if last_section is not None: + self.logger.write_warning("In section: " + last_section) + last_section = None # only write section once + self.logger.write_warning("%04d: %s" % (i, line)) + + f.close() + + self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status) + return False + + # Now extract C files of stdout + C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ] + # remove those that are not to be compiled because included by others + C_files.remove("POUS.c") + if not C_files: + self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n")) + return False + # transform those base names to full names with path + C_files = map(lambda filename:os.path.join(buildpath, filename), C_files) + self.logger.write(_("Extracting Located Variables...\n")) + # Keep track of generated located variables for later use by self._Generate_C + self.PLCGeneratedLocatedVars = self.GetLocations() + # Keep track of generated C files for later use by self.PlugGenerate_C + self.PLCGeneratedCFiles = C_files + # compute CFLAGS for plc + self.plcCFLAGS = "\"-I"+self.ieclib_path+"\"" + return True + + def GetBuilder(self): + """ + Return a Builder (compile C code into machine code) + """ + # Get target, module and class name + targetname = self.GetTarget().getcontent()["name"] + modulename = "targets." + targetname + classname = targetname + "_target" + + # Get module reference + try : + targetmodule = getattr(__import__(modulename), targetname) + + except Exception, msg: + self.logger.write_error(_("Can't find module for target %s!\n")%targetname) + self.logger.write_error(str(msg)) + return None + + # Get target class + targetclass = getattr(targetmodule, classname) + + # if target already + if self._builder is None or not isinstance(self._builder,targetclass): + # Get classname instance + self._builder = targetclass(self) + return self._builder + + def ResetBuildMD5(self): + builder=self.GetBuilder() + if builder is not None: + builder.ResetBinaryCodeMD5() + self.EnableMethod("_Transfer", False) + + def GetLastBuildMD5(self): + builder=self.GetBuilder() + if builder is not None: + return builder.GetBinaryCodeMD5() + else: + return None + + ####################################################################### + # + # C CODE GENERATION METHODS + # + ####################################################################### + + def PlugGenerate_C(self, buildpath, locations): + """ + Return C code generated by iec2c compiler + when _generate_softPLC have been called + @param locations: ignored + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + + return ([(C_file_name, self.plcCFLAGS) + for C_file_name in self.PLCGeneratedCFiles ], + "", # no ldflags + False) # do not expose retreive/publish calls + + def ResetIECProgramsAndVariables(self): + """ + Reset variable and program list that are parsed from + CSV file generated by IEC2C compiler. + """ + self._ProgramList = None + self._VariablesList = None + self._IECPathToIdx = {} + self._Ticktime = 0 + self.TracedIECPath = [] + + def GetIECProgramsAndVariables(self): + """ + Parse CSV-like file VARIABLES.csv resulting from IEC2C compiler. + Each section is marked with a line staring with '//' + list of all variables used in various POUs + """ + if self._ProgramList is None or self._VariablesList is None: + try: + csvfile = os.path.join(self._getBuildPath(),"VARIABLES.csv") + # describes CSV columns + ProgramsListAttributeName = ["num", "C_path", "type"] + VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"] + self._ProgramList = [] + self._VariablesList = [] + self._IECPathToIdx = {} + + # Separate sections + ListGroup = [] + for line in open(csvfile,'r').xreadlines(): + strippedline = line.strip() + if strippedline.startswith("//"): + # Start new section + ListGroup.append([]) + elif len(strippedline) > 0 and len(ListGroup) > 0: + # append to this section + ListGroup[-1].append(strippedline) + + # first section contains programs + for line in ListGroup[0]: + # Split and Maps each field to dictionnary entries + attrs = dict(zip(ProgramsListAttributeName,line.strip().split(';'))) + # Truncate "C_path" to remove conf an ressources names + attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:]) + # Push this dictionnary into result. + self._ProgramList.append(attrs) + + # second section contains all variables + for line in ListGroup[1]: + # Split and Maps each field to dictionnary entries + attrs = dict(zip(VariablesListAttributeName,line.strip().split(';'))) + # Truncate "C_path" to remove conf an ressources names + parts = attrs["C_path"].split(".",2) + if len(parts) > 2: + attrs["C_path"] = '__'.join(parts[1:]) + else: + attrs["C_path"] = '__'.join(parts) + # Push this dictionnary into result. + self._VariablesList.append(attrs) + # Fill in IEC<->C translation dicts + IEC_path=attrs["IEC_path"] + Idx=int(attrs["num"]) + self._IECPathToIdx[IEC_path]=(Idx, attrs["type"]) + + # third section contains ticktime + if len(ListGroup) > 2: + self._Ticktime = int(ListGroup[2][0]) + + except Exception,e: + self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n")) + self.logger.write_error(traceback.format_exc()) + self.ResetIECProgramsAndVariables() + return False + + return True + + def Generate_plc_debugger(self): + """ + Generate trace/debug code out of PLC variable list + """ + self.GetIECProgramsAndVariables() + + # prepare debug code + debug_code = targets.code("plc_debug") % { + "buffer_size": reduce(lambda x, y: x + y, [DebugTypesSize.get(v["type"], 0) for v in self._VariablesList], 0), + "programs_declarations": + "\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]), + "extern_variables_declarations":"\n".join([ + {"EXT":"extern __IEC_%(type)s_p %(C_path)s;", + "IN":"extern __IEC_%(type)s_p %(C_path)s;", + "MEM":"extern __IEC_%(type)s_p %(C_path)s;", + "OUT":"extern __IEC_%(type)s_p %(C_path)s;", + "VAR":"extern __IEC_%(type)s_t %(C_path)s;"}[v["vartype"]]%v + for v in self._VariablesList if v["vartype"] != "FB" and v["C_path"].find('.')<0]), + "for_each_variable_do_code":"\n".join([ + {"EXT":" (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n", + "IN":" (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n", + "MEM":" (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n", + "OUT":" (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n", + "VAR":" (*fp)((void*)&%(C_path)s,%(type)s_ENUM);\n"}[v["vartype"]]%v + for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ]), + "find_variable_case_code":"\n".join([ + " case %(num)s:\n"%v+ + " *varp = (void*)&%(C_path)s;\n"%v+ + {"EXT":" return %(type)s_P_ENUM;\n", + "IN":" return %(type)s_P_ENUM;\n", + "MEM":" return %(type)s_O_ENUM;\n", + "OUT":" return %(type)s_O_ENUM;\n", + "VAR":" return %(type)s_ENUM;\n"}[v["vartype"]]%v + for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])} + + return debug_code + + def Generate_plc_common_main(self): + """ + Use confnodes layout given in LocationCFilesAndCFLAGS to + generate glue code that dispatch calls to all confnodes + """ + # filter location that are related to code that will be called + # in retreive, publish, init, cleanup + locstrs = map(lambda x:"_".join(map(str,x)), + [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls]) + + # Generate main, based on template + if self.BeremizRoot.getEnable_ConfNodes(): + plc_main_code = targets.code("plc_common_main") % { + "calls_prototypes":"\n".join([( + "int __init_%(s)s(int argc,char **argv);\n"+ + "void __cleanup_%(s)s(void);\n"+ + "void __retrieve_%(s)s(void);\n"+ + "void __publish_%(s)s(void);")%{'s':locstr} for locstr in locstrs]), + "retrieve_calls":"\n ".join([ + "__retrieve_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]), + "publish_calls":"\n ".join([ #Call publish in reverse order + "__publish_%s();"%locstr for locstr in locstrs]), + "init_calls":"\n ".join([ + "init_level=%d; "%(i+1)+ + "if((res = __init_%s(argc,argv))){"%locstr + + #"printf(\"%s\"); "%locstr + #for debug + "return res;}" for i,locstr in enumerate(locstrs)]), + "cleanup_calls":"\n ".join([ + "if(init_level >= %d) "%i+ + "__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]) + } + else: + plc_main_code = targets.code("plc_common_main") % { + "calls_prototypes":"\n", + "retrieve_calls":"\n", + "publish_calls":"\n", + "init_calls":"\n", + "cleanup_calls":"\n" + } + plc_main_code += targets.targetcode(self.GetTarget().getcontent()["name"]) + return plc_main_code + + + def _Build(self): + """ + Method called by user to (re)build SoftPLC and confnode tree + """ + if self.AppFrame is not None: + self.AppFrame.ClearErrors() + + buildpath = self._getBuildPath() + + # Eventually create build dir + if not os.path.exists(buildpath): + os.mkdir(buildpath) + # There is something to clean + self.EnableMethod("_Clean", True) + + self.logger.flush() + self.logger.write(_("Start build in %s\n") % buildpath) + + # Generate SoftPLC IEC code + IECGenRes = self._Generate_SoftPLC() + self.ShowMethod("_showIECcode", True) + + # If IEC code gen fail, bail out. + if not IECGenRes: + self.logger.write_error(_("IEC-61131-3 code generation failed !\n")) + self.ResetBuildMD5() + return False + + # Reset variable and program list that are parsed from + # CSV file generated by IEC2C compiler. + self.ResetIECProgramsAndVariables() + + # Generate C code and compilation params from confnode hierarchy + self.logger.write(_("Generating confnodes C code\n")) + try: + self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C( + buildpath, + self.PLCGeneratedLocatedVars) + except Exception, exc: + self.logger.write_error(_("ConfNodes code generation failed !\n")) + self.logger.write_error(traceback.format_exc()) + self.ResetBuildMD5() + return False + + # Get temporary directory path + extrafilespath = self._getExtraFilesPath() + # Remove old directory + if os.path.exists(extrafilespath): + shutil.rmtree(extrafilespath) + # Recreate directory + os.mkdir(extrafilespath) + # Then write the files + for fname,fobject in ExtraFiles: + fpath = os.path.join(extrafilespath,fname) + open(fpath, "wb").write(fobject.read()) + # Now we can forget ExtraFiles (will close files object) + del ExtraFiles + + # Template based part of C code generation + # files are stacked at the beginning, as files of confnode tree root + for generator, filename, name in [ + # debugger code + (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"), + # init/cleanup/retrieve/publish, run and align code + (self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]: + try: + # Do generate + code = generator() + if code is None: + raise + code_path = os.path.join(buildpath,filename) + open(code_path, "w").write(code) + # Insert this file as first file to be compiled at root confnode + self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS)) + except Exception, exc: + self.logger.write_error(name+_(" generation failed !\n")) + self.logger.write_error(traceback.format_exc()) + self.ResetBuildMD5() + return False + + self.logger.write(_("C code generated successfully.\n")) + + # Get current or fresh builder + builder = self.GetBuilder() + if builder is None: + self.logger.write_error(_("Fatal : cannot get builder.\n")) + self.ResetBuildMD5() + return False + + # Build + try: + if not builder.build() : + self.logger.write_error(_("C Build failed.\n")) + return False + except Exception, exc: + self.logger.write_error(_("C Build crashed !\n")) + self.logger.write_error(traceback.format_exc()) + self.ResetBuildMD5() + return False + + self.logger.write(_("Successfully built.\n")) + # Update GUI status about need for transfer + self.CompareLocalAndRemotePLC() + return True + + def ShowError(self, logger, from_location, to_location): + chunk_infos = self.GetChunkInfos(from_location, to_location) + for infos, (start_row, start_col) in chunk_infos: + start = (from_location[0] - start_row, from_location[1] - start_col) + end = (to_location[0] - start_row, to_location[1] - start_col) + #print from_location, to_location, start_row, start_col, start, end + if self.AppFrame is not None: + self.AppFrame.ShowError(infos, start, end) + + def _showIECcode(self): + self._OpenView("IEC code") + + def _editIECrawcode(self): + self._OpenView("IEC raw code") + + def _OpenView(self, name=None): + if name == "IEC code": + plc_file = self._getIECcodepath() + + IEC_code_viewer = TextViewer(self.AppFrame.TabsOpened, "", None, None, instancepath=name) + #IEC_code_viewer.Enable(False) + IEC_code_viewer.SetTextSyntax("ALL") + IEC_code_viewer.SetKeywords(IEC_KEYWORDS) + try: + text = file(plc_file).read() + except: + text = '(* No IEC code have been generated at that time ! *)' + IEC_code_viewer.SetText(text = text) + IEC_code_viewer.SetIcon(self.AppFrame.GenerateBitmap("ST")) + + self.AppFrame.EditProjectElement(IEC_code_viewer, name) + + return IEC_code_viewer + + elif name == "IEC raw code": + controler = MiniTextControler(self._getIECrawcodepath()) + IEC_raw_code_viewer = TextViewer(self.AppFrame.TabsOpened, "", None, controler, instancepath=name) + #IEC_raw_code_viewer.Enable(False) + IEC_raw_code_viewer.SetTextSyntax("ALL") + IEC_raw_code_viewer.SetKeywords(IEC_KEYWORDS) + IEC_raw_code_viewer.RefreshView() + IEC_raw_code_viewer.SetIcon(self.AppFrame.GenerateBitmap("ST")) + + self.AppFrame.EditProjectElement(IEC_raw_code_viewer, name) + + return IEC_raw_code_viewer + + return None + + def _Clean(self): + if os.path.isdir(os.path.join(self._getBuildPath())): + self.logger.write(_("Cleaning the build directory\n")) + shutil.rmtree(os.path.join(self._getBuildPath())) + else: + self.logger.write_error(_("Build directory already clean\n")) + self.ShowMethod("_showIECcode", False) + self.EnableMethod("_Clean", False) + # kill the builder + self._builder = None + self.CompareLocalAndRemotePLC() + + ############# Real PLC object access ############# + def UpdateMethodsFromPLCStatus(self): + # Get PLC state : Running or Stopped + # TODO : use explicit status instead of boolean + status = None + if self._connector is not None: + status = self._connector.GetPLCstatus() + if status is None: + self._connector = None + status = "Disconnected" + if(self.previous_plcstate != status): + for args in { + "Started" : [("_Run", False), + ("_Stop", True)], + "Stopped" : [("_Run", True), + ("_Stop", False)], + "Empty" : [("_Run", False), + ("_Stop", False)], + "Broken" : [], + "Disconnected" :[("_Run", False), + ("_Stop", False), + ("_Transfer", False), + ("_Connect", True), + ("_Disconnect", False)], + }.get(status,[]): + self.ShowMethod(*args) + self.previous_plcstate = status + return True + return False + + def PullPLCStatusProc(self, event): + if self._connector is None: + self.StatusTimer.Stop() + if self.UpdateMethodsFromPLCStatus(): + + status = _(self.previous_plcstate) + {"Broken": self.logger.write_error, + None: lambda x: None}.get( + self.previous_plcstate, self.logger.write)(_("PLC is %s\n")%status) + self.AppFrame.RefreshAll() + + def RegisterDebugVarToConnector(self): + self.DebugTimer=None + Idxs = [] + self.TracedIECPath = [] + if self._connector is not None: + self.IECdebug_lock.acquire() + IECPathsToPop = [] + for IECPath,data_tuple in self.IECdebug_datas.iteritems(): + WeakCallableDict, data_log, status, fvalue = data_tuple + if len(WeakCallableDict) == 0: + # Callable Dict is empty. + # This variable is not needed anymore! + #print "Unused : " + IECPath + IECPathsToPop.append(IECPath) + elif IECPath != "__tick__": + # Convert + Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) + if Idx is not None: + if IEC_Type in DebugTypesSize: + Idxs.append((Idx, IEC_Type, fvalue, IECPath)) + else: + self.logger.write_warning(_("Debug : Unsuppoted type to debug %s\n")%IEC_Type) + else: + self.logger.write_warning(_("Debug : Unknown variable %s\n")%IECPath) + for IECPathToPop in IECPathsToPop: + self.IECdebug_datas.pop(IECPathToPop) + + if Idxs: + Idxs.sort() + self.TracedIECPath = zip(*Idxs)[3] + self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3])) + else: + self.TracedIECPath = [] + self._connector.SetTraceVariablesList([]) + self.IECdebug_lock.release() + + #for IEC_path, IECdebug_data in self.IECdebug_datas.iteritems(): + # print IEC_path, IECdebug_data[0].keys() + + def ReArmDebugRegisterTimer(self): + if self.DebugTimer is not None: + self.DebugTimer.cancel() + + # Timer to prevent rapid-fire when registering many variables + # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead + self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector]) + # Rearm anti-rapid-fire timer + self.DebugTimer.start() + + def GetDebugIECVariableType(self, IECPath): + Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) + return IEC_Type + + def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs): + """ + Dispatching use a dictionnary linking IEC variable paths + to a WeakKeyDictionary linking + weakly referenced callables to optionnal args + """ + if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath): + return None + + self.IECdebug_lock.acquire() + # If no entry exist, create a new one with a fresh WeakKeyDictionary + IECdebug_data = self.IECdebug_datas.get(IECPath, None) + if IECdebug_data is None: + IECdebug_data = [ + WeakKeyDictionary(), # Callables + [], # Data storage [(tick, data),...] + "Registered", # Variable status + None] # Forced value + self.IECdebug_datas[IECPath] = IECdebug_data + + IECdebug_data[0][callableobj]=(args, kwargs) + + self.IECdebug_lock.release() + + self.ReArmDebugRegisterTimer() + + return IECdebug_data[1] + + def UnsubscribeDebugIECVariable(self, IECPath, callableobj): + #print "Unsubscribe", IECPath, callableobj + self.IECdebug_lock.acquire() + IECdebug_data = self.IECdebug_datas.get(IECPath, None) + if IECdebug_data is not None: + IECdebug_data[0].pop(callableobj,None) + self.IECdebug_lock.release() + + self.ReArmDebugRegisterTimer() + + def UnsubscribeAllDebugIECVariable(self): + self.IECdebug_lock.acquire() + IECdebug_data = {} + self.IECdebug_lock.release() + + self.ReArmDebugRegisterTimer() + + def ForceDebugIECVariable(self, IECPath, fvalue): + if not self.IECdebug_datas.has_key(IECPath): + return + + self.IECdebug_lock.acquire() + + # If no entry exist, create a new one with a fresh WeakKeyDictionary + IECdebug_data = self.IECdebug_datas.get(IECPath, None) + IECdebug_data[2] = "Forced" + IECdebug_data[3] = fvalue + + self.IECdebug_lock.release() + + self.ReArmDebugRegisterTimer() + + def ReleaseDebugIECVariable(self, IECPath): + if not self.IECdebug_datas.has_key(IECPath): + return + + self.IECdebug_lock.acquire() + + # If no entry exist, create a new one with a fresh WeakKeyDictionary + IECdebug_data = self.IECdebug_datas.get(IECPath, None) + IECdebug_data[2] = "Registered" + IECdebug_data[3] = None + + self.IECdebug_lock.release() + + self.ReArmDebugRegisterTimer() + + def CallWeakcallables(self, IECPath, function_name, *cargs): + data_tuple = self.IECdebug_datas.get(IECPath, None) + if data_tuple is not None: + WeakCallableDict, data_log, status, fvalue = data_tuple + #data_log.append((debug_tick, value)) + for weakcallable,(args,kwargs) in WeakCallableDict.iteritems(): + #print weakcallable, value, args, kwargs + function = getattr(weakcallable, function_name, None) + if function is not None: + if status == "Forced" and cargs[1] == fvalue: + function(*(cargs + (True,) + args), **kwargs) + else: + function(*(cargs + args), **kwargs) + # This will block thread if more than one call is waiting + + def GetTicktime(self): + return self._Ticktime + + def RemoteExec(self, script, **kwargs): + if self._connector is None: + return -1, "No runtime connected!" + return self._connector.RemoteExec(script, **kwargs) + + def DebugThreadProc(self): + """ + This thread waid PLC debug data, and dispatch them to subscribers + """ + self.debug_break = False + debug_getvar_retry = 0 + while (not self.debug_break) and (self._connector is not None): + Trace = self._connector.GetTraceVariables() + if(Trace): + plc_status, debug_tick, debug_vars = Trace + else: + plc_status = None + debug_getvar_retry += 1 + #print debug_tick, debug_vars + if plc_status == "Started": + self.IECdebug_lock.acquire() + if len(debug_vars) == len(self.TracedIECPath): + if debug_getvar_retry > DEBUG_RETRIES_WARN: + self.logger.write(_("... debugger recovered\n")) + debug_getvar_retry = 0 + for IECPath,value in zip(self.TracedIECPath, debug_vars): + if value is not None: + self.CallWeakcallables(IECPath, "NewValue", debug_tick, value) + self.CallWeakcallables("__tick__", "NewDataAvailable") + self.IECdebug_lock.release() + if debug_getvar_retry == DEBUG_RETRIES_WARN: + self.logger.write(_("Waiting debugger to recover...\n")) + if debug_getvar_retry == DEBUG_RETRIES_REREGISTER: + # re-register debug registry to PLC + wx.CallAfter(self.RegisterDebugVarToConnector) + if debug_getvar_retry != 0: + # Be patient, tollerate PLC to come up before debugging + time.sleep(0.1) + else: + self.debug_break = True + self.logger.write(_("Debugger disabled\n")) + self.DebugThread = None + + def KillDebugThread(self): + tmp_debugthread = self.DebugThread + self.debug_break = True + if tmp_debugthread is not None: + self.logger.writeyield(_("Stopping debugger...\n")) + tmp_debugthread.join(timeout=5) + if tmp_debugthread.isAlive() and self.logger: + self.logger.write_warning(_("Couldn't stop debugger.\n")) + else: + self.logger.write(_("Debugger stopped.\n")) + self.DebugThread = None + + def _connect_debug(self): + if self.AppFrame: + self.AppFrame.ResetGraphicViewers() + self.RegisterDebugVarToConnector() + if self.DebugThread is None: + self.DebugThread = Thread(target=self.DebugThreadProc) + self.DebugThread.start() + + def _Run(self): + """ + Start PLC + """ + if self.GetIECProgramsAndVariables(): + self._connector.StartPLC() + self.logger.write(_("Starting PLC\n")) + self._connect_debug() + else: + self.logger.write_error(_("Couldn't start PLC !\n")) + wx.CallAfter(self.UpdateMethodsFromPLCStatus) + + def _Stop(self): + """ + Stop PLC + """ + if self._connector is not None and not self._connector.StopPLC(): + self.logger.write_error(_("Couldn't stop PLC !\n")) + + # debugthread should die on his own + #self.KillDebugThread() + + wx.CallAfter(self.UpdateMethodsFromPLCStatus) + + def _Connect(self): + # don't accept re-connetion is already connected + if self._connector is not None: + self.logger.write_error(_("Already connected. Please disconnect\n")) + return + + # Get connector uri + uri = self.\ + BeremizRoot.\ + getURI_location().\ + strip() + + # if uri is empty launch discovery dialog + if uri == "": + # Launch Service Discovery dialog + dialog = DiscoveryDialog(self.AppFrame) + answer = dialog.ShowModal() + uri = dialog.GetURI() + dialog.Destroy() + + # Nothing choosed or cancel button + if uri is None or answer == wx.ID_CANCEL: + self.logger.write_error(_("Connection canceled!\n")) + return + else: + self.\ + BeremizRoot.\ + setURI_location(uri) + + # Get connector from uri + try: + self._connector = connectors.ConnectorFactory(uri, self) + except Exception, msg: + self.logger.write_error(_("Exception while connecting %s!\n")%uri) + self.logger.write_error(traceback.format_exc()) + + # Did connection success ? + if self._connector is None: + # Oups. + self.logger.write_error(_("Connection failed to %s!\n")%uri) + else: + self.ShowMethod("_Connect", False) + self.ShowMethod("_Disconnect", True) + self.ShowMethod("_Transfer", True) + + self.CompareLocalAndRemotePLC() + + # Init with actual PLC status and print it + self.UpdateMethodsFromPLCStatus() + if self.previous_plcstate is not None: + status = _(self.previous_plcstate) + else: + status = "" + self.logger.write(_("PLC is %s\n")%status) + + # Start the status Timer + self.StatusTimer.Start(milliseconds=500, oneShot=False) + + if self.previous_plcstate=="Started": + if self.DebugAvailable() and self.GetIECProgramsAndVariables(): + self.logger.write(_("Debug connect matching running PLC\n")) + self._connect_debug() + else: + self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n")) + + def CompareLocalAndRemotePLC(self): + if self._connector is None: + return + # We are now connected. Update button status + MD5 = self.GetLastBuildMD5() + # Check remote target PLC correspondance to that md5 + if MD5 is not None: + if not self._connector.MatchMD5(MD5): +# self.logger.write_warning( +# _("Latest build does not match with target, please transfer.\n")) + self.EnableMethod("_Transfer", True) + else: +# self.logger.write( +# _("Latest build matches target, no transfer needed.\n")) + self.EnableMethod("_Transfer", True) + # warns controller that program match + self.ProgramTransferred() + #self.EnableMethod("_Transfer", False) + else: +# self.logger.write_warning( +# _("Cannot compare latest build to target. Please build.\n")) + self.EnableMethod("_Transfer", False) + + + def _Disconnect(self): + self._connector = None + self.StatusTimer.Stop() + wx.CallAfter(self.UpdateMethodsFromPLCStatus) + + def _Transfer(self): + # Get the last build PLC's + MD5 = self.GetLastBuildMD5() + + # Check if md5 file is empty : ask user to build PLC + if MD5 is None : + self.logger.write_error(_("Failed : Must build before transfer.\n")) + return False + + # Compare PLC project with PLC on target + if self._connector.MatchMD5(MD5): + self.logger.write( + _("Latest build already matches current target. Transfering anyway...\n")) + + # Get temprary directory path + extrafilespath = self._getExtraFilesPath() + extrafiles = [(name, open(os.path.join(extrafilespath, name), + 'rb').read()) \ + for name in os.listdir(extrafilespath) \ + if not name=="CVS"] + + # Send PLC on target + builder = self.GetBuilder() + if builder is not None: + data = builder.GetBinaryCode() + if data is not None : + if self._connector.NewPLC(MD5, data, extrafiles) and self.GetIECProgramsAndVariables(): + self.UnsubscribeAllDebugIECVariable() + self.ProgramTransferred() + if self.AppFrame is not None: + self.AppFrame.RefreshInstancesTree() + self.AppFrame.CloseObsoleteDebugTabs() + self.logger.write(_("Transfer completed successfully.\n")) + else: + self.logger.write_error(_("Transfer failed\n")) + else: + self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n")) + + wx.CallAfter(self.UpdateMethodsFromPLCStatus) + + ConfNodeMethods = [ + {"bitmap" : opjimg("Build"), + "name" : _("Build"), + "tooltip" : _("Build project into build folder"), + "method" : "_Build"}, + {"bitmap" : opjimg("Clean"), + "name" : _("Clean"), + "enabled" : False, + "tooltip" : _("Clean project build folder"), + "method" : "_Clean"}, + {"bitmap" : opjimg("Run"), + "name" : _("Run"), + "shown" : False, + "tooltip" : _("Start PLC"), + "method" : "_Run"}, + {"bitmap" : opjimg("Stop"), + "name" : _("Stop"), + "shown" : False, + "tooltip" : _("Stop Running PLC"), + "method" : "_Stop"}, + {"bitmap" : opjimg("Connect"), + "name" : _("Connect"), + "tooltip" : _("Connect to the target PLC"), + "method" : "_Connect"}, + {"bitmap" : opjimg("Transfer"), + "name" : _("Transfer"), + "shown" : False, + "tooltip" : _("Transfer PLC"), + "method" : "_Transfer"}, + {"bitmap" : opjimg("Disconnect"), + "name" : _("Disconnect"), + "shown" : False, + "tooltip" : _("Disconnect from PLC"), + "method" : "_Disconnect"}, + {"bitmap" : opjimg("ShowIECcode"), + "name" : _("Show code"), + "shown" : False, + "tooltip" : _("Show IEC code generated by PLCGenerator"), + "method" : "_showIECcode"}, + {"bitmap" : opjimg("editIECrawcode"), + "name" : _("Raw IEC code"), + "tooltip" : _("Edit raw IEC code added to code generated by PLCGenerator"), + "method" : "_editIECrawcode"}, + ] diff -r 180e4a7d945c -r 1c23952dbde1 LPCBeremiz.py --- a/LPCBeremiz.py Thu May 03 19:02:34 2012 +0200 +++ b/LPCBeremiz.py Mon May 07 18:47:29 2012 +0200 @@ -59,25 +59,25 @@ __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation from Beremiz import * -from plugger import PluginsRoot, PlugTemplate, opjimg, connectors +from ConfigTree import ConfigTreeRoot, ConfigTreeNode, opjimg, connectors from plcopen.structures import LOCATIONDATATYPES -from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP,\ +from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\ LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY from PLCOpenEditor import IDEFrame, ProjectDialog havecanfestival = False try: - from plugins.canfestival import RootClass as CanOpenRootClass - from plugins.canfestival.canfestival import _SlavePlug, _NodeListPlug, NodeManager + from confnodes.canfestival import RootClass as CanOpenRootClass + from confnodes.canfestival.canfestival import _SlavePlug, _NodeListPlug, NodeManager havecanfestival = True except: havecanfestival = False #------------------------------------------------------------------------------- -# CANFESTIVAL PLUGIN HACK +# CANFESTIVAL CONFNODE HACK #------------------------------------------------------------------------------- -# from plugins.canfestival import canfestival +# from confnodes.canfestival import canfestival # class LPC_canfestival_config: # def getCFLAGS(self, *args): # return "" @@ -148,9 +148,9 @@ if group["type"] == LOCATION_GROUP and child in group["children"]: group["children"].remove(child) -BUS_TEXT = """/* Code generated by LPCBus plugin */ - -/* LPCBus plugin includes */ +BUS_TEXT = """/* Code generated by LPCBus confnode */ + +/* LPCBus confnode includes */ #include "app_glue.h" #ifdef _WINDOWS_H #include "iec_types.h" @@ -160,10 +160,10 @@ %(declare_code)s -/* LPCBus plugin user variables definition */ +/* LPCBus confnode user variables definition */ %(var_decl)s -/* LPCBus plugin functions */ +/* LPCBus confnode functions */ int __init_%(location_str)s(int argc,char **argv) { %(init_code)s @@ -240,7 +240,7 @@ def GetVariableLocationTree(self): return {"name": self.BaseParams.getName(), - "type": LOCATION_PLUGIN, + "type": LOCATION_CONFNODE, "location": self.GetFullIEC_Channel(), "icon": self.Icon, "children": [self._GetVariableLocationTree(self.GetCurrentLocation(), child) @@ -291,7 +291,7 @@ def PlugGenerate_C(self, buildpath, locations): """ Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) @param locations: List of complete variables locations \ [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) "NAME" : name of the variable (generally "__IW0_1_2" style) @@ -367,7 +367,7 @@ return [(Gen_Module_path, matiec_flags)],"",True #------------------------------------------------------------------------------- -# LPC CanFestival Plugin Class +# LPC CanFestival ConfNode Class #------------------------------------------------------------------------------- if havecanfestival: @@ -444,7 +444,7 @@ return "" def LoadChilds(self): - PlugTemplate.LoadChilds(self) + ConfigTreeNode.LoadChilds(self) if self.GetChildByName("Master") is None: master = self.PlugAddChild("Master", "CanOpenNode", 0) @@ -456,7 +456,7 @@ #------------------------------------------------------------------------------- -# LPCPluginsRoot Class +# LPCConfigTreeRoot Class #------------------------------------------------------------------------------- def mycopytree(src, dst): @@ -479,9 +479,9 @@ [SIMULATION_MODE, TRANSFER_MODE] = range(2) -class LPCPluginsRoot(PluginsRoot): - - PluginMethods = [ +class LPCConfigTreeRoot(ConfigTreeRoot): + + ConfNodeMethods = [ {"bitmap" : opjimg("Debug"), "name" : _("Simulate"), "tooltip" : _("Simulate PLC"), @@ -510,7 +510,7 @@ def __init__(self, frame, logger, buildpath): self.OrigBuildPath = buildpath - PluginsRoot.__init__(self, frame, logger) + ConfigTreeRoot.__init__(self, frame, logger) if havecanfestival: self.PlugChildsTypes += [("LPCBus", LPCBus, "LPC bus"), ("CanOpen", LPCCanOpen, "CanOpen bus")] @@ -528,23 +528,23 @@ self.AbortTransferTimer = None - def PluginLibraryFilePath(self): + def ConfNodeLibraryFilePath(self): if self.OrigBuildPath is not None: return os.path.join(self.OrigBuildPath, "pous.xml") else: - return PluginsRoot.PluginLibraryFilePath(self) + return ConfigTreeRoot.ConfNodeLibraryFilePath(self) def GetProjectName(self): return self.Project.getname() def GetDefaultTargetName(self): if self.CurrentMode == SIMULATION_MODE: - return PluginsRoot.GetDefaultTargetName(self) + return ConfigTreeRoot.GetDefaultTargetName(self) else: return "LPC" def GetTarget(self): - target = PluginsRoot.GetTarget(self) + target = ConfigTreeRoot.GetTarget(self) if self.CurrentMode != SIMULATION_MODE: target.getcontent()["value"].setBuildPath(self.BuildPath) return target @@ -555,7 +555,7 @@ self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build") return self.SimulationBuildPath else: - return PluginsRoot._getBuildPath(self) + return ConfigTreeRoot._getBuildPath(self) def _Build(self): save = self.ProjectTestModified() @@ -564,7 +564,7 @@ self.AppFrame._Refresh(TITLE, FILEMENU) if self.BuildPath is not None: mycopytree(self.OrigBuildPath, self.BuildPath) - PluginsRoot._Build(self) + ConfigTreeRoot._Build(self) if save: wx.CallAfter(self.AppFrame.RefreshAll) @@ -678,7 +678,7 @@ self._AddParamsMembers() self.PluggedChilds = {} - # Keep track of the root plugin (i.e. project path) + # Keep track of the root confnode (i.e. project path) self.ProjectPath = ProjectPath self.BuildPath = self._getBuildPath() @@ -686,8 +686,8 @@ mycopytree(self.OrigBuildPath, self.BuildPath) # If dir have already be made, and file exist - if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()): - #Load the plugin.xml file into parameters members + if os.path.isdir(self.PlugPath()) and os.path.isfile(self.ConfNodeXmlFilePath()): + #Load the confnode.xml file into parameters members result = self.LoadXMLParams() if result: return result @@ -703,9 +703,9 @@ self.SaveProject() if wx.GetApp() is None: - self.RefreshPluginsBlockLists() + self.RefreshConfNodesBlockLists() else: - wx.CallAfter(self.RefreshPluginsBlockLists) + wx.CallAfter(self.RefreshConfNodesBlockLists) return None @@ -889,7 +889,7 @@ else: self.LocationCFilesAndCFLAGS = [] - # plugin asks for some LDFLAGS + # confnode asks for some LDFLAGS if PlugLDFLAGS: # LDFLAGS can be either string if type(PlugLDFLAGS)==type(str()): @@ -901,7 +901,7 @@ self.LDFLAGS=[] # Template based part of C code generation - # files are stacked at the beginning, as files of plugin tree root + # files are stacked at the beginning, as files of confnode tree root for generator, filename, name in [ # debugger code (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"), @@ -918,7 +918,7 @@ raise code_path = os.path.join(buildpath,filename) open(code_path, "w").write(code) - # Insert this file as first file to be compiled at root plugin + # Insert this file as first file to be compiled at root confnode self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS)) except Exception, exc: self.logger.write_error(name+_(" generation failed !\n")) @@ -970,7 +970,7 @@ self.ApplyOnlineMode() def _Stop(self): - PluginsRoot._Stop(self) + ConfigTreeRoot._Stop(self) if self.CurrentMode == SIMULATION_MODE: self.StopSimulation() @@ -1001,7 +1001,7 @@ if self.CurrentMode is None and self.OnlineMode != "OFF": self.CurrentMode = TRANSFER_MODE - if PluginsRoot._Build(self): + if ConfigTreeRoot._Build(self): ID_ABORTTRANSFERTIMER = wx.NewId() self.AbortTransferTimer = wx.Timer(self.AppFrame, ID_ABORTTRANSFERTIMER) @@ -1023,7 +1023,7 @@ self.logger.write(_("Start PLC transfer\n")) self.AbortTransferTimer.Stop() - PluginsRoot._Transfer(self) + ConfigTreeRoot._Transfer(self) self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True) def AbortTransfer(self, event): @@ -1113,11 +1113,11 @@ frame.Hide() - self.PluginRoot.ResetAppFrame(lpcberemiz_cmd.Log) - if self.PluginRoot.OnlineMode == 0: - self.PluginRoot._connector = None - - self.PluginRoot.KillDebugThread() + self.CTR.ResetAppFrame(lpcberemiz_cmd.Log) + if self.CTR.OnlineMode == 0: + self.CTR._connector = None + + self.CTR.KillDebugThread() self.KillLocalRuntime() self.SaveLastState() @@ -1141,7 +1141,7 @@ def RefreshFileMenu(self): MenuToolBar = self.Panes["MenuToolBar"] - if self.PluginRoot is not None: + if self.CTR is not None: selected = self.TabsOpened.GetSelection() if selected >= 0: graphic_viewer = isinstance(self.TabsOpened.GetPage(selected), Viewer) @@ -1163,7 +1163,7 @@ self.FileMenu.Enable(wx.ID_PRINT, False) MenuToolBar.EnableTool(wx.ID_PRINT, False) self.FileMenu.Enable(wx.ID_PAGE_SETUP, True) - project_modified = self.PluginRoot.ProjectTestModified() + project_modified = self.CTR.ProjectTestModified() self.FileMenu.Enable(wx.ID_SAVE, project_modified) MenuToolBar.EnableTool(wx.ID_SAVE, project_modified) self.FileMenu.Enable(wx.ID_PROPERTIES, True) @@ -1181,15 +1181,15 @@ self.Freeze() self.ClearSizer(self.PLCParamsSizer) - if self.PluginRoot is not None: + if self.CTR is not None: plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) - if self.PluginRoot.PlugTestModified(): + if self.CTR.PlugTestModified(): bkgdclr = CHANGED_TITLE_COLOUR else: bkgdclr = TITLE_COLOUR - if self.PluginRoot not in self.PluginInfos: - self.PluginInfos[self.PluginRoot] = {"right_visible" : False} + if self.CTR not in self.ConfNodeInfos: + self.ConfNodeInfos[self.CTR] = {"right_visible" : False} plcwindow.SetBackgroundColour(TITLE_COLOUR) plcwindow.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown) @@ -1200,7 +1200,7 @@ st = wx.StaticText(plcwindow, -1) st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - st.SetLabel(self.PluginRoot.GetProjectName()) + st.SetLabel(self.CTR.GetProjectName()) plcwindowsizer.AddWindow(st, 0, border=5, flag=wx.ALL|wx.ALIGN_CENTER) plcwindowmainsizer = wx.BoxSizer(wx.VERTICAL) @@ -1209,38 +1209,38 @@ plcwindowbuttonsizer = wx.BoxSizer(wx.HORIZONTAL) plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER) - msizer = self.GenerateMethodButtonSizer(self.PluginRoot, plcwindow, not self.PluginInfos[self.PluginRoot]["right_visible"]) + msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"]) plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW) self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() self.Thaw() - def GenerateTreeBranch(self, plugin): + def GenerateTreeBranch(self, confnode): leftwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) - if plugin.PlugTestModified(): + if confnode.PlugTestModified(): bkgdclr=CHANGED_WINDOW_COLOUR else: bkgdclr=WINDOW_COLOUR leftwindow.SetBackgroundColour(bkgdclr) - if plugin not in self.PluginInfos: - self.PluginInfos[plugin] = {"expanded" : False, "left_visible" : False, "right_visible" : False} - - self.PluginInfos[plugin]["children"] = plugin.IECSortedChilds() - plugin_infos = plugin.GetVariableLocationTree() - plugin_locations = [] - if len(self.PluginInfos[plugin]["children"]) == 0: - plugin_locations = plugin_infos["children"] - if not self.PluginInfos[plugin].has_key("locations_infos"): - self.PluginInfos[plugin]["locations_infos"] = {"root": {"expanded" : False}} - - self.PluginInfos[plugin]["locations_infos"]["root"]["left"] = None - self.PluginInfos[plugin]["locations_infos"]["root"]["right"] = None - self.PluginInfos[plugin]["locations_infos"]["root"]["children"] = [] - - self.PluginTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW) + if confnode not in self.ConfNodeInfos: + self.ConfNodeInfos[confnode] = {"expanded" : False, "left_visible" : False, "right_visible" : False} + + self.ConfNodeInfos[confnode]["children"] = confnode.IECSortedChilds() + confnode_infos = confnode.GetVariableLocationTree() + confnode_locations = [] + if len(self.ConfNodeInfos[confnode]["children"]) == 0: + confnode_locations = confnode_infos["children"] + if not self.ConfNodeInfos[confnode].has_key("locations_infos"): + self.ConfNodeInfos[confnode]["locations_infos"] = {"root": {"expanded" : False}} + + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["left"] = None + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["right"] = None + self.ConfNodeInfos[confnode]["locations_infos"]["root"]["children"] = [] + + self.ConfNodeTreeSizer.AddWindow(leftwindow, 0, border=0, flag=wx.GROW) leftwindowvsizer = wx.BoxSizer(wx.VERTICAL) leftwindow.SetSizer(leftwindowvsizer) @@ -1248,11 +1248,11 @@ leftwindowsizer = wx.BoxSizer(wx.HORIZONTAL) leftwindowvsizer.AddSizer(leftwindowsizer, 0, border=0, flag=0) - self.GenerateEnableButton(leftwindow, leftwindowsizer, plugin) + self.GenerateEnableButton(leftwindow, leftwindowsizer, confnode) st = wx.StaticText(leftwindow, -1) st.SetFont(wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - st.SetLabel(plugin.GetFullIEC_Channel()) + st.SetLabel(confnode.GetFullIEC_Channel()) leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT) expandbutton_id = wx.NewId() @@ -1264,27 +1264,27 @@ expandbutton.SetUseFocusIndicator(False) expandbutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'minus.png'))) - if len(self.PluginInfos[plugin]["children"]) > 0: - expandbutton.SetToggle(self.PluginInfos[plugin]["expanded"]) + if len(self.ConfNodeInfos[confnode]["children"]) > 0: + expandbutton.SetToggle(self.ConfNodeInfos[confnode]["expanded"]) def togglebutton(event): if expandbutton.GetToggle(): - self.ExpandPlugin(plugin) + self.ExpandConfNode(confnode) else: - self.CollapsePlugin(plugin) - self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle() + self.CollapseConfNode(confnode) + self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() event.Skip() expandbutton.Bind(wx.EVT_BUTTON, togglebutton, id=expandbutton_id) - elif len(plugin_locations) > 0: - locations_infos = self.PluginInfos[plugin]["locations_infos"] + elif len(confnode_locations) > 0: + locations_infos = self.ConfNodeInfos[confnode]["locations_infos"] expandbutton.SetToggle(locations_infos["root"]["expanded"]) def togglebutton(event): if expandbutton.GetToggle(): self.ExpandLocation(locations_infos, "root") else: self.CollapseLocation(locations_infos, "root") - self.PluginInfos[plugin]["expanded"] = expandbutton.GetToggle() + self.ConfNodeInfos[confnode]["expanded"] = expandbutton.GetToggle() locations_infos["root"]["expanded"] = expandbutton.GetToggle() self.PLCConfigMainSizer.Layout() self.RefreshScrollBars() @@ -1295,9 +1295,9 @@ leftwindowsizer.AddWindow(expandbutton, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) sb = wx.StaticBitmap(leftwindow, -1) - icon = plugin_infos.get("icon", None) + icon = confnode_infos.get("icon", None) if icon is None: - icon_bitmap = self.LocationImageList.GetBitmap(self.LocationImageDict[plugin_infos["type"]]) + icon_bitmap = self.LocationImageList.GetBitmap(self.LocationImageDict[confnode_infos["type"]]) else: icon_bitmap = wx.Bitmap(icon) sb.SetBitmap(icon_bitmap) @@ -1306,21 +1306,21 @@ st_id = wx.NewId() st = wx.StaticText(leftwindow, st_id, size=wx.DefaultSize, style=wx.NO_BORDER) st.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) - st.SetLabel(plugin.MandatoryParams[1].getName()) + st.SetLabel(confnode.MandatoryParams[1].getName()) leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL) - rightwindow = self.GenerateParamsPanel(plugin, bkgdclr) - self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) - - self.PluginInfos[plugin]["left"] = leftwindow - self.PluginInfos[plugin]["right"] = rightwindow - for child in self.PluginInfos[plugin]["children"]: + rightwindow = self.GenerateParamsPanel(confnode, bkgdclr) + self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) + + self.ConfNodeInfos[confnode]["left"] = leftwindow + self.ConfNodeInfos[confnode]["right"] = rightwindow + for child in self.ConfNodeInfos[confnode]["children"]: self.GenerateTreeBranch(child) - if not self.PluginInfos[child]["expanded"]: - self.CollapsePlugin(child) - - if len(plugin_locations) > 0: - locations_infos = self.PluginInfos[plugin]["locations_infos"] + if not self.ConfNodeInfos[child]["expanded"]: + self.CollapseConfNode(child) + + if len(confnode_locations) > 0: + locations_infos = self.ConfNodeInfos[confnode]["locations_infos"] treectrl = wx.TreeCtrl(self.PLCConfig, -1, size=wx.DefaultSize, style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.NO_BORDER|wx.TR_HIDE_ROOT|wx.TR_NO_LINES|wx.TR_LINES_AT_ROOT) treectrl.SetImageList(self.LocationImageList) @@ -1329,15 +1329,15 @@ treectrl.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.GenerateLocationExpandCollapseFunction(locations_infos, False)) treectrl.AddRoot("") - self.PluginTreeSizer.AddWindow(treectrl, 0, border=0, flag=0) + self.ConfNodeTreeSizer.AddWindow(treectrl, 0, border=0, flag=0) rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1)) rightwindow.SetBackgroundColour(wx.WHITE) - self.PluginTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) + self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW) locations_infos["root"]["left"] = treectrl locations_infos["root"]["right"] = rightwindow - for location in plugin_locations: + for location in confnode_locations: locations_infos["root"]["children"].append("root.%s" % location["name"]) self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location) if locations_infos["root"]["expanded"]: @@ -1416,11 +1416,11 @@ prompt = "" RefreshTimer = None - def __init__(self, PluginRoot, Log): + def __init__(self, CTR, Log): cmd.Cmd.__init__(self, stdin=Log, stdout=Log) self.use_rawinput = False self.Log = Log - self.PluginRoot = PluginRoot + self.CTR = CTR def RestartTimer(self): if self.RefreshTimer is not None: @@ -1440,7 +1440,7 @@ def Show(self): global frame if frame is not None: - self.PluginRoot.SetAppFrame(frame, frame.Log) + self.CTR.SetAppFrame(frame, frame.Log) frame.Show() frame.Raise() @@ -1454,77 +1454,77 @@ def Close(self): global frame - self.PluginRoot.ResetAppFrame(self.Log) + self.CTR.ResetAppFrame(self.Log) if frame is not None: frame.Hide() def Compile(self): - self.PluginRoot._Build() + self.CTR._Build() def SetProjectProperties(self, projectname, productname, productversion, companyname): - properties = self.PluginRoot.GetProjectProperties() + properties = self.CTR.GetProjectProperties() new_properties = properties.copy() new_properties["projectName"] = projectname new_properties["productName"] = productname new_properties["productVersion"] = productversion new_properties["companyName"] = companyname if new_properties != properties: - self.PluginRoot.SetProjectProperties(properties=new_properties, buffer=False) + self.CTR.SetProjectProperties(properties=new_properties, buffer=False) self.RestartTimer() def SetOnlineMode(self, mode, path=None): - self.PluginRoot.SetOnlineMode(mode, path) + self.CTR.SetOnlineMode(mode, path) self.RestartTimer() def AddBus(self, iec_channel, name, icon=None): - for child in self.PluginRoot.IterChilds(): + for child in self.CTR.IterChilds(): if child.BaseParams.getName() == name: return "Error: A bus named %s already exists\n" % name elif child.BaseParams.getIEC_Channel() == iec_channel: return "Error: A bus with IEC_channel %d already exists\n" % iec_channel - bus = self.PluginRoot.PlugAddChild(name, "LPCBus", iec_channel) + bus = self.CTR.PlugAddChild(name, "LPCBus", iec_channel) if bus is None: return "Error: Unable to create bus\n" bus.SetIcon(icon) self.RestartTimer() def RenameBus(self, iec_channel, name): - bus = self.PluginRoot.GetChildByIECLocation((iec_channel,)) + bus = self.CTR.GetChildByIECLocation((iec_channel,)) if bus is None: return "Error: No bus found\n" - for child in self.PluginRoot.IterChilds(): + for child in self.CTR.IterChilds(): if child != bus and child.BaseParams.getName() == name: return "Error: A bus named %s already exists\n" % name bus.BaseParams.setName(name) self.RestartTimer() def ChangeBusIECChannel(self, old_iec_channel, new_iec_channel): - bus = self.PluginRoot.GetChildByIECLocation((old_iec_channel,)) + bus = self.CTR.GetChildByIECLocation((old_iec_channel,)) if bus is None: return "Error: No bus found\n" - for child in self.PluginRoot.IterChilds(): + for child in self.CTR.IterChilds(): if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel: return "Error: A bus with IEC_channel %d already exists\n" % new_iec_channel if wx.GetApp() is None: - self.PluginRoot.UpdateProjectVariableLocation(str(old_iec_channel), + self.CTR.UpdateProjectVariableLocation(str(old_iec_channel), str(new_iec_channel)) else: - self.PluginRoot.UpdateProjectVariableLocation( + self.CTR.UpdateProjectVariableLocation( str(old_iec_channel), str(new_iec_channel)) bus.BaseParams.setIEC_Channel(new_iec_channel) self.RestartTimer() def RemoveBus(self, iec_channel): - bus = self.PluginRoot.GetChildByIECLocation((iec_channel,)) + bus = self.CTR.GetChildByIECLocation((iec_channel,)) if bus is None: return "Error: No bus found\n" - self.PluginRoot.RemoveProjectVariableByFilter(str(iec_channel)) - self.PluginRoot.PluggedChilds["LPCBus"].remove(bus) + self.CTR.RemoveProjectVariableByFilter(str(iec_channel)) + self.CTR.PluggedChilds["LPCBus"].remove(bus) self.RestartTimer() def AddModule(self, parent, iec_channel, name, icode, icon=None): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" for child in _GetModuleChildren(module): @@ -1541,11 +1541,11 @@ self.RestartTimer() def RenameModule(self, iec_location, name): - module = self.PluginRoot.GetChildByIECLocation(iec_location) + module = self.CTR.GetChildByIECLocation(iec_location) if module is None: return "Error: No module found\n" - parent = self.PluginRoot.GetChildByIECLocation(iec_location[:-1]) - if parent is self.PluginRoot: + parent = self.CTR.GetChildByIECLocation(iec_location[:-1]) + if parent is self.CTR: return "Error: No module found\n" if module["name"] != name: for child in _GetModuleChildren(parent): @@ -1555,39 +1555,39 @@ self.RestartTimer() def ChangeModuleIECChannel(self, old_iec_location, new_iec_channel): - module = self.PluginRoot.GetChildByIECLocation(old_iec_location) + module = self.CTR.GetChildByIECLocation(old_iec_location) if module is None: return "Error: No module found\n" - parent = self.PluginRoot.GetChildByIECLocation(old_iec_location[:-1]) - if parent is self.PluginRoot: + parent = self.CTR.GetChildByIECLocation(old_iec_location[:-1]) + if parent is self.CTR: return "Error: No module found\n" if module["IEC_Channel"] != new_iec_channel: for child in _GetModuleChildren(parent): if child["IEC_Channel"] == new_iec_channel: return "Error: A module with IEC_channel %d already exists\n" % new_iec_channel - self.PluginRoot.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)), ".".join(map(str, old_iec_location[:1] + (new_iec_channel,)))) + self.CTR.UpdateProjectVariableLocation(".".join(map(str, old_iec_location)), ".".join(map(str, old_iec_location[:1] + (new_iec_channel,)))) module["IEC_Channel"] = new_iec_channel self.RestartTimer() def ChangeModuleInitCode(self, iec_location, icode): - module = self.PluginRoot.GetChildByIECLocation(iec_location) + module = self.CTR.GetChildByIECLocation(iec_location) if module is None: return "Error: No module found\n" module["init"] = icode def RemoveModule(self, parent, iec_channel): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" child = _GetModuleBySomething(module, "IEC_Channel", (iec_channel,)) if child is None: return "Error: No module found\n" - self.PluginRoot.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,)))) + self.CTR.RemoveProjectVariableByFilter(".".join(map(str, parent + (iec_channel,)))) _RemoveModuleChild(module, child) self.RestartTimer() def StartGroup(self, parent, name, icon=None): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" for child in module["children"]: @@ -1600,7 +1600,7 @@ self.RestartTimer() def AddVariable(self, parent, location, name, direction, type, rcode, pcode, description=""): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" for child in _GetModuleChildren(module): @@ -1618,7 +1618,7 @@ self.RestartTimer() def ChangeVariableParams(self, parent, location, new_name, new_direction, new_type, new_rcode, new_pcode, new_description=None): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" variable = None @@ -1630,7 +1630,7 @@ if variable is None: return "Error: No variable found\n" if variable["name"] != new_name: - self.PluginRoot.UpdateProjectVariableName(variable["name"], new_name) + self.CTR.UpdateProjectVariableName(variable["name"], new_name) variable["name"] = new_name variable["type"] = LOCATION_TYPES[new_direction] variable["IEC_type"] = new_type @@ -1641,15 +1641,15 @@ self.RestartTimer() def RemoveVariable(self, parent, location, direction): - module = self.PluginRoot.GetChildByIECLocation(parent) + module = self.CTR.GetChildByIECLocation(parent) if module is None: return "Error: No parent found\n" child = _GetModuleVariable(module, location, direction) if child is None: return "Error: No variable found\n" - size = LOCATION_SIZES[self.PluginRoot.GetBaseType(child["IEC_type"])] + size = LOCATION_SIZES[self.CTR.GetBaseType(child["IEC_type"])] address = "%" + LOCATION_DIRS[child["type"]] + size + ".".join(map(str, parent + location)) - self.PluginRoot.RemoveProjectVariableByAddress(address) + self.CTR.RemoveProjectVariableByAddress(address) _RemoveModuleChild(module, child) self.RestartTimer() @@ -1714,7 +1714,7 @@ return res return CmdFunction - def CmdThreadProc(PluginRoot, Log): + def CmdThreadProc(CTR, Log): global lpcberemiz_cmd for function, (arg_types, opt) in {"Exit": ([], 0), "Show": ([], 0), @@ -1738,26 +1738,26 @@ "RemoveVariable": ([location, location], 0)}.iteritems(): setattr(LPCBeremiz_Cmd, "do_%s" % function, GetCmdFunction(function, arg_types, opt)) - lpcberemiz_cmd = LPCBeremiz_Cmd(PluginRoot, Log) + lpcberemiz_cmd = LPCBeremiz_Cmd(CTR, Log) lpcberemiz_cmd.cmdloop() Log = StdoutPseudoFile(port) - PluginRoot = LPCPluginsRoot(None, Log, buildpath) + CTR = LPCConfigTreeRoot(None, Log, buildpath) if projectOpen is not None and os.path.isdir(projectOpen): - result = PluginRoot.LoadProject(projectOpen) + result = CTR.LoadProject(projectOpen) if result: Log.write("Error: Invalid project directory", result) else: Log.write("Error: No such file or directory") - cmd_thread=Thread(target=CmdThreadProc, args=[PluginRoot, Log]) + cmd_thread=Thread(target=CmdThreadProc, args=[CTR, Log]) cmd_thread.start() # Install a exception handle for bug reports AddExceptHook(os.getcwd(),__version__) - frame = LPCBeremiz(None, plugin_root=PluginRoot, debug=True) + frame = LPCBeremiz(None, ctr=CTR, debug=True) app.MainLoop() diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/.cvsignore Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,13 @@ +from os import listdir, path + +_base_path = path.split(__file__)[0] + +__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name.upper() != "CVS" or name.endswith(".py") and not name.startswith("__")] + +helps = [] +for name in __all__: + helpfilename = path.join(_base_path, name, "README") + if path.isfile(helpfilename): + helps.append(open(helpfilename).readline().strip()) + else: + helps.append(name) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/.cvsignore Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/CFileEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/CFileEditor.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,967 @@ +import keyword + +import wx +import wx.grid +import wx.stc as stc +import wx.lib.buttons + +from controls import CustomGrid, CustomTable, EditorPanel + +if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } +else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 12, + 'size2': 10, + } + + +def AppendMenu(parent, help, id, kind, text): + if wx.VERSION >= (2, 6, 0): + parent.Append(help=help, id=id, kind=kind, text=text) + else: + parent.Append(helpString=help, id=id, kind=kind, item=text) + + +[ID_CPPEDITOR, +] = [wx.NewId() for _init_ctrls in range(1)] + +CPP_KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class", + "const", "const_cast", "continue", "default", "delete", "do", "double", + "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", + "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", + "namespace", "new", "operator", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", + "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", + "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", + "void", "volatile", "wchar_t", "while"] + +def GetCursorPos(old, new): + old_length = len(old) + new_length = len(new) + common_length = min(old_length, new_length) + i = 0 + for i in xrange(common_length): + if old[i] != new[i]: + break + if old_length < new_length: + if common_length > 0 and old[i] != new[i]: + return i + new_length - old_length + else: + return i + new_length - old_length + 1 + elif old_length > new_length or i < min(old_length, new_length) - 1: + if common_length > 0 and old[i] != new[i]: + return i + else: + return i + 1 + else: + return None + +class CppEditor(stc.StyledTextCtrl): + + fold_symbols = 3 + + def __init__(self, parent, name, window, controler): + stc.StyledTextCtrl.__init__(self, parent, ID_CPPEDITOR, wx.DefaultPosition, + wx.Size(0, 0), 0) + + self.SetMarginType(1, stc.STC_MARGIN_NUMBER) + self.SetMarginWidth(1, 25) + + self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) + self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) + + self.SetLexer(stc.STC_LEX_CPP) + self.SetKeyWords(0, " ".join(CPP_KEYWORDS)) + + self.SetProperty("fold", "1") + self.SetProperty("tab.timmy.whinge.level", "1") + self.SetMargins(0,0) + + self.SetViewWhiteSpace(False) + #self.SetBufferedDraw(False) + #self.SetViewEOL(True) + #self.SetEOLMode(stc.STC_EOL_CRLF) + #self.SetUseAntiAliasing(True) + + self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) + self.SetEdgeColumn(78) + + # Setup a margin to hold fold markers + #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? + self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + self.SetMarginMask(2, stc.STC_MASK_FOLDERS) + self.SetMarginSensitive(2, True) + self.SetMarginWidth(2, 12) + + if self.fold_symbols == 0: + # Arrow pointing right for contracted folders, arrow pointing down for expanded + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 1: + # Plus for contracted folders, minus for expanded + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 2: + # Like a flattened tree control using circular headers and curved joins + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") + + elif self.fold_symbols == 3: + # Like a flattened tree control using square headers + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") + + + self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) + self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) + self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) + + # Make some styles, The lexer defines what each style is used for, we + # just have to define what each style looks like. This set is adapted from + # Scintilla sample property files. + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) + self.StyleClearAll() # Reset all to be like the default + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces) + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") + self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") + + self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060') + self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060') + self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060') + self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE') + self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056') + self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff') + self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056') + self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold') + self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF') + + # register some images for use in the AutoComplete box. + #self.RegisterImage(1, images.getSmilesBitmap()) + self.RegisterImage(1, + wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) + self.RegisterImage(2, + wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) + self.RegisterImage(3, + wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) + + # Indentation size + self.SetTabWidth(2) + self.SetUseTabs(0) + + self.Controler = controler + self.ParentWindow = window + + self.DisableEvents = True + self.Name = name + self.CurrentAction = None + + self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) + + self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_CPPEDITOR) + self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_CPPEDITOR) + + def OnModification(self, event): + if not self.DisableEvents: + mod_type = event.GetModificationType() + if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): + if mod_type&wx.stc.STC_MOD_BEFOREINSERT: + if self.CurrentAction == None: + self.StartBuffering() + elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: + self.Controler.EndBuffering() + self.StartBuffering() + self.CurrentAction = ("Add", event.GetPosition()) + wx.CallAfter(self.RefreshModel) + elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: + if self.CurrentAction == None: + self.StartBuffering() + elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: + self.Controler.EndBuffering() + self.StartBuffering() + self.CurrentAction = ("Delete", event.GetPosition()) + wx.CallAfter(self.RefreshModel) + event.Skip() + + def OnDoDrop(self, event): + self.ResetBuffer() + wx.CallAfter(self.RefreshModel) + event.Skip() + + # Buffer the last model state + def RefreshBuffer(self): + self.Controler.BufferCFile() + if self.ParentWindow is not None: + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def StartBuffering(self): + self.Controler.StartBuffering() + if self.ParentWindow is not None: + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def ResetBuffer(self): + if self.CurrentAction != None: + self.Controler.EndBuffering() + self.CurrentAction = None + + def RefreshView(self): + self.ResetBuffer() + self.DisableEvents = True + old_cursor_pos = self.GetCurrentPos() + old_text = self.GetText() + new_text = self.Controler.GetPartText(self.Name) + self.SetText(new_text) + new_cursor_pos = GetCursorPos(old_text, new_text) + if new_cursor_pos != None: + self.GotoPos(new_cursor_pos) + else: + self.GotoPos(old_cursor_pos) + self.ScrollToColumn(0) + self.EmptyUndoBuffer() + self.DisableEvents = False + + self.Colourise(0, -1) + + def DoGetBestSize(self): + return self.ParentWindow.GetPanelBestSize() + + def RefreshModel(self): + self.Controler.SetPartText(self.Name, self.GetText()) + + def OnKeyPressed(self, event): + if self.CallTipActive(): + self.CallTipCancel() + key = event.GetKeyCode() + + if key == 32 and event.ControlDown(): + pos = self.GetCurrentPos() + + # Tips + if event.ShiftDown(): + pass +## self.CallTipSetBackground("yellow") +## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' +## 'show some suff, maybe parameters..\n\n' +## 'fubar(param1, param2)') + # Code completion + else: + self.AutoCompSetIgnoreCase(False) # so this needs to match + + # Images are specified with a appended "?type" + self.AutoCompShow(0, " ".join([word + "?1" for word in CPP_KEYWORDS])) + else: + event.Skip() + + def OnKillFocus(self, event): + self.AutoCompCancel() + event.Skip() + + def OnUpdateUI(self, evt): + # check for matching braces + braceAtCaret = -1 + braceOpposite = -1 + charBefore = None + caretPos = self.GetCurrentPos() + + if caretPos > 0: + charBefore = self.GetCharAt(caretPos - 1) + styleBefore = self.GetStyleAt(caretPos - 1) + + # check before + if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: + braceAtCaret = caretPos - 1 + + # check after + if braceAtCaret < 0: + charAfter = self.GetCharAt(caretPos) + styleAfter = self.GetStyleAt(caretPos) + + if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: + braceAtCaret = caretPos + + if braceAtCaret >= 0: + braceOpposite = self.BraceMatch(braceAtCaret) + + if braceAtCaret != -1 and braceOpposite == -1: + self.BraceBadLight(braceAtCaret) + else: + self.BraceHighlight(braceAtCaret, braceOpposite) + #pt = self.PointFromPosition(braceOpposite) + #self.Refresh(True, wxRect(pt.x, pt.y, 5,5)) + #print pt + #self.Refresh(False) + + + def OnMarginClick(self, evt): + # fold and unfold as needed + if evt.GetMargin() == 2: + if evt.GetShift() and evt.GetControl(): + self.FoldAll() + else: + lineClicked = self.LineFromPosition(evt.GetPosition()) + + if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: + if evt.GetShift(): + self.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 1) + elif evt.GetControl(): + if self.GetFoldExpanded(lineClicked): + self.SetFoldExpanded(lineClicked, False) + self.Expand(lineClicked, False, True, 0) + else: + self.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 100) + else: + self.ToggleFold(lineClicked) + + + def FoldAll(self): + lineCount = self.GetLineCount() + expanding = True + + # find out if we are folding or unfolding + for lineNum in range(lineCount): + if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: + expanding = not self.GetFoldExpanded(lineNum) + break + + lineNum = 0 + + while lineNum < lineCount: + level = self.GetFoldLevel(lineNum) + if level & stc.STC_FOLDLEVELHEADERFLAG and \ + (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: + + if expanding: + self.SetFoldExpanded(lineNum, True) + lineNum = self.Expand(lineNum, True) + lineNum = lineNum - 1 + else: + lastChild = self.GetLastChild(lineNum, -1) + self.SetFoldExpanded(lineNum, False) + + if lastChild > lineNum: + self.HideLines(lineNum+1, lastChild) + + lineNum = lineNum + 1 + + + + def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): + lastChild = self.GetLastChild(line, level) + line = line + 1 + + while line <= lastChild: + if force: + if visLevels > 0: + self.ShowLines(line, line) + else: + self.HideLines(line, line) + else: + if doExpand: + self.ShowLines(line, line) + + if level == -1: + level = self.GetFoldLevel(line) + + if level & stc.STC_FOLDLEVELHEADERFLAG: + if force: + if visLevels > 1: + self.SetFoldExpanded(line, True) + else: + self.SetFoldExpanded(line, False) + + line = self.Expand(line, doExpand, force, visLevels-1) + + else: + if doExpand and self.GetFoldExpanded(line): + line = self.Expand(line, True, force, visLevels-1) + else: + line = self.Expand(line, False, force, visLevels-1) + else: + line = line + 1 + + return line + + def Cut(self): + self.ResetBuffer() + self.DisableEvents = True + self.CmdKeyExecute(wx.stc.STC_CMD_CUT) + self.DisableEvents = False + self.RefreshModel() + self.RefreshBuffer() + + def Copy(self): + self.CmdKeyExecute(wx.stc.STC_CMD_COPY) + + def Paste(self): + self.ResetBuffer() + self.DisableEvents = True + self.CmdKeyExecute(wx.stc.STC_CMD_PASTE) + self.DisableEvents = False + self.RefreshModel() + self.RefreshBuffer() + + +#------------------------------------------------------------------------------- +# Helper for VariablesGrid values +#------------------------------------------------------------------------------- + +class VariablesTable(CustomTable): + + def GetValue(self, row, col): + if row < self.GetNumberRows(): + if col == 0: + return row + 1 + else: + return str(self.data[row].get(self.GetColLabelValue(col, False), "")) + + def _updateColAttrs(self, grid): + """ + wxGrid -> update the column attributes to add the + appropriate renderer given the column name. + + Otherwise default to the default renderer. + """ + + typelist = None + accesslist = None + for row in range(self.GetNumberRows()): + for col in range(self.GetNumberCols()): + editor = None + renderer = None + colname = self.GetColLabelValue(col, False) + + if colname == "Name": + editor = wx.grid.GridCellTextEditor() + elif colname == "Class": + editor = wx.grid.GridCellChoiceEditor() + editor.SetParameters("input,memory,output") + elif colname == "Type": + pass + else: + grid.SetReadOnly(row, col, True) + + grid.SetCellEditor(row, col, editor) + grid.SetCellRenderer(row, col, renderer) + + grid.SetCellBackgroundColour(row, col, wx.WHITE) + self.ResizeRow(grid, row) + + +[ID_VARIABLESEDITOR, ID_VARIABLESEDITORVARIABLESGRID, + ID_VARIABLESEDITORADDVARIABLEBUTTON, ID_VARIABLESEDITORDELETEVARIABLEBUTTON, + ID_VARIABLESEDITORUPVARIABLEBUTTON, ID_VARIABLESEDITORDOWNVARIABLEBUTTON +] = [wx.NewId() for _init_ctrls in range(6)] + +class VariablesEditor(wx.Panel): + + if wx.VERSION < (2, 6, 0): + def Bind(self, event, function, id = None): + if id is not None: + event(self, id, function) + else: + event(self, function) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW) + parent.AddSizer(self.ButtonsSizer, 0, border=0, flag=wx.GROW) + + def _init_coll_ButtonsSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_coll_ButtonsSizer_Items(self, parent): + parent.AddWindow(self.AddVariableButton, 0, border=0, flag=wx.ALIGN_RIGHT) + parent.AddWindow(self.DeleteVariableButton, 0, border=0, flag=0) + parent.AddWindow(self.UpVariableButton, 0, border=0, flag=0) + parent.AddWindow(self.DownVariableButton, 0, border=0, flag=0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4) + self.ButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) + + self._init_coll_MainSizer_Growables(self.MainSizer) + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_ButtonsSizer_Growables(self.ButtonsSizer) + self._init_coll_ButtonsSizer_Items(self.ButtonsSizer) + + self.SetSizer(self.MainSizer) + + def _init_ctrls(self, prnt): + wx.Panel.__init__(self, id=ID_VARIABLESEDITOR, name='', parent=prnt, + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) + + self.VariablesGrid = CustomGrid(id=ID_VARIABLESEDITORVARIABLESGRID, + name='VariablesGrid', parent=self, pos=wx.Point(0, 0), + size=wx.Size(-1, -1), style=wx.VSCROLL) + if wx.VERSION >= (2, 5, 0): + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) + self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) + else: + wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange) + wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick) + wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown) + + self.AddVariableButton = wx.Button(id=ID_VARIABLESEDITORADDVARIABLEBUTTON, label='Add Variable', + name='AddVariableButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(122, 32), style=0) + + self.DeleteVariableButton = wx.Button(id=ID_VARIABLESEDITORDELETEVARIABLEBUTTON, label='Delete Variable', + name='DeleteVariableButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(122, 32), style=0) + + self.UpVariableButton = wx.Button(id=ID_VARIABLESEDITORUPVARIABLEBUTTON, label='^', + name='UpVariableButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(32, 32), style=0) + + self.DownVariableButton = wx.Button(id=ID_VARIABLESEDITORDOWNVARIABLEBUTTON, label='v', + name='DownVariableButton', parent=self, pos=wx.Point(0, 0), + size=wx.Size(32, 32), style=0) + + self._init_sizers() + + def __init__(self, parent, window, controler): + self._init_ctrls(parent) + + self.ParentWindow = window + self.Controler = controler + + self.VariablesDefaultValue = {"Name" : "", "Class" : "input", "Type" : ""} + self.Table = VariablesTable(self, [], ["#", "Name", "Class", "Type"]) + self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] + self.ColSizes = [40, 200, 150, 150] + self.VariablesGrid.SetTable(self.Table) + self.VariablesGrid.SetButtons({"Add": self.AddVariableButton, + "Delete": self.DeleteVariableButton, + "Up": self.UpVariableButton, + "Down": self.DownVariableButton}) + + def _AddVariable(new_row): + self.Table.InsertRow(new_row, self.VariablesDefaultValue.copy()) + self.RefreshModel() + self.RefreshView() + return new_row + setattr(self.VariablesGrid, "_AddRow", _AddVariable) + + def _DeleteVariable(row): + self.Table.RemoveRow(row) + self.RefreshModel() + self.RefreshView() + setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) + + def _MoveVariable(row, move): + new_row = self.Table.MoveRow(row, move) + if new_row != row: + self.RefreshModel() + self.RefreshView() + return new_row + setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) + + self.VariablesGrid.SetRowLabelSize(0) + for col in range(self.Table.GetNumberCols()): + attr = wx.grid.GridCellAttr() + attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) + self.VariablesGrid.SetColAttr(col, attr) + self.VariablesGrid.SetColSize(col, self.ColSizes[col]) + self.Table.ResetView(self.VariablesGrid) + + def RefreshModel(self): + self.Controler.SetVariables(self.Table.GetData()) + self.RefreshBuffer() + + # Buffer the last model state + def RefreshBuffer(self): + self.Controler.BufferCFile() + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def RefreshView(self): + self.Table.SetData(self.Controler.GetVariables()) + self.Table.ResetView(self.VariablesGrid) + self.VariablesGrid.RefreshButtons() + + def DoGetBestSize(self): + return self.ParentWindow.GetPanelBestSize() + + def OnVariablesGridCellChange(self, event): + self.RefreshModel() + wx.CallAfter(self.RefreshView) + event.Skip() + + def OnVariablesGridEditorShown(self, event): + row, col = event.GetRow(), event.GetCol() + if self.Table.GetColLabelValue(col) == "Type": + type_menu = wx.Menu(title='') + base_menu = wx.Menu(title='') + for base_type in self.Controler.GetBaseTypes(): + new_id = wx.NewId() + AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) + self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) + type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu) + datatype_menu = wx.Menu(title='') + for datatype in self.Controler.GetDataTypes(basetypes=False, only_locatables=True): + new_id = wx.NewId() + AppendMenu(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(), "User Data Types", datatype_menu) + rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) + + self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) + type_menu.Destroy() + event.Veto() + else: + event.Skip() + + def GetVariableTypeFunction(self, base_type): + def VariableTypeFunction(event): + row = self.VariablesGrid.GetGridCursorRow() + self.Table.SetValueByName(row, "Type", base_type) + self.Table.ResetView(self.VariablesGrid) + self.RefreshModel() + self.RefreshView() + event.Skip() + return VariableTypeFunction + + def OnVariablesGridCellLeftClick(self, event): + if event.GetCol() == 0: + row = event.GetRow() + num = 0 + if self.Table.GetValueByName(row, "Class") == "input": + dir = "%I" + for i in xrange(row): + if self.Table.GetValueByName(i, "Class") == "input": + num += 1 + elif self.Table.GetValueByName(row, "Class") == "memory": + dir = "%M" + for i in xrange(row): + if self.Table.GetValueByName(i, "Class") == "memory": + num += 1 + else: + dir = "%Q" + for i in xrange(row): + if self.Table.GetValueByName(i, "Class") == "output": + num += 1 + data_type = self.Table.GetValueByName(row, "Type") + var_name = self.Table.GetValueByName(row, "Name") + base_location = ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation())) + location = "%s%s%s.%d"%(dir, self.Controler.GetSizeOfType(data_type), base_location, num) + data = wx.TextDataObject(str((location, "location", data_type, var_name, ""))) + dragSource = wx.DropSource(self.VariablesGrid) + dragSource.SetData(data) + dragSource.DoDragDrop() + event.Skip() + + +#------------------------------------------------------------------------------- +# SVGUIEditor Main Frame Class +#------------------------------------------------------------------------------- + +CFILE_PARTS = [ + ("Includes", CppEditor), + ("Variables", VariablesEditor), + ("Globals", CppEditor), + ("Init", CppEditor), + ("CleanUp", CppEditor), + ("Retrieve", CppEditor), + ("Publish", CppEditor), +] + +#---------------------------------------------------------------------- +# different icons for the collapsed/expanded states. +# Taken from standard Windows XP collapsed/expanded states. +#---------------------------------------------------------------------- + +def GetCollapsedIconData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\ +\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\ +\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\ +H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\ +\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\ +\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\ +\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\ +\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\ +zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\ +\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\ +~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\ +\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\ +\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\ +\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\ +0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\ +\x00\x00\x00IEND\xaeB`\x82' + +def GetCollapsedIconBitmap(): + return wx.BitmapFromImage(GetCollapsedIconImage()) + +def GetCollapsedIconImage(): + import cStringIO + stream = cStringIO.StringIO(GetCollapsedIconData()) + return wx.ImageFromStream(stream) + +#---------------------------------------------------------------------- +def GetExpandedIconData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\ +\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\ +\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\ +\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\ +\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\ +\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\ +\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\ +\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\ +\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\ +\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\ +\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\ +\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\ +\x05\x10\x81\xce\xc9\xa8\xf6>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\ +\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\ +`\x82' + +def GetExpandedIconBitmap(): + return wx.BitmapFromImage(GetExpandedIconImage()) + +def GetExpandedIconImage(): + import cStringIO + stream = cStringIO.StringIO(GetExpandedIconData()) + return wx.ImageFromStream(stream) + +class FoldPanelCaption(wx.lib.buttons.GenBitmapTextToggleButton): + + def GetBackgroundBrush(self, dc): + colBg = self.GetBackgroundColour() + brush = wx.Brush(colBg, wx.SOLID) + if self.style & wx.BORDER_NONE: + myAttr = self.GetDefaultAttributes() + parAttr = self.GetParent().GetDefaultAttributes() + myDef = colBg == myAttr.colBg + parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg + if myDef and parDef: + if wx.Platform == "__WXMAC__": + brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive + elif wx.Platform == "__WXMSW__": + if self.DoEraseBackground(dc): + brush = None + elif myDef and not parDef: + colBg = self.GetParent().GetBackgroundColour() + brush = wx.Brush(colBg, wx.SOLID) + return brush + + def DrawLabel(self, dc, width, height, dx=0, dy=0): + bmp = self.bmpLabel + if bmp is not None: # if the bitmap is used + if self.bmpDisabled and not self.IsEnabled(): + bmp = self.bmpDisabled + if self.bmpFocus and self.hasFocus: + bmp = self.bmpFocus + if self.bmpSelected and not self.up: + bmp = self.bmpSelected + bw,bh = bmp.GetWidth(), bmp.GetHeight() + hasMask = bmp.GetMask() is not None + else: + bw = bh = 0 # no bitmap -> size is zero + + dc.SetFont(self.GetFont()) + if self.IsEnabled(): + dc.SetTextForeground(self.GetForegroundColour()) + else: + dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) + + label = self.GetLabel() + tw, th = dc.GetTextExtent(label) # size of text + + if bmp is not None: + dc.DrawBitmap(bmp, width - bw - 2, (height-bh)/2, hasMask) # draw bitmap if available + + dc.DrawText(label, 2, (height-th)/2) # draw the text + + dc.SetPen(wx.Pen(self.GetForegroundColour())) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.DrawRectangle(0, 0, width, height) + +[ID_CFILEEDITOR, ID_CFILEEDITORMAINSPLITTER, + ID_CFILEEDITORCFILETREE, ID_CFILEEDITORPARTSOPENED, +] = [wx.NewId() for _init_ctrls in range(4)] + +class CFileEditor(EditorPanel): + + def _init_Editor(self, prnt): + self.Editor = wx.Panel(id=ID_CFILEEDITOR, parent=prnt, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) + + self.Panels = {} + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2 * len(CFILE_PARTS) + 1, vgap=0) + self.MainSizer.AddGrowableCol(0) + + for idx, (name, panel_class) in enumerate(CFILE_PARTS): + button_id = wx.NewId() + button = FoldPanelCaption(id=button_id, name='FoldPanelCaption_%s' % name, + label=name, bitmap=GetCollapsedIconBitmap(), parent=self.Editor, pos=wx.Point(0, 0), + size=wx.Size(0, 20), style=wx.NO_BORDER|wx.ALIGN_LEFT) + button.SetBitmapSelected(GetExpandedIconBitmap()) + button.Bind(wx.EVT_BUTTON, self.GenPanelButtonCallback(name), id=button_id) + self.MainSizer.AddWindow(button, 0, border=0, flag=wx.TOP|wx.GROW) + + if panel_class == VariablesEditor: + panel = VariablesEditor(self.Editor, self.ParentWindow, self.Controler) + else: + panel = panel_class(self.Editor, name, self.ParentWindow, self.Controler) + self.MainSizer.AddWindow(panel, 0, border=0, flag=wx.BOTTOM|wx.GROW) + panel.Hide() + + self.Panels[name] = {"button": button, "panel": panel, "expanded": False, "row": 2 * idx + 1} + + self.Spacer = wx.Panel(self.Editor, -1) + self.SpacerExpanded = True + self.MainSizer.AddWindow(self.Spacer, 0, border=0, flag=wx.GROW) + + self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS)) + + self.Editor.SetSizer(self.MainSizer) + + def __init__(self, parent, controler, window): + EditorPanel.__init__(self, parent, "", window, controler) + + img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() + self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) + + def __del__(self): + self.Controler.OnCloseEditor(self) + + def GetTitle(self): + fullname = self.Controler.PlugFullName() + if not self.Controler.CFileIsSaved(): + return "~%s~" % fullname + return fullname + + def GetBufferState(self): + return self.Controler.GetBufferState() + + def Undo(self): + self.Controler.LoadPrevious() + self.RefreshView() + + def Redo(self): + self.Controler.LoadNext() + self.RefreshView() + + def HasNoModel(self): + return False + + def RefreshView(self): + for infos in self.Panels.itervalues(): + infos["panel"].RefreshView() + + def GenPanelButtonCallback(self, name): + def PanelButtonCallback(event): + self.TogglePanel(name) + return PanelButtonCallback + + def ExpandPanel(self, name): + infos = self.Panels.get(name, None) + if infos is not None and not infos["expanded"]: + infos["expanded"] = True + infos["button"].SetToggle(True) + infos["panel"].Show() + self.MainSizer.AddGrowableRow(infos["row"]) + + self.RefreshSizerLayout() + + def CollapsePanel(self, name): + infos = self.Panels.get(name, None) + if infos is not None and infos["expanded"]: + infos["expanded"] = False + infos["button"].SetToggle(False) + infos["panel"].Hide() + self.MainSizer.RemoveGrowableRow(infos["row"]) + + self.RefreshSizerLayout() + + def TogglePanel(self, name): + infos = self.Panels.get(name, None) + if infos is not None: + infos["expanded"] = not infos["expanded"] + infos["button"].SetToggle(infos["expanded"]) + if infos["expanded"]: + infos["panel"].Show() + self.MainSizer.AddGrowableRow(infos["row"]) + else: + infos["panel"].Hide() + self.MainSizer.RemoveGrowableRow(infos["row"]) + + self.RefreshSizerLayout() + + def RefreshSizerLayout(self): + expand_spacer = True + for infos in self.Panels.itervalues(): + expand_spacer = expand_spacer and not infos["expanded"] + + if self.SpacerExpanded != expand_spacer: + self.SpacerExpanded = expand_spacer + if expand_spacer: + self.Spacer.Show() + self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS)) + else: + self.Spacer.Hide() + self.MainSizer.RemoveGrowableRow(2 * len(CFILE_PARTS)) + + self.MainSizer.Layout() + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/README Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +C extension \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +from c_ext import * diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/c_ext.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/c_ext.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,315 @@ +import wx +import os +from xml.dom import minidom +import cPickle + +from xmlclass import * + +from ConfigTree import ConfigTreeNode, opjimg +from CFileEditor import CFileEditor +from PLCControler import PLCControler, UndoBuffer, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY + +CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd")) + +TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", + "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L", + "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"} + +class _Cfile: + XSD = """ + + + + + + + + + """ + EditorType = CFileEditor + + def __init__(self): + filepath = self.CFileName() + + self.CFile = CFileClasses["CFile"]() + if os.path.isfile(filepath): + xmlfile = open(filepath, 'r') + tree = minidom.parse(xmlfile) + xmlfile.close() + + for child in tree.childNodes: + if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile": + self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) + self.CreateCFileBuffer(True) + else: + self.CreateCFileBuffer(False) + self.OnPlugSave() + + def CFileName(self): + return os.path.join(self.PlugPath(), "cfile.xml") + + def GetBaseTypes(self): + return self.GetPlugRoot().GetBaseTypes() + + def GetDataTypes(self, basetypes = False, only_locatables = False): + return self.GetPlugRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables) + + def GetSizeOfType(self, type): + return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None) + + def SetVariables(self, variables): + self.CFile.variables.setvariable([]) + for var in variables: + variable = CFileClasses["variables_variable"]() + variable.setname(var["Name"]) + variable.settype(var["Type"]) + variable.setclass(var["Class"]) + self.CFile.variables.appendvariable(variable) + + def GetVariables(self): + datas = [] + for var in self.CFile.variables.getvariable(): + datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()}) + return datas + + def GetVariableLocationTree(self): + '''See ConfigTreeNode.GetVariableLocationTree() for a description.''' + + current_location = ".".join(map(str, self.GetCurrentLocation())) + + vars = [] + input = memory = output = 0 + for var in self.CFile.variables.getvariable(): + var_size = self.GetSizeOfType(var.gettype()) + var_location = "" + if var.getclass() == "input": + var_class = LOCATION_VAR_INPUT + if var_size is not None: + var_location = "%%I%s%s.%d"%(var_size, current_location, input) + input += 1 + elif var.getclass() == "memory": + var_class = LOCATION_VAR_INPUT + if var_size is not None: + var_location = "%%M%s%s.%d"%(var_size, current_location, memory) + memory += 1 + else: + var_class = LOCATION_VAR_OUTPUT + if var_size is not None: + var_location = "%%Q%s%s.%d"%(var_size, current_location, output) + output += 1 + vars.append({"name": var.getname(), + "type": var_class, + "size": var_size, + "IEC_type": var.gettype(), + "var_name": var.getname(), + "location": var_location, + "description": "", + "children": []}) + + return {"name": self.BaseParams.getName(), + "type": LOCATION_CONFNODE, + "location": self.GetFullIEC_Channel(), + "children": vars} + + def SetPartText(self, name, text): + if name == "Includes": + self.CFile.includes.settext(text) + elif name == "Globals": + self.CFile.globals.settext(text) + elif name == "Init": + self.CFile.initFunction.settext(text) + elif name == "CleanUp": + self.CFile.cleanUpFunction.settext(text) + elif name == "Retrieve": + self.CFile.retrieveFunction.settext(text) + elif name == "Publish": + self.CFile.publishFunction.settext(text) + + def GetPartText(self, name): + if name == "Includes": + return self.CFile.includes.gettext() + elif name == "Globals": + return self.CFile.globals.gettext() + elif name == "Init": + return self.CFile.initFunction.gettext() + elif name == "CleanUp": + return self.CFile.cleanUpFunction.gettext() + elif name == "Retrieve": + return self.CFile.retrieveFunction.gettext() + elif name == "Publish": + return self.CFile.publishFunction.gettext() + return "" + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images", "EditCfile"), + "name" : _("Edit C File"), + "tooltip" : _("Edit C File"), + "method" : "_OpenView"}, + ] + + def PlugTestModified(self): + return self.ChangesToSave or not self.CFileIsSaved() + + def OnPlugSave(self): + filepath = self.CFileName() + + text = "\n" + extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", + "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation" : "cext_xsd.xsd"} + text += self.CFile.generateXMLText("CFile", 0, extras) + + xmlfile = open(filepath,"w") + xmlfile.write(text.encode("utf-8")) + xmlfile.close() + + self.MarkCFileAsSaved() + return True + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + location_str = "_".join(map(str, current_location)) + + text = "/* Code generated by Beremiz c_ext confnode */\n\n" + + # Adding includes + text += "/* User includes */\n" + text += self.CFile.includes.gettext() + text += "\n" + + text += """/* Beremiz c_ext confnode includes */ +#ifdef _WINDOWS_H + #include "iec_types.h" +#else + #include "iec_std_lib.h" +#endif + +""" + + # Adding variables + vars = [] + inputs = memories = outputs = 0 + for variable in self.CFile.variables.variable: + var = {"Name" : variable.getname(), "Type" : variable.gettype()} + if variable.getclass() == "input": + var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs) + inputs += 1 + elif variable.getclass() == "memory": + var["location"] = "__M%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, memories) + memories += 1 + else: + var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs) + outputs += 1 + vars.append(var) + text += "/* Beremiz c_ext confnode user variables definition */\n" + base_types = self.GetPlugRoot().GetBaseTypes() + for var in vars: + if var["Type"] in base_types: + prefix = "IEC_" + else: + prefix = "" + text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"]) + text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"]) + text += "/* User variables reference */\n" + for var in vars: + text += "#define %s beremiz%s\n"%(var["Name"], var["location"]) + text += "\n" + + # Adding user global variables and routines + text += "/* User internal user variables and routines */\n" + text += self.CFile.globals.gettext() + + # Adding Beremiz confnode functions + text += "/* Beremiz confnode functions */\n" + text += "int __init_%s(int argc,char **argv)\n{\n"%location_str + text += self.CFile.initFunction.gettext() + text += " return 0;\n" + text += "\n}\n\n" + + text += "void __cleanup_%s(void)\n{\n"%location_str + text += self.CFile.cleanUpFunction.gettext() + text += "\n}\n\n" + + text += "void __retrieve_%s(void)\n{\n"%location_str + text += self.CFile.retrieveFunction.gettext() + text += "\n}\n\n" + + text += "void __publish_%s(void)\n{\n"%location_str + text += self.CFile.publishFunction.gettext() + text += "\n}\n\n" + + Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str) + cfile = open(Gen_Cfile_path,'w') + cfile.write(text) + cfile.close() + + matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()) + + return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True + + +#------------------------------------------------------------------------------- +# Current Buffering Management Functions +#------------------------------------------------------------------------------- + + """ + Return a copy of the cfile model + """ + def Copy(self, model): + return cPickle.loads(cPickle.dumps(model)) + + def CreateCFileBuffer(self, saved): + self.Buffering = False + self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved) + + def BufferCFile(self): + self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) + + def StartBuffering(self): + self.Buffering = True + + def EndBuffering(self): + if self.Buffering: + self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) + self.Buffering = False + + def MarkCFileAsSaved(self): + self.EndBuffering() + self.CFileBuffer.CurrentSaved() + + def CFileIsSaved(self): + return self.CFileBuffer.IsCurrentSaved() and not self.Buffering + + def LoadPrevious(self): + self.EndBuffering() + self.CFile = cPickle.loads(self.CFileBuffer.Previous()) + + def LoadNext(self): + self.CFile = cPickle.loads(self.CFileBuffer.Next()) + + def GetBufferState(self): + first = self.CFileBuffer.IsFirst() and not self.Buffering + last = self.CFileBuffer.IsLast() + return not first, not last + +class RootClass: + + PlugChildsTypes = [("C_File",_Cfile, "C file")] + + def PlugGenerate_C(self, buildpath, locations): + return [],"",False + + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/c_ext/cext_xsd.xsd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/c_ext/cext_xsd.xsd Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Formatted text according to parts of XHTML 1.1 + + + + + + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/.cvsignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/.cvsignore Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/NetworkEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/NetworkEditor.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,122 @@ +import os, sys +base_folder = os.path.split(sys.path[0])[0] +CanFestivalPath = os.path.join(base_folder, "CanFestival-3") + +import wx + +from subindextable import EditingPanel +from networkedit import NetworkEditorTemplate +from controls import EditorPanel + +[ID_NETWORKEDITOR, +] = [wx.NewId() for _init_ctrls in range(1)] + +[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, + ID_NETWORKEDITORCONFNODEMENUMASTER, +] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(3)] + +[ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE, + ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, + ID_NETWORKEDITORMASTERMENUADD, +] = [wx.NewId() for _init_coll_MasterMenu_Items in range(5)] + +[ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT, + ID_NETWORKEDITORADDMENUPDOTRANSMIT, ID_NETWORKEDITORADDMENUPDORECEIVE, + ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE, +] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] + +class NetworkEditor(EditorPanel, NetworkEditorTemplate): + + ID = ID_NETWORKEDITOR + + def _init_coll_MainSizer_Items(self, parent): + parent.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL) + + def _init_coll_MainSizer_Growables(self, parent): + parent.AddGrowableCol(0) + parent.AddGrowableRow(0) + + def _init_sizers(self): + self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0) + + self._init_coll_MainSizer_Items(self.MainSizer) + self._init_coll_MainSizer_Growables(self.MainSizer) + + self.Editor.SetSizer(self.MainSizer) + + def _init_Editor(self, prnt): + self.Editor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0), + size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) + + NetworkEditorTemplate._init_ctrls(self, self.Editor) + + self._init_sizers() + + def __init__(self, parent, controler, window): + EditorPanel.__init__(self, parent, "", window, controler) + NetworkEditorTemplate.__init__(self, controler, window, False) + + img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() + self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) + + self.RefreshNetworkNodes() + self.RefreshBufferState() + + def __del__(self): + self.Controler.OnCloseEditor(self) + + def GetConfNodeMenuItems(self): + add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), + (wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)), + (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_NETWORKEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)), + (wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), + (wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), + (wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] + + profile = self.Manager.GetCurrentProfileName() + if profile not in ("None", "DS-301"): + other_profile_text = _("%s Profile") % profile + add_menu.append((wx.ITEM_SEPARATOR, None)) + for text, indexes in self.Manager.GetCurrentSpecificMenu(): + add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) + else: + other_profile_text = _('Other Profile') + + master_menu = [(wx.ITEM_NORMAL, (_('Node infos'), ID_NETWORKEDITORMASTERMENUNODEINFOS, '', self.OnNodeInfosMenu)), + (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)), + (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), + (wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), + (wx.ITEM_SEPARATOR, None), + (add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))] + + return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORCONFNODEMENUADDSLAVE, '', self.OnAddSlaveMenu)), + (wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)), + (wx.ITEM_SEPARATOR, None), + (master_menu, (_('Master'), ID_NETWORKEDITORCONFNODEMENUMASTER))] + + def RefreshMainMenu(self): + pass + + def RefreshConfNodeMenu(self, confnode_menu): + confnode_menu.Enable(ID_NETWORKEDITORCONFNODEMENUMASTER, self.NetworkNodes.GetSelection() == 0) + + def GetTitle(self): + fullname = self.Controler.PlugFullName() + if not self.Manager.CurrentIsSaved(): + return "~%s~" % fullname + return fullname + + def RefreshView(self): + self.RefreshCurrentIndexList() + + def RefreshBufferState(self): + NetworkEditorTemplate.RefreshBufferState(self) + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def OnNodeSelectedChanged(self, event): + NetworkEditorTemplate.OnNodeSelectedChanged(self, event) + wx.CallAfter(self.ParentWindow.RefreshConfNodeMenu) + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/README Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +CANOpen \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/SlaveEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/SlaveEditor.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,83 @@ +import os, sys +base_folder = os.path.split(sys.path[0])[0] +CanFestivalPath = os.path.join(base_folder, "CanFestival-3") + +import wx + +from subindextable import EditingPanel +from nodeeditor import NodeEditorTemplate +from controls import EditorPanel + +[ID_SLAVEEDITORCONFNODEMENUNODEINFOS, ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, + ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, + ID_SLAVEEDITORCONFNODEMENUADD, +] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(5)] + +[ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT, + ID_SLAVEEDITORADDMENUPDOTRANSMIT, ID_SLAVEEDITORADDMENUPDORECEIVE, + ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE, +] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] + +class SlaveEditor(EditorPanel, NodeEditorTemplate): + + def _init_Editor(self, prnt): + self.Editor = EditingPanel(prnt, self, self.Controler, self.Editable) + + def __init__(self, parent, controler, window, editable=True): + self.Editable = editable + EditorPanel.__init__(self, parent, "", window, controler) + NodeEditorTemplate.__init__(self, controler, window, False) + + img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() + self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) + + def __del__(self): + self.Controler.OnCloseEditor(self) + + def GetConfNodeMenuItems(self): + if self.Editable: + add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), + (wx.ITEM_NORMAL, (_('SDO Client'), ID_SLAVEEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)), + (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_SLAVEEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)), + (wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), + (wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), + (wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] + + profile = self.Controler.GetCurrentProfileName() + if profile not in ("None", "DS-301"): + other_profile_text = _("%s Profile") % profile + add_menu.append((wx.ITEM_SEPARATOR, None)) + for text, indexes in self.Manager.GetCurrentSpecificMenu(): + add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) + else: + other_profile_text = _('Other Profile') + + return [(wx.ITEM_NORMAL, (_('Node infos'), ID_SLAVEEDITORCONFNODEMENUNODEINFOS, '', self.OnNodeInfosMenu)), + (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, '', self.OnCommunicationMenu)), + (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), + (wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), + (wx.ITEM_SEPARATOR, None), + (add_menu, (_('Add'), ID_SLAVEEDITORCONFNODEMENUADD))] + return [] + + def RefreshConfNodeMenu(self, confnode_menu): + confnode_menu.Enable(ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, False) + + def GetTitle(self): + fullname = self.Controler.PlugFullName() + if not self.Controler.CurrentIsSaved(): + return "~%s~" % fullname + return fullname + + def RefreshView(self): + self.Editor.RefreshIndexList() + + def RefreshCurrentIndexList(self): + self.RefreshView() + + def RefreshBufferState(self): + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +from canfestival import * diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/canfestival.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/canfestival.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,484 @@ +import os, sys +base_folder = os.path.split(sys.path[0])[0] +CanFestivalPath = os.path.join(base_folder, "CanFestival-3") +sys.path.append(os.path.join(CanFestivalPath, "objdictgen")) + +from nodelist import NodeList +from nodemanager import NodeManager +import config_utils, gen_cfile, eds_utils +from networkedit import networkedit +from objdictedit import objdictedit +import canfestival_config as local_canfestival_config +from ConfigTree import ConfigTreeNode +from commondialogs import CreateNodeDialog +import wx + +from SlaveEditor import SlaveEditor +from NetworkEditor import NetworkEditor + +from gnosis.xml.pickle import * +from gnosis.xml.pickle.util import setParanoia +setParanoia(0) + +if wx.Platform == '__WXMSW__': + DEFAULT_SETTINGS = { + "CAN_Driver": "can_tcp_win32", + "CAN_Device": "127.0.0.1", + "CAN_Baudrate": "125K", + "Slave_NodeId": 2, + "Master_NodeId": 1, + } +else: + DEFAULT_SETTINGS = { + "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so", + "CAN_Device": "vcan0", + "CAN_Baudrate": "125K", + "Slave_NodeId": 2, + "Master_NodeId": 1, + } + +#-------------------------------------------------- +# SLAVE +#-------------------------------------------------- + +class _SlavePlug(NodeManager): + XSD = """ + + + + + + + + + + + + + + + + + + + """ % DEFAULT_SETTINGS + + EditorType = SlaveEditor + + def __init__(self): + # TODO change netname when name change + NodeManager.__init__(self) + odfilepath = self.GetSlaveODPath() + if(os.path.isfile(odfilepath)): + self.OpenFileInCurrent(odfilepath) + else: + self.FilePath = "" + dialog = CreateNodeDialog(None, wx.OK) + dialog.Type.Enable(False) + dialog.GenSYNC.Enable(False) + if dialog.ShowModal() == wx.ID_OK: + name, id, nodetype, description = dialog.GetValues() + profile, filepath = dialog.GetProfile() + NMT = dialog.GetNMTManagement() + options = dialog.GetOptions() + self.CreateNewNode(name, # Name - will be changed at build time + id, # NodeID - will be changed at build time + "slave", # Type + description,# description + profile, # profile + filepath, # prfile filepath + NMT, # NMT + options) # options + else: + self.CreateNewNode("SlaveNode", # Name - will be changed at build time + 0x00, # NodeID - will be changed at build time + "slave", # Type + "", # description + "None", # profile + "", # prfile filepath + "heartbeat", # NMT + []) # options + dialog.Destroy() + self.OnPlugSave() + + def GetSlaveODPath(self): + return os.path.join(self.PlugPath(), 'slave.od') + + def GetCanDevice(self): + return self.CanFestivalSlaveNode.getCan_Device() + + def _OpenView(self): + ConfigTreeNode._OpenView(self) + if self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images", "NetworkEdit"), + "name" : "Edit slave", + "tooltip" : "Edit CanOpen slave with ObjdictEdit", + "method" : "_OpenView"}, + ] + + def OnPlugClose(self): + if self._View: + self._View.Close() + + def PlugTestModified(self): + return self.ChangesToSave or self.OneFileHasChanged() + + def OnPlugSave(self): + return self.SaveCurrentInFile(self.GetSlaveODPath()) + + def SetParamsAttribute(self, path, value): + result = ConfigTreeNode.SetParamsAttribute(self, path, value) + + # Filter IEC_Channel and Name, that have specific behavior + if path == "BaseParams.IEC_Channel" and self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + return result + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + prefix = "_".join(map(str, current_location)) + Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) + # Create a new copy of the model + slave = self.GetCurrentNodeCopy() + slave.SetNodeName("OD_%s"%prefix) + # allow access to local OD from Slave PLC + pointers = config_utils.LocalODPointers(locations, current_location, slave) + res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers) + if res : + raise Exception, res + res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave) + if res : + raise Exception, res + return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False + + def LoadPrevious(self): + self.LoadCurrentPrevious() + + def LoadNext(self): + self.LoadCurrentNext() + + def GetBufferState(self): + return self.GetCurrentBufferState() + +#-------------------------------------------------- +# MASTER +#-------------------------------------------------- + +class MiniNodeManager(NodeManager): + + def __init__(self, parent, filepath, fullname): + NodeManager.__init__(self) + + self.OpenFileInCurrent(filepath) + + self.Parent = parent + self.Fullname = fullname + + def OnCloseEditor(self, view): + self.Parent.OnCloseEditor(view) + + def PlugFullName(self): + return self.Fullname + + def GetBufferState(self): + return self.GetCurrentBufferState() + +class _NodeListPlug(NodeList): + XSD = """ + + + + + + + + + + + """ % DEFAULT_SETTINGS + + EditorType = NetworkEditor + + def __init__(self): + manager = NodeManager() + NodeList.__init__(self, manager) + self.LoadProject(self.PlugPath()) + self.SetNetworkName(self.BaseParams.getName()) + + def GetCanDevice(self): + return self.CanFestivalNode.getCan_Device() + + def SetParamsAttribute(self, path, value): + result = ConfigTreeNode.SetParamsAttribute(self, path, value) + + # Filter IEC_Channel and Name, that have specific behavior + if path == "BaseParams.IEC_Channel" and self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + elif path == "BaseParams.Name": + self.SetNetworkName(value) + + return result + + def _OpenView(self): + ConfigTreeNode._OpenView(self) + if self._View is not None: + self._View.SetBusId(self.GetCurrentLocation()) + + _GeneratedView = None + def _ShowMasterGenerated(self): + if self._GeneratedView is None: + buildpath = self._getBuildPath() + # Eventually create build dir + if not os.path.exists(buildpath): + self.GetPlugRoot().logger.write_error(_("Error: No PLC built\n")) + return + + masterpath = os.path.join(buildpath, "MasterGenerated.od") + if not os.path.exists(masterpath): + self.GetPlugRoot().logger.write_error(_("Error: No Master generated\n")) + return + + app_frame = self.GetPlugRoot().AppFrame + + manager = MiniNodeManager(self, masterpath, self.PlugFullName() + ".generated_master") + self._GeneratedView = SlaveEditor(app_frame.TabsOpened, manager, app_frame, False) + + app_frame.EditProjectElement(self._GeneratedView, "MasterGenerated") + + def _CloseGenerateView(self): + if self._GeneratedView is not None: + app_frame = self.GetPlugRoot().AppFrame + if app_frame is not None: + app_frame.DeletePage(self._GeneratedView) + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images", "NetworkEdit"), + "name" : _("Edit network"), + "tooltip" : _("Edit CanOpen Network with NetworkEdit"), + "method" : "_OpenView"}, + {"bitmap" : os.path.join("images", "ShowMaster"), + "name" : _("Show Master"), + "tooltip" : _("Show Master generated by config_utils"), + "method" : "_ShowMasterGenerated"} + ] + + def OnCloseEditor(self, view): + ConfigTreeNode.OnCloseEditor(self, view) + if self._GeneratedView == view: + self._GeneratedView = None + + def OnPlugClose(self): + ConfigTreeNode.OnPlugClose(self) + self._CloseGenerateView() + return True + + def PlugTestModified(self): + return self.ChangesToSave or self.HasChanged() + + def OnPlugSave(self): + self.SetRoot(self.PlugPath()) + return self.SaveProject() is None + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + self._CloseGenerateView() + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + prefix = "_".join(map(str, current_location)) + Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) + # Create a new copy of the model with DCF loaded with PDO mappings for desired location + try: + master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) + except config_utils.PDOmappingException, e: + raise Exception, e.message + # Do generate C file. + res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) + if res : + raise Exception, res + + file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") + dump(master, file) + file.close() + + return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False + + def LoadPrevious(self): + self.Manager.LoadCurrentPrevious() + + def LoadNext(self): + self.Manager.LoadCurrentNext() + + def GetBufferState(self): + return self.Manager.GetCurrentBufferState() + +class RootClass: + XSD = """ + + + + + + + + + """ % DEFAULT_SETTINGS + + PlugChildsTypes = [("CanOpenNode",_NodeListPlug, "CanOpen Master"), + ("CanOpenSlave",_SlavePlug, "CanOpen Slave")] + def GetParamsAttributes(self, path = None): + infos = ConfigTreeNode.GetParamsAttributes(self, path = None) + for element in infos: + if element["name"] == "CanFestivalInstance": + for child in element["children"]: + if child["name"] == "CAN_Driver": + DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None) + if DLL_LIST is not None: + child["type"] = DLL_LIST + return infos + + def GetCanDriver(self): + can_driver = self.CanFestivalInstance.getCAN_Driver() + if sys.platform == 'win32': + if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))): + can_driver += '_DEBUG.dll' + else: + can_driver += '.dll' + return can_driver + + def PlugGenerate_C(self, buildpath, locations): + + format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), + "candriver" : self.GetCanDriver(), + "nodes_includes" : "", + "board_decls" : "", + "nodes_init" : "", + "nodes_open" : "", + "nodes_stop" : "", + "nodes_close" : "", + "nodes_send_sync" : "", + "nodes_proceed_sync" : "", + "slavebootups" : "", + "slavebootup_register" : "", + "post_sync" : "", + "post_sync_register" : "", + } + for child in self.IECSortedChilds(): + childlocstr = "_".join(map(str,child.GetCurrentLocation())) + nodename = "OD_%s" % childlocstr + + # Try to get Slave Node + child_data = getattr(child, "CanFestivalSlaveNode", None) + if child_data is None: + # Not a slave -> master + child_data = getattr(child, "CanFestivalNode") + # Apply sync setting + format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%( + nodename, + child_data.getNodeId()) + if child_data.getSync_TPDOs(): + format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename) + format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename) + + # initialize and declare node boot status variables for post_SlaveBootup lookup + SlaveIDs = child.GetSlaveIDs() + if len(SlaveIDs) == 0: + # define post_SlaveBootup lookup functions + format_dict["slavebootups"] += ( + "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename)) + else: + for id in SlaveIDs: + format_dict["slavebootups"] += ( + "int %s_slave_%d_booted = 0;\n"%(nodename, id)) + # define post_SlaveBootup lookup functions + format_dict["slavebootups"] += ( + "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+ + " switch(nodeId){\n") + # one case per declared node, mark node as booted + for id in SlaveIDs: + format_dict["slavebootups"] += ( + " case %d:\n"%(id)+ + " %s_slave_%d_booted = 1;\n"%(nodename, id)+ + " break;\n") + format_dict["slavebootups"] += ( + " default:\n"+ + " break;\n"+ + " }\n"+ + " if( ") + # expression to test if all declared nodes booted + format_dict["slavebootups"] += " && ".join(["%s_slave_%d_booted"%(nodename, id) for id in SlaveIDs]) + format_dict["slavebootups"] += " )\n" + ( + " Master_post_SlaveBootup(d,nodeId);\n"+ + "}\n") + # register previously declared func as post_SlaveBootup callback for that node + format_dict["slavebootup_register"] += ( + "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename)) + else: + # Slave node + align = child_data.getSync_Align() + align_ratio=child_data.getSync_Align_Ratio() + if align > 0: + format_dict["post_sync"] += ( + "static int %s_CalCount = 0;\n"%(nodename)+ + "static void %s_post_sync(CO_Data* d){\n"%(nodename)+ + " if(%s_CalCount < %d){\n"%(nodename, align)+ + " %s_CalCount++;\n"%(nodename)+ + " align_tick(-1);\n"+ + " }else{\n"+ + " align_tick(%d);\n"%(align_ratio)+ + " }\n"+ + "}\n") + format_dict["post_sync_register"] += ( + "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename)) + format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%( + nodename, + child_data.getNodeId()) + + # Include generated OD headers + format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) + # Declare CAN channels according user filled config + format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%( + nodename, + child.GetCanDevice(), + child_data.getCAN_Baudrate()) + format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) + format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) + format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename) + + filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c") + cf_main = open(filename).read() % format_dict + cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict) + f = open(cf_main_path,'w') + f.write(cf_main) + f.close() + + return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True + + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/cf_runtime.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/cf_runtime.c Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,150 @@ + +#include "canfestival.h" + +/* CanFestival nodes generated OD headers*/ +%(nodes_includes)s + +#define BOARD_DECL(nodename, busname, baudrate)\ + s_BOARD nodename##Board = {busname, baudrate}; + +/* CAN channels declaration */ +%(board_decls)s + +/* Keep track of init level to cleanup correctly */ +static int init_level=0; +/* Retrieve PLC cycle time */ +extern int common_ticktime__; + +/* Called once all NetworkEdit declares slaves have booted*/ +static void Master_post_SlaveBootup(CO_Data* d, UNS8 nodeId) +{ + /* Put the master in operational mode */ + setState(d, Operational); + + /* Ask slave node to go in operational mode */ + masterSendNMTstateChange (d, 0, NMT_Start_Node); +} + +/* Per master node slavebootup callbacks. Checks that + * every node have booted before calling Master_post_SlaveBootup */ +%(slavebootups)s + +/* One slave node post_sync callback. + * Used to align PLC tick-time on CANopen SYNC + */ +%(post_sync)s + +#define NODE_FORCE_SYNC(nodename) \ + /* Artificially force sync state to 1 so that it is not started */\ + nodename##_Data.CurrentCommunicationState.csSYNC = -1;\ + /* Force sync period to common_ticktime__ so that other node can read it*/\ + *nodename##_Data.COB_ID_Sync = 0x40000080;\ + *nodename##_Data.Sync_Cycle_Period = common_ticktime__ * 1000; + +#define NODE_INIT(nodename, nodeid) \ + /* Defining the node Id */\ + setNodeId(&nodename##_Data, nodeid);\ + /* init */\ + setState(&nodename##_Data, Initialisation); + +#define NODE_MASTER_INIT(nodename, nodeid) \ + NODE_FORCE_SYNC(nodename) \ + NODE_INIT(nodename, nodeid) + +#define NODE_SLAVE_INIT(nodename, nodeid) \ + NODE_INIT(nodename, nodeid) + +void InitNodes(CO_Data* d, UNS32 id) +{ + %(slavebootup_register)s + %(post_sync_register)s + %(nodes_init)s +} + +#define NODE_STOP(nodename) \ + if(init_level-- > 0)\ + {\ + masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\ + setState(&nodename##_Data, Stopped);\ + } + +void Exit(CO_Data* d, UNS32 id) +{ + %(nodes_stop)s +} + +#define NODE_CLOSE(nodename) \ + if(init_level_c-- > 0)\ + {\ + canClose(&nodename##_Data);\ + } + +void __cleanup_%(locstr)s(void) +{ + // Stop timer thread + if(init_level-- > 0){ + int init_level_c = init_level; + StopTimerLoop(&Exit); + %(nodes_close)s + } + + TimerCleanup(); +} + +#ifndef stderr +#define fprintf(...) +#define fflush(...) +#endif + +#define NODE_OPEN(nodename)\ + if(!canOpen(&nodename##Board,&nodename##_Data)){\ + fprintf(stderr,"Cannot open CAN intefrace %%s at speed %%s\n for CANopen node \"" #nodename "\"",nodename##Board.busname, nodename##Board.baudrate);\ + fflush(stderr);\ + return -1;\ + }\ + init_level++; + +/*************************** INIT *****************************************/ +int __init_%(locstr)s(int argc,char **argv) +{ +#ifndef NOT_USE_DYNAMIC_LOADING + if( !LoadCanDriver("%(candriver)s") ){ + fprintf(stderr, "Cannot load CAN interface library for CanFestival (%(candriver)s)\n");\ + fflush(stderr);\ + return -1;\ + } +#endif + + TimerInit(); + + %(nodes_open)s + + // Start timer thread + StartTimerLoop(&InitNodes); + init_level++; + return 0; +} + +#define NODE_SEND_SYNC(nodename)\ + sendSYNCMessage(&nodename##_Data); + +void __retrieve_%(locstr)s(void) +{ + /* Locks the stack, so that no changes occurs while PLC access variables + * TODO : implement buffers to avoid such a big lock + * */ + EnterMutex(); + /* Send Sync */ + %(nodes_send_sync)s +} + +#define NODE_PROCEED_SYNC(nodename)\ + proceedSYNC(&nodename##_Data); + +void __publish_%(locstr)s(void) +{ + /* Process sync event */ + %(nodes_proceed_sync)s + LeaveMutex(); +} + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/config_utils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/config_utils.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,737 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +#This file is part of Beremiz, a Integrated Development Environment for +#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. +# +#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 types import * + +# Translation between IEC types and Can Open types +IECToCOType = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10, + "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08, + "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07, + "LWORD":0x1B,"WSTRING":0x0B} + +# Constants for PDO types +RPDO = 1 +TPDO = 2 + +SlavePDOType = {"I" : TPDO, "Q" : RPDO} +InvertPDOType = {RPDO : TPDO, TPDO : RPDO} +PDOTypeBaseIndex = {RPDO : 0x1400, TPDO : 0x1800} +PDOTypeBaseCobId = {RPDO : 0x200, TPDO : 0x180} + +VariableIncrement = 0x100 +VariableStartIndex = {TPDO : 0x2000, RPDO : 0x4000} +VariableDirText = {TPDO : "__I", RPDO : "__Q"} +VariableTypeOffset = dict(zip(["","X","B","W","D","L"], range(6))) + +TrashVariables = [(1, 0x01), (8, 0x05), (16, 0x06), (32, 0x07), (64, 0x1B)] + +#------------------------------------------------------------------------------- +# Specific exception for PDO mapping errors +#------------------------------------------------------------------------------- + +class PDOmappingException(Exception): + pass + + +def LE_to_BE(value, size): + """ + Convert Little Endian to Big Endian + @param value: value expressed in integer + @param size: number of bytes generated + @return: a string containing the value converted + """ + + data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value + list_car = [data[i:i+2] for i in xrange(0, len(data), 2)] + list_car.reverse() + return "".join([chr(int(car, 16)) for car in list_car]) + + +def GetNodePDOIndexes(node, type, parameters = False): + """ + Find the PDO indexes of a node + @param node: node + @param type: type of PDO searched (RPDO or TPDO or both) + @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) + @return: a list of indexes found + """ + + indexes = [] + if type & RPDO: + indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF]) + if type & TPDO: + indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF]) + if not parameters: + return [idx + 0x200 for idx in indexes] + else: + return indexes + + +def SearchNodePDOMapping(loc_infos, node): + """ + Find the PDO indexes of a node + @param node: node + @param type: type of PDO searched (RPDO or TPDO or both) + @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) + @return: a list of indexes found + """ + + model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + + for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]): + values = node.GetEntry(PDOidx) + if values != None: + for subindex, mapping in enumerate(values): + if subindex != 0 and mapping & 0xFFFFFF00 == model: + return PDOidx, subindex + return None + + +def GeneratePDOMappingDCF(idx, cobid, transmittype, pdomapping): + """ + Build concise DCF value for configuring a PDO + @param idx: index of PDO parameters + @param cobid: PDO generated COB ID + @param transmittype : PDO transmit type + @param pdomapping: list of PDO mappings + @return: a tuple of value and number of parameters to add to DCF + """ + + # Create entry for RPDO or TPDO parameters and Disable PDO + dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4) + # Set Transmit type synchrone + dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(transmittype, 1) + # Re-Enable PDO + # ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------ + dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4) + nbparams = 3 + if len(pdomapping) > 0: + dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(0x00, 1) + LE_to_BE(0x01, 4) + LE_to_BE(len(pdomapping), 1) + nbparams += 1 + # Map Variables + for subindex, (name, loc_infos) in enumerate(pdomapping): + value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"] + dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4) + nbparams += 1 + return dcfdata, nbparams + +class ConciseDCFGenerator: + + def __init__(self, nodelist, nodename): + # Dictionary of location informations classed by name + self.IECLocations = {} + # Dictionary of location that have not been mapped yet + self.LocationsNotMapped = {} + # Dictionary of location informations classed by name + self.MasterMapping = {} + # List of COB IDs available + self.ListCobIDAvailable = range(0x180, 0x580) + # Dictionary of mapping value where unexpected variables are stored + self.TrashVariables = {} + # Dictionary of pointed variables + self.PointedVariables = {} + + self.NodeList = nodelist + self.Manager = self.NodeList.Manager + self.MasterNode = self.Manager.GetCurrentNodeCopy() + self.MasterNode.SetNodeName(nodename) + self.PrepareMasterNode() + + def GetPointedVariables(self): + return self.PointedVariables + + def RemoveUsedNodeCobId(self, node): + """ + Remove all PDO COB ID used by the given node from the list of available COB ID + @param node: node + @return: a tuple of number of RPDO and TPDO for the node + """ + + # Get list of all node TPDO and RPDO indexes + nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True) + nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True) + + # Mark all the COB ID of the node already mapped PDO as not available + for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes: + pdo_cobid = node.GetEntry(PdoIdx, 0x01) + # Extract COB ID, if PDO isn't active + if pdo_cobid > 0x600 : + pdo_cobid -= 0x80000000 + # Remove COB ID from the list of available COB ID + if pdo_cobid in self.ListCobIDAvailable: + self.ListCobIDAvailable.remove(pdo_cobid) + + return len(nodeRpdoIndexes), len(nodeTpdoIndexes) + + + def PrepareMasterNode(self): + """ + Add mandatory entries for DCF generation into MasterNode. + """ + + # Adding DCF entry into Master node + if not self.MasterNode.IsEntry(0x1F22): + self.MasterNode.AddEntry(0x1F22, 1, "") + self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode) + + # Adding trash mappable variables for unused mapped datas + idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID() + # Add an entry for storing unexpected all variable + self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode) + for subidx, (size, typeidx) in enumerate(TrashVariables): + # Add a subentry for storing unexpected variable of this size + self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode) + self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode) + # Store the mapping value for this entry + self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size + + RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode) + + # Store the indexes of the first RPDO and TPDO available for MasterNode + self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber} + + # Prepare MasterNode with all nodelist slaves + for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()): + node = nodeinfos["Node"] + node.SetNodeID(nodeid) + + RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node) + + # Get Slave's default SDO server parameters + RSDO_cobid = node.GetEntry(0x1200,0x01) + if not RSDO_cobid: + RSDO_cobid = 0x600 + nodeid + TSDO_cobid = node.GetEntry(0x1200,0x02) + if not TSDO_cobid: + TSDO_cobid = 0x580 + nodeid + + # Configure Master's SDO parameters entries + self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode) + self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid) + self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid) + self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid) + + + def GetMasterNode(self): + """ + Return MasterNode. + """ + return self.MasterNode + + def AddParamsToDCF(self, nodeid, data, nbparams): + """ + Add entry to DCF, for the requested nodeID + @param nodeid: id of the slave (int) + @param data: data to add to slave DCF (string) + @param nbparams: number of params added to slave DCF (int) + """ + # Get current DCF for slave + nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid) + + # Extract data and number of params in current DCF + if nodeDCF != None and nodeDCF != '': + tmpnbparams = [i for i in nodeDCF[:4]] + tmpnbparams.reverse() + nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16) + data = nodeDCF[4:] + data + + # Build new DCF + dcf = LE_to_BE(nbparams, 0x04) + data + # Set new DCF for slave + self.MasterNode.SetEntry(0x1F22, nodeid, dcf) + + def GetEmptyPDO(self, nodeid, pdotype, start_index=None): + """ + Search a not configured PDO for a slave + @param node: the slave node object + @param pdotype: type of PDO to generated (RPDO or TPDO) + @param start_index: Index where search must start (default: None) + @return tuple of PDO index, COB ID and number of subindex defined + """ + # If no start_index defined, start with PDOtype base index + if start_index is None: + index = PDOTypeBaseIndex[pdotype] + else: + index = start_index + + # Search for all PDO possible index until find a configurable PDO + # starting from start_index + while index < PDOTypeBaseIndex[pdotype] + 0x200: + values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200) + if values != None and values[0] > 0: + # Check that all subindex upper than 0 equal 0 => configurable PDO + if reduce(lambda x, y: x and y, map(lambda x: x == 0, values[1:]), True): + cobid = self.NodeList.GetSlaveNodeEntry(nodeid, index, 1) + # If no COB ID defined in PDO, generate a new one (not used) + if cobid == 0: + if len(self.ListCobIDAvailable) == 0: + return None + # Calculate COB ID from standard values + if index < PDOTypeBaseIndex[pdotype] + 4: + cobid = PDOTypeBaseCobId[pdotype] + 0x100 * (index - PDOTypeBaseIndex[pdotype]) + nodeid + if cobid not in self.ListCobIDAvailable: + cobid = self.ListCobIDAvailable.pop(0) + return index, cobid, values[0] + index += 1 + return None + + def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs): + """ + Record a new mapping request for a slave, and add related slave config to the DCF + @param nodeid: id of the slave (int) + @param pdotype: type of PDO to generated (RPDO or TPDO) + @param pdomapping: list od variables to map with PDO + """ + # Add an entry to MasterMapping + self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype], + "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]} + + # Return the data to add to DCF + if sync_TPDOs: + return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping) + else: + return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping) + return 0, "" + + def GenerateDCF(self, locations, current_location, sync_TPDOs): + """ + Generate Concise DCF of MasterNode for the locations list given + @param locations: list of locations to be mapped + @param current_location: tuple of the located prefixes not to be considered + @param sync_TPDOs: indicate if TPDO must be synchronous + """ + + #------------------------------------------------------------------------------- + # Verify that locations correspond to real slave variables + #------------------------------------------------------------------------------- + + # Get list of locations check if exists and mappables -> put them in IECLocations + for location in locations: + COlocationtype = IECToCOType[location["IEC_TYPE"]] + name = location["NAME"] + if name in self.IECLocations: + if self.IECLocations[name]["type"] != COlocationtype: + raise PDOmappingException, _("Type conflict for location \"%s\"") % name + else: + # Get only the part of the location that concern this node + loc = location["LOC"][len(current_location):] + # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) + if len(loc) not in (2, 3, 4): + raise PDOmappingException, _("Bad location size : %s") % str(loc) + elif len(loc) == 2: + continue + + direction = location["DIR"] + + sizelocation = location["SIZE"] + + # Extract and check nodeid + nodeid, index, subindex = loc[:3] + + # Check Id is in slave node list + if nodeid not in self.NodeList.SlaveNodes.keys(): + raise PDOmappingException, _("Non existing node ID : %d (variable %s)") % (nodeid,name) + + # Get the model for this node (made from EDS) + node = self.NodeList.SlaveNodes[nodeid]["Node"] + + # Extract and check index and subindex + if not node.IsEntry(index, subindex): + raise PDOmappingException, _("No such index/subindex (%x,%x) in ID : %d (variable %s)") % (index,subindex,nodeid,name) + + # Get the entry info + subentry_infos = node.GetSubentryInfos(index, subindex) + + # If a PDO mappable + if subentry_infos and subentry_infos["pdo"]: + if sizelocation == "X" and len(loc) > 3: + numbit = loc[3] + elif sizelocation != "X" and len(loc) > 3: + raise PDOmappingException, _("Cannot set bit offset for non bool '%s' variable (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex) + else: + numbit = None + + if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype: + raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) + + typeinfos = node.GetEntryInfos(COlocationtype) + self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction], + "nodeid": nodeid, "index": index,"subindex": subindex, + "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation} + else: + raise PDOmappingException, _("Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex) + + #------------------------------------------------------------------------------- + # Search for locations already mapped + #------------------------------------------------------------------------------- + + for name, locationinfos in self.IECLocations.items(): + node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"] + + # Search if slave has a PDO mapping this locations + result = SearchNodePDOMapping(locationinfos, node) + if result != None: + index, subindex = result + # Get COB ID of the PDO + cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1) + + # Add PDO to MasterMapping + if cobid not in self.MasterMapping.keys(): + # Verify that PDO transmit type is conform to sync_TPDOs + transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2) + if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF: + if sync_TPDOs: + # Change TransmitType to SYNCHRONE + data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, []) + else: + # Change TransmitType to ASYCHRONE + data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, []) + + # Add entry to slave dcf to change transmit type of + self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams) + + mapping = [None] + values = node.GetEntry(index) + # Store the size of each entry mapped in PDO + for value in values[1:]: + if value != 0: + mapping.append(value % 0x100) + self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping} + + # Indicate that this PDO entry must be saved + if locationinfos["bit"] is not None: + if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType): + self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex] + if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]): + self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name) + else: + self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name) + + else: + # Add location to those that haven't been mapped yet + if locationinfos["nodeid"] not in self.LocationsNotMapped.keys(): + self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []} + self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos)) + + #------------------------------------------------------------------------------- + # Build concise DCF for the others locations + #------------------------------------------------------------------------------- + + for nodeid, locations in self.LocationsNotMapped.items(): + node = self.NodeList.SlaveNodes[nodeid]["Node"] + + # Initialize number of params and data to add to node DCF + nbparams = 0 + dataparams = "" + + # Generate the best PDO mapping for each type of PDO + for pdotype in (TPDO, RPDO): + if len(locations[pdotype]) > 0: + pdosize = 0 + pdomapping = [] + result = self.GetEmptyPDO(nodeid, pdotype) + if result is None: + raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid + pdoindex, pdocobid, pdonbparams = result + for name, loc_infos in locations[pdotype]: + pdosize += loc_infos["size"] + # If pdo's size > 64 bits + if pdosize > 64 or len(pdomapping) >= pdonbparams: + # Generate a new PDO Mapping + data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs) + dataparams += data + nbparams += nbaddedparams + pdosize = loc_infos["size"] + pdomapping = [(name, loc_infos)] + result = self.GetEmptyPDO(nodeid, pdotype, pdoindex + 1) + if result is None: + raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid + pdoindex, pdocobid, pdonbparams = result + else: + pdomapping.append((name, loc_infos)) + # If there isn't locations yet but there is still a PDO to generate + if len(pdomapping) > 0: + # Generate a new PDO Mapping + data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs) + dataparams += data + nbparams += nbaddedparams + + # Add number of params and data to node DCF + self.AddParamsToDCF(nodeid, dataparams, nbparams) + + #------------------------------------------------------------------------------- + # Master Node Configuration + #------------------------------------------------------------------------------- + + # Generate Master's Configuration from informations stored in MasterMapping + for cobid, pdo_infos in self.MasterMapping.items(): + # Get next PDO index in MasterNode for this PDO type + current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]] + + # Search if there is already a PDO in MasterNode with this cob id + for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True): + if self.MasterNode.GetEntry(idx, 1) == cobid: + current_idx = idx + + # Add a PDO to MasterNode if not PDO have been found + if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]: + addinglist = [current_idx, current_idx + 0x200] + self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode) + self.MasterNode.SetEntry(current_idx, 0x01, cobid) + + # Increment the number of PDO for this PDO type + self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1 + + # Change the transmit type of the PDO + if sync_TPDOs: + self.MasterNode.SetEntry(current_idx, 0x02, 0x01) + else: + self.MasterNode.SetEntry(current_idx, 0x02, 0xFF) + + mapping = [] + for item in pdo_infos["mapping"]: + if isinstance(item, ListType): + mapping.extend(item) + else: + mapping.append(item) + + # Add some subentries to PDO mapping if there is not enough + if len(mapping) > 1: + self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode) + + # Generate MasterNode's PDO mapping + for subindex, variable in enumerate(mapping): + if subindex == 0: + continue + new_index = False + + if isinstance(variable, (IntType, LongType)): + # If variable is an integer then variable is unexpected + self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable]) + else: + typeidx, varname = variable + variable_infos = self.IECLocations[varname] + + # Calculate base index for storing variable + mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \ + VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \ + variable_infos["nodeid"] + + # Generate entry name + indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]], + variable_infos["sizelocation"], + '_'.join(map(str,current_location)), + variable_infos["nodeid"]) + + # Search for an entry that has an empty subindex + while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: + # Entry doesn't exist + if not self.MasterNode.IsEntry(mapvariableidx): + # Add entry to MasterNode + self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode) + new_index = True + nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00) + else: + # Get Number of subentries already defined + nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00) + # if entry is full, go to next entry possible or stop now + if nbsubentries == 0xFF: + mapvariableidx += 8 * VariableIncrement + else: + break + + # Verify that a not full entry has been found + if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: + # Generate subentry name + if variable_infos["bit"] != None: + subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos + else: + subindexname = "%(index)d_%(subindex)d"%variable_infos + # If entry have just been created, no subentry have to be added + if not new_index: + self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode) + nbsubentries += 1 + # Add informations to the new subentry created + self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname}) + self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx}) + + # Set value of the PDO mapping + typeinfos = self.Manager.GetEntryInfos(typeidx) + if typeinfos != None: + value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"] + self.MasterNode.SetEntry(current_idx + 0x200, subindex, value) + + # Add variable to pointed variables + self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname) + +def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename): + """ + Fills a CanFestival network editor model, with DCF with requested PDO mappings. + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @param nodelist: CanFestival network editor model + @return: a modified copy of the given CanFestival network editor model + """ + + dcfgenerator = ConciseDCFGenerator(nodelist, nodename) + dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs) + masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables() + # allow access to local OD from Master PLC + pointers.update(LocalODPointers(locations, current_location, masternode)) + return masternode,pointers + +def LocalODPointers(locations, current_location, slave): + IECLocations = {} + pointers = {} + for location in locations: + COlocationtype = IECToCOType[location["IEC_TYPE"]] + name = location["NAME"] + if name in IECLocations: + if IECLocations[name] != COlocationtype: + raise PDOmappingException, _("Type conflict for location \"%s\"") % name + else: + # Get only the part of the location that concern this node + loc = location["LOC"][len(current_location):] + # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) + if len(loc) not in (2, 3, 4): + raise PDOmappingException, _("Bad location size : %s") % str(loc) + elif len(loc) != 2: + continue + + # Extract and check nodeid + index, subindex = loc[:2] + + # Extract and check index and subindex + if not slave.IsEntry(index, subindex): + raise PDOmappingException, _("No such index/subindex (%x,%x) (variable %s)") % (index, subindex, name) + + # Get the entry info + subentry_infos = slave.GetSubentryInfos(index, subindex) + if subentry_infos["type"] != COlocationtype: + raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) + + IECLocations[name] = COlocationtype + pointers[(index, subindex)] = name + return pointers + +if __name__ == "__main__": + import os, sys, getopt + + def usage(): + print """ +Usage of config_utils.py test : + + %s [options] + +Options: + --help (-h) + Displays help informations for config_utils + + --reset (-r) + Reset the reference result of config_utils test. + Use with caution. Be sure that config_utils + is currently working properly. +"""%sys.argv[0] + + # Boolean that indicate if reference result must be redefined + reset = False + + # Extract command options + try: + opts, args = getopt.getopt(sys.argv[1:], "hr", ["help","reset"]) + except getopt.GetoptError: + # print help information and exit: + usage() + sys.exit(2) + + # Test each option + for o, a in opts: + if o in ("-h", "--help"): + usage() + sys.exit() + elif o in ("-r", "--reset"): + reset = True + + # Extract workspace base folder + base_folder = sys.path[0] + for i in xrange(3): + base_folder = os.path.split(base_folder)[0] + # Add CanFestival folder to search pathes + sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen")) + + from nodemanager import * + from nodelist import * + + # Open the test nodelist contained into test_config folder + manager = NodeManager() + nodelist = NodeList(manager) + result = nodelist.LoadProject("test_config") + + # List of locations, we try to map for test + locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)}, + {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)}, + {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)}, + {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)}, + {"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24578_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24578,1)}, + {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)}, + {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)}, + {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)}, + {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)}, + {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}] + + # Generate MasterNode configuration + try: + masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode") + except ValueError, message: + print "%s\nTest Failed!"%message + sys.exit() + + import pprint + # Get Text corresponding to MasterNode + result_node = masternode.PrintString() + result_vars = pprint.pformat(pointedvariables) + result = result_node + "\n********POINTERS*********\n" + result_vars + "\n" + + # If reset has been choosen + if reset: + # Write Text into reference result file + testfile = open("test_config/result.txt", "w") + testfile.write(result) + testfile.close() + + print "Reset Successful!" + else: + import os + + testfile = open("test_config/result_tmp.txt", "w") + testfile.write(result) + testfile.close() + + os.system("diff test_config/result.txt test_config/result_tmp.txt") + os.remove("test_config/result_tmp.txt") diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/test_config/eds/PEAK MicroMod.eds --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/test_config/eds/PEAK MicroMod.eds Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1289 @@ +[FileInfo] +CreatedBy=ESAcademy +ModifiedBy=ESAcademy +Description=PEAK MicroMod CANopenIA Generic +CreationTime=09:41PM +CreationDate=05-05-2003 +ModificationTime=05:05PM +ModificationDate=03-23-2005 +FileName=C:\CANopenCT\Tests\PEAK MicroMod.eds +FileVersion=1 +FileRevision=1 +EDSVersion=4 + +[DeviceInfo] +VendorName=PEAK System Technik +VendorNumber=0x00000175 +ProductName=PEAK MicroMod CANopenIA Generic +ProductNumber=0x00100000 +RevisionNumber=0x00010001 +OrderCode=na +BaudRate_10=0 +BaudRate_20=0 +BaudRate_50=1 +BaudRate_125=1 +BaudRate_250=1 +BaudRate_500=1 +BaudRate_800=1 +BaudRate_1000=1 +SimpleBootUpMaster=0 +SimpleBootUpSlave=1 +Granularity=0 +DynamicChannelsSupported=0 +CompactPDO=0 +GroupMessaging=0 +NrOfRXPDO=4 +NrOfTXPDO=4 +LSS_Supported=0 + +[DummyUsage] +Dummy0001=0 +Dummy0002=0 +Dummy0003=0 +Dummy0004=0 +Dummy0005=1 +Dummy0006=1 +Dummy0007=1 + +[Comments] +Lines=0 + +[MandatoryObjects] +SupportedObjects=3 +1=0x1000 +2=0x1001 +3=0x1018 + +[1000] +ParameterName=Device Type +ObjectType=0x7 +DataType=0x0007 +AccessType=ro +DefaultValue=0x000F0191 +PDOMapping=0 + +[1001] +ParameterName=Error Register +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=0 +PDOMapping=0 + +[1018] +ParameterName=Identity Object +ObjectType=0x9 +SubNumber=4 + +[1018sub0] +ParameterName=number of entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=3 +PDOMapping=0 + +[1018sub1] +ParameterName=Vendor ID +ObjectType=0x7 +DataType=0x0007 +AccessType=ro +DefaultValue=0x00000175 +PDOMapping=0 + +[1018sub2] +ParameterName=Product Code +ObjectType=0x7 +DataType=0x0007 +AccessType=ro +DefaultValue=0x00100000 +PDOMapping=0 + +[1018sub3] +ParameterName=Revision number +ObjectType=0x7 +DataType=0x0007 +AccessType=ro +DefaultValue=0x00010001 +PDOMapping=0 + +[OptionalObjects] +SupportedObjects=41 +1=0x1002 +2=0x1005 +3=0x1008 +4=0x1009 +5=0x100A +6=0x100C +7=0x100D +8=0x1010 +9=0x1011 +10=0x1016 +11=0x1017 +12=0x1020 +13=0x1400 +14=0x1401 +15=0x1402 +16=0x1403 +17=0x1600 +18=0x1601 +19=0x1602 +20=0x1603 +21=0x1800 +22=0x1801 +23=0x1802 +24=0x1803 +25=0x1A00 +26=0x1A01 +27=0x1A02 +28=0x1A03 +29=0x1F50 +30=0x6000 +31=0x6002 +32=0x6200 +33=0x6202 +34=0x6206 +35=0x6207 +36=0x6401 +37=0x6411 +38=0x6423 +39=0x6426 +40=0x6443 +41=0x6444 + +[1002] +ParameterName=PEAK Status Register +ObjectType=0x7 +DataType=0x0007 +AccessType=ro +PDOMapping=0 + +[1005] +ParameterName=COB-ID SYNC +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x00000080 +PDOMapping=0 + +[1008] +ParameterName=Manufacturer Device Name +ObjectType=0x7 +DataType=0x0009 +AccessType=const +PDOMapping=0 + +[1009] +ParameterName=Manufacturer Hardware Version +ObjectType=0x7 +DataType=0x0009 +AccessType=const +PDOMapping=0 + +[100a] +ParameterName=Manufacturer Software Version +ObjectType=0x7 +DataType=0x0009 +AccessType=const +PDOMapping=0 + +[100c] +ParameterName=Guard Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[100d] +ParameterName=Life Time Factor +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0x00 +PDOMapping=0 + +[1010] +ParameterName=Store Parameter Field +ObjectType=0x8 +SubNumber=2 + +[1010sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1010sub1] +ParameterName=Save all Parameters +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +PDOMapping=0 + +[1011] +ParameterName=Restore Default Parameters +ObjectType=0x8 +SubNumber=2 + +[1011sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[1011sub1] +ParameterName=Restore all Default Parameters +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +PDOMapping=0 + +[1016] +ParameterName=Consumer Heartbeat Time +ObjectType=0x8 +SubNumber=4 + +[1016sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=3 +PDOMapping=0 +LowLimit=0x1 + +[1016sub1] +ParameterName=Consumer Heartbeat Time +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1016sub2] +ParameterName=Consumer Heartbeat Time +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1016sub3] +ParameterName=Consumer Heartbeat Time +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1017] +ParameterName=Producer Heartbeat Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1020] +ParameterName=Verify Configuration +ObjectType=0x8 +SubNumber=3 + +[1020sub0] +ParameterName=Number of entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1020sub1] +ParameterName=Configuration date +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +PDOMapping=0 + +[1020sub2] +ParameterName=Configuration time +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +PDOMapping=0 + +[1400] +ParameterName=Receive PDO Communication Parameter +ObjectType=0x9 +SubNumber=3 + +[1400sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1400sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x200 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1400sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1401] +ParameterName=Receive PDO Communication Parameter +ObjectType=0x9 +SubNumber=3 + +[1401sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 + +[1401sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x300 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1401sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1402] +ParameterName=Receive PDO Communication Parameter +ObjectType=0x9 +SubNumber=3 + +[1402sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1402sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x80000400 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1402sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1403] +ParameterName=Receive PDO Communication Parameter +ObjectType=0x9 +SubNumber=3 + +[1403sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=2 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1403sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x80000500 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1403sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1600] +ParameterName=Receive PDO Mapping Parameter +ObjectType=0x9 +SubNumber=2 + +[1600sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=1 +PDOMapping=0 + +[1600sub1] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x62000108 +PDOMapping=0 + +[1601] +ParameterName=Receive PDO Mapping Parameter +ObjectType=0x9 +SubNumber=5 + +[1601sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=4 +PDOMapping=0 + +[1601sub1] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64110110 +PDOMapping=0 + +[1601sub2] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64110210 +PDOMapping=0 + +[1601sub3] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64110310 +PDOMapping=0 + +[1601sub4] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64110410 +PDOMapping=0 + +[1602] +ParameterName=Receive PDO Mapping Parameter +ObjectType=0x9 +SubNumber=1 + +[1602sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1603] +ParameterName=Receive PDO Mapping Parameter +ObjectType=0x9 +SubNumber=1 + +[1603sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1800] +ParameterName=Transmit PDO Communication Parameter +ObjectType=0x9 +SubNumber=5 + +[1800sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=5 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1800sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x180 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1800sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1800sub3] +ParameterName=Inhibit Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0x0000 +PDOMapping=0 + +[1800sub5] +ParameterName=Event Timer +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1801] +ParameterName=Transmit PDO Communication Parameter +ObjectType=0x9 +SubNumber=5 + +[1801sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=5 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1801sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x280 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1801sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1801sub3] +ParameterName=Inhibit Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0x0000 +PDOMapping=0 + +[1801sub5] +ParameterName=Event Timer +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1802] +ParameterName=Transmit PDO Communication Parameter +ObjectType=0x9 +SubNumber=5 + +[1802sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=5 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1802sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x380 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1802sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1802sub3] +ParameterName=Inhibit Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0x0000 +PDOMapping=0 + +[1802sub5] +ParameterName=Event Timer +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1803] +ParameterName=Transmit PDO Communication Parameter +ObjectType=0x9 +SubNumber=5 + +[1803sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=5 +PDOMapping=0 +LowLimit=0x02 +HighLimit=0x05 + +[1803sub1] +ParameterName=COB-ID +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=$NODEID+0x80000480 +PDOMapping=0 +LowLimit=0x00000001 +HighLimit=0xFFFFFFFF + +[1803sub2] +ParameterName=Transmission Type +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=255 +PDOMapping=0 + +[1803sub3] +ParameterName=Inhibit Time +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0x0000 +PDOMapping=0 + +[1803sub5] +ParameterName=Event Timer +ObjectType=0x7 +DataType=0x0006 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1a00] +ParameterName=Transmit PDO Mapping Parameter +ObjectType=0x9 +SubNumber=2 + +[1a00sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=1 +PDOMapping=0 + +[1a00sub1] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x60000108 +PDOMapping=0 + +[1a01] +ParameterName=Transmit PDO Mapping Parameter +ObjectType=0x9 +SubNumber=5 + +[1a01sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=4 +PDOMapping=0 + +[1a01sub1] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010110 +PDOMapping=0 + +[1a01sub2] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010210 +PDOMapping=0 + +[1a01sub3] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010310 +PDOMapping=0 + +[1a01sub4] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010410 +PDOMapping=0 + +[1a02] +ParameterName=Transmit PDO Mapping Parameter +ObjectType=0x9 +SubNumber=5 + +[1a02sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=4 +PDOMapping=0 + +[1a02sub1] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010510 +PDOMapping=0 + +[1a02sub2] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010610 +PDOMapping=0 + +[1a02sub3] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010710 +PDOMapping=0 + +[1a02sub4] +ParameterName=PDO Mapping Entry +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0x64010810 +PDOMapping=0 + +[1a03] +ParameterName=Transmit PDO Mapping Parameter +ObjectType=0x9 +SubNumber=1 + +[1a03sub0] +ParameterName=Number of Entries +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[1f50] +ParameterName=Download Program Data +ObjectType=0x8 +SubNumber=2 + +[1f50sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=3 +PDOMapping=0 + +[1f50sub3] +ParameterName=Download Program Data - HW Settings +ObjectType=0x7 +DataType=0x000F +AccessType=rw +PDOMapping=0 + +[6000] +ParameterName=Read Digital Input 8-bit +ObjectType=0x8 +SubNumber=2 + +[6000sub0] +ParameterName=Number of Elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6000sub1] +ParameterName=DigInput8_1 +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +PDOMapping=1 + +[6002] +ParameterName=Polarity Digital Input +ObjectType=0x8 +SubNumber=2 + +[6002sub0] +ParameterName=Number of Elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6002sub1] +ParameterName=Polarity8_1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6200] +ParameterName=Write Digital Output 8-bit +ObjectType=0x8 +SubNumber=2 + +[6200sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6200sub1] +ParameterName=DigOutput8_1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rww +PDOMapping=1 + +[6202] +ParameterName=Polarity Digital Output +ObjectType=0x8 +SubNumber=2 + +[6202sub0] +ParameterName=Number of Elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6202sub1] +ParameterName=Polarity8_1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6206] +ParameterName=Error Mode Digital Output +ObjectType=0x8 +SubNumber=2 + +[6206sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6206sub1] +ParameterName=Error Mode 1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6207] +ParameterName=Error Value Digital Output +ObjectType=0x8 +SubNumber=2 + +[6207sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=1 +PDOMapping=0 + +[6207sub1] +ParameterName=Error Value 1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6401] +ParameterName=Read Analog Input 16-bit +ObjectType=0x8 +SubNumber=9 + +[6401sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=8 +PDOMapping=0 + +[6401sub1] +ParameterName=AnalogInput16_1 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub2] +ParameterName=AnalogInput16_2 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub3] +ParameterName=AnalogInput16_3 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub4] +ParameterName=AnalogInput16_4 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub5] +ParameterName=AnalogInput16_5 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub6] +ParameterName=AnalogInput16_6 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub7] +ParameterName=AnalogInput16_7 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6401sub8] +ParameterName=AnalogInput16_8 +ObjectType=0x7 +DataType=0x0003 +AccessType=ro +PDOMapping=1 + +[6411] +ParameterName=Write Analog Output 16-bit +ObjectType=0x8 +SubNumber=5 + +[6411sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=4 +PDOMapping=0 + +[6411sub1] +ParameterName=AnalogOutput16_1 +ObjectType=0x7 +DataType=0x0003 +AccessType=rww +PDOMapping=1 + +[6411sub2] +ParameterName=AnalogOutput16_2 +ObjectType=0x7 +DataType=0x0003 +AccessType=rww +PDOMapping=1 + +[6411sub3] +ParameterName=AnalogOutput16_3 +ObjectType=0x7 +DataType=0x0003 +AccessType=rww +PDOMapping=1 + +[6411sub4] +ParameterName=AnalogOutput16_4 +ObjectType=0x7 +DataType=0x0003 +AccessType=rww +PDOMapping=1 + +[6423] +ParameterName=Analog Input Global Interrupt +ObjectType=0x7 +DataType=0x0001 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426] +ParameterName=Analog Input Interrupt Delta +ObjectType=0x8 +SubNumber=9 + +[6426sub0] +ParameterName=NrOfObjects +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=8 +PDOMapping=0 + +[6426sub1] +ParameterName=Analog Input Delta 1 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub2] +ParameterName=Analog Input Delta 2 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub3] +ParameterName=Analog Input Delta 3 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub4] +ParameterName=Analog Input Delta 4 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub5] +ParameterName=Analog Input Delta 5 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub6] +ParameterName=Analog Input Delta 6 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub7] +ParameterName=Analog Input Delta 7 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6426sub8] +ParameterName=Analog Input Delta 8 +ObjectType=0x7 +DataType=0x0007 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6443] +ParameterName=Error Mode Analog Output +ObjectType=0x8 +SubNumber=5 + +[6443sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=4 +PDOMapping=0 + +[6443sub1] +ParameterName=Error Mode 1 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6443sub2] +ParameterName=Error Mode 2 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6443sub3] +ParameterName=Error Mode 3 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6443sub4] +ParameterName=Error Mode 4 +ObjectType=0x7 +DataType=0x0005 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6444] +ParameterName=Error Value Analog Output +ObjectType=0x8 +SubNumber=5 + +[6444sub0] +ParameterName=Number of elements +ObjectType=0x7 +DataType=0x0005 +AccessType=ro +DefaultValue=4 +PDOMapping=0 + +[6444sub1] +ParameterName=Error Value 1 +ObjectType=0x7 +DataType=0x0004 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6444sub2] +ParameterName=Error Value 2 +ObjectType=0x7 +DataType=0x0004 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6444sub3] +ParameterName=Error Value 3 +ObjectType=0x7 +DataType=0x0004 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[6444sub4] +ParameterName=Error Value 4 +ObjectType=0x7 +DataType=0x0004 +AccessType=rw +DefaultValue=0 +PDOMapping=0 + +[ManufacturerObjects] +SupportedObjects=0 diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/test_config/master.od --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/test_config/master.od Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Read Inputs + + + + + + + Read Inputs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +master + +TestMaster + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/test_config/nodelist.cpj --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/test_config/nodelist.cpj Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,7 @@ +[TOPOLOGY] +NetName=None +Nodes=0x01 +Node64Present=0x01 +Node64Name=micromod +Node64DCFName=PEAK MicroMod.eds +EDSBaseName=eds diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/canfestival/test_config/result.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/canfestival/test_config/result.txt Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,257 @@ +1000 (Device Type): 12E +1001 (Error Register): 0 +1005 (SYNC COB ID): 40000080 +1006 (Communication / Cycle Period): C350 +1016 (Consumer Heartbeat Time): +1016 01 (Consumer Heartbeat Time): 4005DC +1018 (Identity): +1018 01 (Vendor ID): 0 +1018 02 (Product Code): 0 +1018 03 (Revision Number): 0 +1018 04 (Serial Number): 0 +1280 (Client SDO 1 Parameter): +1280 01 (COB ID Client to Server (Transmit SDO)): 640 +1280 02 (COB ID Server to Client (Receive SDO)): 5C0 +1280 03 (Node ID of the SDO Server): 40 +1400 (Receive PDO 1 Parameter): +1400 01 (COB ID used by PDO): 1C0 +1400 02 (Transmission Type): 1 +1400 03 (Inhibit Time): 0 +1400 04 (Compatibility Entry): 0 +1400 05 (Event Timer): 0 +1401 (Receive PDO 2 Parameter): +1401 01 (COB ID used by PDO): 2C0 +1401 02 (Transmission Type): 1 +1401 03 (Inhibit Time): 0 +1401 04 (Compatibility Entry): 0 +1401 05 (Event Timer): 0 +1402 (Receive PDO 3 Parameter): +1402 01 (COB ID used by PDO): 182 +1402 02 (Transmission Type): 1 +1402 03 (Inhibit Time): 0 +1402 04 (Compatibility Entry): 0 +1402 05 (Event Timer): 0 +1403 (Receive PDO 4 Parameter): +1403 01 (COB ID used by PDO): 183 +1403 02 (Transmission Type): 1 +1403 03 (Inhibit Time): 0 +1403 04 (Compatibility Entry): 0 +1403 05 (Event Timer): 0 +1404 (Receive PDO 5 Parameter): +1404 01 (COB ID used by PDO): 181 +1404 02 (Transmission Type): 1 +1404 03 (Inhibit Time): 0 +1404 04 (Compatibility Entry): 0 +1404 05 (Event Timer): 0 +1600 (Receive PDO 1 Mapping): +1600 01 (PDO 1 Mapping for an application object 1): 22400108 +1600 02 (PDO 1 Mapping for an application object 2): 0 +1601 (Receive PDO 2 Mapping): +1601 01 (PDO 2 Mapping for an application object 1): 20000310 +1601 02 (PDO 2 Mapping for an application object 2): 23400110 +1601 03 (PDO 2 Mapping for an application object 3): 23400210 +1601 04 (PDO 2 Mapping for an application object 4): 20000310 +1602 (Receive PDO 3 Mapping): +1602 01 (PDO 3 Mapping for an application object 1): 24400120 +1602 02 (PDO 3 Mapping for an application object 2): 24400220 +1603 (Receive PDO 4 Mapping): +1603 01 (PDO 4 Mapping for an application object 1): 24400320 +1604 (Receive PDO 5 Mapping): +1604 01 (PDO 5 Mapping for an application object 1): 22400208 +1604 02 (PDO 5 Mapping for an application object 2): 24400420 +1800 (Transmit PDO 1 Parameter): +1800 01 (COB ID used by PDO): {True:"$NODEID+0x%X80"%(base+1),False:0x80000000}[base<4] +1800 02 (Transmission Type): 0 +1800 03 (Inhibit Time): 0 +1800 04 (Compatibility Entry): 0 +1800 05 (Event Timer): 0 +1801 (Transmit PDO 2 Parameter): +1801 01 (COB ID used by PDO): 340 +1801 02 (Transmission Type): 1 +1801 03 (Inhibit Time): 0 +1801 04 (Compatibility Entry): 0 +1801 05 (Event Timer): 0 +1A00 (Transmit PDO 1 Mapping): +1A00 01 (PDO 1 Mapping for a process data variable 1): 10010008 +1A01 (Transmit PDO 2 Mapping): +1A01 01 (PDO 2 Mapping for a process data variable 1): 43400110 +1A01 02 (PDO 2 Mapping for a process data variable 2): 20000310 +1A01 03 (PDO 2 Mapping for a process data variable 3): 20000310 +1A01 04 (PDO 2 Mapping for a process data variable 4): 20000310 +1F22 (Concise DCF): +1F22 01 (Concise DCF for Node 1): +1F22 02 (Concise DCF for Node 2): +1F22 03 (Concise DCF for Node 3): +1F22 04 (Concise DCF for Node 4): +1F22 05 (Concise DCF for Node 5): +1F22 06 (Concise DCF for Node 6): +1F22 07 (Concise DCF for Node 7): +1F22 08 (Concise DCF for Node 8): +1F22 09 (Concise DCF for Node 9): +1F22 0A (Concise DCF for Node 10): +1F22 0B (Concise DCF for Node 11): +1F22 0C (Concise DCF for Node 12): +1F22 0D (Concise DCF for Node 13): +1F22 0E (Concise DCF for Node 14): +1F22 0F (Concise DCF for Node 15): +1F22 10 (Concise DCF for Node 16): +1F22 11 (Concise DCF for Node 17): +1F22 12 (Concise DCF for Node 18): +1F22 13 (Concise DCF for Node 19): +1F22 14 (Concise DCF for Node 20): +1F22 15 (Concise DCF for Node 21): +1F22 16 (Concise DCF for Node 22): +1F22 17 (Concise DCF for Node 23): +1F22 18 (Concise DCF for Node 24): +1F22 19 (Concise DCF for Node 25): +1F22 1A (Concise DCF for Node 26): +1F22 1B (Concise DCF for Node 27): +1F22 1C (Concise DCF for Node 28): +1F22 1D (Concise DCF for Node 29): +1F22 1E (Concise DCF for Node 30): +1F22 1F (Concise DCF for Node 31): +1F22 20 (Concise DCF for Node 32): +1F22 21 (Concise DCF for Node 33): +1F22 22 (Concise DCF for Node 34): +1F22 23 (Concise DCF for Node 35): +1F22 24 (Concise DCF for Node 36): +1F22 25 (Concise DCF for Node 37): +1F22 26 (Concise DCF for Node 38): +1F22 27 (Concise DCF for Node 39): +1F22 28 (Concise DCF for Node 40): +1F22 29 (Concise DCF for Node 41): +1F22 2A (Concise DCF for Node 42): +1F22 2B (Concise DCF for Node 43): +1F22 2C (Concise DCF for Node 44): +1F22 2D (Concise DCF for Node 45): +1F22 2E (Concise DCF for Node 46): +1F22 2F (Concise DCF for Node 47): +1F22 30 (Concise DCF for Node 48): +1F22 31 (Concise DCF for Node 49): +1F22 32 (Concise DCF for Node 50): +1F22 33 (Concise DCF for Node 51): +1F22 34 (Concise DCF for Node 52): +1F22 35 (Concise DCF for Node 53): +1F22 36 (Concise DCF for Node 54): +1F22 37 (Concise DCF for Node 55): +1F22 38 (Concise DCF for Node 56): +1F22 39 (Concise DCF for Node 57): +1F22 3A (Concise DCF for Node 58): +1F22 3B (Concise DCF for Node 59): +1F22 3C (Concise DCF for Node 60): +1F22 3D (Concise DCF for Node 61): +1F22 3E (Concise DCF for Node 62): +1F22 3F (Concise DCF for Node 63): +1F22 40 (Concise DCF for Node 64): 23 arg defined +1F22 40, arg 1: 1800 01 00000004 800001C0 +1F22 40, arg 2: 1800 02 00000001 01 +1F22 40, arg 3: 1800 01 00000004 000001C0 +1F22 40, arg 4: 1801 01 00000004 800002C0 +1F22 40, arg 5: 1801 02 00000001 01 +1F22 40, arg 6: 1801 01 00000004 000002C0 +1F22 40, arg 7: 1401 01 00000004 80000340 +1F22 40, arg 8: 1401 02 00000001 01 +1F22 40, arg 9: 1401 01 00000004 00000340 +1F22 40, arg 10: 1804 01 00000004 80000181 +1F22 40, arg 11: 1804 02 00000001 01 +1F22 40, arg 12: 1804 01 00000004 00000181 +1F22 40, arg 13: 1A04 01 00000004 60020108 +1F22 40, arg 14: 1A04 02 00000004 64260120 +1F22 40, arg 15: 1805 01 00000004 80000182 +1F22 40, arg 16: 1805 02 00000001 01 +1F22 40, arg 17: 1805 01 00000004 00000182 +1F22 40, arg 18: 1A05 01 00000004 64260220 +1F22 40, arg 19: 1A05 02 00000004 64260320 +1F22 40, arg 20: 1806 01 00000004 80000183 +1F22 40, arg 21: 1806 02 00000001 01 +1F22 40, arg 22: 1806 01 00000004 00000183 +1F22 40, arg 23: 1A06 01 00000004 64260420 +1F22 41 (Concise DCF for Node 65): +1F22 42 (Concise DCF for Node 66): +1F22 43 (Concise DCF for Node 67): +1F22 44 (Concise DCF for Node 68): +1F22 45 (Concise DCF for Node 69): +1F22 46 (Concise DCF for Node 70): +1F22 47 (Concise DCF for Node 71): +1F22 48 (Concise DCF for Node 72): +1F22 49 (Concise DCF for Node 73): +1F22 4A (Concise DCF for Node 74): +1F22 4B (Concise DCF for Node 75): +1F22 4C (Concise DCF for Node 76): +1F22 4D (Concise DCF for Node 77): +1F22 4E (Concise DCF for Node 78): +1F22 4F (Concise DCF for Node 79): +1F22 50 (Concise DCF for Node 80): +1F22 51 (Concise DCF for Node 81): +1F22 52 (Concise DCF for Node 82): +1F22 53 (Concise DCF for Node 83): +1F22 54 (Concise DCF for Node 84): +1F22 55 (Concise DCF for Node 85): +1F22 56 (Concise DCF for Node 86): +1F22 57 (Concise DCF for Node 87): +1F22 58 (Concise DCF for Node 88): +1F22 59 (Concise DCF for Node 89): +1F22 5A (Concise DCF for Node 90): +1F22 5B (Concise DCF for Node 91): +1F22 5C (Concise DCF for Node 92): +1F22 5D (Concise DCF for Node 93): +1F22 5E (Concise DCF for Node 94): +1F22 5F (Concise DCF for Node 95): +1F22 60 (Concise DCF for Node 96): +1F22 61 (Concise DCF for Node 97): +1F22 62 (Concise DCF for Node 98): +1F22 63 (Concise DCF for Node 99): +1F22 64 (Concise DCF for Node 100): +1F22 65 (Concise DCF for Node 101): +1F22 66 (Concise DCF for Node 102): +1F22 67 (Concise DCF for Node 103): +1F22 68 (Concise DCF for Node 104): +1F22 69 (Concise DCF for Node 105): +1F22 6A (Concise DCF for Node 106): +1F22 6B (Concise DCF for Node 107): +1F22 6C (Concise DCF for Node 108): +1F22 6D (Concise DCF for Node 109): +1F22 6E (Concise DCF for Node 110): +1F22 6F (Concise DCF for Node 111): +1F22 70 (Concise DCF for Node 112): +1F22 71 (Concise DCF for Node 113): +1F22 72 (Concise DCF for Node 114): +1F22 73 (Concise DCF for Node 115): +1F22 74 (Concise DCF for Node 116): +1F22 75 (Concise DCF for Node 117): +1F22 76 (Concise DCF for Node 118): +1F22 77 (Concise DCF for Node 119): +1F22 78 (Concise DCF for Node 120): +1F22 79 (Concise DCF for Node 121): +1F22 7A (Concise DCF for Node 122): +1F22 7B (Concise DCF for Node 123): +1F22 7C (Concise DCF for Node 124): +1F22 7D (Concise DCF for Node 125): +1F22 7E (Concise DCF for Node 126): +1F22 7F (Concise DCF for Node 127): +2000 (Read Inputs): 0 +2240 (beremiz__IB0_1_64): +2240 01 (24576_1): 0 +2240 02 (24578_1): 0 +2340 (beremiz__IW0_1_64): +2340 01 (25601_2): 0 +2340 02 (25601_3): 0 +2440 (beremiz__ID0_1_64): +2440 01 (25638_2): 0 +2440 02 (25638_3): 0 +2440 03 (25638_4): 0 +2440 04 (25638_1): 0 +4340 (beremiz__QW0_1_64): +4340 01 (25617_1): 0 + +********POINTERS********* +{(4096, 0): '__ID0_1_4096_0', + (8768, 1): '__IB0_1_64_24576_1', + (8768, 2): '__IB0_1_64_24578_1', + (9024, 1): '__IW0_1_64_25601_2', + (9024, 2): '__IW0_1_64_25601_3', + (9280, 1): '__ID0_1_64_25638_2', + (9280, 2): '__ID0_1_64_25638_3', + (9280, 3): '__ID0_1_64_25638_4', + (9280, 4): '__ID0_1_64_25638_1', + (17216, 1): '__QW0_1_64_25617_1'} diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/PythonEditor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/PythonEditor.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,505 @@ +import wx, wx.grid +import wx.stc as stc +import keyword + +from controls import EditorPanel + +if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } +elif wx.Platform == '__WXMAC__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Monaco', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 12, + 'size2': 10, + } +else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 12, + 'size2': 10, + } + +[ID_PYTHONEDITOR, +] = [wx.NewId() for _init_ctrls in range(1)] + +def GetCursorPos(old, new): + old_length = len(old) + new_length = len(new) + common_length = min(old_length, new_length) + i = 0 + for i in xrange(common_length): + if old[i] != new[i]: + break + if old_length < new_length: + if common_length > 0 and old[i] != new[i]: + return i + new_length - old_length + else: + return i + new_length - old_length + 1 + elif old_length > new_length or i < min(old_length, new_length) - 1: + if common_length > 0 and old[i] != new[i]: + return i + else: + return i + 1 + else: + return None + +class PythonEditor(EditorPanel): + + fold_symbols = 3 + + def _init_Editor(self, prnt): + self.Editor = stc.StyledTextCtrl(id=ID_PYTHONEDITOR, parent=prnt, + name="TextViewer", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0) + + self.Editor.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) + self.Editor.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) + + self.Editor.SetLexer(stc.STC_LEX_PYTHON) + self.Editor.SetKeyWords(0, " ".join(keyword.kwlist)) + + self.Editor.SetProperty("fold", "1") + self.Editor.SetProperty("tab.timmy.whinge.level", "1") + self.Editor.SetMargins(0,0) + + self.Editor.SetViewWhiteSpace(False) + + self.Editor.SetEdgeMode(stc.STC_EDGE_BACKGROUND) + self.Editor.SetEdgeColumn(78) + + # Set up the numbers in the margin for margin #1 + self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) + # Reasonable value for, say, 4-5 digits using a mono font (40 pix) + self.Editor.SetMarginWidth(1, 40) + + # Setup a margin to hold fold markers + self.Editor.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + self.Editor.SetMarginMask(2, stc.STC_MASK_FOLDERS) + self.Editor.SetMarginSensitive(2, True) + self.Editor.SetMarginWidth(2, 12) + + if self.fold_symbols == 0: + # Arrow pointing right for contracted folders, arrow pointing down for expanded + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 1: + # Plus for contracted folders, minus for expanded + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 2: + # Like a flattened tree control using circular headers and curved joins + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") + + elif self.fold_symbols == 3: + # Like a flattened tree control using square headers + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") + self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") + + + self.Editor.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) + self.Editor.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) + self.Editor.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) + + # Global default style + if wx.Platform == '__WXMSW__': + self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New') + elif wx.Platform == '__WXMAC__': + # TODO: if this looks fine on Linux too, remove the Mac-specific case + # and use this whenever OS != MSW. + self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Monaco') + else: + defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() + self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) + + # Clear styles and revert to default. + self.Editor.StyleClearAll() + + # Following style specs only indicate differences from default. + # The rest remains unchanged. + + # Line numbers in margin + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') + # Highlighted brace + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') + # Unmatched brace + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') + # Indentation guide + self.Editor.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") + + # Python styles + self.Editor.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') + # Comments + self.Editor.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') + self.Editor.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') + # Numbers + self.Editor.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') + # Strings and characters + self.Editor.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') + self.Editor.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') + # Keywords + self.Editor.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') + # Triple quotes + self.Editor.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') + self.Editor.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') + # Class names + self.Editor.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') + # Function names + self.Editor.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') + # Operators + self.Editor.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') + # Identifiers. I leave this as not bold because everything seems + # to be an identifier if it doesn't match the above criterae + self.Editor.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') + + # Caret color + self.Editor.SetCaretForeground("BLUE") + # Selection background + self.Editor.SetSelBackground(1, '#66CCFF') + + self.Editor.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) + self.Editor.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) + + # register some images for use in the AutoComplete box. + #self.RegisterImage(1, images.getSmilesBitmap()) + self.Editor.RegisterImage(1, + wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) + self.Editor.RegisterImage(2, + wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) + self.Editor.RegisterImage(3, + wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) + + # Indentation and tab stuff + self.Editor.SetIndent(4) # Proscribed indent size for wx + self.Editor.SetIndentationGuides(True) # Show indent guides + self.Editor.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space + self.Editor.SetTabIndents(True) # Tab key indents + self.Editor.SetTabWidth(4) # Proscribed tab size for wx + self.Editor.SetUseTabs(False) # Use spaces rather than tabs, or + # TabTimmy will complain! + # White space + self.Editor.SetViewWhiteSpace(False) # Don't view white space + + # EOL: Since we are loading/saving ourselves, and the + # strings will always have \n's in them, set the STC to + # edit them that way. + self.Editor.SetEOLMode(wx.stc.STC_EOL_LF) + self.Editor.SetViewEOL(False) + + # No right-edge mode indicator + self.Editor.SetEdgeMode(stc.STC_EDGE_NONE) + + self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) + + self.Editor.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) + self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + self.Editor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR) + + + def __init__(self, parent, controler, window): + EditorPanel.__init__(self, parent, "", window, controler) + + self.DisableEvents = False + self.CurrentAction = None + + img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() + self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) + + def __del__(self): + self.Controler.OnCloseEditor(self) + + def GetTitle(self): + fullname = self.Controler.PlugFullName() + if not self.Controler.PythonIsSaved(): + return "~%s~" % fullname + return fullname + + def GetBufferState(self): + return self.Controler.GetBufferState() + + def Undo(self): + self.Controler.LoadPrevious() + self.RefreshView() + + def Redo(self): + self.Controler.LoadNext() + self.RefreshView() + + def HasNoModel(self): + return False + + def OnModification(self, event): + if not self.DisableEvents: + mod_type = event.GetModificationType() + if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): + if mod_type&wx.stc.STC_MOD_BEFOREINSERT: + if self.CurrentAction is None: + self.StartBuffering() + elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: + self.Controler.EndBuffering() + self.StartBuffering() + self.CurrentAction = ("Add", event.GetPosition()) + wx.CallAfter(self.RefreshModel) + elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: + if self.CurrentAction == None: + self.StartBuffering() + elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: + self.Controler.EndBuffering() + self.StartBuffering() + self.CurrentAction = ("Delete", event.GetPosition()) + wx.CallAfter(self.RefreshModel) + event.Skip() + + def OnDoDrop(self, event): + self.ResetBuffer() + wx.CallAfter(self.RefreshModel) + event.Skip() + + # Buffer the last model state + def RefreshBuffer(self): + self.Controler.BufferPython() + if self.ParentWindow is not None: + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def StartBuffering(self): + self.Controler.StartBuffering() + if self.ParentWindow is not None: + self.ParentWindow.RefreshTitle() + self.ParentWindow.RefreshFileMenu() + self.ParentWindow.RefreshEditMenu() + self.ParentWindow.RefreshPageTitles() + + def ResetBuffer(self): + if self.CurrentAction != None: + self.Controler.EndBuffering() + self.CurrentAction = None + + def RefreshView(self): + self.ResetBuffer() + self.DisableEvents = True + old_cursor_pos = self.Editor.GetCurrentPos() + old_text = self.Editor.GetText() + new_text = self.Controler.GetPythonCode() + self.Editor.SetText(new_text) + new_cursor_pos = GetCursorPos(old_text, new_text) + if new_cursor_pos != None: + self.Editor.GotoPos(new_cursor_pos) + else: + self.Editor.GotoPos(old_cursor_pos) + self.Editor.ScrollToColumn(0) + self.Editor.EmptyUndoBuffer() + self.DisableEvents = False + + self.Editor.Colourise(0, -1) + + def RefreshModel(self): + self.Controler.SetPythonCode(self.Editor.GetText()) + + def OnKeyPressed(self, event): + if self.Editor.CallTipActive(): + self.Editor.CallTipCancel() + key = event.GetKeyCode() + + if key == 32 and event.ControlDown(): + pos = self.Editor.GetCurrentPos() + + # Tips + if event.ShiftDown(): + pass +## self.CallTipSetBackground("yellow") +## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' +## 'show some suff, maybe parameters..\n\n' +## 'fubar(param1, param2)') + # Code completion + else: + self.Editor.AutoCompSetIgnoreCase(False) # so this needs to match + + # Images are specified with a appended "?type" + self.Editor.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) + else: + event.Skip() + + def OnKillFocus(self, event): + self.Editor.AutoCompCancel() + event.Skip() + + def OnUpdateUI(self, evt): + # check for matching braces + braceAtCaret = -1 + braceOpposite = -1 + charBefore = None + caretPos = self.Editor.GetCurrentPos() + + if caretPos > 0: + charBefore = self.Editor.GetCharAt(caretPos - 1) + styleBefore = self.Editor.GetStyleAt(caretPos - 1) + + # check before + if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: + braceAtCaret = caretPos - 1 + + # check after + if braceAtCaret < 0: + charAfter = self.Editor.GetCharAt(caretPos) + styleAfter = self.Editor.GetStyleAt(caretPos) + + if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: + braceAtCaret = caretPos + + if braceAtCaret >= 0: + braceOpposite = self.Editor.BraceMatch(braceAtCaret) + + if braceAtCaret != -1 and braceOpposite == -1: + self.Editor.BraceBadLight(braceAtCaret) + else: + self.Editor.BraceHighlight(braceAtCaret, braceOpposite) + #pt = self.Editor.PointFromPosition(braceOpposite) + #self.Editor.Refresh(True, wxRect(pt.x, pt.y, 5,5)) + #print pt + #self.Editor.Refresh(False) + + + def OnMarginClick(self, evt): + # fold and unfold as needed + if evt.GetMargin() == 2: + if evt.GetShift() and evt.GetControl(): + self.FoldAll() + else: + lineClicked = self.Editor.LineFromPosition(evt.GetPosition()) + + if self.Editor.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: + if evt.GetShift(): + self.Editor.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 1) + elif evt.GetControl(): + if self.Editor.GetFoldExpanded(lineClicked): + self.Editor.SetFoldExpanded(lineClicked, False) + self.Expand(lineClicked, False, True, 0) + else: + self.Editor.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 100) + else: + self.Editor.ToggleFold(lineClicked) + + + def FoldAll(self): + lineCount = self.Editor.GetLineCount() + expanding = True + + # find out if we are folding or unfolding + for lineNum in range(lineCount): + if self.Editor.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: + expanding = not self.Editor.GetFoldExpanded(lineNum) + break + + lineNum = 0 + + while lineNum < lineCount: + level = self.Editor.GetFoldLevel(lineNum) + if level & stc.STC_FOLDLEVELHEADERFLAG and \ + (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: + + if expanding: + self.Editor.SetFoldExpanded(lineNum, True) + lineNum = self.Expand(lineNum, True) + lineNum = lineNum - 1 + else: + lastChild = self.Editor.GetLastChild(lineNum, -1) + self.Editor.SetFoldExpanded(lineNum, False) + + if lastChild > lineNum: + self.Editor.HideLines(lineNum+1, lastChild) + + lineNum = lineNum + 1 + + + + def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): + lastChild = self.Editor.GetLastChild(line, level) + line = line + 1 + + while line <= lastChild: + if force: + if visLevels > 0: + self.Editor.ShowLines(line, line) + else: + self.Editor.HideLines(line, line) + else: + if doExpand: + self.Editor.ShowLines(line, line) + + if level == -1: + level = self.Editor.GetFoldLevel(line) + + if level & stc.STC_FOLDLEVELHEADERFLAG: + if force: + if visLevels > 1: + self.Editor.SetFoldExpanded(line, True) + else: + self.Editor.SetFoldExpanded(line, False) + + line = self.Expand(line, doExpand, force, visLevels-1) + + else: + if doExpand and self.Editor.GetFoldExpanded(line): + line = self.Expand(line, True, force, visLevels-1) + else: + line = self.Expand(line, False, force, visLevels-1) + else: + line = line + 1 + + return line + + def Cut(self): + self.ResetBuffer() + self.DisableEvents = True + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_CUT) + self.DisableEvents = False + self.RefreshModel() + self.RefreshBuffer() + + def Copy(self): + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY) + + def Paste(self): + self.ResetBuffer() + self.DisableEvents = True + self.Editor.CmdKeyExecute(wx.stc.STC_CMD_PASTE) + self.DisableEvents = False + self.RefreshModel() + self.RefreshBuffer() diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/README Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +Asynchronous Python Interpreter diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +from python import * diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,13 @@ +from os import listdir, path + +_base_path = path.split(__file__)[0] + +__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name.upper() != "CVS" or name.endswith(".py") and not name.startswith("__")] + +helps = [] +for name in __all__: + helpfilename = path.join(_base_path, name, "README") + if path.isfile(helpfilename): + helps.append(open(helpfilename).readline().strip()) + else: + helps.append(name) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/README Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +SVGUI HMI \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +from svgui import * diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/livesvg.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/livesvg.js Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,59 @@ +// import Nevow.Athena +// import Divmod.Base + +function updateAttr(id, param, value) { + Nevow.Athena.Widget.fromAthenaID(1).callRemote('HMIexec', 'setattr', id, param, value); +} + +var svguiWidgets = new Array(); + +var currentObject = null; +function setCurrentObject(obj) { + currentObject = obj; +} +function isCurrentObject(obj) { + return currentObject == obj; +} + +function getSVGElementById(id) { + return document.getElementById(id); +} + +function blockSVGElementDrag(element) { + element.addEventListener("draggesture", function(event){event.stopPropagation()}, true); +} + +LiveSVGPage.LiveSVGWidget = Nevow.Athena.Widget.subclass('LiveSVGPage.LiveSVGWidget'); +LiveSVGPage.LiveSVGWidget.methods( + + function handleEvent(self, evt) { + if (currentObject != null) { + currentObject.handleEvent(evt); + } + }, + + function receiveData(self, data){ + dataReceived = json_parse(data); + gadget = svguiWidgets[dataReceived.id] + if (gadget) { + gadget.updateValues(json_parse(dataReceived.kwargs)); + } + //console.log("OBJET : " + dataReceived.back_id + " STATE : " + newState); + }, + + function init(self, arg1){ + //console.log("Object received : " + arg1); + for (ind in arg1) { + gad = json_parse(arg1[ind]); + args = json_parse(gad.kwargs); + gadget = new svguilib[gad.__class__](self, gad.id, args); + svguiWidgets[gadget.id]=gadget; + //console.log('GADGET :' + gadget); + } + var elements = document.getElementsByTagName("svg"); + for (var i = 0; i < elements.length; i++) { + elements[i].addEventListener("mouseup", self, false); + } + //console.log("SVGUIWIDGETS : " + svguiWidgets); + } +); diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pous.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pous.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1428 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'createSVGUIControl("textControl", back_id="' + + + + + + + back_id + + + + + + + '")' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + BOOL#1 + + + + + + + + + + + ID + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + set_text + + + + + + + 'setAttr(' + + + + + + + ',"text","' + + + + + + + '")' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'createSVGUIControl("button",back_id="' + + + + + + + '",sele_id="' + + + + + + + ',active=True)' + + + + + + + BOOL#1 + + + + + + + back_id + + + + + + + sele_id + + + + + + + set_state + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + state_in + + + + + + + + + + + state_out + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + 'setAttr(' + + + + + + + ',"state",' + + + + + + + ')' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + 'int(getAttr(' + + + + + + + ',"state",False))' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '",toggle=' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + toggle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 'createSVGUIControl("button",back_id="' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + '",sele_id="' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + '",toggle=True,active=False)' + + + + + + + BOOL#1 + + + + + + + back_id + + + + + + + sele_id + + + + + + + 'setAttr(' + + + + + + + ',"state",' + + + + + + + ')' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ID + + + + + + + + + + + + + + + + + state_in + + + + + + + + + + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ +from pyjs import * + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/build.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/build.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,724 @@ +#!/usr/bin/env python + +import sys +import os +import shutil +from copy import copy +from os.path import join, dirname, basename, abspath, split, isfile, isdir +from optparse import OptionParser +import pyjs +from cStringIO import StringIO +try: + # Python 2.5 and above + from hashlib import md5 +except: + import md5 +import re + +usage = """ + usage: %prog [options] + +This is the command line builder for the pyjamas project, which can +be used to build Ajax applications from Python. +For more information, see the website at http://pyjs.org/ +""" + +# GWT1.2 Impl | GWT1.2 Output | Pyjamas 0.2 Platform | Pyjamas 0.2 Output +# -------------+-----------------------+----------------------+---------------------- +# IE6 | ie6 | IE6 | ie6 +# Opera | opera | Opera | opera +# Safari | safari | Safari | safari +# -- | gecko1_8 | Mozilla | mozilla +# -- | gecko | OldMoz | oldmoz +# Standard | all | (default code) | all +# Mozilla | gecko1_8, gecko | -- | -- +# Old | safari, gecko, opera | -- | -- + +version = "%prog pyjamas version 2006-08-19" + +# these names in lowercase need match the strings +# returned by "provider$user.agent" in order to be selected corretly +app_platforms = ['IE6', 'Opera', 'OldMoz', 'Safari', 'Mozilla'] + +# usually defaults to e.g. /usr/share/pyjamas +_data_dir = os.path.join(pyjs.prefix, "share/pyjamas") + + +# .cache.html files produces look like this +CACHE_HTML_PAT=re.compile('^[a-z]*.[0-9a-f]{32}\.cache\.html$') + +# ok these are the three "default" library directories, containing +# the builtins (str, List, Dict, ord, round, len, range etc.) +# the main pyjamas libraries (pyjamas.ui, pyjamas.Window etc.) +# and the contributed addons + +for p in ["library/builtins", + "library", + "addons"]: + p = os.path.join(_data_dir, p) + if os.path.isdir(p): + pyjs.path.append(p) + + +def read_boilerplate(data_dir, filename): + return open(join(data_dir, "builder/boilerplate", filename)).read() + +def copy_boilerplate(data_dir, filename, output_dir): + filename = join(data_dir, "builder/boilerplate", filename) + shutil.copy(filename, output_dir) + + +# taken and modified from python2.4 +def copytree_exists(src, dst, symlinks=False): + if not os.path.exists(src): + return + + names = os.listdir(src) + try: + os.mkdir(dst) + except: + pass + + errors = [] + for name in names: + if name.startswith('CVS'): + continue + if name.startswith('.git'): + continue + if name.startswith('.svn'): + continue + + srcname = os.path.join(src, name) + dstname = os.path.join(dst, name) + try: + if symlinks and os.path.islink(srcname): + linkto = os.readlink(srcname) + os.symlink(linkto, dstname) + elif isdir(srcname): + copytree_exists(srcname, dstname, symlinks) + else: + shutil.copy2(srcname, dstname) + except (IOError, os.error), why: + errors.append((srcname, dstname, why)) + if errors: + print errors + +def check_html_file(source_file, dest_path): + """ Checks if a base HTML-file is available in the PyJamas + output directory. + If the HTML-file isn't available, it will be created. + + If a CSS-file with the same name is available + in the output directory, a reference to this CSS-file + is included. + + If no CSS-file is found, this function will look for a special + CSS-file in the output directory, with the name + "pyjamas_default.css", and if found it will be referenced + in the generated HTML-file. + + [thank you to stef mientki for contributing this function] + """ + + base_html = """\ + + + + + %(css)s + %(title)s + + + + + +""" + + filename = os.path.split ( source_file )[1] + mod_name = os.path.splitext ( filename )[0] + file_name = os.path.join ( dest_path, mod_name + '.html' ) + + # if html file in output directory exists, leave it alone. + if os.path.exists ( file_name ): + return 0 + + if os.path.exists ( + os.path.join ( dest_path, mod_name + '.css' ) ) : + css = "" + elif os.path.exists ( + os.path.join ( dest_path, 'pyjamas_default.css' ) ) : + css = "" + + else: + css = '' + + title = 'PyJamas Auto-Generated HTML file ' + mod_name + + base_html = base_html % {'modulename': mod_name, 'title': title, 'css': css} + + fh = open (file_name, 'w') + fh.write (base_html) + fh.close () + + return 1 + + +def build(app_name, output, js_includes=(), debug=False, dynamic=0, + data_dir=None, cache_buster=False, optimize=False): + + # make sure the output directory is always created in the current working + # directory or at the place given if it is an absolute path. + output = os.path.abspath(output) + msg = "Building '%(app_name)s' to output directory '%(output)s'" % locals() + if debug: + msg += " with debugging statements" + print msg + + # check the output directory + if os.path.exists(output) and not os.path.isdir(output): + print >>sys.stderr, "Output destination %s exists and is not a directory" % output + return + if not os.path.isdir(output): + try: + print "Creating output directory" + os.mkdir(output) + except StandardError, e: + print >>sys.stderr, "Exception creating output directory %s: %s" % (output, e) + + ## public dir + for p in pyjs.path: + pub_dir = join(p, 'public') + if isdir(pub_dir): + print "Copying: public directory of library %r" % p + copytree_exists(pub_dir, output) + + ## AppName.html - can be in current or public directory + html_input_filename = app_name + ".html" + html_output_filename = join(output, basename(html_input_filename)) + if os.path.isfile(html_input_filename): + if not os.path.isfile(html_output_filename) or \ + os.path.getmtime(html_input_filename) > \ + os.path.getmtime(html_output_filename): + try: + shutil.copy(html_input_filename, html_output_filename) + except: + print >>sys.stderr, "Warning: Missing module HTML file %s" % html_input_filename + + print "Copying: %(html_input_filename)s" % locals() + + if check_html_file(html_input_filename, output): + print >>sys.stderr, "Warning: Module HTML file %s has been auto-generated" % html_input_filename + + ## pygwt.js + + print "Copying: pygwt.js" + + pygwt_js_template = read_boilerplate(data_dir, "pygwt.js") + pygwt_js_output = open(join(output, "pygwt.js"), "w") + + print >>pygwt_js_output, pygwt_js_template + + pygwt_js_output.close() + + ## Images + + print "Copying: Images and History" + copy_boilerplate(data_dir, "corner_dialog_topleft_black.png", output) + copy_boilerplate(data_dir, "corner_dialog_topright_black.png", output) + copy_boilerplate(data_dir, "corner_dialog_bottomright_black.png", output) + copy_boilerplate(data_dir, "corner_dialog_bottomleft_black.png", output) + copy_boilerplate(data_dir, "corner_dialog_edge_black.png", output) + copy_boilerplate(data_dir, "corner_dialog_topleft.png", output) + copy_boilerplate(data_dir, "corner_dialog_topright.png", output) + copy_boilerplate(data_dir, "corner_dialog_bottomright.png", output) + copy_boilerplate(data_dir, "corner_dialog_bottomleft.png", output) + copy_boilerplate(data_dir, "corner_dialog_edge.png", output) + copy_boilerplate(data_dir, "tree_closed.gif", output) + copy_boilerplate(data_dir, "tree_open.gif", output) + copy_boilerplate(data_dir, "tree_white.gif", output) + copy_boilerplate(data_dir, "history.html", output) + + + ## all.cache.html + app_files = generateAppFiles(data_dir, js_includes, app_name, debug, + output, dynamic, cache_buster, optimize) + + ## AppName.nocache.html + + print "Creating: %(app_name)s.nocache.html" % locals() + + home_nocache_html_template = read_boilerplate(data_dir, "home.nocache.html") + home_nocache_html_output = open(join(output, app_name + ".nocache.html"), + "w") + + # the selector templ is added to the selectScript function + select_tmpl = """O(["true","%s"],"%s");""" + script_selectors = StringIO() + + for platform, file_prefix in app_files: + print >> script_selectors, select_tmpl % (platform, file_prefix) + + print >>home_nocache_html_output, home_nocache_html_template % dict( + app_name = app_name, + script_selectors = script_selectors.getvalue(), + ) + + home_nocache_html_output.close() + + print "Done. You can run your app by opening '%(html_output_filename)s' in a browser" % locals() + + +def generateAppFiles(data_dir, js_includes, app_name, debug, output, dynamic, + cache_buster, optimize): + + all_cache_html_template = read_boilerplate(data_dir, "all.cache.html") + mod_cache_html_template = read_boilerplate(data_dir, "mod.cache.html") + + # clean out the old ones first + for name in os.listdir(output): + if CACHE_HTML_PAT.match(name): + p = join(output, name) + print "Deleting existing app file %s" % p + os.unlink(p) + + app_files = [] + tmpl = read_boilerplate(data_dir, "all.cache.html") + parser = pyjs.PlatformParser("platform") + app_headers = '' + scripts = [''%script \ + for script in js_includes] + app_body = '\n'.join(scripts) + + mod_code = {} + mod_libs = {} + modules = {} + app_libs = {} + early_app_libs = {} + app_code = {} + overrides = {} + pover = {} + app_modnames = {} + mod_levels = {} + + # First, generate all the code. + # Second, (dynamic only), post-analyse the places where modules + # haven't changed + # Third, write everything out. + + for platform in app_platforms: + + mod_code[platform] = {} + mod_libs[platform] = {} + modules[platform] = [] + pover[platform] = {} + app_libs[platform] = '' + early_app_libs[platform] = '' + app_code[platform] = {} + app_modnames[platform] = {} + + # Application.Platform.cache.html + + parser.setPlatform(platform) + app_translator = pyjs.AppTranslator( + parser=parser, dynamic=dynamic, optimize=optimize) + early_app_libs[platform], appcode = \ + app_translator.translate(None, is_app=False, + debug=debug, + library_modules=['dynamicajax.js', + '_pyjs.js', 'sys', + 'pyjslib']) + pover[platform].update(app_translator.overrides.items()) + for mname, name in app_translator.overrides.items(): + pd = overrides.setdefault(mname, {}) + pd[platform] = name + + print appcode + #mod_code[platform][app_name] = appcode + + # platform.Module.cache.js + + modules_done = ['pyjslib', 'sys', '_pyjs.js'] + #modules_to_do = [app_name] + app_translator.library_modules + modules_to_do = [app_name] + app_translator.library_modules + + dependencies = {} + + deps = map(pyjs.strip_py, modules_to_do) + for d in deps: + sublist = add_subdeps(dependencies, d) + modules_to_do += sublist + deps = uniquify(deps) + #dependencies[app_name] = deps + + modules[platform] = modules_done + modules_to_do + + while modules_to_do: + + #print "modules to do", modules_to_do + + mn = modules_to_do.pop() + mod_name = pyjs.strip_py(mn) + + if mod_name in modules_done: + continue + + modules_done.append(mod_name) + + mod_cache_name = "%s.%s.cache.js" % (platform.lower(), mod_name) + + parser.setPlatform(platform) + mod_translator = pyjs.AppTranslator(parser=parser, optimize=optimize) + mod_libs[platform][mod_name], mod_code[platform][mod_name] = \ + mod_translator.translate(mod_name, + is_app=False, + debug=debug) + pover[platform].update(mod_translator.overrides.items()) + for mname, name in mod_translator.overrides.items(): + pd = overrides.setdefault(mname, {}) + pd[platform] = name + + mods = mod_translator.library_modules + modules_to_do += mods + modules[platform] += mods + + deps = map(pyjs.strip_py, mods) + sd = subdeps(mod_name) + if len(sd) > 1: + deps += sd[:-1] + while mod_name in deps: + deps.remove(mod_name) + + #print + #print + #print "modname preadd:", mod_name, deps + #print + #print + for d in deps: + sublist = add_subdeps(dependencies, d) + modules_to_do += sublist + modules_to_do += add_subdeps(dependencies, mod_name) + #print "modname:", mod_name, deps + deps = uniquify(deps) + #print "modname:", mod_name, deps + dependencies[mod_name] = deps + + # work out the dependency ordering of the modules + + mod_levels[platform] = make_deps(None, dependencies, modules_done) + + # now write everything out + + for platform in app_platforms: + + early_app_libs_ = early_app_libs[platform] + app_libs_ = app_libs[platform] + app_code_ = app_code[platform] + #modules_ = filter_mods(app_name, modules[platform]) + mods = flattenlist(mod_levels[platform]) + mods.reverse() + modules_ = filter_mods(None, mods) + + for mod_name in modules_: + + mod_code_ = mod_code[platform][mod_name] + + mod_name = pyjs.strip_py(mod_name) + + override_name = "%s.%s" % (platform.lower(), mod_name) + if pover[platform].has_key(override_name): + mod_cache_name = "%s.cache.js" % (override_name) + else: + mod_cache_name = "%s.cache.js" % (mod_name) + + print "Creating: " + mod_cache_name + + modlevels = make_deps(None, dependencies, dependencies[mod_name]) + + modnames = [] + + for md in modlevels: + mnames = map(lambda x: "'%s'" % x, md) + mnames = "new pyjslib.List([\n\t\t\t%s])" % ',\n\t\t\t'.join(mnames) + modnames.append(mnames) + + modnames.reverse() + modnames = "new pyjslib.List([\n\t\t%s\n\t])" % ',\n\t\t'.join(modnames) + + # convert the overrides + + overnames = map(lambda x: "'%s': '%s'" % x, pover[platform].items()) + overnames = "new pyjslib.Dict({\n\t\t%s\n\t})" % ',\n\t\t'.join(overnames) + + if dynamic: + mod_cache_html_output = open(join(output, mod_cache_name), "w") + else: + mod_cache_html_output = StringIO() + + print >>mod_cache_html_output, mod_cache_html_template % dict( + mod_name = mod_name, + app_name = app_name, + modnames = modnames, + overrides = overnames, + mod_libs = mod_libs[platform][mod_name], + dynamic = dynamic, + mod_code = mod_code_, + ) + + if dynamic: + mod_cache_html_output.close() + else: + mod_cache_html_output.seek(0) + app_libs_ += mod_cache_html_output.read() + + # write out the dependency ordering of the modules + + app_modnames = [] + + for md in mod_levels[platform]: + mnames = map(lambda x: "'%s'" % x, md) + mnames = "new pyjslib.List([\n\t\t\t%s])" % ',\n\t\t\t'.join(mnames) + app_modnames.append(mnames) + + app_modnames.reverse() + app_modnames = "new pyjslib.List([\n\t\t%s\n\t])" % ',\n\t\t'.join(app_modnames) + + # convert the overrides + + overnames = map(lambda x: "'%s': '%s'" % x, pover[platform].items()) + overnames = "new pyjslib.Dict({\n\t\t%s\n\t})" % ',\n\t\t'.join(overnames) + + #print "platform names", platform, overnames + #print pover + + # now write app.allcache including dependency-ordered list of + # library modules + + file_contents = all_cache_html_template % dict( + app_name = app_name, + early_app_libs = early_app_libs_, + app_libs = app_libs_, + app_code = app_code_, + app_body = app_body, + overrides = overnames, + platform = platform.lower(), + dynamic = dynamic, + app_modnames = app_modnames, + app_headers = app_headers + ) + if cache_buster: + digest = md5.new(file_contents).hexdigest() + file_name = "%s.%s.%s" % (platform.lower(), app_name, digest) + else: + file_name = "%s.%s" % (platform.lower(), app_name) + file_name += ".cache.html" + out_path = join(output, file_name) + out_file = open(out_path, 'w') + out_file.write(file_contents) + out_file.close() + app_files.append((platform.lower(), file_name)) + print "Created app file %s:%s: %s" % ( + app_name, platform, out_path) + + return app_files + +def flattenlist(ll): + res = [] + for l in ll: + res += l + return res + +# creates sub-dependencies e.g. pyjamas.ui.Widget +# creates pyjamas.ui.Widget, pyjamas.ui and pyjamas. +def subdeps(m): + d = [] + m = m.split(".") + for i in range(0, len(m)): + d.append('.'.join(m[:i+1])) + return d + +import time + +def add_subdeps(deps, mod_name): + sd = subdeps(mod_name) + if len(sd) == 1: + return [] + #print "subdeps", mod_name, sd + #print "deps", deps + res = [] + for i in range(0, len(sd)-1): + parent = sd[i] + child = sd[i+1] + l = deps.get(child, []) + l.append(parent) + deps[child] = l + if parent not in res: + res.append(parent) + #print deps + return res + +# makes unique and preserves list order +def uniquify(md): + res = [] + for m in md: + if m not in res: + res.append(m) + return res + +def filter_mods(app_name, md): + while 'sys' in md: + md.remove('sys') + while 'pyjslib' in md: + md.remove('pyjslib') + while app_name in md: + md.remove(app_name) + md = filter(lambda x: not x.endswith('.js'), md) + md = map(pyjs.strip_py, md) + + return uniquify(md) + +def filter_deps(app_name, deps): + + res = {} + for (k, l) in deps.items(): + mods = filter_mods(k, l) + while k in mods: + mods.remove(k) + res[k] = mods + return res + +def has_nodeps(mod, deps): + if not deps.has_key(mod) or not deps[mod]: + return True + return False + +def nodeps_list(mod_list, deps): + res = [] + for mod in mod_list: + if has_nodeps(mod, deps): + res.append(mod) + return res + +# this function takes a dictionary of dependent modules and +# creates a list of lists. the first list will be modules +# that have no dependencies; the second list will be those +# modules that have the first list as dependencies; the +# third will be those modules that have the first and second... +# etc. + + +def make_deps(app_name, deps, mod_list): + print "Calculating Dependencies ..." + mod_list = filter_mods(app_name, mod_list) + deps = filter_deps(app_name, deps) + + if not mod_list: + return [] + + #print mod_list + #print deps + + ordered_deps = [] + last_len = -1 + while deps: + l_deps = len(deps) + #print l_deps + if l_deps==last_len: + for m, dl in deps.items(): + for d in dl: + if m in deps.get(d, []): + raise Exception('Circular Imports found: \n%s %s -> %s %s' + % (m, dl, d, deps[d])) + #raise Exception('Could not calculate dependencies: \n%s' % deps) + break + last_len = l_deps + #print "modlist", mod_list + nodeps = nodeps_list(mod_list, deps) + #print "nodeps", nodeps + mod_list = filter(lambda x: x not in nodeps, mod_list) + newdeps = {} + for k in deps.keys(): + depslist = deps[k] + depslist = filter(lambda x: x not in nodeps, depslist) + if depslist: + newdeps[k] = depslist + #print "newdeps", newdeps + deps = newdeps + ordered_deps.append(nodeps) + #time.sleep(0) + + if mod_list: + ordered_deps.append(mod_list) # last dependencies - usually the app(s) + + ordered_deps.reverse() + + return ordered_deps + +def main(): + global app_platforms + + parser = OptionParser(usage = usage, version = version) + parser.add_option("-o", "--output", dest="output", + help="directory to which the webapp should be written") + parser.add_option("-j", "--include-js", dest="js_includes", action="append", + help="javascripts to load into the same frame as the rest of the script") + parser.add_option("-I", "--library_dir", dest="library_dirs", + action="append", help="additional paths appended to PYJSPATH") + parser.add_option("-D", "--data_dir", dest="data_dir", + help="path for data directory") + parser.add_option("-m", "--dynamic-modules", action="store_true", + dest="dynamic", default=False, + help="Split output into separate dynamically-loaded modules (experimental)") + parser.add_option("-P", "--platforms", dest="platforms", + help="platforms to build for, comma-separated") + parser.add_option("-d", "--debug", action="store_true", dest="debug") + parser.add_option("-O", "--optimize", action="store_true", + dest="optimize", default=False, + help="Optimize generated code (removes all print statements)", + ) + parser.add_option("-c", "--cache_buster", action="store_true", + dest="cache_buster", + help="Enable browser cache-busting (MD5 hash added to output filenames)") + + parser.set_defaults(output = "output", js_includes=[], library_dirs=[], + platforms=(','.join(app_platforms)), + data_dir=os.path.join(sys.prefix, "share/pyjamas"), + dynamic=False, + cache_buster=False, + debug=False) + (options, args) = parser.parse_args() + if len(args) != 1: + parser.error("incorrect number of arguments") + + data_dir = abspath(options.data_dir) + + app_path = args[0] + if app_path.endswith('.py'): + app_path = abspath(app_path) + if not isfile(app_path): + parser.error("Application file not found %r" % app_path) + app_path, app_name = split(app_path) + app_name = app_name[:-3] + pyjs.path.append(app_path) + elif os.path.sep in app_path: + parser.error("Not a valid module declaration %r" % app_path) + else: + app_name = app_path + + for d in options.library_dirs: + pyjs.path.append(abspath(d)) + + if options.platforms: + app_platforms = options.platforms.split(',') + + # this is mostly for getting boilerplate stuff + data_dir = os.path.abspath(options.data_dir) + + build(app_name, options.output, options.js_includes, + options.debug, options.dynamic and 1 or 0, data_dir, + options.cache_buster, options.optimize) + +if __name__ == "__main__": + main() + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/jsonrpc/README.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/jsonrpc/README.txt Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,12 @@ +These classes are intended for use server-side. + +e.g. in a django view.py : + + from pyjs.jsonrpc.django import JSONService, jsonremote + + jsonservice = JSONRPCService() + + @jsonremote(jsonservice) + def test(request, echo_param): + return "echoing the param back: %s" % echo_param + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/jsonrpc/django/jsonrpc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,226 @@ +# jsonrpc.py +# original code: http://trac.pyworks.org/pyjamas/wiki/DjangoWithPyJamas +# also from: http://www.pimentech.fr/technologies/outils +from django.utils import simplejson +from django.http import HttpResponse +import sys + +from pyjs.jsonrpc import JSONRPCServiceBase +# JSONRPCService and jsonremote are used in combination to drastically +# simplify the provision of JSONRPC services. use as follows: +# +# jsonservice = JSONRPCService() +# +# @jsonremote(jsonservice) +# def test(request, echo_param): +# return "echoing the param back: %s" % echo_param +# +# dump jsonservice into urlpatterns: +# (r'^service1/$', 'djangoapp.views.jsonservice'), + +class JSONRPCService(JSONRPCServiceBase): + + def __call__(self, request, extra=None): + return self.process(request.raw_post_data) + +def jsonremote(service): + """Make JSONRPCService a decorator so that you can write : + + from jsonrpc import JSONRPCService + chatservice = JSONRPCService() + + @jsonremote(chatservice) + def login(request, user_name): + (...) + """ + def remotify(func): + if isinstance(service, JSONRPCService): + service.add_method(func.__name__, func) + else: + emsg = 'Service "%s" not found' % str(service.__name__) + raise NotImplementedError, emsg + return func + return remotify + + +# FormProcessor provides a mechanism for turning Django Forms into JSONRPC +# Services. If you have an existing Django app which makes prevalent +# use of Django Forms it will save you rewriting the app. +# use as follows. in djangoapp/views.py : +# +# class SimpleForm(forms.Form): +# testfield = forms.CharField(max_length=100) +# +# class SimpleForm2(forms.Form): +# testfield = forms.CharField(max_length=20) +# +# processor = FormProcessor({'processsimpleform': SimpleForm, +# 'processsimpleform2': SimpleForm2}) +# +# this will result in a JSONRPC service being created with two +# RPC functions. dump "processor" into urlpatterns to make it +# part of the app: +# (r'^formsservice/$', 'djangoapp.views.processor'), + +from django import forms + +def builderrors(form): + d = {} + for error in form.errors.keys(): + if error not in d: + d[error] = [] + for errorval in form.errors[error]: + d[error].append(unicode(errorval)) + return d + + +# contains the list of arguments in each field +field_names = { + 'CharField': ['max_length', 'min_length'], + 'IntegerField': ['max_value', 'min_value'], + 'FloatField': ['max_value', 'min_value'], + 'DecimalField': ['max_value', 'min_value', 'max_digits', 'decimal_places'], + 'DateField': ['input_formats'], + 'DateTimeField': ['input_formats'], + 'TimeField': ['input_formats'], + 'RegexField': ['max_length', 'min_length'], # sadly we can't get the expr + 'EmailField': ['max_length', 'min_length'], + 'URLField': ['max_length', 'min_length', 'verify_exists', 'user_agent'], + 'ChoiceField': ['choices'], + 'FilePathField': ['path', 'match', 'recursive', 'choices'], + 'IPAddressField': ['max_length', 'min_length'], + } + +def describe_field_errors(field): + res = {} + field_type = field.__class__.__name__ + msgs = {} + for n, m in field.error_messages.items(): + msgs[n] = unicode(m) + res['error_messages'] = msgs + if field_type in ['ComboField', 'MultiValueField', 'SplitDateTimeField']: + res['fields'] = map(describe_field, field.fields) + return res + +def describe_fields_errors(fields, field_names): + res = {} + if not field_names: + field_names = fields.keys() + for name in field_names: + field = fields[name] + res[name] = describe_field_errors(field) + return res + +def describe_field(field): + res = {} + field_type = field.__class__.__name__ + for fname in field_names.get(field_type, []) + \ + ['help_text', 'label', 'initial', 'required']: + res[fname] = getattr(field, fname) + if field_type in ['ComboField', 'MultiValueField', 'SplitDateTimeField']: + res['fields'] = map(describe_field, field.fields) + return res + +def describe_fields(fields, field_names): + res = {} + if not field_names: + field_names = fields.keys() + for name in field_names: + field = fields[name] + res[name] = describe_field(field) + return res + +class FormProcessor(JSONRPCService): + def __init__(self, forms, _formcls=None): + + if _formcls is None: + JSONRPCService.__init__(self) + for k in forms.keys(): + s = FormProcessor({}, forms[k]) + self.add_method(k, s.__process) + else: + JSONRPCService.__init__(self, forms) + self.formcls = _formcls + + def __process(self, request, params, command=None): + + f = self.formcls(params) + + if command is None: # just validate + if not f.is_valid(): + return {'success':False, 'errors': builderrors(f)} + return {'success':True} + + elif command.has_key('describe_errors'): + field_names = command['describe_errors'] + return describe_fields_errors(f.fields, field_names) + + elif command.has_key('describe'): + field_names = command['describe'] + return describe_fields(f.fields, field_names) + + elif command.has_key('save'): + if not f.is_valid(): + return {'success':False, 'errors': builderrors(f)} + instance = f.save() # XXX: if you want more, over-ride save. + return {'success': True, 'instance': json_convert(instance) } + + elif command.has_key('html'): + return {'success': True, 'html': f.as_table()} + + return "unrecognised command" + + + + +# The following is incredibly convenient for saving vast amounts of +# coding, avoiding doing silly things like this: +# jsonresult = {'field1': djangoobject.field1, +# 'field2': djangoobject.date.strftime('%Y.%M'), +# ..... } +# +# The date/time flatten function is there because JSONRPC doesn't +# support date/time objects or formats, so conversion to a string +# is the most logical choice. pyjamas, being python, can easily +# be used to parse the string result at the other end. +# +# use as follows: +# +# jsonservice = JSONRPCService() +# +# @jsonremote(jsonservice) +# def list_some_model(request, start=0, count=10): +# l = SomeDjangoModelClass.objects.filter() +# res = json_convert(l[start:end]) +# +# @jsonremote(jsonservice) +# def list_another_model(request, start=0, count=10): +# l = AnotherDjangoModelClass.objects.filter() +# res = json_convert(l[start:end]) +# +# dump jsonservice into urlpatterns to make the two RPC functions, +# list_some_model and list_another_model part of the django app: +# (r'^service1/$', 'djangoapp.views.jsonservice'), + +from django.core.serializers import serialize +import datetime +from datetime import date + +def dict_datetimeflatten(item): + d = {} + for k, v in item.items(): + k = str(k) + if isinstance(v, datetime.date): + d[k] = str(v) + elif isinstance(v, dict): + d[k] = dict_datetimeflatten(v) + else: + d[k] = v + return d + +def json_convert(l, fields=None): + res = [] + for item in serialize('python', l, fields=fields): + res.append(dict_datetimeflatten(item)) + return res + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/jsonrpc/jsonrpc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/jsonrpc/jsonrpc.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,43 @@ +import gluon.contrib.simplejson as simplejson +import types +import sys + +class JSONRPCServiceBase: + + def __init__(self): + self.methods={} + + def response(self, id, result): + return simplejson.dumps({'version': '1.1', 'id':id, + 'result':result, 'error':None}) + def error(self, id, code, message): + return simplejson.dumps({'id': id, + 'version': '1.1', + 'error': {'name': 'JSONRPCError', + 'code': code, + 'message': message + } + }) + + def add_method(self, name, method): + self.methods[name] = method + + def process(self, data): + data = simplejson.loads(data) + id, method, params = data["id"], data["method"], data["params"] + if method in self.methods: + try: + result =self.methods[method](*params) + return self.response(id, result) + except BaseException: + etype, eval, etb = sys.exc_info() + return self.error(id, 100, '%s: %s' %(etype.__name__, eval)) + except: + etype, eval, etb = sys.exc_info() + return self.error(id, 100, 'Exception %s: %s' %(etype, eval)) + else: + return self.error(id, 100, 'method "%s" does not exist' % method) + + def listmethods(self): + return self.methods.keys() + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/jsonrpc/web2py/jsonrpc.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,11 @@ +from pyjs.jsonrpc import JSONRPCServiceBase + +class JSONRPCService(JSONRPCServiceBase): + + def serve(self): + return self.process(request.body.read()) + + def __call__(self,func): + self.methods[func.__name__]=func + return func + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/lib/_pyjs.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/lib/_pyjs.js Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,160 @@ +function pyjs_extend(klass, base) { + function klass_object_inherit() {} + klass_object_inherit.prototype = base.prototype; + klass_object = new klass_object_inherit(); + for (var i in base.prototype.__class__) { + v = base.prototype.__class__[i]; + if (typeof v == "function" && (v.class_method || v.static_method || v.unbound_method)) + { + klass_object[i] = v; + } + } + + function klass_inherit() {} + klass_inherit.prototype = klass_object; + klass.prototype = new klass_inherit(); + klass_object.constructor = klass; + klass.prototype.__class__ = klass_object; + + for (var i in base.prototype) { + v = base.prototype[i]; + if (typeof v == "function" && v.instance_method) + { + klass.prototype[i] = v; + } + } +} + +/* creates a class, derived from bases, with methods and variables */ +function pyjs_type(clsname, bases, methods) +{ + var fn_cls = function() {}; + fn_cls.__name__ = clsname; + var fn = function() { + var instance = new fn_cls(); + if(instance.__init__) instance.__init__.apply(instance, arguments); + return instance; + } + fn_cls.__initialize__ = function() { + if (fn_cls.__was_initialized__) return; + fn_cls.__was_initialized__ = true; + fn_cls.__extend_baseclasses(); + fn_cls.prototype.__class__.__new__ = fn; + fn_cls.prototype.__class__.__name__ = clsname; + } + fn_cls.__extend_baseclasses = function() { + var bi; + for (bi in fn_cls.__baseclasses) + { + var b = fn_cls.__baseclasses[bi]; + if (b.__was_initialized__) + { + continue; + } + b.__initialize__(); + } + for (bi in fn_cls.__baseclasses) + { + var b = fn_cls.__baseclasses[bi]; + pyjs_extend(fn_cls, b); + } + } + if (!bases) { + bases = [pyjslib.__Object]; + } + fn_cls.__baseclasses = bases; + + fn_cls.__initialize__(); + + for (k in methods) { + var mth = methods[k]; + var mtype = typeof mth; + if (mtype == "function" ) { + fn_cls.prototype[k] = mth; + fn_cls.prototype.__class__[k] = function () { + return fn_cls.prototype[k].call.apply( + fn_cls.prototype[k], arguments); + }; + fn_cls.prototype.__class__[k].unbound_method = true; + fn_cls.prototype.instance_method = true; + fn_cls.prototype.__class__[k].__name__ = k; + fn_cls.prototype[k].__name__ = k; + } else { + fn_cls.prototype.__class__[k] = mth; + } + } + return fn; +} +function pyjs_kwargs_call(obj, func, star_args, args) +{ + var call_args; + + if (star_args) + { + if (!pyjslib.isIteratable(star_args)) + { + throw (pyjslib.TypeError(func.__name__ + "() arguments after * must be a sequence" + pyjslib.repr(star_args))); + } + call_args = Array(); + var __i = star_args.__iter__(); + var i = 0; + try { + while (true) { + call_args[i]=__i.next(); + i++; + } + } catch (e) { + if (e != pyjslib.StopIteration) { + throw e; + } + } + + if (args) + { + var n = star_args.length; + for (var i=0; i < args.length; i++) { + call_args[n+i]=args[i]; + } + } + } + else + { + call_args = args; + } + return func.apply(obj, call_args); +} + +function pyjs_kwargs_function_call(func, star_args, args) +{ + return pyjs_kwargs_call(null, func, star_args, args); +} + +function pyjs_kwargs_method_call(obj, method_name, star_args, args) +{ + var method = obj[method_name]; + if (method.parse_kwargs) + { + args = method.parse_kwargs.apply(null, args); + } + return pyjs_kwargs_call(obj, method, star_args, args); +} + +//String.prototype.__getitem__ = String.prototype.charAt; +//String.prototype.upper = String.prototype.toUpperCase; +//String.prototype.lower = String.prototype.toLowerCase; +//String.prototype.find=pyjslib.String_find; +//String.prototype.join=pyjslib.String_join; +//String.prototype.isdigit=pyjslib.String_isdigit; +//String.prototype.__iter__=pyjslib.String___iter__; +// +//String.prototype.__replace=String.prototype.replace; +//String.prototype.replace=pyjslib.String_replace; +// +//String.prototype.split=pyjslib.String_split; +//String.prototype.strip=pyjslib.String_strip; +//String.prototype.lstrip=pyjslib.String_lstrip; +//String.prototype.rstrip=pyjslib.String_rstrip; +//String.prototype.startswith=pyjslib.String_startswith; + +var str = String; + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/lib/json.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/lib/json.js Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,293 @@ +json_parse = (function () { + +// This is a function that can parse a JSON text, producing a JavaScript +// data structure. It is a simple, recursive descent parser. It does not use +// eval or regular expressions, so it can be used as a model for implementing +// a JSON parser in other languages. + +// We are defining the function inside of another function to avoid creating +// global variables. + + var at, // The index of the current character + ch, // The current character + escapee = { + '"': '"', + '\\': '\\', + '/': '/', + b: '\b', + f: '\f', + n: '\n', + r: '\r', + t: '\t' + }, + text, + + error = function (m) { + +// Call error when something is wrong. + + throw { + name: 'SyntaxError', + message: m, + at: at, + text: text + }; + }, + + next = function (c) { + +// If a c parameter is provided, verify that it matches the current character. + + if (c && c !== ch) { + error("Expected '" + c + "' instead of '" + ch + "'"); + } + +// Get the next character. When there are no more characters, +// return the empty string. + + ch = text.charAt(at); + at += 1; + return ch; + }, + + number = function () { + +// Parse a number value. + + var number, + string = ''; + + if (ch === '-') { + string = '-'; + next('-'); + } + while (ch >= '0' && ch <= '9') { + string += ch; + next(); + } + if (ch === '.') { + string += '.'; + while (next() && ch >= '0' && ch <= '9') { + string += ch; + } + } + if (ch === 'e' || ch === 'E') { + string += ch; + next(); + if (ch === '-' || ch === '+') { + string += ch; + next(); + } + while (ch >= '0' && ch <= '9') { + string += ch; + next(); + } + } + number = +string; + if (isNaN(number)) { + error("Bad number"); + } else { + return number; + } + }, + + string = function () { + +// Parse a string value. + + var hex, + i, + string = '', + uffff; + +// When parsing for string values, we must look for " and \ characters. + + if (ch === '"') { + while (next()) { + if (ch === '"') { + next(); + return string; + } else if (ch === '\\') { + next(); + if (ch === 'u') { + uffff = 0; + for (i = 0; i < 4; i += 1) { + hex = parseInt(next(), 16); + if (!isFinite(hex)) { + break; + } + uffff = uffff * 16 + hex; + } + string += String.fromCharCode(uffff); + } else if (typeof escapee[ch] === 'string') { + string += escapee[ch]; + } else { + break; + } + } else { + string += ch; + } + } + } + error("Bad string"); + }, + + white = function () { + +// Skip whitespace. + + while (ch && ch <= ' ') { + next(); + } + }, + + word = function () { + +// true, false, or null. + + switch (ch) { + case 't': + next('t'); + next('r'); + next('u'); + next('e'); + return true; + case 'f': + next('f'); + next('a'); + next('l'); + next('s'); + next('e'); + return false; + case 'n': + next('n'); + next('u'); + next('l'); + next('l'); + return null; + } + error("Unexpected '" + ch + "'"); + }, + + value, // Place holder for the value function. + + array = function () { + +// Parse an array value. + + var array = []; + + if (ch === '[') { + next('['); + white(); + if (ch === ']') { + next(']'); + return array; // empty array + } + while (ch) { + array.push(value()); + white(); + if (ch === ']') { + next(']'); + return array; + } + next(','); + white(); + } + } + error("Bad array"); + }, + + object = function () { + +// Parse an object value. + + var key, + object = {}; + + if (ch === '{') { + next('{'); + white(); + if (ch === '}') { + next('}'); + return object; // empty object + } + while (ch) { + key = string(); + white(); + next(':'); + if (Object.hasOwnProperty.call(object, key)) { + error('Duplicate key "' + key + '"'); + } + object[key] = value(); + white(); + if (ch === '}') { + next('}'); + return object; + } + next(','); + white(); + } + } + error("Bad object"); + }; + + value = function () { + +// Parse a JSON value. It could be an object, an array, a string, a number, +// or a word. + + white(); + switch (ch) { + case '{': + return object(); + case '[': + return array(); + case '"': + return string(); + case '-': + return number(); + default: + return ch >= '0' && ch <= '9' ? number() : word(); + } + }; + +// Return the json_parse function. It will have access to all of the above +// functions and variables. + + return function (source, reviver) { + var result; + + text = source; + at = 0; + ch = ' '; + result = value(); + white(); + if (ch) { + error("Syntax error"); + } + +// If there is a reviver function, we recursively walk the new structure, +// passing each name/value pair to the reviver function for possible +// transformation, starting with a temporary root object that holds the result +// in an empty key. If there is not a reviver function, we simply return the +// result. + + return typeof reviver === 'function' ? (function walk(holder, key) { + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + }({'': result}, '')) : result; + }; +}()); diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/lib/pyjslib.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/lib/pyjslib.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1365 @@ +# Copyright 2006 James Tauber and contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# iteration from Bob Ippolito's Iteration in JavaScript + +from __pyjamas__ import JS + +# must declare import _before_ importing sys + +def import_module(path, parent_module, module_name, dynamic=1, async=False): + """ + """ + + JS(""" + var cache_file; + + if (module_name == "sys" || module_name == 'pyjslib') + { + /*module_load_request[module_name] = 1;*/ + return; + } + + if (path == null) + { + path = './'; + } + + var override_name = sys.platform + "." + module_name; + if (((sys.overrides != null) && + (sys.overrides.has_key(override_name)))) + { + cache_file = sys.overrides.__getitem__(override_name) ; + } + else + { + cache_file = module_name ; + } + + cache_file = (path + cache_file + '.cache.js' ) ; + + //alert("cache " + cache_file + " " + module_name + " " + parent_module); + + /* already loaded? */ + if (module_load_request[module_name]) + { + if (module_load_request[module_name] >= 3 && parent_module != null) + { + //onload_fn = parent_module + '.' + module_name + ' = ' + module_name + ';'; + //pyjs_eval(onload_fn); /* set up the parent-module namespace */ + } + return; + } + if (typeof (module_load_request[module_name]) == 'undefined') + { + module_load_request[module_name] = 1; + } + + /* following a load, this first executes the script + * "preparation" function MODULENAME_loaded_fn() + * and then sets up the loaded module in the namespace + * of the parent. + */ + + onload_fn = ''; // module_name + "_loaded_fn();" + + if (parent_module != null) + { + //onload_fn += parent_module + '.' + module_name + ' = ' + module_name + ';'; + /*pmod = parent_module + '.' + module_name; + onload_fn += 'alert("' + pmod + '"+' + pmod+');';*/ + } + + + if (dynamic) + { + /* this one tacks the script onto the end of the DOM + */ + + pyjs_load_script(cache_file, onload_fn, async); + + /* this one actually RUNS the script (eval) into the page. + my feeling is that this would be better for non-async + but i can't get it to work entirely yet. + */ + /*pyjs_ajax_eval(cache_file, onload_fn, async);*/ + } + else + { + if (module_name != "pyjslib" && + module_name != "sys") + pyjs_eval(onload_fn); + } + + """) + +JS(""" +function import_wait(proceed_fn, parent_mod, dynamic) { + + var data = ''; + var element = $doc.createElement("div"); + $doc.body.appendChild(element); + function write_dom(txt) { + element.innerHTML = txt + '
'; + } + + var timeoutperiod = 1; + if (dynamic) + var timeoutperiod = 1; + + var wait = function() { + + var status = ''; + for (l in module_load_request) + { + var m = module_load_request[l]; + if (l == "sys" || l == 'pyjslib') + continue; + status += l + m + " "; + } + + //write_dom( " import wait " + wait_count + " " + status + " parent_mod " + parent_mod); + wait_count += 1; + + if (status == '') + { + setTimeout(wait, timeoutperiod); + return; + } + + for (l in module_load_request) + { + var m = module_load_request[l]; + if (l == "sys" || l == 'pyjslib') + { + module_load_request[l] = 4; + continue; + } + if ((parent_mod != null) && (l == parent_mod)) + { + if (m == 1) + { + setTimeout(wait, timeoutperiod); + return; + } + if (m == 2) + { + /* cheat and move app on to next stage */ + module_load_request[l] = 3; + } + } + if (m == 1 || m == 2) + { + setTimeout(wait, timeoutperiod); + return; + } + if (m == 3) + { + //alert("waited for module " + l + ": loaded"); + module_load_request[l] = 4; + mod_fn = modules[l]; + } + } + //alert("module wait done"); + + if (proceed_fn.importDone) + proceed_fn.importDone(proceed_fn); + else + proceed_fn(); + } + + wait(); +} +""") + +class Object: + pass + +object = Object + +class Modload: + + def __init__(self, path, app_modlist, app_imported_fn, dynamic, + parent_mod): + self.app_modlist = app_modlist + self.app_imported_fn = app_imported_fn + self.path = path + self.idx = 0; + self.dynamic = dynamic + self.parent_mod = parent_mod + + def next(self): + + for i in range(len(self.app_modlist[self.idx])): + app = self.app_modlist[self.idx][i] + import_module(self.path, self.parent_mod, app, self.dynamic, True); + self.idx += 1 + + if self.idx >= len(self.app_modlist): + import_wait(self.app_imported_fn, self.parent_mod, self.dynamic) + else: + import_wait(getattr(self, "next"), self.parent_mod, self.dynamic) + +def get_module(module_name): + ev = "__mod = %s;" % module_name + JS("pyjs_eval(ev);") + return __mod + +def preload_app_modules(path, app_modnames, app_imported_fn, dynamic, + parent_mod=None): + + loader = Modload(path, app_modnames, app_imported_fn, dynamic, parent_mod) + loader.next() + +import sys + +class BaseException: + + name = "BaseException" + + def __init__(self, *args): + self.args = args + + def __str__(self): + if len(self.args) is 0: + return '' + elif len(self.args) is 1: + return repr(self.args[0]) + return repr(self.args) + + def toString(self): + return str(self) + +class Exception(BaseException): + + name = "Exception" + +class TypeError(BaseException): + name = "TypeError" + +class StandardError(Exception): + name = "StandardError" + +class LookupError(StandardError): + name = "LookupError" + + def toString(self): + return self.name + ": " + self.args[0] + +class KeyError(LookupError): + name = "KeyError" + +class AttributeError(StandardError): + + name = "AttributeError" + + def toString(self): + return "AttributeError: %s of %s" % (self.args[1], self.args[0]) + +JS(""" +pyjslib.StopIteration = function () { }; +pyjslib.StopIteration.prototype = new Error(); +pyjslib.StopIteration.name = 'StopIteration'; +pyjslib.StopIteration.message = 'StopIteration'; + +pyjslib.String_find = function(sub, start, end) { + var pos=this.indexOf(sub, start); + if (pyjslib.isUndefined(end)) return pos; + + if (pos + sub.length>end) return -1; + return pos; +} + +pyjslib.String_join = function(data) { + var text=""; + + if (pyjslib.isArray(data)) { + return data.join(this); + } + else if (pyjslib.isIteratable(data)) { + var iter=data.__iter__(); + try { + text+=iter.next(); + while (true) { + var item=iter.next(); + text+=this + item; + } + } + catch (e) { + if (e != pyjslib.StopIteration) throw e; + } + } + + return text; +} + +pyjslib.String_isdigit = function() { + return (this.match(/^\d+$/g) != null); +} + +pyjslib.String_replace = function(old, replace, count) { + var do_max=false; + var start=0; + var new_str=""; + var pos=0; + + if (!pyjslib.isString(old)) return this.__replace(old, replace); + if (!pyjslib.isUndefined(count)) do_max=true; + + while (start= s.length) { + throw pyjslib.StopIteration; + } + return s.substring(i++, i, 1); + }, + '__iter__': function() { + return this; + } + }; +} + +pyjslib.String_strip = function(chars) { + return this.lstrip(chars).rstrip(chars); +} + +pyjslib.String_lstrip = function(chars) { + if (pyjslib.isUndefined(chars)) return this.replace(/^\s+/, ""); + + return this.replace(new RegExp("^[" + chars + "]+"), ""); +} + +pyjslib.String_rstrip = function(chars) { + if (pyjslib.isUndefined(chars)) return this.replace(/\s+$/, ""); + + return this.replace(new RegExp("[" + chars + "]+$"), ""); +} + +pyjslib.String_startswith = function(prefix, start) { + if (pyjslib.isUndefined(start)) start = 0; + + if (this.substring(start, prefix.length) == prefix) return true; + return false; +} + +pyjslib.abs = Math.abs; + +""") + +class Class: + def __init__(self, name): + self.name = name + + def __str___(self): + return self.name + +def eq(a,b): + JS(""" + if (pyjslib.hasattr(a, "__cmp__")) { + return a.__cmp__(b) == 0; + } else if (pyjslib.hasattr(b, "__cmp__")) { + return b.__cmp__(a) == 0; + } + return a == b; + """) + +def cmp(a,b): + if hasattr(a, "__cmp__"): + return a.__cmp__(b) + elif hasattr(b, "__cmp__"): + return -b.__cmp__(a) + if a > b: + return 1 + elif b > a: + return -1 + else: + return 0 + +def bool(v): + # this needs to stay in native code without any dependencies here, + # because this is used by if and while, we need to prevent + # recursion + JS(""" + if (!v) return false; + switch(typeof v){ + case 'boolean': + return v; + case 'object': + if (v.__nonzero__){ + return v.__nonzero__(); + }else if (v.__len__){ + return v.__len__()>0; + } + return true; + } + return Boolean(v); + """) + +class List: + def __init__(self, data=None): + JS(""" + this.l = []; + this.extend(data); + """) + + def append(self, item): + JS(""" this.l[this.l.length] = item;""") + + def extend(self, data): + JS(""" + if (pyjslib.isArray(data)) { + n = this.l.length; + for (var i=0; i < data.length; i++) { + this.l[n+i]=data[i]; + } + } + else if (pyjslib.isIteratable(data)) { + var iter=data.__iter__(); + var i=this.l.length; + try { + while (true) { + var item=iter.next(); + this.l[i++]=item; + } + } + catch (e) { + if (e != pyjslib.StopIteration) throw e; + } + } + """) + + def remove(self, value): + JS(""" + var index=this.index(value); + if (index<0) return false; + this.l.splice(index, 1); + return true; + """) + + def index(self, value, start=0): + JS(""" + var length=this.l.length; + for (var i=start; i= 0 + + def __iter__(self): + JS(""" + var i = 0; + var l = this.l; + return { + 'next': function() { + if (i >= l.length) { + throw pyjslib.StopIteration; + } + return l[i++]; + }, + '__iter__': function() { + return this; + } + }; + """) + + def reverse(self): + JS(""" this.l.reverse();""") + + def sort(self, compareFunc=None, keyFunc=None, reverse=False): + if not compareFunc: + global cmp + compareFunc = cmp + if keyFunc and reverse: + def thisSort1(a,b): + return -compareFunc(keyFunc(a), keyFunc(b)) + self.l.sort(thisSort1) + elif keyFunc: + def thisSort2(a,b): + return compareFunc(keyFunc(a), keyFunc(b)) + self.l.sort(thisSort2) + elif reverse: + def thisSort3(a,b): + return -compareFunc(a, b) + self.l.sort(thisSort3) + else: + self.l.sort(compareFunc) + + def getArray(self): + """ + Access the javascript Array that is used internally by this list + """ + return self.l + + def __str__(self): + return repr(self) + +list = List + +class Tuple: + def __init__(self, data=None): + JS(""" + this.l = []; + this.extend(data); + """) + + def append(self, item): + JS(""" this.l[this.l.length] = item;""") + + def extend(self, data): + JS(""" + if (pyjslib.isArray(data)) { + n = this.l.length; + for (var i=0; i < data.length; i++) { + this.l[n+i]=data[i]; + } + } + else if (pyjslib.isIteratable(data)) { + var iter=data.__iter__(); + var i=this.l.length; + try { + while (true) { + var item=iter.next(); + this.l[i++]=item; + } + } + catch (e) { + if (e != pyjslib.StopIteration) throw e; + } + } + """) + + def remove(self, value): + JS(""" + var index=this.index(value); + if (index<0) return false; + this.l.splice(index, 1); + return true; + """) + + def index(self, value, start=0): + JS(""" + var length=this.l.length; + for (var i=start; i= 0 + + def __iter__(self): + JS(""" + var i = 0; + var l = this.l; + return { + 'next': function() { + if (i >= l.length) { + throw pyjslib.StopIteration; + } + return l[i++]; + }, + '__iter__': function() { + return this; + } + }; + """) + + def reverse(self): + JS(""" this.l.reverse();""") + + def sort(self, compareFunc=None, keyFunc=None, reverse=False): + if not compareFunc: + global cmp + compareFunc = cmp + if keyFunc and reverse: + def thisSort1(a,b): + return -compareFunc(keyFunc(a), keyFunc(b)) + self.l.sort(thisSort1) + elif keyFunc: + def thisSort2(a,b): + return compareFunc(keyFunc(a), keyFunc(b)) + self.l.sort(thisSort2) + elif reverse: + def thisSort3(a,b): + return -compareFunc(a, b) + self.l.sort(thisSort3) + else: + self.l.sort(compareFunc) + + def getArray(self): + """ + Access the javascript Array that is used internally by this list + """ + return self.l + + def __str__(self): + return repr(self) + +tuple = Tuple + + +class Dict: + def __init__(self, data=None): + JS(""" + this.d = {}; + + if (pyjslib.isArray(data)) { + for (var i in data) { + var item=data[i]; + this.__setitem__(item[0], item[1]); + //var sKey=pyjslib.hash(item[0]); + //this.d[sKey]=item[1]; + } + } + else if (pyjslib.isIteratable(data)) { + var iter=data.__iter__(); + try { + while (true) { + var item=iter.next(); + this.__setitem__(item.__getitem__(0), item.__getitem__(1)); + } + } + catch (e) { + if (e != pyjslib.StopIteration) throw e; + } + } + else if (pyjslib.isObject(data)) { + for (var key in data) { + this.__setitem__(key, data[key]); + } + } + """) + + def __setitem__(self, key, value): + JS(""" + var sKey = pyjslib.hash(key); + this.d[sKey]=[key, value]; + """) + + def __getitem__(self, key): + JS(""" + var sKey = pyjslib.hash(key); + var value=this.d[sKey]; + if (pyjslib.isUndefined(value)){ + throw pyjslib.KeyError(key); + } + return value[1]; + """) + + def __nonzero__(self): + JS(""" + for (var i in this.d){ + return true; + } + return false; + """) + + def __len__(self): + JS(""" + var size=0; + for (var i in this.d) size++; + return size; + """) + + def has_key(self, key): + return self.__contains__(key) + + def __delitem__(self, key): + JS(""" + var sKey = pyjslib.hash(key); + delete this.d[sKey]; + """) + + def __contains__(self, key): + JS(""" + var sKey = pyjslib.hash(key); + return (pyjslib.isUndefined(this.d[sKey])) ? false : true; + """) + + def keys(self): + JS(""" + var keys=new pyjslib.List(); + for (var key in this.d) { + keys.append(this.d[key][0]); + } + return keys; + """) + + def values(self): + JS(""" + var values=new pyjslib.List(); + for (var key in this.d) values.append(this.d[key][1]); + return values; + """) + + def items(self): + JS(""" + var items = new pyjslib.List(); + for (var key in this.d) { + var kv = this.d[key]; + items.append(new pyjslib.List(kv)) + } + return items; + """) + + def __iter__(self): + return self.keys().__iter__() + + def iterkeys(self): + return self.__iter__() + + def itervalues(self): + return self.values().__iter__(); + + def iteritems(self): + return self.items().__iter__(); + + def setdefault(self, key, default_value): + if not self.has_key(key): + self[key] = default_value + + def get(self, key, default_=None): + if not self.has_key(key): + return default_ + return self[key] + + def update(self, d): + for k,v in d.iteritems(): + self[k] = v + + def getObject(self): + """ + Return the javascript Object which this class uses to store + dictionary keys and values + """ + return self.d + + def copy(self): + return Dict(self.items()) + + def __str__(self): + return repr(self) + +dict = Dict + +# taken from mochikit: range( [start,] stop[, step] ) +def range(): + JS(""" + var start = 0; + var stop = 0; + var step = 1; + + if (arguments.length == 2) { + start = arguments[0]; + stop = arguments[1]; + } + else if (arguments.length == 3) { + start = arguments[0]; + stop = arguments[1]; + step = arguments[2]; + } + else if (arguments.length>0) stop = arguments[0]; + + return { + 'next': function() { + if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) throw pyjslib.StopIteration; + var rval = start; + start += step; + return rval; + }, + '__iter__': function() { + return this; + } + } + """) + +def slice(object, lower, upper): + JS(""" + if (pyjslib.isString(object)) { + if (lower < 0) { + lower = object.length + lower; + } + if (upper < 0) { + upper = object.length + upper; + } + if (pyjslib.isNull(upper)) upper=object.length; + return object.substring(lower, upper); + } + if (pyjslib.isObject(object) && object.slice) + return object.slice(lower, upper); + + return null; + """) + +def str(text): + JS(""" + if (pyjslib.hasattr(text,"__str__")) { + return text.__str__(); + } + return String(text); + """) + +def ord(x): + if(isString(x) and len(x) is 1): + JS(""" + return x.charCodeAt(0); + """) + else: + JS(""" + throw pyjslib.TypeError(); + """) + return None + +def chr(x): + JS(""" + return String.fromCharCode(x) + """) + +def is_basetype(x): + JS(""" + var t = typeof(x); + return t == 'boolean' || + t == 'function' || + t == 'number' || + t == 'string' || + t == 'undefined' + ; + """) + +def get_pyjs_classtype(x): + JS(""" + if (pyjslib.hasattr(x, "__class__")) + if (pyjslib.hasattr(x.__class__, "__new__")) + var src = x.__class__.__name__; + return src; + return null; + """) + +def repr(x): + """ Return the string representation of 'x'. + """ + JS(""" + if (x === null) + return "null"; + + if (x === undefined) + return "undefined"; + + var t = typeof(x); + + //alert("repr typeof " + t + " : " + x); + + if (t == "boolean") + return x.toString(); + + if (t == "function") + return ""; + + if (t == "number") + return x.toString(); + + if (t == "string") { + if (x.indexOf("'") == -1) + return "'" + x + "'"; + if (x.indexOf('"') == -1) + return '"' + x + '"'; + var s = x.replace(new RegExp('"', "g"), '\\\\"'); + return '"' + s + '"'; + }; + + if (t == "undefined") + return "undefined"; + + // If we get here, x is an object. See if it's a Pyjamas class. + + if (!pyjslib.hasattr(x, "__init__")) + return "<" + x.toString() + ">"; + + // Handle the common Pyjamas data types. + + var constructor = "UNKNOWN"; + + constructor = pyjslib.get_pyjs_classtype(x); + + //alert("repr constructor: " + constructor); + + if (constructor == "Tuple") { + var contents = x.getArray(); + var s = "("; + for (var i=0; i < contents.length; i++) { + s += pyjslib.repr(contents[i]); + if (i < contents.length - 1) + s += ", "; + }; + s += ")" + return s; + }; + + if (constructor == "List") { + var contents = x.getArray(); + var s = "["; + for (var i=0; i < contents.length; i++) { + s += pyjslib.repr(contents[i]); + if (i < contents.length - 1) + s += ", "; + }; + s += "]" + return s; + }; + + if (constructor == "Dict") { + var keys = new Array(); + for (var key in x.d) + keys.push(key); + + var s = "{"; + for (var i=0; i return the class name. + // Note that we replace underscores with dots so that the name will + // (hopefully!) look like the original Python name. + + //var s = constructor.replace(new RegExp('_', "g"), '.'); + return "<" + constructor + " object>"; + """) + +def float(text): + JS(""" + return parseFloat(text); + """) + +def int(text, radix=0): + JS(""" + return parseInt(text, radix); + """) + +def len(object): + JS(""" + if (object==null) return 0; + if (pyjslib.isObject(object) && object.__len__) return object.__len__(); + return object.length; + """) + +def isinstance(object_, classinfo): + if pyjslib.isUndefined(object_): + return False + if not pyjslib.isObject(object_): + + return False + if _isinstance(classinfo, Tuple): + for ci in classinfo: + if isinstance(object_, ci): + return True + return False + else: + return _isinstance(object_, classinfo) + +def _isinstance(object_, classinfo): + if not pyjslib.isObject(object_): + return False + JS(""" + if (object_.__class__){ + var res = object_ instanceof classinfo.constructor; + return res; + } + return false; + """) + +def getattr(obj, name, default_): + JS(""" + if ((!pyjslib.isObject(obj))||(pyjslib.isUndefined(obj[name]))){ + if (pyjslib.isUndefined(default_)){ + throw pyjslib.AttributeError(obj, name); + }else{ + return default_; + } + } + if (!pyjslib.isFunction(obj[name])) return obj[name]; + var fnwrap = function() { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + return obj[name].apply(obj,args); + } + fnwrap.__name__ = name; + return fnwrap; + """) + +def setattr(obj, name, value): + JS(""" + if (!pyjslib.isObject(obj)) return null; + + obj[name] = value; + + """) + +def hasattr(obj, name): + JS(""" + if (!pyjslib.isObject(obj)) return false; + if (pyjslib.isUndefined(obj[name])) return false; + + return true; + """) + +def dir(obj): + JS(""" + var properties=new pyjslib.List(); + for (property in obj) properties.append(property); + return properties; + """) + +def filter(obj, method, sequence=None): + # object context is LOST when a method is passed, hence object must be passed separately + # to emulate python behaviour, should generate this code inline rather than as a function call + items = [] + if sequence is None: + sequence = method + method = obj + + for item in sequence: + if method(item): + items.append(item) + else: + for item in sequence: + if method.call(obj, item): + items.append(item) + + return items + + +def map(obj, method, sequence=None): + items = [] + + if sequence is None: + sequence = method + method = obj + + for item in sequence: + items.append(method(item)) + else: + for item in sequence: + items.append(method.call(obj, item)) + + return items + + +def enumerate(sequence): + enumeration = [] + nextIndex = 0 + for item in sequence: + enumeration.append([nextIndex, item]) + nextIndex = nextIndex + 1 + return enumeration + + +def min(*sequence): + minValue = None + for item in sequence: + if minValue is None: + minValue = item + elif item < minValue: + minValue = item + return minValue + + +def max(*sequence): + maxValue = None + for item in sequence: + if maxValue is None: + maxValue = item + elif item > maxValue: + maxValue = item + return maxValue + + +next_hash_id = 0 + +def hash(obj): + JS(""" + if (obj == null) return null; + + if (obj.$H) return obj.$H; + if (obj.__hash__) return obj.__hash__(); + if (obj.constructor == String || obj.constructor == Number || obj.constructor == Date) return obj; + + obj.$H = ++pyjslib.next_hash_id; + return obj.$H; + """) + + +# type functions from Douglas Crockford's Remedial Javascript: http://www.crockford.com/javascript/remedial.html +def isObject(a): + JS(""" + return (a != null && (typeof a == 'object')) || pyjslib.isFunction(a); + """) + +def isFunction(a): + JS(""" + return typeof a == 'function'; + """) + +def isString(a): + JS(""" + return typeof a == 'string'; + """) + +def isNull(a): + JS(""" + return typeof a == 'object' && !a; + """) + +def isArray(a): + JS(""" + return pyjslib.isObject(a) && a.constructor == Array; + """) + +def isUndefined(a): + JS(""" + return typeof a == 'undefined'; + """) + +def isIteratable(a): + JS(""" + return pyjslib.isString(a) || (pyjslib.isObject(a) && a.__iter__); + """) + +def isNumber(a): + JS(""" + return typeof a == 'number' && isFinite(a); + """) + +def toJSObjects(x): + """ + Convert the pyjs pythonic List and Dict objects into javascript Object and Array + objects, recursively. + """ + if isArray(x): + JS(""" + var result = []; + for(var k=0; k < x.length; k++) { + var v = x[k]; + var tv = pyjslib.toJSObjects(v); + result.push(tv); + } + return result; + """) + if isObject(x): + if isinstance(x, Dict): + JS(""" + var o = x.getObject(); + var result = {}; + for (var i in o) { + result[o[i][0].toString()] = o[i][1]; + } + return pyjslib.toJSObjects(result) + """) + elif isinstance(x, List): + return toJSObjects(x.l) + elif hasattr(x, '__class__'): + # we do not have a special implementation for custom + # classes, just pass it on + return x + if isObject(x): + JS(""" + var result = {}; + for(var k in x) { + var v = x[k]; + var tv = pyjslib.toJSObjects(v) + result[k] = tv; + } + return result; + """) + return x + +def printFunc(objs): + JS(""" + if ($wnd.console==undefined) return; + var s = ""; + for(var i=0; i < objs.length; i++) { + if(s != "") s += " "; + s += objs[i]; + } + console.debug(s) + """) + +def type(clsname, bases=None, methods=None): + """ creates a class, derived from bases, with methods and variables + """ + + JS(" var mths = {}; ") + if methods: + for k in methods.keys(): + mth = methods[k] + JS(" mths[k] = mth; ") + + JS(" var bss = null; ") + if bases: + JS("bss = bases.l;") + JS(" return pyjs_type(clsname, bss, mths); ") + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/lib/sys.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/lib/sys.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,59 @@ +# the platform name (PyV8, smjs, Mozilla, IE6, Opera, Safari etc.) +platform = '' # to be updated by app, on compile + +# a dictionary of module override names (platform-specific) +overrides = None # to be updated by app, on compile + +# the remote path for loading modules +loadpath = None + +stacktrace = None + +appname = None + +def setloadpath(lp): + global loadpath + loadpath = lp + +def setappname(an): + global appname + appname = an + +def getloadpath(): + global loadpath + return loadpath + +def addoverride(module_name, path): + global overrides + overrides[module_name] = path + +def addstack(linedebug): + JS(""" + if (pyjslib.bool((sys.stacktrace === null))) { + sys.stacktrace = new pyjslib.List([]); + } + sys.stacktrace.append(linedebug); + """) +def popstack(): + JS(""" + sys.stacktrace.pop() + """) + +def printstack(): + JS(""" + var res = ''; + + var __l = sys.stacktrace.__iter__(); + try { + while (true) { + var l = __l.next(); + res += ( l + '\\n' ) ; + } + } catch (e) { + if (e != pyjslib.StopIteration) { + throw e; + } + } + + return res; + """) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/pyjs/pyjs.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/pyjs/pyjs.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1777 @@ +#!/usr/bin/env python +# Copyright 2006 James Tauber and contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import sys +from types import StringType +import compiler +from compiler import ast +import os +import copy + +# the standard location for builtins (e.g. pyjslib) can be +# over-ridden by changing this. it defaults to sys.prefix +# so that on a system-wide install of pyjamas the builtins +# can be found in e.g. {sys.prefix}/share/pyjamas +# +# over-rides can be done by either explicitly modifying +# pyjs.prefix or by setting an environment variable, PYJSPREFIX. + +prefix = sys.prefix + +if os.environ.has_key('PYJSPREFIX'): + prefix = os.environ['PYJSPREFIX'] + +# pyjs.path is the list of paths, just like sys.path, from which +# library modules will be searched for, for compile purposes. +# obviously we don't want to use sys.path because that would result +# in compiling standard python modules into javascript! + +path = [os.path.abspath('')] + +if os.environ.has_key('PYJSPATH'): + for p in os.environ['PYJSPATH'].split(os.pathsep): + p = os.path.abspath(p) + if os.path.isdir(p): + path.append(p) + +# this is the python function used to wrap native javascript +NATIVE_JS_FUNC_NAME = "JS" + +UU = "" + +PYJSLIB_BUILTIN_FUNCTIONS=("cmp", + "map", + "filter", + "dir", + "getattr", + "setattr", + "hasattr", + "int", + "float", + "str", + "repr", + "range", + "len", + "hash", + "abs", + "ord", + "chr", + "enumerate", + "min", + "max", + "bool", + "type", + "isinstance") + +PYJSLIB_BUILTIN_CLASSES=("BaseException", + "Exception", + "StandardError", + "StopIteration", + "AttributeError", + "TypeError", + "KeyError", + "LookupError", + "list", + "dict", + "object", + "tuple", + ) + +def pyjs_builtin_remap(name): + # XXX HACK! + if name == 'list': + name = 'List' + if name == 'object': + name = '__Object' + if name == 'dict': + name = 'Dict' + if name == 'tuple': + name = 'Tuple' + return name + +# XXX: this is a hack: these should be dealt with another way +# however, console is currently the only global name which is causing +# problems. +PYJS_GLOBAL_VARS=("console") + +# This is taken from the django project. +# Escape every ASCII character with a value less than 32. +JS_ESCAPES = ( + ('\\', r'\x5C'), + ('\'', r'\x27'), + ('"', r'\x22'), + ('>', r'\x3E'), + ('<', r'\x3C'), + ('&', r'\x26'), + (';', r'\x3B') + ) + tuple([('%c' % z, '\\x%02X' % z) for z in range(32)]) + +def escapejs(value): + """Hex encodes characters for use in JavaScript strings.""" + for bad, good in JS_ESCAPES: + value = value.replace(bad, good) + return value + +def uuprefix(name, leave_alone=0): + name = name.split(".") + name = name[:leave_alone] + map(lambda x: "__%s" % x, name[leave_alone:]) + return '.'.join(name) + +class Klass: + + klasses = {} + + def __init__(self, name, name_): + self.name = name + self.name_ = name_ + self.klasses[name] = self + self.functions = set() + + def set_base(self, base_name): + self.base = self.klasses.get(base_name) + + def add_function(self, function_name): + self.functions.add(function_name) + + +class TranslationError(Exception): + def __init__(self, message, node): + self.message = "line %s:\n%s\n%s" % (node.lineno, message, node) + + def __str__(self): + return self.message + +def strip_py(name): + return name + +def mod_var_name_decl(raw_module_name): + """ function to get the last component of the module e.g. + pyjamas.ui.DOM into the "namespace". i.e. doing + "import pyjamas.ui.DOM" actually ends up with _two_ + variables - one pyjamas.ui.DOM, the other just "DOM". + but "DOM" is actually local, hence the "var" prefix. + + for PyV8, this might end up causing problems - we'll have + to see: gen_mod_import and mod_var_name_decl might have + to end up in a library-specific module, somewhere. + """ + name = raw_module_name.split(".") + if len(name) == 1: + return '' + child_name = name[-1] + return "var %s = %s;\n" % (child_name, raw_module_name) + +def gen_mod_import(parentName, importName, dynamic=1): + #pyjs_ajax_eval("%(n)s.cache.js", null, true); + return """ + pyjslib.import_module(sys.loadpath, '%(p)s', '%(n)s', %(d)d, false); + """ % ({'p': parentName, 'd': dynamic, 'n': importName}) + \ + mod_var_name_decl(importName) + +class Translator: + + def __init__(self, mn, module_name, raw_module_name, src, debug, mod, output, + dynamic=0, optimize=False, + findFile=None): + + if module_name: + self.module_prefix = module_name + "." + else: + self.module_prefix = "" + self.raw_module_name = raw_module_name + src = src.replace("\r\n", "\n") + src = src.replace("\n\r", "\n") + src = src.replace("\r", "\n") + self.src = src.split("\n") + self.debug = debug + self.imported_modules = [] + self.imported_modules_as = [] + self.imported_js = set() + self.top_level_functions = set() + self.top_level_classes = set() + self.top_level_vars = set() + self.local_arg_stack = [[]] + self.output = output + self.imported_classes = {} + self.method_imported_globals = set() + self.method_self = None + self.nextTupleAssignID = 1 + self.dynamic = dynamic + self.optimize = optimize + self.findFile = findFile + + if module_name.find(".") >= 0: + vdec = '' + else: + vdec = 'var ' + print >>self.output, UU+"%s%s = function (__mod_name__) {" % (vdec, module_name) + + print >>self.output, " if("+module_name+".__was_initialized__) return;" + print >>self.output, " "+UU+module_name+".__was_initialized__ = true;" + print >>self.output, UU+"if (__mod_name__ == null) __mod_name__ = '%s';" % (mn) + print >>self.output, UU+"%s.__name__ = __mod_name__;" % (raw_module_name) + + decl = mod_var_name_decl(raw_module_name) + if decl: + print >>self.output, decl + + + if self.debug: + haltException = self.module_prefix + "HaltException" + print >>self.output, haltException + ' = function () {' + print >>self.output, ' this.message = "Program Halted";' + print >>self.output, ' this.name = "' + haltException + '";' + print >>self.output, '}' + print >>self.output, '' + print >>self.output, haltException + ".prototype.__str__ = function()" + print >>self.output, '{' + print >>self.output, 'return this.message ;' + print >>self.output, '}' + + print >>self.output, haltException + ".prototype.toString = function()" + print >>self.output, '{' + print >>self.output, 'return this.name + ": \\"" + this.message + "\\"";' + print >>self.output, '}' + + isHaltFunction = self.module_prefix + "IsHaltException" + print >>self.output, """ + %s = function (s) { + var suffix="HaltException"; + if (s.length < suffix.length) { + //alert(s + " " + suffix); + return false; + } else { + var ss = s.substring(s.length, (s.length - suffix.length)); + //alert(s + " " + suffix + " " + ss); + return ss == suffix; + } + } + """ % isHaltFunction + for child in mod.node: + if isinstance(child, ast.Function): + self.top_level_functions.add(child.name) + elif isinstance(child, ast.Class): + self.top_level_classes.add(child.name) + + for child in mod.node: + if isinstance(child, ast.Function): + self._function(child, False) + elif isinstance(child, ast.Class): + self._class(child) + elif isinstance(child, ast.Import): + importName = child.names[0][0] + if importName == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter + pass + elif importName.endswith('.js'): + self.imported_js.add(importName) + else: + self.add_imported_module(strip_py(importName)) + elif isinstance(child, ast.From): + if child.modname == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter + pass + else: + self.add_imported_module(child.modname) + self._from(child) + elif isinstance(child, ast.Discard): + self._discard(child, None) + elif isinstance(child, ast.Assign): + self._assign(child, None, True) + elif isinstance(child, ast.AugAssign): + self._augassign(child, None) + elif isinstance(child, ast.If): + self._if(child, None) + elif isinstance(child, ast.For): + self._for(child, None) + elif isinstance(child, ast.While): + self._while(child, None) + elif isinstance(child, ast.Subscript): + self._subscript_stmt(child, None) + elif isinstance(child, ast.Global): + self._global(child, None) + elif isinstance(child, ast.Printnl): + self._print(child, None) + elif isinstance(child, ast.Print): + self._print(child, None) + elif isinstance(child, ast.TryExcept): + self._tryExcept(child, None) + elif isinstance(child, ast.Raise): + self._raise(child, None) + elif isinstance(child, ast.Stmt): + self._stmt(child, None) + else: + raise TranslationError("unsupported type (in __init__)", child) + + # Initialize all classes for this module + #print >> self.output, "__"+self.modpfx()+\ + # "classes_initialize = function() {\n" + #for className in self.top_level_classes: + # print >> self.output, "\t"+UU+self.modpfx()+"__"+className+"_initialize();" + #print >> self.output, "};\n" + + print >> self.output, "return this;\n" + print >> self.output, "}; /* end %s */ \n" % module_name + + def module_imports(self): + return self.imported_modules + self.imported_modules_as + + def add_local_arg(self, varname): + local_vars = self.local_arg_stack[-1] + if varname not in local_vars: + local_vars.append(varname) + + def add_imported_module(self, importName): + + if importName in self.imported_modules: + return + self.imported_modules.append(importName) + name = importName.split(".") + if len(name) != 1: + # add the name of the module to the namespace, + # but don't add the short name to imported_modules + # because then the short name would be attempted to be + # added to the dependencies, and it's half way up the + # module import directory structure! + child_name = name[-1] + self.imported_modules_as.append(child_name) + print >> self.output, gen_mod_import(self.raw_module_name, + strip_py(importName), + self.dynamic) + + def _default_args_handler(self, node, arg_names, current_klass, + output=None): + if len(node.defaults): + output = output or self.output + default_pos = len(arg_names) - len(node.defaults) + if arg_names and arg_names[0] == self.method_self: + default_pos -= 1 + for default_node in node.defaults: + if isinstance(default_node, ast.Const): + default_value = self._const(default_node) + elif isinstance(default_node, ast.Name): + default_value = self._name(default_node, current_klass) + elif isinstance(default_node, ast.UnarySub): + default_value = self._unarysub(default_node, current_klass) + else: + raise TranslationError("unsupported type (in _method)", default_node) + + default_name = arg_names[default_pos] + default_pos += 1 + print >> output, " if (typeof %s == 'undefined') %s=%s;" % (default_name, default_name, default_value) + + def _varargs_handler(self, node, varargname, arg_names, current_klass): + print >>self.output, " var", varargname, '= new pyjslib.Tuple();' + print >>self.output, " for(var __va_arg="+str(len(arg_names))+"; __va_arg < arguments.length; __va_arg++) {" + print >>self.output, " var __arg = arguments[__va_arg];" + print >>self.output, " "+varargname+".append(__arg);" + print >>self.output, " }" + + def _kwargs_parser(self, node, function_name, arg_names, current_klass): + if len(node.defaults) or node.kwargs: + default_pos = len(arg_names) - len(node.defaults) + if arg_names and arg_names[0] == self.method_self: + default_pos -= 1 + print >>self.output, function_name+'.parse_kwargs = function (', ", ".join(["__kwargs"]+arg_names), ") {" + for default_node in node.defaults: + default_value = self.expr(default_node, current_klass) +# if isinstance(default_node, ast.Const): +# default_value = self._const(default_node) +# elif isinstance(default_node, ast.Name): +# default_value = self._name(default_node) +# elif isinstance(default_node, ast.UnarySub): +# default_value = self._unarysub(default_node, current_klass) +# else: +# raise TranslationError("unsupported type (in _method)", default_node) + + default_name = arg_names[default_pos] + print >>self.output, " if (typeof %s == 'undefined')"%(default_name) + print >>self.output, " %s=__kwargs.%s;"% (default_name, default_name) + default_pos += 1 + + #self._default_args_handler(node, arg_names, current_klass) + if node.kwargs: arg_names += ["pyjslib.Dict(__kwargs)"] + print >>self.output, " var __r = "+"".join(["[", ", ".join(arg_names), "]"])+";" + if node.varargs: + self._varargs_handler(node, "__args", arg_names, current_klass) + print >>self.output, " __r.push.apply(__r, __args.getArray())" + print >>self.output, " return __r;" + print >>self.output, "};" + + def _function(self, node, local=False): + if local: + function_name = node.name + self.add_local_arg(function_name) + else: + function_name = UU + self.modpfx() + node.name + + arg_names = list(node.argnames) + normal_arg_names = list(arg_names) + if node.kwargs: kwargname = normal_arg_names.pop() + if node.varargs: varargname = normal_arg_names.pop() + declared_arg_names = list(normal_arg_names) + if node.kwargs: declared_arg_names.append(kwargname) + + function_args = "(" + ", ".join(declared_arg_names) + ")" + print >>self.output, "%s = function%s {" % (function_name, function_args) + self._default_args_handler(node, normal_arg_names, None) + + local_arg_names = normal_arg_names + declared_arg_names + + if node.varargs: + self._varargs_handler(node, varargname, declared_arg_names, None) + local_arg_names.append(varargname) + + # stack of local variable names for this function call + self.local_arg_stack.append(local_arg_names) + + for child in node.code: + self._stmt(child, None) + + # remove the top local arg names + self.local_arg_stack.pop() + + # we need to return null always, so it is not undefined + lastStmt = [p for p in node.code][-1] + if not isinstance(lastStmt, ast.Return): + if not self._isNativeFunc(lastStmt): + print >>self.output, " return null;" + + print >>self.output, "};" + print >>self.output, "%s.__name__ = '%s';\n" % (function_name, node.name) + + + self._kwargs_parser(node, function_name, normal_arg_names, None) + + + def _return(self, node, current_klass): + expr = self.expr(node.value, current_klass) + # in python a function call always returns None, so we do it + # here too + print >>self.output, " return " + expr + ";" + + + def _break(self, node, current_klass): + print >>self.output, " break;" + + + def _continue(self, node, current_klass): + print >>self.output, " continue;" + + + def _callfunc(self, v, current_klass): + + if isinstance(v.node, ast.Name): + if v.node.name in self.top_level_functions: + call_name = self.modpfx() + v.node.name + elif v.node.name in self.top_level_classes: + call_name = self.modpfx() + v.node.name + elif self.imported_classes.has_key(v.node.name): + call_name = self.imported_classes[v.node.name] + '.' + v.node.name + elif v.node.name in PYJSLIB_BUILTIN_FUNCTIONS: + call_name = 'pyjslib.' + v.node.name + elif v.node.name in PYJSLIB_BUILTIN_CLASSES: + name = pyjs_builtin_remap(v.node.name) + call_name = 'pyjslib.' + name + elif v.node.name == "callable": + call_name = "pyjslib.isFunction" + else: + call_name = v.node.name + call_args = [] + elif isinstance(v.node, ast.Getattr): + attr_name = v.node.attrname + + if isinstance(v.node.expr, ast.Name): + call_name = self._name2(v.node.expr, current_klass, attr_name) + call_args = [] + elif isinstance(v.node.expr, ast.Getattr): + call_name = self._getattr2(v.node.expr, current_klass, attr_name) + call_args = [] + elif isinstance(v.node.expr, ast.CallFunc): + call_name = self._callfunc(v.node.expr, current_klass) + "." + v.node.attrname + call_args = [] + elif isinstance(v.node.expr, ast.Subscript): + call_name = self._subscript(v.node.expr, current_klass) + "." + v.node.attrname + call_args = [] + elif isinstance(v.node.expr, ast.Const): + call_name = self.expr(v.node.expr, current_klass) + "." + v.node.attrname + call_args = [] + else: + raise TranslationError("unsupported type (in _callfunc)", v.node.expr) + else: + raise TranslationError("unsupported type (in _callfunc)", v.node) + + call_name = strip_py(call_name) + + kwargs = [] + star_arg_name = None + if v.star_args: + star_arg_name = self.expr(v.star_args, current_klass) + + for ch4 in v.args: + if isinstance(ch4, ast.Keyword): + kwarg = ch4.name + ":" + self.expr(ch4.expr, current_klass) + kwargs.append(kwarg) + else: + arg = self.expr(ch4, current_klass) + call_args.append(arg) + + if kwargs: + fn_args = ", ".join(['{' + ', '.join(kwargs) + '}']+call_args) + else: + fn_args = ", ".join(call_args) + + if kwargs or star_arg_name: + if not star_arg_name: + star_arg_name = 'null' + try: call_this, method_name = call_name.rsplit(".", 1) + except ValueError: + # Must be a function call ... + return ("pyjs_kwargs_function_call("+call_name+", " + + star_arg_name + + ", ["+fn_args+"]" + + ")" ) + else: + return ("pyjs_kwargs_method_call("+call_this+", '"+method_name+"', " + + star_arg_name + + ", ["+fn_args+"]" + + ")") + else: + return call_name + "(" + ", ".join(call_args) + ")" + + def _print(self, node, current_klass): + if self.optimize: + return + call_args = [] + for ch4 in node.nodes: + arg = self.expr(ch4, current_klass) + call_args.append(arg) + + print >>self.output, "pyjslib.printFunc([", ', '.join(call_args), "],", int(isinstance(node, ast.Printnl)), ");" + + def _tryExcept(self, node, current_klass): + if len(node.handlers) != 1: + raise TranslationError("except statements in this form are" + + " not supported", node) + + expr = node.handlers[0][0] + as_ = node.handlers[0][1] + if as_: + errName = as_.name + else: + errName = 'err' + + # XXX TODO: check that this should instead be added as a _separate_ + # local scope, temporary to the function. oh dearie me. + self.add_local_arg(errName) + + print >>self.output, " try {" + for stmt in node.body.nodes: + self._stmt(stmt, current_klass) + print >> self.output, " } catch(%s) {" % errName + if expr: + l = [] + if isinstance(expr, ast.Tuple): + for x in expr.nodes: + l.append("(%(err)s.__name__ == %(expr)s.__name__)" % dict (err=errName, expr=self.expr(x, current_klass))) + else: + l = [ " (%(err)s.__name__ == %(expr)s.__name__) " % dict (err=errName, expr=self.expr(expr, current_klass)) ] + print >> self.output, " if(%s) {" % '||\n\t\t'.join(l) + for stmt in node.handlers[0][2]: + self._stmt(stmt, current_klass) + if expr: + #print >> self.output, "} else { throw(%s); } " % errName + print >> self.output, "}" + if node.else_ != None: + print >>self.output, " } finally {" + for stmt in node.else_: + self._stmt(stmt, current_klass) + print >>self.output, " }" + + # XXX: change use_getattr to True to enable "strict" compilation + # but incurring a 100% performance penalty. oops. + def _getattr(self, v, current_klass, use_getattr=False): + attr_name = v.attrname + if isinstance(v.expr, ast.Name): + obj = self._name(v.expr, current_klass, return_none_for_module=True) + if obj == None and v.expr.name in self.module_imports(): + # XXX TODO: distinguish between module import classes + # and variables. right now, this is a hack to get + # the sys module working. + #if v.expr.name == 'sys': + return v.expr.name+'.'+attr_name + #return v.expr.name+'.__'+attr_name+'.prototype.__class__' + if not use_getattr or attr_name == '__class__' or \ + attr_name == '__name__': + return obj + "." + attr_name + return "pyjslib.getattr(%s, '%s')" % (obj, attr_name) + elif isinstance(v.expr, ast.Getattr): + return self._getattr(v.expr, current_klass) + "." + attr_name + elif isinstance(v.expr, ast.Subscript): + return self._subscript(v.expr, self.modpfx()) + "." + attr_name + elif isinstance(v.expr, ast.CallFunc): + return self._callfunc(v.expr, self.modpfx()) + "." + attr_name + else: + raise TranslationError("unsupported type (in _getattr)", v.expr) + + + def modpfx(self): + return strip_py(self.module_prefix) + + def _name(self, v, current_klass, top_level=False, + return_none_for_module=False): + + if v.name == 'ilikesillynamesfornicedebugcode': + print top_level, current_klass, repr(v) + print self.top_level_vars + print self.top_level_functions + print self.local_arg_stack + print "error..." + + local_var_names = None + las = len(self.local_arg_stack) + if las > 0: + local_var_names = self.local_arg_stack[-1] + + if v.name == "True": + return "true" + elif v.name == "False": + return "false" + elif v.name == "None": + return "null" + elif v.name == '__name__' and current_klass is None: + return self.modpfx() + v.name + elif v.name == self.method_self: + return "this" + elif v.name in self.top_level_functions: + return UU+self.modpfx() + v.name + elif v.name in self.method_imported_globals: + return UU+self.modpfx() + v.name + elif not current_klass and las == 1 and v.name in self.top_level_vars: + return UU+self.modpfx() + v.name + elif v.name in local_var_names: + return v.name + elif self.imported_classes.has_key(v.name): + return UU+self.imported_classes[v.name] + '.__' + v.name + ".prototype.__class__" + elif v.name in self.top_level_classes: + return UU+self.modpfx() + "__" + v.name + ".prototype.__class__" + elif v.name in self.module_imports() and return_none_for_module: + return None + elif v.name in PYJSLIB_BUILTIN_CLASSES: + return "pyjslib." + pyjs_builtin_remap( v.name ) + elif current_klass: + if v.name not in local_var_names and \ + v.name not in self.top_level_vars and \ + v.name not in PYJS_GLOBAL_VARS and \ + v.name not in self.top_level_functions: + + cls_name = current_klass + if hasattr(cls_name, "name"): + cls_name_ = cls_name.name_ + cls_name = cls_name.name + else: + cls_name_ = current_klass + "_" # XXX ??? + name = UU+cls_name_ + ".prototype.__class__." \ + + v.name + if v.name == 'listener': + name = 'listener+' + name + return name + + return v.name + + def _name2(self, v, current_klass, attr_name): + obj = v.name + + if obj in self.method_imported_globals: + call_name = UU+self.modpfx() + obj + "." + attr_name + elif self.imported_classes.has_key(obj): + #attr_str = "" + #if attr_name != "__init__": + attr_str = ".prototype.__class__." + attr_name + call_name = UU+self.imported_classes[obj] + '.__' + obj + attr_str + elif obj in self.module_imports(): + call_name = obj + "." + attr_name + elif obj[0] == obj[0].upper(): # XXX HACK ALERT + call_name = UU + self.modpfx() + "__" + obj + ".prototype.__class__." + attr_name + else: + call_name = UU+self._name(v, current_klass) + "." + attr_name + + return call_name + + + def _getattr2(self, v, current_klass, attr_name): + if isinstance(v.expr, ast.Getattr): + call_name = self._getattr2(v.expr, current_klass, v.attrname + "." + attr_name) + elif isinstance(v.expr, ast.Name) and v.expr.name in self.module_imports(): + call_name = UU+v.expr.name + '.__' +v.attrname+".prototype.__class__."+attr_name + else: + obj = self.expr(v.expr, current_klass) + call_name = obj + "." + v.attrname + "." + attr_name + + return call_name + + + def _class(self, node): + """ + Handle a class definition. + + In order to translate python semantics reasonably well, the following + structure is used: + + A special object is created for the class, which inherits attributes + from the superclass, or Object if there's no superclass. This is the + class object; the object which you refer to when specifying the + class by name. Static, class, and unbound methods are copied + from the superclass object. + + A special constructor function is created with the same name as the + class, which is used to create instances of that class. + + A javascript class (e.g. a function with a prototype attribute) is + created which is the javascript class of created instances, and + which inherits attributes from the class object. Bound methods are + copied from the superclass into this class rather than inherited, + because the class object contains unbound, class, and static methods + that we don't necessarily want to inherit. + + The type of a method can now be determined by inspecting its + static_method, unbound_method, class_method, or instance_method + attribute; only one of these should be true. + + Much of this work is done in pyjs_extend, is pyjslib.py + """ + class_name = self.modpfx() + uuprefix(node.name, 1) + class_name_ = self.modpfx() + uuprefix(node.name) + current_klass = Klass(class_name, class_name_) + init_method = None + for child in node.code: + if isinstance(child, ast.Function): + current_klass.add_function(child.name) + if child.name == "__init__": + init_method = child + + + if len(node.bases) == 0: + base_class = "pyjslib.__Object" + elif len(node.bases) == 1: + if isinstance(node.bases[0], ast.Name): + if self.imported_classes.has_key(node.bases[0].name): + base_class_ = self.imported_classes[node.bases[0].name] + '.__' + node.bases[0].name + base_class = self.imported_classes[node.bases[0].name] + '.' + node.bases[0].name + else: + base_class_ = self.modpfx() + "__" + node.bases[0].name + base_class = self.modpfx() + node.bases[0].name + elif isinstance(node.bases[0], ast.Getattr): + # the bases are not in scope of the class so do not + # pass our class to self._name + base_class_ = self._name(node.bases[0].expr, None) + \ + ".__" + node.bases[0].attrname + base_class = self._name(node.bases[0].expr, None) + \ + "." + node.bases[0].attrname + else: + raise TranslationError("unsupported type (in _class)", node.bases[0]) + + current_klass.set_base(base_class) + else: + raise TranslationError("more than one base (in _class)", node) + + print >>self.output, UU+class_name_ + " = function () {" + # call superconstructor + #if base_class: + # print >>self.output, " __" + base_class + ".call(this);" + print >>self.output, "}" + + if not init_method: + init_method = ast.Function([], "__init__", ["self"], [], 0, None, []) + #self._method(init_method, current_klass, class_name) + + # Generate a function which constructs the object + clsfunc = ast.Function([], + node.name, + init_method.argnames[1:], + init_method.defaults, + init_method.flags, + None, + [ast.Discard(ast.CallFunc(ast.Name("JS"), [ast.Const( +# I attempted lazy initialization, but then you can't access static class members +# " if(!__"+base_class+".__was_initialized__)"+ +# " __" + class_name + "_initialize();\n" + + " var instance = new " + UU + class_name_ + "();\n" + + " if(instance.__init__) instance.__init__.apply(instance, arguments);\n" + + " return instance;" + )]))]) + + self._function(clsfunc, False) + print >>self.output, UU+class_name_ + ".__initialize__ = function () {" + print >>self.output, " if("+UU+class_name_+".__was_initialized__) return;" + print >>self.output, " "+UU+class_name_+".__was_initialized__ = true;" + cls_obj = UU+class_name_ + '.prototype.__class__' + + if class_name == "pyjslib.__Object": + print >>self.output, " "+cls_obj+" = {};" + else: + if base_class and base_class not in ("object", "pyjslib.__Object"): + print >>self.output, " if(!"+UU+base_class_+".__was_initialized__)" + print >>self.output, " "+UU+base_class_+".__initialize__();" + print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+base_class_+");" + else: + print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+"pyjslib.__Object);" + + print >>self.output, " "+cls_obj+".__new__ = "+UU+class_name+";" + print >>self.output, " "+cls_obj+".__name__ = '"+UU+node.name+"';" + + for child in node.code: + if isinstance(child, ast.Pass): + pass + elif isinstance(child, ast.Function): + self._method(child, current_klass, class_name, class_name_) + elif isinstance(child, ast.Assign): + self.classattr(child, current_klass) + elif isinstance(child, ast.Discard) and isinstance(child.expr, ast.Const): + # Probably a docstring, turf it + pass + else: + raise TranslationError("unsupported type (in _class)", child) + print >>self.output, "}" + + print >> self.output, class_name_+".__initialize__();" + + + def classattr(self, node, current_klass): + self._assign(node, current_klass, True) + + def _raise(self, node, current_klass): + if node.expr2: + raise TranslationError("More than one expression unsupported", + node) + print >> self.output, "throw (%s);" % self.expr( + node.expr1, current_klass) + + def _method(self, node, current_klass, class_name, class_name_): + # reset global var scope + self.method_imported_globals = set() + + arg_names = list(node.argnames) + + classmethod = False + staticmethod = False + if node.decorators: + for d in node.decorators: + if d.name == "classmethod": + classmethod = True + elif d.name == "staticmethod": + staticmethod = True + + if staticmethod: + staticfunc = ast.Function([], class_name_+"."+node.name, node.argnames, node.defaults, node.flags, node.doc, node.code, node.lineno) + self._function(staticfunc, True) + print >>self.output, " " + UU+class_name_ + ".prototype.__class__." + node.name + " = " + class_name_+"."+node.name+";"; + print >>self.output, " " + UU+class_name_ + ".prototype.__class__." + node.name + ".static_method = true;"; + return + else: + if len(arg_names) == 0: + raise TranslationError("methods must take an argument 'self' (in _method)", node) + self.method_self = arg_names[0] + + #if not classmethod and arg_names[0] != "self": + # raise TranslationError("first arg not 'self' (in _method)", node) + + normal_arg_names = arg_names[1:] + if node.kwargs: kwargname = normal_arg_names.pop() + if node.varargs: varargname = normal_arg_names.pop() + declared_arg_names = list(normal_arg_names) + if node.kwargs: declared_arg_names.append(kwargname) + + function_args = "(" + ", ".join(declared_arg_names) + ")" + + if classmethod: + fexpr = UU + class_name_ + ".prototype.__class__." + node.name + else: + fexpr = UU + class_name_ + ".prototype." + node.name + print >>self.output, " "+fexpr + " = function" + function_args + " {" + + # default arguments + self._default_args_handler(node, normal_arg_names, current_klass) + + local_arg_names = normal_arg_names + declared_arg_names + + if node.varargs: + self._varargs_handler(node, varargname, declared_arg_names, current_klass) + local_arg_names.append(varargname) + + + # stack of local variable names for this function call + self.local_arg_stack.append(local_arg_names) + + for child in node.code: + self._stmt(child, current_klass) + + # remove the top local arg names + self.local_arg_stack.pop() + + print >>self.output, " };" + + self._kwargs_parser(node, fexpr, normal_arg_names, current_klass) + + if classmethod: + # Have to create a version on the instances which automatically passes the + # class as "self" + altexpr = UU + class_name_ + ".prototype." + node.name + print >>self.output, " "+altexpr + " = function() {" + print >>self.output, " return " + fexpr + ".apply(this.__class__, arguments);" + print >>self.output, " };" + print >>self.output, " "+fexpr+".class_method = true;" + print >>self.output, " "+altexpr+".instance_method = true;" + else: + # For instance methods, we need an unbound version in the class object + altexpr = UU + class_name_ + ".prototype.__class__." + node.name + print >>self.output, " "+altexpr + " = function() {" + print >>self.output, " return " + fexpr + ".call.apply("+fexpr+", arguments);" + print >>self.output, " };" + print >>self.output, " "+altexpr+".unbound_method = true;" + print >>self.output, " "+fexpr+".instance_method = true;" + print >>self.output, " "+altexpr+".__name__ = '%s';" % node.name + + print >>self.output, UU + class_name_ + ".prototype.%s.__name__ = '%s';" % \ + (node.name, node.name) + + if node.kwargs or len(node.defaults): + print >>self.output, " "+altexpr + ".parse_kwargs = " + fexpr + ".parse_kwargs;" + + self.method_self = None + self.method_imported_globals = set() + + def _isNativeFunc(self, node): + if isinstance(node, ast.Discard): + if isinstance(node.expr, ast.CallFunc): + if isinstance(node.expr.node, ast.Name) and \ + node.expr.node.name == NATIVE_JS_FUNC_NAME: + return True + return False + + def _stmt(self, node, current_klass): + debugStmt = self.debug and not self._isNativeFunc(node) + if debugStmt: + print >>self.output, ' try {' + + if isinstance(node, ast.Return): + self._return(node, current_klass) + elif isinstance(node, ast.Break): + self._break(node, current_klass) + elif isinstance(node, ast.Continue): + self._continue(node, current_klass) + elif isinstance(node, ast.Assign): + self._assign(node, current_klass) + elif isinstance(node, ast.AugAssign): + self._augassign(node, current_klass) + elif isinstance(node, ast.Discard): + self._discard(node, current_klass) + elif isinstance(node, ast.If): + self._if(node, current_klass) + elif isinstance(node, ast.For): + self._for(node, current_klass) + elif isinstance(node, ast.While): + self._while(node, current_klass) + elif isinstance(node, ast.Subscript): + self._subscript_stmt(node, current_klass) + elif isinstance(node, ast.Global): + self._global(node, current_klass) + elif isinstance(node, ast.Pass): + pass + elif isinstance(node, ast.Function): + self._function(node, True) + elif isinstance(node, ast.Printnl): + self._print(node, current_klass) + elif isinstance(node, ast.Print): + self._print(node, current_klass) + elif isinstance(node, ast.TryExcept): + self._tryExcept(node, current_klass) + elif isinstance(node, ast.Raise): + self._raise(node, current_klass) + else: + raise TranslationError("unsupported type (in _stmt)", node) + + if debugStmt: + + lt = self.get_line_trace(node) + + haltException = self.module_prefix + "HaltException" + isHaltFunction = self.module_prefix + "IsHaltException" + + print >>self.output, ' } catch (__err) {' + print >>self.output, ' if (' + isHaltFunction + '(__err.name)) {' + print >>self.output, ' throw __err;' + print >>self.output, ' } else {' + print >>self.output, " st = sys.printstack() + "\ + + '"%s"' % lt + "+ '\\n' ;" + print >>self.output, ' alert("' + "Error in " \ + + lt + '"' \ + + '+"\\n"+__err.name+": "+__err.message'\ + + '+"\\n\\nStack trace:\\n"' \ + + '+st' \ + + ');' + print >>self.output, ' debugger;' + + print >>self.output, ' throw new ' + self.module_prefix + "HaltException();" + print >>self.output, ' }' + print >>self.output, ' }' + + + def get_line_trace(self, node): + lineNum = "Unknown" + srcLine = "" + if hasattr(node, "lineno"): + if node.lineno != None: + lineNum = node.lineno + srcLine = self.src[min(lineNum, len(self.src))-1] + srcLine = srcLine.replace('\\', '\\\\') + srcLine = srcLine.replace('"', '\\"') + srcLine = srcLine.replace("'", "\\'") + + return self.raw_module_name + ".py, line " \ + + str(lineNum) + ":"\ + + "\\n" \ + + " " + srcLine + + def _augassign(self, node, current_klass): + v = node.node + if isinstance(v, ast.Getattr): + # XXX HACK! don't allow += on return result of getattr. + # TODO: create a temporary variable or something. + lhs = self._getattr(v, current_klass, False) + else: + lhs = self._name(node.node, current_klass) + op = node.op + rhs = self.expr(node.expr, current_klass) + print >>self.output, " " + lhs + " " + op + " " + rhs + ";" + + + def _assign(self, node, current_klass, top_level = False): + if len(node.nodes) != 1: + tempvar = '__temp'+str(node.lineno) + tnode = ast.Assign([ast.AssName(tempvar, "OP_ASSIGN", node.lineno)], node.expr, node.lineno) + self._assign(tnode, current_klass, top_level) + for v in node.nodes: + tnode2 = ast.Assign([v], ast.Name(tempvar, node.lineno), node.lineno) + self._assign(tnode2, current_klass, top_level) + return + + local_var_names = None + if len(self.local_arg_stack) > 0: + local_var_names = self.local_arg_stack[-1] + + def _lhsFromAttr(v, current_klass): + attr_name = v.attrname + if isinstance(v.expr, ast.Name): + obj = v.expr.name + lhs = self._name(v.expr, current_klass) + "." + attr_name + elif isinstance(v.expr, ast.Getattr): + lhs = self._getattr(v, current_klass) + elif isinstance(v.expr, ast.Subscript): + lhs = self._subscript(v.expr, current_klass) + "." + attr_name + else: + raise TranslationError("unsupported type (in _assign)", v.expr) + return lhs + + def _lhsFromName(v, top_level, current_klass): + if top_level: + if current_klass: + lhs = UU+current_klass.name_ + ".prototype.__class__." \ + + v.name + else: + self.top_level_vars.add(v.name) + vname = self.modpfx() + v.name + if not self.modpfx() and v.name not in\ + self.method_imported_globals: + lhs = "var " + vname + else: + lhs = UU + vname + self.add_local_arg(v.name) + else: + if v.name in local_var_names: + lhs = v.name + elif v.name in self.method_imported_globals: + lhs = self.modpfx() + v.name + else: + lhs = "var " + v.name + self.add_local_arg(v.name) + return lhs + + dbg = 0 + v = node.nodes[0] + if isinstance(v, ast.AssAttr): + lhs = _lhsFromAttr(v, current_klass) + if v.flags == "OP_ASSIGN": + op = "=" + else: + raise TranslationError("unsupported flag (in _assign)", v) + + elif isinstance(v, ast.AssName): + lhs = _lhsFromName(v, top_level, current_klass) + if v.flags == "OP_ASSIGN": + op = "=" + else: + raise TranslationError("unsupported flag (in _assign)", v) + elif isinstance(v, ast.Subscript): + if v.flags == "OP_ASSIGN": + obj = self.expr(v.expr, current_klass) + if len(v.subs) != 1: + raise TranslationError("must have one sub (in _assign)", v) + idx = self.expr(v.subs[0], current_klass) + value = self.expr(node.expr, current_klass) + print >>self.output, " " + obj + ".__setitem__(" + idx + ", " + value + ");" + return + else: + raise TranslationError("unsupported flag (in _assign)", v) + elif isinstance(v, (ast.AssList, ast.AssTuple)): + uniqueID = self.nextTupleAssignID + self.nextTupleAssignID += 1 + tempName = "__tupleassign" + str(uniqueID) + "__" + print >>self.output, " var " + tempName + " = " + \ + self.expr(node.expr, current_klass) + ";" + for index,child in enumerate(v.getChildNodes()): + rhs = tempName + ".__getitem__(" + str(index) + ")" + + if isinstance(child, ast.AssAttr): + lhs = _lhsFromAttr(child, current_klass) + elif isinstance(child, ast.AssName): + lhs = _lhsFromName(child, top_level, current_klass) + elif isinstance(child, ast.Subscript): + if child.flags == "OP_ASSIGN": + obj = self.expr(child.expr, current_klass) + if len(child.subs) != 1: + raise TranslationError("must have one sub " + + "(in _assign)", child) + idx = self.expr(child.subs[0], current_klass) + value = self.expr(node.expr, current_klass) + print >>self.output, " " + obj + ".__setitem__(" \ + + idx + ", " + rhs + ");" + continue + print >>self.output, " " + lhs + " = " + rhs + ";" + return + else: + raise TranslationError("unsupported type (in _assign)", v) + + rhs = self.expr(node.expr, current_klass) + if dbg: + print "b", repr(node.expr), rhs + print >>self.output, " " + lhs + " " + op + " " + rhs + ";" + + + def _discard(self, node, current_klass): + + if isinstance(node.expr, ast.CallFunc): + debugStmt = self.debug and not self._isNativeFunc(node) + if debugStmt and isinstance(node.expr.node, ast.Name) and \ + node.expr.node.name == 'import_wait': + debugStmt = False + if debugStmt: + st = self.get_line_trace(node) + print >>self.output, "sys.addstack('%s');\n" % st + if isinstance(node.expr.node, ast.Name) and node.expr.node.name == NATIVE_JS_FUNC_NAME: + if len(node.expr.args) != 1: + raise TranslationError("native javascript function %s must have one arg" % NATIVE_JS_FUNC_NAME, node.expr) + if not isinstance(node.expr.args[0], ast.Const): + raise TranslationError("native javascript function %s must have constant arg" % NATIVE_JS_FUNC_NAME, node.expr) + raw_js = node.expr.args[0].value + print >>self.output, raw_js + else: + expr = self._callfunc(node.expr, current_klass) + print >>self.output, " " + expr + ";" + + if debugStmt: + print >>self.output, "sys.popstack();\n" + + elif isinstance(node.expr, ast.Const): + if node.expr.value is not None: # Empty statements generate ignore None + print >>self.output, self._const(node.expr) + else: + raise TranslationError("unsupported type (in _discard)", node.expr) + + + def _if(self, node, current_klass): + for i in range(len(node.tests)): + test, consequence = node.tests[i] + if i == 0: + keyword = "if" + else: + keyword = "else if" + + self._if_test(keyword, test, consequence, current_klass) + + if node.else_: + keyword = "else" + test = None + consequence = node.else_ + + self._if_test(keyword, test, consequence, current_klass) + + + def _if_test(self, keyword, test, consequence, current_klass): + if test: + expr = self.expr(test, current_klass) + + print >>self.output, " " + keyword + " (pyjslib.bool(" + expr + ")) {" + else: + print >>self.output, " " + keyword + " {" + + if isinstance(consequence, ast.Stmt): + for child in consequence.nodes: + self._stmt(child, current_klass) + else: + raise TranslationError("unsupported type (in _if_test)", consequence) + + print >>self.output, " }" + + + def _from(self, node): + for name in node.names: + # look up "hack" in AppTranslator as to how findFile gets here + module_name = node.modname + "." + name[0] + try: + ff = self.findFile(module_name + ".py") + except Exception: + ff = None + if ff: + self.add_imported_module(module_name) + else: + self.imported_classes[name[0]] = node.modname + + + def _compare(self, node, current_klass): + lhs = self.expr(node.expr, current_klass) + + if len(node.ops) != 1: + raise TranslationError("only one ops supported (in _compare)", node) + + op = node.ops[0][0] + rhs_node = node.ops[0][1] + rhs = self.expr(rhs_node, current_klass) + + if op == "==": + return "pyjslib.eq(%s, %s)" % (lhs, rhs) + if op == "in": + return rhs + ".__contains__(" + lhs + ")" + elif op == "not in": + return "!" + rhs + ".__contains__(" + lhs + ")" + elif op == "is": + op = "===" + elif op == "is not": + op = "!==" + + return "(" + lhs + " " + op + " " + rhs + ")" + + + def _not(self, node, current_klass): + expr = self.expr(node.expr, current_klass) + + return "!(" + expr + ")" + + def _or(self, node, current_klass): + expr = "("+(") || (".join([self.expr(child, current_klass) for child in node.nodes]))+')' + return expr + + def _and(self, node, current_klass): + expr = "("+(") && (".join([self.expr(child, current_klass) for child in node.nodes]))+")" + return expr + + def _for(self, node, current_klass): + assign_name = "" + assign_tuple = "" + + # based on Bob Ippolito's Iteration in Javascript code + if isinstance(node.assign, ast.AssName): + assign_name = node.assign.name + self.add_local_arg(assign_name) + if node.assign.flags == "OP_ASSIGN": + op = "=" + elif isinstance(node.assign, ast.AssTuple): + op = "=" + i = 0 + for child in node.assign: + child_name = child.name + if assign_name == "": + assign_name = "temp_" + child_name + self.add_local_arg(child_name) + assign_tuple += """ + var %(child_name)s %(op)s %(assign_name)s.__getitem__(%(i)i); + """ % locals() + i += 1 + else: + raise TranslationError("unsupported type (in _for)", node.assign) + + if isinstance(node.list, ast.Name): + list_expr = self._name(node.list, current_klass) + elif isinstance(node.list, ast.Getattr): + list_expr = self._getattr(node.list, current_klass) + elif isinstance(node.list, ast.CallFunc): + list_expr = self._callfunc(node.list, current_klass) + else: + raise TranslationError("unsupported type (in _for)", node.list) + + lhs = "var " + assign_name + iterator_name = "__" + assign_name + + print >>self.output, """ + var %(iterator_name)s = %(list_expr)s.__iter__(); + try { + while (true) { + %(lhs)s %(op)s %(iterator_name)s.next(); + %(assign_tuple)s + """ % locals() + for node in node.body.nodes: + self._stmt(node, current_klass) + print >>self.output, """ + } + } catch (e) { + if (e.__name__ != pyjslib.StopIteration.__name__) { + throw e; + } + } + """ % locals() + + + def _while(self, node, current_klass): + test = self.expr(node.test, current_klass) + print >>self.output, " while (pyjslib.bool(" + test + ")) {" + if isinstance(node.body, ast.Stmt): + for child in node.body.nodes: + self._stmt(child, current_klass) + else: + raise TranslationError("unsupported type (in _while)", node.body) + print >>self.output, " }" + + + def _const(self, node): + if isinstance(node.value, int): + return str(node.value) + elif isinstance(node.value, float): + return str(node.value) + elif isinstance(node.value, basestring): + v = node.value + if isinstance(node.value, unicode): + v = v.encode('utf-8') + return "String('%s')" % escapejs(v) + elif node.value is None: + return "null" + else: + raise TranslationError("unsupported type (in _const)", node) + + def _unaryadd(self, node, current_klass): + return self.expr(node.expr, current_klass) + + def _unarysub(self, node, current_klass): + return "-" + self.expr(node.expr, current_klass) + + def _add(self, node, current_klass): + return self.expr(node.left, current_klass) + " + " + self.expr(node.right, current_klass) + + def _sub(self, node, current_klass): + return self.expr(node.left, current_klass) + " - " + self.expr(node.right, current_klass) + + def _div(self, node, current_klass): + return self.expr(node.left, current_klass) + " / " + self.expr(node.right, current_klass) + + def _mul(self, node, current_klass): + return self.expr(node.left, current_klass) + " * " + self.expr(node.right, current_klass) + + def _mod(self, node, current_klass): + if isinstance(node.left, ast.Const) and isinstance(node.left.value, StringType): + self.imported_js.add("sprintf.js") # Include the sprintf functionality if it is used + return "sprintf("+self.expr(node.left, current_klass) + ", " + self.expr(node.right, current_klass)+")" + return self.expr(node.left, current_klass) + " % " + self.expr(node.right, current_klass) + + def _invert(self, node, current_klass): + return "~" + self.expr(node.expr, current_klass) + + def _bitand(self, node, current_klass): + return " & ".join([self.expr(child, current_klass) for child in node.nodes]) + + def _bitshiftleft(self, node, current_klass): + return self.expr(node.left, current_klass) + " << " + self.expr(node.right, current_klass) + + def _bitshiftright(self, node, current_klass): + return self.expr(node.left, current_klass) + " >>> " + self.expr(node.right, current_klass) + + def _bitxor(self,node, current_klass): + return " ^ ".join([self.expr(child, current_klass) for child in node.nodes]) + + def _bitor(self, node, current_klass): + return " | ".join([self.expr(child, current_klass) for child in node.nodes]) + + def _subscript(self, node, current_klass): + if node.flags == "OP_APPLY": + if len(node.subs) == 1: + return self.expr(node.expr, current_klass) + ".__getitem__(" + self.expr(node.subs[0], current_klass) + ")" + else: + raise TranslationError("must have one sub (in _subscript)", node) + else: + raise TranslationError("unsupported flag (in _subscript)", node) + + def _subscript_stmt(self, node, current_klass): + if node.flags == "OP_DELETE": + print >>self.output, " " + self.expr(node.expr, current_klass) + ".__delitem__(" + self.expr(node.subs[0], current_klass) + ");" + else: + raise TranslationError("unsupported flag (in _subscript)", node) + + def _list(self, node, current_klass): + return "new pyjslib.List([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])" + + def _dict(self, node, current_klass): + items = [] + for x in node.items: + key = self.expr(x[0], current_klass) + value = self.expr(x[1], current_klass) + items.append("[" + key + ", " + value + "]") + return "new pyjslib.Dict([" + ", ".join(items) + "])" + + def _tuple(self, node, current_klass): + return "new pyjslib.Tuple([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])" + + def _lambda(self, node, current_klass): + if node.varargs: + raise TranslationError("varargs are not supported in Lambdas", node) + if node.kwargs: + raise TranslationError("kwargs are not supported in Lambdas", node) + res = cStringIO.StringIO() + arg_names = list(node.argnames) + function_args = ", ".join(arg_names) + for child in node.getChildNodes(): + expr = self.expr(child, None) + print >> res, "function (%s){" % function_args + self._default_args_handler(node, arg_names, None, + output=res) + print >> res, 'return %s;}' % expr + return res.getvalue() + + def _slice(self, node, current_klass): + if node.flags == "OP_APPLY": + lower = "null" + upper = "null" + if node.lower != None: + lower = self.expr(node.lower, current_klass) + if node.upper != None: + upper = self.expr(node.upper, current_klass) + return "pyjslib.slice(" + self.expr(node.expr, current_klass) + ", " + lower + ", " + upper + ")" + else: + raise TranslationError("unsupported flag (in _slice)", node) + + def _global(self, node, current_klass): + for name in node.names: + self.method_imported_globals.add(name) + + def expr(self, node, current_klass): + if isinstance(node, ast.Const): + return self._const(node) + # @@@ not sure if the parentheses should be here or in individual operator functions - JKT + elif isinstance(node, ast.Mul): + return " ( " + self._mul(node, current_klass) + " ) " + elif isinstance(node, ast.Add): + return " ( " + self._add(node, current_klass) + " ) " + elif isinstance(node, ast.Sub): + return " ( " + self._sub(node, current_klass) + " ) " + elif isinstance(node, ast.Div): + return " ( " + self._div(node, current_klass) + " ) " + elif isinstance(node, ast.Mod): + return self._mod(node, current_klass) + elif isinstance(node, ast.UnaryAdd): + return self._unaryadd(node, current_klass) + elif isinstance(node, ast.UnarySub): + return self._unarysub(node, current_klass) + elif isinstance(node, ast.Not): + return self._not(node, current_klass) + elif isinstance(node, ast.Or): + return self._or(node, current_klass) + elif isinstance(node, ast.And): + return self._and(node, current_klass) + elif isinstance(node, ast.Invert): + return self._invert(node, current_klass) + elif isinstance(node, ast.Bitand): + return "("+self._bitand(node, current_klass)+")" + elif isinstance(node,ast.LeftShift): + return self._bitshiftleft(node, current_klass) + elif isinstance(node, ast.RightShift): + return self._bitshiftright(node, current_klass) + elif isinstance(node, ast.Bitxor): + return "("+self._bitxor(node, current_klass)+")" + elif isinstance(node, ast.Bitor): + return "("+self._bitor(node, current_klass)+")" + elif isinstance(node, ast.Compare): + return self._compare(node, current_klass) + elif isinstance(node, ast.CallFunc): + return self._callfunc(node, current_klass) + elif isinstance(node, ast.Name): + return self._name(node, current_klass) + elif isinstance(node, ast.Subscript): + return self._subscript(node, current_klass) + elif isinstance(node, ast.Getattr): + return self._getattr(node, current_klass) + elif isinstance(node, ast.List): + return self._list(node, current_klass) + elif isinstance(node, ast.Dict): + return self._dict(node, current_klass) + elif isinstance(node, ast.Tuple): + return self._tuple(node, current_klass) + elif isinstance(node, ast.Slice): + return self._slice(node, current_klass) + elif isinstance(node, ast.Lambda): + return self._lambda(node, current_klass) + else: + raise TranslationError("unsupported type (in expr)", node) + + + +import cStringIO + +def translate(file_name, module_name, debug=False): + f = file(file_name, "r") + src = f.read() + f.close() + output = cStringIO.StringIO() + mod = compiler.parseFile(file_name) + t = Translator(module_name, module_name, module_name, src, debug, mod, output) + return output.getvalue() + + +class PlatformParser: + def __init__(self, platform_dir = "", verbose=True): + self.platform_dir = platform_dir + self.parse_cache = {} + self.platform = "" + self.verbose = verbose + + def setPlatform(self, platform): + self.platform = platform + + def parseModule(self, module_name, file_name): + + importing = False + if not self.parse_cache.has_key(file_name): + importing = True + mod = compiler.parseFile(file_name) + self.parse_cache[file_name] = mod + else: + mod = self.parse_cache[file_name] + + override = False + platform_file_name = self.generatePlatformFilename(file_name) + if self.platform and os.path.isfile(platform_file_name): + mod = copy.deepcopy(mod) + mod_override = compiler.parseFile(platform_file_name) + self.merge(mod, mod_override) + override = True + + if self.verbose: + if override: + print "Importing %s (Platform %s)" % (module_name, self.platform) + elif importing: + print "Importing %s" % (module_name) + + return mod, override + + def generatePlatformFilename(self, file_name): + (module_name, extension) = os.path.splitext(os.path.basename(file_name)) + platform_file_name = module_name + self.platform + extension + + return os.path.join(os.path.dirname(file_name), self.platform_dir, platform_file_name) + + def merge(self, tree1, tree2): + for child in tree2.node: + if isinstance(child, ast.Function): + self.replaceFunction(tree1, child.name, child) + elif isinstance(child, ast.Class): + self.replaceClassMethods(tree1, child.name, child) + + return tree1 + + def replaceFunction(self, tree, function_name, function_node): + # find function to replace + for child in tree.node: + if isinstance(child, ast.Function) and child.name == function_name: + self.copyFunction(child, function_node) + return + raise TranslationError("function not found: " + function_name, function_node) + + def replaceClassMethods(self, tree, class_name, class_node): + # find class to replace + old_class_node = None + for child in tree.node: + if isinstance(child, ast.Class) and child.name == class_name: + old_class_node = child + break + + if not old_class_node: + raise TranslationError("class not found: " + class_name, class_node) + + # replace methods + for function_node in class_node.code: + if isinstance(function_node, ast.Function): + found = False + for child in old_class_node.code: + if isinstance(child, ast.Function) and child.name == function_node.name: + found = True + self.copyFunction(child, function_node) + break + + if not found: + raise TranslationError("class method not found: " + class_name + "." + function_node.name, function_node) + + def copyFunction(self, target, source): + target.code = source.code + target.argnames = source.argnames + target.defaults = source.defaults + target.doc = source.doc # @@@ not sure we need to do this any more + +def dotreplace(fname): + path, ext = os.path.splitext(fname) + return path.replace(".", "/") + ext + +class AppTranslator: + + def __init__(self, library_dirs=[], parser=None, dynamic=False, + optimize=False, verbose=True): + self.extension = ".py" + self.optimize = optimize + self.library_modules = [] + self.overrides = {} + self.library_dirs = path + library_dirs + self.dynamic = dynamic + self.verbose = verbose + + if not parser: + self.parser = PlatformParser() + else: + self.parser = parser + + self.parser.dynamic = dynamic + + def findFile(self, file_name): + if os.path.isfile(file_name): + return file_name + + for library_dir in self.library_dirs: + file_name = dotreplace(file_name) + full_file_name = os.path.join( + os.path.abspath(os.path.dirname(__file__)), library_dir, file_name) + if os.path.isfile(full_file_name): + return full_file_name + + fnameinit, ext = os.path.splitext(file_name) + fnameinit = fnameinit + "/__init__.py" + + full_file_name = os.path.join( + os.path.abspath(os.path.dirname(__file__)), library_dir, fnameinit) + if os.path.isfile(full_file_name): + return full_file_name + + raise Exception("file not found: " + file_name) + + def _translate(self, module_name, is_app=True, debug=False, + imported_js=set()): + if module_name not in self.library_modules: + self.library_modules.append(module_name) + + file_name = self.findFile(module_name + self.extension) + + output = cStringIO.StringIO() + + f = file(file_name, "r") + src = f.read() + f.close() + + mod, override = self.parser.parseModule(module_name, file_name) + if override: + override_name = "%s.%s" % (self.parser.platform.lower(), + module_name) + self.overrides[override_name] = override_name + if is_app: + mn = '__main__' + else: + mn = module_name + t = Translator(mn, module_name, module_name, + src, debug, mod, output, self.dynamic, self.optimize, + self.findFile) + + module_str = output.getvalue() + imported_js.update(set(t.imported_js)) + imported_modules_str = "" + for module in t.imported_modules: + if module not in self.library_modules: + self.library_modules.append(module) + #imported_js.update(set(t.imported_js)) + #imported_modules_str += self._translate( + # module, False, debug=debug, imported_js=imported_js) + + return imported_modules_str + module_str + + + def translate(self, module_name, is_app=True, debug=False, + library_modules=[]): + app_code = cStringIO.StringIO() + lib_code = cStringIO.StringIO() + imported_js = set() + self.library_modules = [] + self.overrides = {} + for library in library_modules: + if library.endswith(".js"): + imported_js.add(library) + continue + self.library_modules.append(library) + if self.verbose: + print 'Including LIB', library + print >> lib_code, '\n//\n// BEGIN LIB '+library+'\n//\n' + print >> lib_code, self._translate( + library, False, debug=debug, imported_js=imported_js) + + print >> lib_code, "/* initialize static library */" + print >> lib_code, "%s%s();\n" % (UU, library) + + print >> lib_code, '\n//\n// END LIB '+library+'\n//\n' + if module_name: + print >> app_code, self._translate( + module_name, is_app, debug=debug, imported_js=imported_js) + for js in imported_js: + path = self.findFile(js) + if os.path.isfile(path): + if self.verbose: + print 'Including JS', js + print >> lib_code, '\n//\n// BEGIN JS '+js+'\n//\n' + print >> lib_code, file(path).read() + print >> lib_code, '\n//\n// END JS '+js+'\n//\n' + else: + print >>sys.stderr, 'Warning: Unable to find imported javascript:', js + return lib_code.getvalue(), app_code.getvalue() + +usage = """ + usage: %s file_name [module_name] +""" + +def main(): + import sys + if len(sys.argv)<2: + print >> sys.stderr, usage % sys.argv[0] + sys.exit(1) + file_name = os.path.abspath(sys.argv[1]) + if not os.path.isfile(file_name): + print >> sys.stderr, "File not found %s" % file_name + sys.exit(1) + if len(sys.argv) > 2: + module_name = sys.argv[2] + else: + module_name = None + print translate(file_name, module_name), + +if __name__ == "__main__": + main() + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/svgui.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/svgui.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,112 @@ +import wx +import os, sys, shutil + +from ConfigTree import opjimg +from confnodes.python import PythonCodeTemplate + +from pyjs import translate + +from docutils import * + +class RootClass: + + ConfNodeMethods = [ + {"bitmap" : os.path.join("images","ImportSVG"), + "name" : _("Import SVG"), + "tooltip" : _("Import SVG"), + "method" : "_ImportSVG"}, + {"bitmap" : os.path.join("images","ImportSVG"), + "name" : _("Inkscape"), + "tooltip" : _("Create HMI"), + "method" : "_StartInkscape"}, + ] + + def ConfNodePath(self): + return os.path.join(self.PlugParent.ConfNodePath(), "modules", self.PlugType) + + def _getSVGpath(self): + # define name for IEC raw code file + return os.path.join(self.PlugPath(), "gui.svg") + + def _getSVGUIserverpath(self): + return os.path.join(os.path.dirname(__file__), "svgui_server.py") + + def PlugGenerate_C(self, buildpath, locations): + """ + Return C code generated by iec2c compiler + when _generate_softPLC have been called + @param locations: ignored + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + location_str = "_".join(map(lambda x:str(x), current_location)) + + res = ([], "", False) + + svgfile=self._getSVGpath() + if os.path.exists(svgfile): + res += (("gui.svg", file(svgfile,"rb")),) + + svguiserverfile = open(self._getSVGUIserverpath(), 'r') + svguiservercode = svguiserverfile.read() + svguiserverfile.close() + + svguilibpath = os.path.join(self._getBuildPath(), "svguilib.js") + svguilibfile = open(svguilibpath, 'w') + svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "sys.py"), "sys")) + svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "_pyjs.js"), 'r').read()) + svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "pyjslib.py"), "pyjslib")) + svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "svguilib.py"), "svguilib")) + svguilibfile.write("pyjslib();\nsvguilib();\n") + svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "json.js"), 'r').read()) + svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "livesvg.js"), 'r').read()) + svguilibfile.close() + jsmodules = {"LiveSVGPage": "svguilib.js"} + res += (("svguilib.js", file(svguilibpath,"rb")),) + + runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) + runtimefile = open(runtimefile_path, 'w') + runtimefile.write(svguiservercode % {"svgfile" : "gui.svg"}) + runtimefile.write(""" +def _runtime_%(location)s_begin(): + website.LoadHMI(%(svgui_class)s, %(jsmodules)s) + +def _runtime_%(location)s_cleanup(): + website.UnLoadHMI() + +""" % {"location": location_str, + "svgui_class": "SVGUI_HMI", + "jsmodules" : str(jsmodules), + }) + runtimefile.close() + + res += (("runtime_%s.py"%location_str, file(runtimefile_path,"rb")),) + + return res + + def _ImportSVG(self): + dialog = wx.FileDialog(self.GetPlugRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN) + if dialog.ShowModal() == wx.ID_OK: + svgpath = dialog.GetPath() + if os.path.isfile(svgpath): + shutil.copy(svgpath, self._getSVGpath()) + else: + self.GetPlugRoot().logger.write_error(_("No such SVG file: %s\n")%svgpath) + dialog.Destroy() + + def _StartInkscape(self): + svgfile = self._getSVGpath() + open_inkscape = True + if not self.GetPlugRoot().CheckProjectPathPerm(): + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen Inkscape anyway ?"), + _("Open Inkscape"), + wx.YES_NO|wx.ICON_QUESTION) + open_inkscape = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_inkscape: + if not os.path.isfile(svgfile): + svgfile = None + open_svg(svgfile) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/svgui_server.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/svgui_server.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,130 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os + +from nevow import rend, appserver, inevow, tags, loaders, athena +import simplejson as json + +svgfile = '%(svgfile)s' + +svguiWidgets = {} + +currentId = 0 +def getNewId(): + global currentId + currentId += 1 + return currentId + +class SvguiWidget: + + def __init__(self, classname, id, **kwargs): + self.classname = classname + self.id = id + self.attrs = kwargs.copy() + self.inputs = {} + self.outputs = {} + self.inhibit = False + self.changed = False + + def setinput(self, attrname, value): + self.inputs[attrname] = value + + def getinput(self, attrname, default=None): + if not self.inputs.has_key(attrname): + self.inputs[attrname] = default + return self.inputs[attrname] + + def setoutput(self, attrname, value): + if self.outputs.get(attrname) != value: + self.outputs[attrname] = value + self.changed = True + self.RefreshInterface() + + def updateoutputs(self, **kwargs): + for attrname, value in kwargs.iteritems(): + if self.outputs.get(attrname) != value: + self.outputs[attrname] = value + self.changed = True + self.RefreshInterface() + + def RefreshInterface(self): + interface = website.getHMI() + if isinstance(interface, SVGUI_HMI) and self.changed and not self.inhibit: + self.changed = False + d = interface.sendData(self) + if d is not None: + self.inhibit = True + d.addCallback(self.InterfaceRefreshed) + + def InterfaceRefreshed(self, result): + self.inhibit = False + if self.changed: + self.RefreshInterface() + +def get_object_init_state(obj): + # Convert objects to a dictionary of their representation + attrs = obj.attrs.copy() + attrs.update(obj.inputs) + d = { '__class__': obj.classname, + 'id': obj.id, + 'kwargs': json.dumps(attrs), + } + return d + +def get_object_current_state(obj): + # Convert objects to a dictionary of their representation + d = { '__class__': obj.classname, + 'id': obj.id, + 'kwargs': json.dumps(obj.outputs), + } + return d + +class SVGUI_HMI(website.PLCHMI): + jsClass = u"LiveSVGPage.LiveSVGWidget" + + docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ + tags.xml(loaders.xmlfile(os.path.join(WorkingDir, svgfile))), + ]) + + def HMIinitialisation(self): + gadgets = [] + for gadget in svguiWidgets.values(): + gadgets.append(unicode(json.dumps(gadget, default=get_object_init_state, indent=2), 'ascii')) + d = self.callRemote('init', gadgets) + d.addCallback(self.HMIinitialised) + + def sendData(self,data): + if self.initialised: + return self.callRemote('receiveData',unicode(json.dumps(data, default=get_object_current_state, indent=2), 'ascii')) + return None + + def setattr(self, id, attrname, value): + svguiWidgets[id].setinput(attrname, value) + +def createSVGUIControl(*args, **kwargs): + id = getNewId() + gad = SvguiWidget(args[0], id, **kwargs) + svguiWidgets[id] = gad + gadget = [unicode(json.dumps(gad, default=get_object_init_state, indent=2), 'ascii')] + interface = website.getHMI() + if isinstance(interface, SVGUI_HMI) and interface.initialised: + interface.callRemote('init', gadget) + return id + +def setAttr(id, attrname, value): + gad = svguiWidgets.get(id, None) + if gad is not None: + gad.setoutput(attrname, value) + +def updateAttr(id, **kwargs): + gad = svguiWidgets.get(id, None) + if gad is not None: + gad.updateoutput(**kwargs) + +def getAttr(id, attrname, default=None): + gad = svguiWidgets.get(id, None) + if gad is not None: + return gad.getinput(attrname, default) + return default + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/svgui/svguilib.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/svgui/svguilib.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,117 @@ + +class button: + + def __init__(self, parent, id, args): + self.parent = parent + self.id = id + self.back_elt = getSVGElementById(args.back_id) + self.sele_elt = getSVGElementById(args.sele_id) + self.toggle = args.toggle + self.active = args.active + if args.state != undefined: + self.state = args.state + else: + self.state = False + self.dragging = False + if self.toggle: + self.up = not self.state + else: + self.up = True + + # Add event on each element of the button + if self.active: + self.back_elt.addEventListener("mouseup", self, False) + self.back_elt.addEventListener("mousedown", self, False) + self.back_elt.addEventListener("mouseover", self, False) + self.back_elt.addEventListener("mouseout", self, False) + + self.sele_elt.addEventListener("mouseup", self, False) + self.sele_elt.addEventListener("mousedown", self, False) + self.sele_elt.addEventListener("mouseover", self, False) + self.sele_elt.addEventListener("mouseout", self, False) + + blockSVGElementDrag(self.back_elt) + blockSVGElementDrag(self.sele_elt) + + self.updateElements() + + # method to display the current state of interface + def updateElements(self): + if self.up: + self.sele_elt.setAttribute("display", "none") + self.back_elt.removeAttribute("display") + else: + self.sele_elt.removeAttribute("display") + self.back_elt.setAttribute("display", "none") + + def updateValues(self, values): + if values.state != self.state: + self.state = values.state + self.up = not self.state + updateAttr(self.id, 'state', self.state) + self.updateElements() + + def handleEvent(self, evt): + # Quand le bouton de la souris est presse + if evt.type == "mousedown": + evt.stopPropagation() + setCurrentObject(self) + + self.dragging = True + + if self.toggle: + self.up = self.state + else: + self.up = False + self.state = True + updateAttr(self.id, 'state', self.state) + self.updateElements() + + if isCurrentObject(self) and self.dragging: + # Quand le bouton est survole + if evt.type == "mouseover" and self.toggle: + self.up = self.state + self.updateElements() + + # Quand le curseur quitte la zone du bouton + elif evt.type == "mouseout" and self.toggle: + self.up = not self.state + self.updateElements() + + # Quand le bouton de la souris est relache + elif evt.type == "mouseup": + evt.stopPropagation() + if self.toggle and self.up == self.state: + self.state = not self.state + updateAttr(self.id, 'state', self.state) + elif not self.toggle: + self.up = True + self.state = False + updateAttr(self.id, 'state', self.state) + self.updateElements() + self.dragging = False + +class textControl: + + def __init__(self, parent, id, args): + self.parent = parent + self.id = id + self.back_elt = getSVGElementById(args.back_id) + if args.text != undefined: + self.text = args.text + else: + self.text = "" + self.updateElements() + + def updateValues(self, values): + if values.text != self.value: + self.text = values.text + updateAttr(self.id, 'text', self.text) + self.updateElements() + + def updateElements(self): + self.back_elt.firstChild.firstChild.textContent = self.text + + def handleEvent(self, evt): + pass + \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/wxglade_hmi/README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/wxglade_hmi/README Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +WxGlade HMI \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/wxglade_hmi/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/wxglade_hmi/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,1 @@ +from wxglade_hmi import * diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/modules/wxglade_hmi/wxglade_hmi.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/modules/wxglade_hmi/wxglade_hmi.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,124 @@ +import wx +import os, sys +from xml.dom import minidom + +from ConfigTree import opjimg +from confnodes.python import PythonCodeTemplate + +class RootClass(PythonCodeTemplate): + + ConfNodeMethods = [ + {"bitmap" : opjimg("editWXGLADE"), + "name" : _("WXGLADE GUI"), + "tooltip" : _("Edit a WxWidgets GUI with WXGlade"), + "method" : "_editWXGLADE"}, + ] + + def _getWXGLADEpath(self): + # define name for IEC raw code file + return os.path.join(self.PlugPath(), "hmi.wxg") + + def launch_wxglade(self, options, wait=False): + from wxglade import __file__ as fileName + path = os.path.dirname(fileName) + glade = os.path.join(path, 'wxglade.py') + if wx.Platform == '__WXMSW__': + glade = "\"%s\""%glade + mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] + os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options) + + + def PlugGenerate_C(self, buildpath, locations): + """ + Return C code generated by iec2c compiler + when _generate_softPLC have been called + @param locations: ignored + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + location_str = "_".join(map(lambda x:str(x), current_location)) + + runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) + runtimefile = open(runtimefile_path, 'w') + + hmi_frames = {} + + wxgfile_path=self._getWXGLADEpath() + if os.path.exists(wxgfile_path): + wxgfile = open(wxgfile_path, 'r') + wxgtree = minidom.parse(wxgfile) + wxgfile.close() + + for node in wxgtree.childNodes[1].childNodes: + if node.nodeType == wxgtree.ELEMENT_NODE: + hmi_frames[node._attrs["name"].value] = node._attrs["class"].value + + hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py") + if wx.Platform == '__WXMSW__': + wxgfile_path = "\"%s\""%wxgfile_path + wxghmipyfile_path = "\"%s\""%hmipyfile_path + else: + wxghmipyfile_path = hmipyfile_path + self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) + + hmipyfile = open(hmipyfile_path, 'r') + runtimefile.write(hmipyfile.read()) + hmipyfile.close() + + runtimefile.write(self.GetPythonCode()) + runtimefile.write(""" +%(declare)s + +def _runtime_%(location)s_begin(): + global %(global)s + + def OnCloseFrame(evt): + wx.MessageBox(_("Please stop PLC to close")) + + %(init)s + +def _runtime_%(location)s_cleanup(): + global %(global)s + + %(cleanup)s + +""" % {"location": location_str, + "declare": "\n".join(map(lambda x:"%s = None" % x, hmi_frames.keys())), + "global": ",".join(hmi_frames.keys()), + "init": "\n".join(map(lambda x: """ + %(name)s = %(class)s(None) + %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) + %(name)s.Show() +""" % {"name": x[0], "class": x[1]}, + hmi_frames.items())), + "cleanup": "\n ".join(map(lambda x:"%s.Destroy()" % x, hmi_frames.keys()))}) + runtimefile.close() + + return [], "", False, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) + + def _editWXGLADE(self): + wxg_filename = self._getWXGLADEpath() + open_wxglade = True + if not self.GetPlugRoot().CheckProjectPathPerm(): + dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, + _("You don't have write permissions.\nOpen wxGlade anyway ?"), + _("Open wxGlade"), + wx.YES_NO|wx.ICON_QUESTION) + open_wxglade = dialog.ShowModal() == wx.ID_YES + dialog.Destroy() + if open_wxglade: + if not os.path.exists(wxg_filename): + hmi_name = self.BaseParams.getName() + open(wxg_filename,"w").write(""" + + + + frame_1 + + + """ % {"name": hmi_name, "class": "Class_%s" % hmi_name}) + if wx.Platform == '__WXMSW__': + wxg_filename = "\"%s\""%wxg_filename + self.launch_wxglade([wxg_filename]) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/plc_python.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/plc_python.c Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,216 @@ +/* + * Python Asynchronous execution code + * + * PLC put python commands in a fifo, respecting execution order + * with the help of C pragmas inserted in python_eval FB code + * + * Buffer content is read asynchronously, (from non real time part), + * commands are executed and result stored for later use by PLC. + * + * In this implementation, fifo is a list of pointer to python_eval + * function blocks structures. Some local variables have been added in + * python_eval interface. We use those local variables as buffer and state + * flags. + * + * */ + +#include "iec_types_all.h" +#include "POUS.h" +#include + +/* The fifo (fixed size, as number of FB is fixed) */ +static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d]; +/* Producer and consumer cursors */ +static int Current_PLC_EvalFB; +static int Current_Python_EvalFB; + +/* A global IEC-Python gateway state, for use inside python_eval FBs*/ +static int PythonState; +#define PYTHON_LOCKED_BY_PYTHON 0 +#define PYTHON_LOCKED_BY_PLC 1 +#define PYTHON_MUSTWAKEUP 2 +#define PYTHON_FINISHED 4 + +/* Each python_eval FunctionBlock have it own state */ +#define PYTHON_FB_FREE 0 +#define PYTHON_FB_REQUESTED 1 +#define PYTHON_FB_PROCESSING 2 +#define PYTHON_FB_ANSWERED 3 + +int WaitPythonCommands(void); +void UnBlockPythonCommands(void); +int TryLockPython(void); +void UnLockPython(void); +void LockPython(void); + +int __init_%(location)s() +{ + int i; + /* Initialize cursors */ + Current_Python_EvalFB = 0; + Current_PLC_EvalFB = 0; + PythonState = PYTHON_LOCKED_BY_PYTHON; + for(i = 0; i < %(python_eval_fb_count)d; i++) + EvalFBs[i] = NULL; + return 0; +} + +void __cleanup_%(location)s() +{ + PythonState = PYTHON_FINISHED; + UnBlockPythonCommands(); +} + +void __retrieve_%(location)s() +{ + /* Check Python thread is not being + * modifying internal python_eval data */ + PythonState = TryLockPython() ? + PYTHON_LOCKED_BY_PLC : + PYTHON_LOCKED_BY_PYTHON; + /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON + * and python_eval will no do anything */ +} + +void __publish_%(location)s() +{ + if(PythonState & PYTHON_LOCKED_BY_PLC){ + /* If runnig PLC did push something in the fifo*/ + if(PythonState & PYTHON_MUSTWAKEUP){ + /* WakeUp python thread */ + UnBlockPythonCommands(); + } + UnLockPython(); + } +} +/** + * Called by the PLC, each time a python_eval + * FB instance is executed + */ +void __PythonEvalFB(int poll, PYTHON_EVAL* data__) +{ + /* detect rising edge on TRIG to trigger evaluation */ + if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || + /* polling is equivalent to trig on value rather than on rising edge*/ + (poll && __GET_VAR(data__->TRIG) )) && + /* trig only if not already trigged */ + __GET_VAR(data__->TRIGGED) == 0){ + /* mark as trigged */ + __SET_VAR(data__->, TRIGGED, 1); + /* make a safe copy of the code */ + __SET_VAR(data__->, PREBUFFER, __GET_VAR(data__->CODE)); + } + /* retain value for next rising edge detection */ + __SET_VAR(data__->, TRIGM1, __GET_VAR(data__->TRIG)); + + /* python thread is not in ? */ + if( PythonState & PYTHON_LOCKED_BY_PLC){ + /* if some answer are waiting, publish*/ + if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ + /* Copy buffer content into result*/ + __SET_VAR(data__->, RESULT, __GET_VAR(data__->BUFFER)); + /* signal result presece to PLC*/ + __SET_VAR(data__->, ACK, 1); + /* Mark as free */ + __SET_VAR(data__->, STATE, PYTHON_FB_FREE); + /* mark as not trigged */ + if(!poll) + __SET_VAR(data__->, TRIGGED, 0); + /*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + }else if(poll){ + /* when in polling, no answer == ack down */ + __SET_VAR(data__->, ACK, 0); + } + /* got the order to act ?*/ + if(__GET_VAR(data__->TRIGGED) == 1 && + /* and not already being processed */ + __GET_VAR(data__->STATE) == PYTHON_FB_FREE) + { + /* Enter the block in the fifo + * Don't have to check if fifo cell is free + * as fifo size == FB count, and a FB cannot + * be requested twice */ + EvalFBs[Current_PLC_EvalFB] = data__; + /* copy into BUFFER local*/ + __SET_VAR(data__->, BUFFER, __GET_VAR(data__->PREBUFFER)); + /* Set ACK pin to low so that we can set a rising edge on result */ + if(!poll){ + /* when not polling, a new answer imply reseting ack*/ + __SET_VAR(data__->, ACK, 0); + }else{ + /* when in polling, acting reset trigger */ + __SET_VAR(data__->, TRIGGED, 0); + } + /* Mark FB busy */ + __SET_VAR(data__->, STATE, PYTHON_FB_REQUESTED); + /* Have to wakeup python thread in case he was asleep */ + PythonState |= PYTHON_MUSTWAKEUP; + /*printf("__PythonEvalFB push %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ + /* Get a new line */ + Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d; + } + } +} + +char* PythonIterator(char* result) +{ + char* next_command; + PYTHON_EVAL* data__; + //printf("PythonIterator result %%s\n", result); + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + /* take python mutex to prevent changing PLC data while PLC running */ + LockPython(); + /* Get current FB */ + data__ = EvalFBs[Current_Python_EvalFB]; + if(data__ && /* may be null at first run */ + __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ + /* If result not None */ + if(result){ + /* Get results len */ + __SET_VAR(data__->, BUFFER, strlen(result), .len); + /* prevent results overrun */ + if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) + { + __SET_VAR(data__->, BUFFER, STR_MAX_LEN, .len ); + /* TODO : signal error */ + } + /* Copy results to buffer */ + strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); + }else{ + __SET_VAR(data__->, BUFFER, 0, .len); + } + /* remove block from fifo*/ + EvalFBs[Current_Python_EvalFB] = NULL; + /* Mark block as answered */ + __SET_VAR(data__->, STATE, PYTHON_FB_ANSWERED); + /* Get a new line */ + Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d; + //printf("PythonIterator ++ Current_Python_EvalFB %%d\n", Current_Python_EvalFB); + } + /* while next slot is empty */ + while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || + /* or doesn't contain command */ + __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) + { + UnLockPython(); + /* wait next FB to eval */ + //printf("PythonIterator wait\n"); + if(WaitPythonCommands()) return NULL; + /*emergency exit*/ + if(PythonState & PYTHON_FINISHED) return NULL; + LockPython(); + } + /* Mark block as processing */ + __SET_VAR(data__->, STATE, PYTHON_FB_PROCESSING); + //printf("PythonIterator\n"); + /* make BUFFER a null terminated string */ + __SET_VAR(data__->, BUFFER, 0, .body[__GET_VAR(data__->BUFFER, .len)]); + /* next command is BUFFER */ + next_command = (char*)__GET_VAR(data__->BUFFER, .body); + /* free python mutex */ + UnLockPython(); + /* return the next command to eval */ + return next_command; +} + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/pous.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/pous.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,457 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + N + + + + + + + TRIG + + + + + + + CODE + + + + + + + + + + + ACK + + + + + + + + + + + RESULT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + COUNTER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + USINT#1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + USINT#0 + + + + + + + + + + + COUNTER + + + + + + + + + + diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/python.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/python.py Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,185 @@ +import wx +import os +import modules +from ConfigTree import ConfigTreeNode, opjimg +from PLCControler import UndoBuffer +from PythonEditor import PythonEditor + +from xml.dom import minidom +from xmlclass import * +import cPickle + +PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "python_xsd.xsd")) + +class PythonCodeTemplate: + + EditorType = PythonEditor + + def __init__(self): + + self.ConfNodeMethods.insert(0, + {"bitmap" : opjimg("editPYTHONcode"), + "name" : _("Edit Python File"), + "tooltip" : _("Edit Python File"), + "method" : "_OpenView"}, + ) + + filepath = self.PythonFileName() + + self.PythonCode = PythonClasses["Python"]() + if os.path.isfile(filepath): + xmlfile = open(filepath, 'r') + tree = minidom.parse(xmlfile) + xmlfile.close() + + for child in tree.childNodes: + if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python": + self.PythonCode.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) + self.CreatePythonBuffer(True) + else: + self.CreatePythonBuffer(False) + self.OnPlugSave() + + def ConfNodePath(self): + return os.path.join(self.PlugParent.ConfNodePath(), "modules", self.PlugType) + + def PythonFileName(self): + return os.path.join(self.PlugPath(), "python.xml") + + def GetFilename(self): + if self.PythonBuffer.IsCurrentSaved(): + return "python" + else: + return "~python~" + + def SetPythonCode(self, text): + self.PythonCode.settext(text) + + def GetPythonCode(self): + return self.PythonCode.gettext() + + def PlugTestModified(self): + return self.ChangesToSave or not self.PythonIsSaved() + + def OnPlugSave(self): + filepath = self.PythonFileName() + + text = "\n" + extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", + "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", + "xsi:schemaLocation" : "python_xsd.xsd"} + text += self.PythonCode.generateXMLText("Python", 0, extras) + + xmlfile = open(filepath,"w") + xmlfile.write(text.encode("utf-8")) + xmlfile.close() + + self.MarkPythonAsSaved() + return True + +#------------------------------------------------------------------------------- +# Current Buffering Management Functions +#------------------------------------------------------------------------------- + + """ + Return a copy of the project + """ + def Copy(self, model): + return cPickle.loads(cPickle.dumps(model)) + + def CreatePythonBuffer(self, saved): + self.Buffering = False + self.PythonBuffer = UndoBuffer(cPickle.dumps(self.PythonCode), saved) + + def BufferPython(self): + self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) + + def StartBuffering(self): + self.Buffering = True + + def EndBuffering(self): + if self.Buffering: + self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) + self.Buffering = False + + def MarkPythonAsSaved(self): + self.EndBuffering() + self.PythonBuffer.CurrentSaved() + + def PythonIsSaved(self): + return self.PythonBuffer.IsCurrentSaved() and not self.Buffering + + def LoadPrevious(self): + self.EndBuffering() + self.PythonCode = cPickle.loads(self.PythonBuffer.Previous()) + + def LoadNext(self): + self.PythonCode = cPickle.loads(self.PythonBuffer.Next()) + + def GetBufferState(self): + first = self.PythonBuffer.IsFirst() and not self.Buffering + last = self.PythonBuffer.IsLast() + return not first, not last + +def _GetClassFunction(name): + def GetRootClass(): + __import__("confnodes.python.modules." + name) + return getattr(modules, name).RootClass + return GetRootClass + +class RootClass(PythonCodeTemplate): + + # For root object, available Childs Types are modules of the modules packages. + PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(modules.__all__,modules.helps)] + + def ConfNodePath(self): + return os.path.join(self.PlugParent.ConfNodePath(), self.PlugType) + + def PlugGenerate_C(self, buildpath, locations): + """ + Generate C code + @param current_location: Tupple containing confnode IEC location : %I0.0.4.5 => (0,0,4,5) + @param locations: List of complete variables locations \ + [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) + "NAME" : name of the variable (generally "__IW0_1_2" style) + "DIR" : direction "Q","I" or "M" + "SIZE" : size "X", "B", "W", "D", "L" + "LOC" : tuple of interger for IEC location (0,1,2,...) + }, ...] + @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND + """ + current_location = self.GetCurrentLocation() + # define a unique name for the generated C file + location_str = "_".join(map(lambda x:str(x), current_location)) + + ctr = self.GetPlugRoot() + ctr.GetIECProgramsAndVariables() + + plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c") + plc_python_file = open(plc_python_filepath, 'r') + plc_python_code = plc_python_file.read() + plc_python_file.close() + python_eval_fb_list = [] + for v in ctr._VariablesList: + if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: + python_eval_fb_list.append(v) + python_eval_fb_count = max(1, len(python_eval_fb_list)) + + # prepare python code + plc_python_code = plc_python_code % { + "python_eval_fb_count": python_eval_fb_count, + "location": location_str} + + Gen_Pythonfile_path = os.path.join(buildpath, "python_%s.c"%location_str) + pythonfile = open(Gen_Pythonfile_path,'w') + pythonfile.write(plc_python_code) + pythonfile.close() + + runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) + runtimefile = open(runtimefile_path, 'w') + runtimefile.write(self.GetPythonCode()) + runtimefile.close() + + matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()) + + return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) diff -r 180e4a7d945c -r 1c23952dbde1 confnodes/python/python_xsd.xsd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/confnodes/python/python_xsd.xsd Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,18 @@ + + + + + + + Formatted text according to parts of XHTML 1.1 + + + + + + + diff -r 180e4a7d945c -r 1c23952dbde1 connectors/LPC/LPCBootObject.py --- a/connectors/LPC/LPCBootObject.py Thu May 03 19:02:34 2012 +0200 +++ b/connectors/LPC/LPCBootObject.py Mon May 07 18:47:29 2012 +0200 @@ -26,8 +26,8 @@ from LPCObject import * class LPCBootObject(LPCObject): - def __init__(self, pluginsroot, comportstr): - LPCObject.__init__(self, pluginsroot, comportstr) + def __init__(self, confnodesroot, comportstr): + LPCObject.__init__(self, confnodesroot, comportstr) self.successfully_transfered = False def connect(self,comport): diff -r 180e4a7d945c -r 1c23952dbde1 connectors/LPC/LPCObject.py --- a/connectors/LPC/LPCObject.py Thu May 03 19:02:34 2012 +0200 +++ b/connectors/LPC/LPCObject.py Mon May 07 18:47:29 2012 +0200 @@ -27,16 +27,16 @@ class LPCObject(): - def __init__(self, pluginsroot, comportstr): + def __init__(self, confnodesroot, comportstr): self.PLCStatus = "Disconnected" - self.pluginsroot = pluginsroot - self.PLCprint = pluginsroot.logger.writeyield + self.confnodesroot = confnodesroot + self.PLCprint = confnodesroot.logger.writeyield self._Idxs = [] comport = int(comportstr[3:]) - 1 try: self.connect(comportstr) except Exception,e: - self.pluginsroot.logger.write_error(str(e)+"\n") + self.confnodesroot.logger.write_error(str(e)+"\n") self.SerialConnection = None self.PLCStatus = "Disconnected" @@ -46,14 +46,14 @@ self.PLCStatus, res = self.SerialConnection.HandleTransaction(transaction) return res except LPCProtoError,e: - self.pluginsroot.logger.write(_("PLC disconnected\n")) + self.confnodesroot.logger.write(_("PLC disconnected\n")) if self.SerialConnection is not None: self.SerialConnection.close() self.SerialConnection = None self.PLCStatus = "Disconnected" return None except Exception,e: - self.pluginsroot.logger.write_warning(str(e)+"\n") + self.confnodesroot.logger.write_warning(str(e)+"\n") def StartPLC(self, debug=False): raise LPCProtoError("Not implemented") diff -r 180e4a7d945c -r 1c23952dbde1 connectors/LPC/__init__.py --- a/connectors/LPC/__init__.py Thu May 03 19:02:34 2012 +0200 +++ b/connectors/LPC/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -19,7 +19,7 @@ #License along with this library; if not, write to the Free Software #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -def LPC_connector_factory(uri, pluginsroot): +def LPC_connector_factory(uri, confnodesroot): """ This returns the connector to LPC style PLCobject """ @@ -27,9 +27,9 @@ mode,comportstr = location.split('/') if mode=="APPLICATION": from LPCAppObject import LPCAppObject - return LPCAppObject(pluginsroot,comportstr) + return LPCAppObject(confnodesroot,comportstr) elif mode=="BOOTLOADER": from LPCBootObject import LPCBootObject - return LPCBootObject(pluginsroot,comportstr) + return LPCBootObject(confnodesroot,comportstr) diff -r 180e4a7d945c -r 1c23952dbde1 connectors/PYRO/__init__.py --- a/connectors/PYRO/__init__.py Thu May 03 19:02:34 2012 +0200 +++ b/connectors/PYRO/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -26,17 +26,17 @@ import copy # this module attribute contains a list of DNS-SD (Zeroconf) service types -# supported by this connector plugin. +# supported by this connector confnode. # # for connectors that do not support DNS-SD, this attribute can be omitted # or set to an empty list. supported_dnssd_services = ["_PYRO._tcp.local."] -def PYRO_connector_factory(uri, pluginsroot): +def PYRO_connector_factory(uri, confnodesroot): """ This returns the connector to Pyro style PLCobject """ - pluginsroot.logger.write(_("Connecting to URI : %s\n")%uri) + confnodesroot.logger.write(_("Connecting to URI : %s\n")%uri) servicetype, location = uri.split("://") @@ -44,8 +44,8 @@ try : RemotePLCObjectProxy = pyro.getAttrProxyForURI("PYROLOC://"+location+"/PLCObject") except Exception, msg: - pluginsroot.logger.write_error(_("Wrong URI, please check it !\n")) - pluginsroot.logger.write_error(traceback.format_exc()) + confnodesroot.logger.write_error(_("Wrong URI, please check it !\n")) + confnodesroot.logger.write_error(traceback.format_exc()) return None def PyroCatcher(func, default=None): @@ -59,21 +59,21 @@ except Pyro.errors.ProtocolError, e: pass except Pyro.errors.ConnectionClosedError, e: - pluginsroot.logger.write_error("Connection lost!\n") - pluginsroot._connector = None + confnodesroot.logger.write_error("Connection lost!\n") + confnodesroot._connector = None except Exception,e: - #pluginsroot.logger.write_error(traceback.format_exc()) + #confnodesroot.logger.write_error(traceback.format_exc()) errmess = ''.join(Pyro.util.getPyroTraceback(e)) - pluginsroot.logger.write_error(errmess+"\n") + confnodesroot.logger.write_error(errmess+"\n") print errmess - pluginsroot._connector = None + confnodesroot._connector = None return default return catcher_func # Check connection is effective. # lambda is for getattr of GetPLCstatus to happen inside catcher if PyroCatcher(lambda:RemotePLCObjectProxy.GetPLCstatus())() == None: - pluginsroot.logger.write_error(_("Cannot get PLC status - connection failed.\n")) + confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n")) return None @@ -95,25 +95,25 @@ def _PyroStartPLC(self, *args, **kwargs): """ - pluginsroot._connector.GetPyroProxy() is used + confnodesroot._connector.GetPyroProxy() is used rather than RemotePLCObjectProxy because object is recreated meanwhile, so we must not keep ref to it here """ - current_status = pluginsroot._connector.GetPyroProxy().GetPLCstatus() + current_status = confnodesroot._connector.GetPyroProxy().GetPLCstatus() if current_status == "Dirty": """ Some bad libs with static symbols may polute PLC ask runtime to suicide and come back again """ - pluginsroot.logger.write(_("Force runtime reload\n")) - pluginsroot._connector.GetPyroProxy().ForceReload() - pluginsroot._Disconnect() + confnodesroot.logger.write(_("Force runtime reload\n")) + confnodesroot._connector.GetPyroProxy().ForceReload() + confnodesroot._Disconnect() # let remote PLC time to resurect.(freeze app) sleep(0.5) - pluginsroot._Connect() - self.RemotePLCObjectProxyCopy = copy.copy(pluginsroot._connector.GetPyroProxy()) - return pluginsroot._connector.GetPyroProxy().StartPLC(*args, **kwargs) + confnodesroot._Connect() + self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy()) + return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs) StartPLC = PyroCatcher(_PyroStartPLC, False) @@ -122,7 +122,7 @@ for safe use in from debug thread, must use the copy """ if self.RemotePLCObjectProxyCopy is None: - self.RemotePLCObjectProxyCopy = copy.copy(pluginsroot._connector.GetPyroProxy()) + self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy()) return self.RemotePLCObjectProxyCopy.GetTraceVariables() GetTraceVariables = PyroCatcher(_PyroGetTraceVariables,("Broken",None,None)) diff -r 180e4a7d945c -r 1c23952dbde1 connectors/__init__.py --- a/connectors/__init__.py Thu May 03 19:02:34 2012 +0200 +++ b/connectors/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -46,7 +46,7 @@ for st in new_module.supported_dnssd_services: dnssd_connectors[st] = new_module -def ConnectorFactory(uri, pluginsroot): +def ConnectorFactory(uri, confnodesroot): """ Return a connector corresponding to the URI or None if cannot connect to URI @@ -56,12 +56,12 @@ # import module according to uri type connectormodule = connector_modules[servicetype] factoryname = servicetype + "_connector_factory" - return getattr(connectormodule, factoryname)(uri, pluginsroot) + return getattr(connectormodule, factoryname)(uri, confnodesroot) elif servicetype == "LOCAL": - runtime_port = pluginsroot.AppFrame.StartLocalRuntime(taskbaricon=True) + runtime_port = confnodesroot.AppFrame.StartLocalRuntime(taskbaricon=True) return PYRO.PYRO_connector_factory( "PYRO://127.0.0.1:"+str(runtime_port), - pluginsroot) + confnodesroot) else : return None diff -r 180e4a7d945c -r 1c23952dbde1 plugger.py --- a/plugger.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2063 +0,0 @@ -""" -Base definitions for beremiz plugins -""" - -import os,sys,traceback -import time -import plugins -import types -import shutil -from xml.dom import minidom -import wx - -#Quick hack to be able to find Beremiz IEC tools. Should be config params. -base_folder = os.path.split(sys.path[0])[0] - -from xmlclass import GenerateClassesFromXSDstring -from wxPopen import ProcessLogger - -from PLCControler import PLCControler, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY - -_BaseParamsClass = GenerateClassesFromXSDstring(""" - - - - - - - - - """)["BaseParams"] - -NameTypeSeparator = '@' - -class MiniTextControler: - - def __init__(self, filepath): - self.FilePath = filepath - - def PlugFullName(self): - return "" - - def SetEditedElementText(self, tagname, text): - file = open(self.FilePath, "w") - file.write(text) - file.close() - - def GetEditedElementText(self, tagname, debug = False): - if os.path.isfile(self.FilePath): - file = open(self.FilePath, "r") - text = file.read() - file.close() - return text - return "" - - def GetEditedElementInterfaceVars(self, tagname, debug = False): - return [] - - def GetEditedElementType(self, tagname, debug = False): - return "program" - - def GetBlockTypes(self, tagname = "", debug = False): - return [] - - def GetDataTypes(self, tagname = "", basetypes = True, only_locatables = False, debug = False): - return [] - - def GetEnumeratedDataValues(self, debug = False): - return [] - - def StartBuffering(self): - pass - - def EndBuffering(self): - pass - - def BufferProject(self): - pass - -# helper func to get path to images -def opjimg(imgname): - return os.path.join(base_folder, "beremiz", "images",imgname) - -# helper func to check path write permission -def CheckPathPerm(path): - if path is None or not os.path.isdir(path): - return False - for root, dirs, files in os.walk(path): - for name in files: - if os.access(root, os.W_OK) is not True or os.access(os.path.join(root, name), os.W_OK) is not True: - return False - return True - -class PlugTemplate: - """ - This class is the one that define plugins. - """ - - XSD = None - PlugChildsTypes = [] - PlugMaxCount = None - PluginMethods = [] - LibraryControler = None - EditorType = None - - def _AddParamsMembers(self): - self.PlugParams = None - if self.XSD: - self.Classes = GenerateClassesFromXSDstring(self.XSD) - Classes = [(name, XSDclass) for name, XSDclass in self.Classes.items() if XSDclass.IsBaseClass] - if len(Classes) == 1: - name, XSDclass = Classes[0] - obj = XSDclass() - self.PlugParams = (name, obj) - setattr(self, name, obj) - - def __init__(self): - # Create BaseParam - self.BaseParams = _BaseParamsClass() - self.MandatoryParams = ("BaseParams", self.BaseParams) - self._AddParamsMembers() - self.PluggedChilds = {} - self._View = None - # copy PluginMethods so that it can be later customized - self.PluginMethods = [dic.copy() for dic in self.PluginMethods] - self.LoadSTLibrary() - - def PluginBaseXmlFilePath(self, PlugName=None): - return os.path.join(self.PlugPath(PlugName), "baseplugin.xml") - - def PluginXmlFilePath(self, PlugName=None): - return os.path.join(self.PlugPath(PlugName), "plugin.xml") - - def PluginLibraryFilePath(self): - return os.path.join(self.PluginPath(), "pous.xml") - - def PluginPath(self): - return os.path.join(self.PlugParent.PluginPath(), self.PlugType) - - def PlugPath(self,PlugName=None): - if not PlugName: - PlugName = self.PlugName() - return os.path.join(self.PlugParent.PlugPath(), - PlugName + NameTypeSeparator + self.PlugType) - - def PlugName(self): - return self.BaseParams.getName() - - def PlugEnabled(self): - return self.BaseParams.getEnabled() - - def PlugFullName(self): - parent = self.PlugParent.PlugFullName() - if parent != "": - return parent + "." + self.PlugName() - return self.BaseParams.getName() - - def GetIconPath(self, name): - return opjimg(name) - - def PlugTestModified(self): - return self.ChangesToSave - - def ProjectTestModified(self): - """ - recursively check modified status - """ - if self.PlugTestModified(): - return True - - for PlugChild in self.IterChilds(): - if PlugChild.ProjectTestModified(): - return True - - return False - - def RemoteExec(self, script, **kwargs): - return self.PlugParent.RemoteExec(script, **kwargs) - - def OnPlugSave(self): - #Default, do nothing and return success - return True - - def GetParamsAttributes(self, path = None): - if path: - parts = path.split(".", 1) - if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: - return self.MandatoryParams[1].getElementInfos(parts[0], parts[1]) - elif self.PlugParams and parts[0] == self.PlugParams[0]: - return self.PlugParams[1].getElementInfos(parts[0], parts[1]) - else: - params = [] - if wx.VERSION < (2, 8, 0) and self.MandatoryParams: - params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0])) - if self.PlugParams: - params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0])) - return params - - def SetParamsAttribute(self, path, value): - self.ChangesToSave = True - # Filter IEC_Channel and Name, that have specific behavior - if path == "BaseParams.IEC_Channel": - old_leading = ".".join(map(str, self.GetCurrentLocation())) - new_value = self.FindNewIEC_Channel(value) - new_leading = ".".join(map(str, self.PlugParent.GetCurrentLocation() + (new_value,))) - self.GetPlugRoot().UpdateProjectVariableLocation(old_leading, new_leading) - return new_value, True - elif path == "BaseParams.Name": - res = self.FindNewName(value) - self.PlugRequestSave() - return res, True - - parts = path.split(".", 1) - if self.MandatoryParams and parts[0] == self.MandatoryParams[0]: - self.MandatoryParams[1].setElementValue(parts[1], value) - elif self.PlugParams and parts[0] == self.PlugParams[0]: - self.PlugParams[1].setElementValue(parts[1], value) - return value, False - - def PlugMakeDir(self): - os.mkdir(self.PlugPath()) - - def PlugRequestSave(self): - if self.GetPlugRoot().CheckProjectPathPerm(False): - # If plugin do not have corresponding directory - plugpath = self.PlugPath() - if not os.path.isdir(plugpath): - # Create it - os.mkdir(plugpath) - - # generate XML for base XML parameters controller of the plugin - if self.MandatoryParams: - BaseXMLFile = open(self.PluginBaseXmlFilePath(),'w') - BaseXMLFile.write("\n") - BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0).encode("utf-8")) - BaseXMLFile.close() - - # generate XML for XML parameters controller of the plugin - if self.PlugParams: - XMLFile = open(self.PluginXmlFilePath(),'w') - XMLFile.write("\n") - XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0).encode("utf-8")) - XMLFile.close() - - # Call the plugin specific OnPlugSave method - result = self.OnPlugSave() - if not result: - return _("Error while saving \"%s\"\n")%self.PlugPath() - - # mark plugin as saved - self.ChangesToSave = False - # go through all childs and do the same - for PlugChild in self.IterChilds(): - result = PlugChild.PlugRequestSave() - if result: - return result - return None - - def PlugImport(self, src_PlugPath): - shutil.copytree(src_PlugPath, self.PlugPath) - return True - - def PlugGenerate_C(self, buildpath, locations): - """ - Generate C code - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - self.GetPlugRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n") - return [],"",False - - def _Generate_C(self, buildpath, locations): - # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files - # extra_files = [(fname,fobject), ...] - gen_result = self.PlugGenerate_C(buildpath, locations) - PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3] - extra_files = gen_result[3:] - # if some files have been generated put them in the list with their location - if PlugCFilesAndCFLAGS: - LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)] - else: - LocationCFilesAndCFLAGS = [] - - # plugin asks for some LDFLAGS - if PlugLDFLAGS: - # LDFLAGS can be either string - if type(PlugLDFLAGS)==type(str()): - LDFLAGS=[PlugLDFLAGS] - #or list of strings - elif type(PlugLDFLAGS)==type(list()): - LDFLAGS=PlugLDFLAGS[:] - else: - LDFLAGS=[] - - # recurse through all childs, and stack their results - for PlugChild in self.IECSortedChilds(): - new_location = PlugChild.GetCurrentLocation() - # How deep are we in the tree ? - depth=len(new_location) - _LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \ - PlugChild._Generate_C( - #keep the same path - buildpath, - # filter locations that start with current IEC location - [loc for loc in locations if loc["LOC"][0:depth] == new_location ]) - # stack the result - LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS - LDFLAGS += _LDFLAGS - extra_files += _extra_files - - return LocationCFilesAndCFLAGS, LDFLAGS, extra_files - - def PluginTypesFactory(self): - if self.LibraryControler is not None: - return [{"name" : self.PlugType, "types": self.LibraryControler.Project}] - return [] - - def ParentsTypesFactory(self): - return self.PlugParent.ParentsTypesFactory() + self.PluginTypesFactory() - - def PluginsTypesFactory(self): - list = self.PluginTypesFactory() - for PlugChild in self.IterChilds(): - list += PlugChild.PluginsTypesFactory() - return list - - def STLibraryFactory(self): - if self.LibraryControler is not None: - program, errors, warnings = self.LibraryControler.GenerateProgram() - return program + "\n" - return "" - - def PluginsSTLibraryFactory(self): - program = self.STLibraryFactory() - for PlugChild in self.IECSortedChilds(): - program += PlugChild.PluginsSTLibraryFactory() - return program - - def IterChilds(self): - for PlugType, PluggedChilds in self.PluggedChilds.items(): - for PlugInstance in PluggedChilds: - yield PlugInstance - - def IECSortedChilds(self): - # reorder childs by IEC_channels - ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChilds()] - if ordered: - ordered.sort() - return zip(*ordered)[1] - else: - return [] - - def _GetChildBySomething(self, something, toks): - for PlugInstance in self.IterChilds(): - # if match component of the name - if getattr(PlugInstance.BaseParams, something) == toks[0]: - # if Name have other components - if len(toks) >= 2: - # Recurse in order to find the latest object - return PlugInstance._GetChildBySomething( something, toks[1:]) - # No sub name -> found - return PlugInstance - # Not found - return None - - def GetChildByName(self, Name): - if Name: - toks = Name.split('.') - return self._GetChildBySomething("Name", toks) - else: - return self - - def GetChildByIECLocation(self, Location): - if Location: - return self._GetChildBySomething("IEC_Channel", Location) - else: - return self - - def GetCurrentLocation(self): - """ - @return: Tupple containing plugin IEC location of current plugin : %I0.0.4.5 => (0,0,4,5) - """ - return self.PlugParent.GetCurrentLocation() + (self.BaseParams.getIEC_Channel(),) - - def GetCurrentName(self): - """ - @return: String "ParentParentName.ParentName.Name" - """ - return self.PlugParent._GetCurrentName() + self.BaseParams.getName() - - def _GetCurrentName(self): - """ - @return: String "ParentParentName.ParentName.Name." - """ - return self.PlugParent._GetCurrentName() + self.BaseParams.getName() + "." - - def GetPlugRoot(self): - return self.PlugParent.GetPlugRoot() - - def GetFullIEC_Channel(self): - return ".".join([str(i) for i in self.GetCurrentLocation()]) + ".x" - - def GetLocations(self): - location = self.GetCurrentLocation() - return [loc for loc in self.PlugParent.GetLocations() if loc["LOC"][0:len(location)] == location] - - def GetVariableLocationTree(self): - ''' - This function is meant to be overridden by plugins. - - It should returns an list of dictionaries - - - IEC_type is an IEC type like BOOL/BYTE/SINT/... - - location is a string of this variable's location, like "%IX0.0.0" - ''' - children = [] - for child in self.IECSortedChilds(): - children.append(child.GetVariableLocationTree()) - return {"name": self.BaseParams.getName(), - "type": LOCATION_PLUGIN, - "location": self.GetFullIEC_Channel(), - "children": children} - - def FindNewName(self, DesiredName): - """ - Changes Name to DesiredName if available, Name-N if not. - @param DesiredName: The desired Name (string) - """ - # Get Current Name - CurrentName = self.BaseParams.getName() - # Do nothing if no change - #if CurrentName == DesiredName: return CurrentName - # Build a list of used Name out of parent's PluggedChilds - AllNames=[] - for PlugInstance in self.PlugParent.IterChilds(): - if PlugInstance != self: - AllNames.append(PlugInstance.BaseParams.getName()) - - # Find a free name, eventually appending digit - res = DesiredName - suffix = 1 - while res in AllNames: - res = "%s-%d"%(DesiredName, suffix) - suffix += 1 - - # Get old path - oldname = self.PlugPath() - # Check previous plugin existance - dontexist = self.BaseParams.getName() == "__unnamed__" - # Set the new name - self.BaseParams.setName(res) - # Rename plugin dir if exist - if not dontexist: - shutil.move(oldname, self.PlugPath()) - # warn user he has two left hands - if DesiredName != res: - self.GetPlugRoot().logger.write_warning(_("A child names \"%s\" already exist -> \"%s\"\n")%(DesiredName,res)) - return res - - def GetAllChannels(self): - AllChannels=[] - for PlugInstance in self.PlugParent.IterChilds(): - if PlugInstance != self: - AllChannels.append(PlugInstance.BaseParams.getIEC_Channel()) - AllChannels.sort() - return AllChannels - - def FindNewIEC_Channel(self, DesiredChannel): - """ - Changes IEC Channel number to DesiredChannel if available, nearest available if not. - @param DesiredChannel: The desired IEC channel (int) - """ - # Get Current IEC channel - CurrentChannel = self.BaseParams.getIEC_Channel() - # Do nothing if no change - #if CurrentChannel == DesiredChannel: return CurrentChannel - # Build a list of used Channels out of parent's PluggedChilds - AllChannels = self.GetAllChannels() - - # Now, try to guess the nearest available channel - res = DesiredChannel - while res in AllChannels: # While channel not free - if res < CurrentChannel: # Want to go down ? - res -= 1 # Test for n-1 - if res < 0 : - self.GetPlugRoot().logger.write_warning(_("Cannot find lower free IEC channel than %d\n")%CurrentChannel) - return CurrentChannel # Can't go bellow 0, do nothing - else : # Want to go up ? - res += 1 # Test for n-1 - # Finally set IEC Channel - self.BaseParams.setIEC_Channel(res) - return res - - def _OpenView(self, name=None): - if self.EditorType is not None and self._View is None: - app_frame = self.GetPlugRoot().AppFrame - - self._View = self.EditorType(app_frame.TabsOpened, self, app_frame) - - app_frame.EditProjectElement(self._View, self.PlugName()) - - return self._View - return None - - def OnCloseEditor(self, view): - if self._View == view: - self._View = None - - def OnPlugClose(self): - if self._View is not None: - app_frame = self.GetPlugRoot().AppFrame - if app_frame is not None: - app_frame.DeletePage(self._View) - return True - - def _doRemoveChild(self, PlugInstance): - # Remove all childs of child - for SubPlugInstance in PlugInstance.IterChilds(): - PlugInstance._doRemoveChild(SubPlugInstance) - # Call the OnCloseMethod - PlugInstance.OnPlugClose() - # Delete plugin dir - shutil.rmtree(PlugInstance.PlugPath()) - # Remove child of PluggedChilds - self.PluggedChilds[PlugInstance.PlugType].remove(PlugInstance) - # Forget it... (View have to refresh) - - def PlugRemove(self): - # Fetch the plugin - #PlugInstance = self.GetChildByName(PlugName) - # Ask to his parent to remove it - self.PlugParent._doRemoveChild(self) - - def PlugAddChild(self, PlugName, PlugType, IEC_Channel=0): - """ - Create the plugins that may be added as child to this node self - @param PlugType: string desining the plugin class name (get name from PlugChildsTypes) - @param PlugName: string for the name of the plugin instance - """ - # reorgabize self.PlugChildsTypes tuples from (name, PlugClass, Help) - # to ( name, (PlugClass, Help)), an make a dict - transpose = zip(*self.PlugChildsTypes) - PlugChildsTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2]))) - # Check that adding this plugin is allowed - try: - PlugClass, PlugHelp = PlugChildsTypes[PlugType] - except KeyError: - raise Exception, _("Cannot create child %s of type %s ")%(PlugName, PlugType) - - # if PlugClass is a class factory, call it. (prevent unneeded imports) - if type(PlugClass) == types.FunctionType: - PlugClass = PlugClass() - - # Eventualy Initialize child instance list for this class of plugin - PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType, list()) - # Check count - if getattr(PlugClass, "PlugMaxCount", None) and len(PluggedChildsWithSameClass) >= PlugClass.PlugMaxCount: - raise Exception, _("Max count (%d) reached for this plugin of type %s ")%(PlugClass.PlugMaxCount, PlugType) - - # create the final class, derived of provided plugin and template - class FinalPlugClass(PlugClass, PlugTemplate): - """ - Plugin class is derivated into FinalPlugClass before being instanciated - This way __init__ is overloaded to ensure PlugTemplate.__init__ is called - before PlugClass.__init__, and to do the file related stuff. - """ - def __init__(_self): - # self is the parent - _self.PlugParent = self - # Keep track of the plugin type name - _self.PlugType = PlugType - # remind the help string, for more fancy display - _self.PlugHelp = PlugHelp - # Call the base plugin template init - change XSD into class members - PlugTemplate.__init__(_self) - # check name is unique - NewPlugName = _self.FindNewName(PlugName) - # If dir have already be made, and file exist - if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.PluginXmlFilePath(PlugName)): - #Load the plugin.xml file into parameters members - _self.LoadXMLParams(NewPlugName) - # Basic check. Better to fail immediately. - if (_self.BaseParams.getName() != NewPlugName): - raise Exception, _("Project tree layout do not match plugin.xml %s!=%s ")%(NewPlugName, _self.BaseParams.getName()) - - # Now, self.PlugPath() should be OK - - # Check that IEC_Channel is not already in use. - _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel()) - # Call the plugin real __init__ - if getattr(PlugClass, "__init__", None): - PlugClass.__init__(_self) - #Load and init all the childs - _self.LoadChilds() - #just loaded, nothing to saved - _self.ChangesToSave = False - else: - # If plugin do not have corresponding file/dirs - they will be created on Save - _self.PlugMakeDir() - # Find an IEC number - _self.FindNewIEC_Channel(IEC_Channel) - # Call the plugin real __init__ - if getattr(PlugClass, "__init__", None): - PlugClass.__init__(_self) - _self.PlugRequestSave() - #just created, must be saved - _self.ChangesToSave = True - - def _getBuildPath(_self): - return self._getBuildPath() - - # Create the object out of the resulting class - newPluginOpj = FinalPlugClass() - # Store it in PluggedChils - PluggedChildsWithSameClass.append(newPluginOpj) - - return newPluginOpj - - def ClearPluggedChilds(self): - for child in self.IterChilds(): - child.ClearPluggedChilds() - self.PluggedChilds = {} - - def LoadSTLibrary(self): - # Get library blocks if plcopen library exist - library_path = self.PluginLibraryFilePath() - if os.path.isfile(library_path): - self.LibraryControler = PLCControler() - self.LibraryControler.OpenXMLFile(library_path) - self.LibraryControler.ClearPluginTypes() - self.LibraryControler.AddPluginTypesList(self.ParentsTypesFactory()) - - def LoadXMLParams(self, PlugName = None): - methode_name = os.path.join(self.PlugPath(PlugName), "methods.py") - if os.path.isfile(methode_name): - execfile(methode_name) - - # Get the base xml tree - if self.MandatoryParams: - try: - basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r') - basetree = minidom.parse(basexmlfile) - self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0]) - basexmlfile.close() - except Exception, exc: - self.GetPlugRoot().logger.write_error(_("Couldn't load plugin base parameters %s :\n %s") % (PlugName, str(exc))) - self.GetPlugRoot().logger.write_error(traceback.format_exc()) - - # Get the xml tree - if self.PlugParams: - try: - xmlfile = open(self.PluginXmlFilePath(PlugName), 'r') - tree = minidom.parse(xmlfile) - self.PlugParams[1].loadXMLTree(tree.childNodes[0]) - xmlfile.close() - except Exception, exc: - self.GetPlugRoot().logger.write_error(_("Couldn't load plugin parameters %s :\n %s") % (PlugName, str(exc))) - self.GetPlugRoot().logger.write_error(traceback.format_exc()) - - def LoadChilds(self): - # Iterate over all PlugName@PlugType in plugin directory, and try to open them - for PlugDir in os.listdir(self.PlugPath()): - if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \ - PlugDir.count(NameTypeSeparator) == 1: - pname, ptype = PlugDir.split(NameTypeSeparator) - try: - self.PlugAddChild(pname, ptype) - except Exception, exc: - self.GetPlugRoot().logger.write_error(_("Could not add child \"%s\", type %s :\n%s\n")%(pname, ptype, str(exc))) - self.GetPlugRoot().logger.write_error(traceback.format_exc()) - - def EnableMethod(self, method, value): - for d in self.PluginMethods: - if d["method"]==method: - d["enabled"]=value - return True - return False - - def ShowMethod(self, method, value): - for d in self.PluginMethods: - if d["method"]==method: - d["shown"]=value - return True - return False - - def CallMethod(self, method): - for d in self.PluginMethods: - if d["method"]==method and d.get("enabled", True) and d.get("shown", True): - getattr(self, method)() - -def _GetClassFunction(name): - def GetRootClass(): - return getattr(__import__("plugins." + name), name).RootClass - return GetRootClass - - -#################################################################################### -#################################################################################### -#################################################################################### -################################### ROOT ###################################### -#################################################################################### -#################################################################################### -#################################################################################### - -if wx.Platform == '__WXMSW__': - exe_ext=".exe" -else: - exe_ext="" - -# import for project creation timestamping -from threading import Timer, Lock, Thread, Semaphore -from time import localtime -from datetime import datetime -# import necessary stuff from PLCOpenEditor -from PLCOpenEditor import PLCOpenEditor, ProjectDialog -from TextViewer import TextViewer -from plcopen.structures import IEC_KEYWORDS, TypeHierarchy_list - - -import re, tempfile -import targets -from targets.typemapping import DebugTypesSize - -import connectors -from discovery import DiscoveryDialog -from weakref import WeakKeyDictionary - -MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): error : (.*)$") - -DEBUG_RETRIES_WARN = 3 -DEBUG_RETRIES_REREGISTER = 4 - -class PluginsRoot(PlugTemplate, PLCControler): - """ - This class define Root object of the plugin tree. - It is responsible of : - - Managing project directory - - Building project - - Handling PLCOpenEditor controler and view - - Loading user plugins and instanciante them as childs - - ... - - """ - - # For root object, available Childs Types are modules of the plugin packages. - PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(plugins.__all__,plugins.helps)] - - XSD = """ - - - - - - - - """+targets.targetchoices+""" - - - - - - - - - - """ - - def __init__(self, frame, logger): - PLCControler.__init__(self) - - self.MandatoryParams = None - self.SetAppFrame(frame, logger) - self._builder = None - self._connector = None - - self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext) - self.ieclib_path = os.path.join(base_folder, "matiec", "lib") - - # Setup debug information - self.IECdebug_datas = {} - self.IECdebug_lock = Lock() - - self.DebugTimer=None - self.ResetIECProgramsAndVariables() - - #This method are not called here... but in NewProject and OpenProject - #self._AddParamsMembers() - #self.PluggedChilds = {} - - # In both new or load scenario, no need to save - self.ChangesToSave = False - # root have no parent - self.PlugParent = None - # Keep track of the plugin type name - self.PlugType = "Beremiz" - self.PluggedChilds = {} - # After __init__ root plugin is not valid - self.ProjectPath = None - self._setBuildPath(None) - self.DebugThread = None - self.debug_break = False - self.previous_plcstate = None - # copy PluginMethods so that it can be later customized - self.PluginMethods = [dic.copy() for dic in self.PluginMethods] - self.LoadSTLibrary() - - def __del__(self): - if self.DebugTimer: - self.DebugTimer.cancel() - self.KillDebugThread() - - def SetAppFrame(self, frame, logger): - self.AppFrame = frame - self.logger = logger - self.StatusTimer = None - - if frame is not None: - # Timer to pull PLC status - ID_STATUSTIMER = wx.NewId() - self.StatusTimer = wx.Timer(self.AppFrame, ID_STATUSTIMER) - self.AppFrame.Bind(wx.EVT_TIMER, self.PullPLCStatusProc, self.StatusTimer) - - self.RefreshPluginsBlockLists() - - def ResetAppFrame(self, logger): - if self.AppFrame is not None: - self.AppFrame.Unbind(wx.EVT_TIMER, self.StatusTimer) - self.StatusTimer = None - self.AppFrame = None - - self.logger = logger - - def PluginLibraryFilePath(self): - return os.path.join(os.path.split(__file__)[0], "pous.xml") - - def PlugTestModified(self): - return self.ChangesToSave or not self.ProjectIsSaved() - - def PlugFullName(self): - return "" - - def GetPlugRoot(self): - return self - - def GetIECLibPath(self): - return self.ieclib_path - - def GetIEC2cPath(self): - return self.iec2c_path - - def GetCurrentLocation(self): - return () - - def GetCurrentName(self): - return "" - - def _GetCurrentName(self): - return "" - - def GetProjectPath(self): - return self.ProjectPath - - def GetProjectName(self): - return os.path.split(self.ProjectPath)[1] - - def GetDefaultTargetName(self): - if wx.Platform == '__WXMSW__': - return "Win32" - else: - return "Linux" - - def GetTarget(self): - target = self.BeremizRoot.getTargetType() - if target.getcontent() is None: - target = self.Classes["BeremizRoot_TargetType"]() - target_name = self.GetDefaultTargetName() - target.setcontent({"name": target_name, "value": self.Classes["TargetType_%s"%target_name]()}) - return target - - def GetParamsAttributes(self, path = None): - params = PlugTemplate.GetParamsAttributes(self, path) - if params[0]["name"] == "BeremizRoot": - for child in params[0]["children"]: - if child["name"] == "TargetType" and child["value"] == '': - child.update(self.GetTarget().getElementInfos("TargetType")) - return params - - def SetParamsAttribute(self, path, value): - if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None: - self.BeremizRoot.setTargetType(self.GetTarget()) - return PlugTemplate.SetParamsAttribute(self, path, value) - - # helper func to check project path write permission - def CheckProjectPathPerm(self, dosave=True): - if CheckPathPerm(self.ProjectPath): - return True - dialog = wx.MessageDialog(self.AppFrame, - _('You must have permission to work on the project\nWork on a project copy ?'), - _('Error'), - wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) - answer = dialog.ShowModal() - dialog.Destroy() - if answer == wx.ID_YES: - if self.SaveProjectAs(): - self.AppFrame.RefreshAll() - self.AppFrame.RefreshTitle() - self.AppFrame.RefreshFileMenu() - return True - return False - - def NewProject(self, ProjectPath, BuildPath=None): - """ - Create a new project in an empty folder - @param ProjectPath: path of the folder where project have to be created - @param PLCParams: properties of the PLCOpen program created - """ - # Verify that chosen folder is empty - if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0: - return _("Chosen folder isn't empty. You can't use it for a new project!") - - dialog = ProjectDialog(self.AppFrame) - if dialog.ShowModal() == wx.ID_OK: - values = dialog.GetValues() - values["creationDateTime"] = datetime(*localtime()[:6]) - dialog.Destroy() - else: - dialog.Destroy() - return _("Project not created") - - # Create PLCOpen program - self.CreateNewProject(values) - # Change XSD into class members - self._AddParamsMembers() - self.PluggedChilds = {} - # Keep track of the root plugin (i.e. project path) - self.ProjectPath = ProjectPath - self._setBuildPath(BuildPath) - # get plugins bloclist (is that usefull at project creation?) - self.RefreshPluginsBlockLists() - # this will create files base XML files - self.SaveProject() - return None - - def LoadProject(self, ProjectPath, BuildPath=None): - """ - Load a project contained in a folder - @param ProjectPath: path of the project folder - """ - if os.path.basename(ProjectPath) == "": - ProjectPath = os.path.dirname(ProjectPath) - # Verify that project contains a PLCOpen program - plc_file = os.path.join(ProjectPath, "plc.xml") - if not os.path.isfile(plc_file): - return _("Chosen folder doesn't contain a program. It's not a valid project!") - # Load PLCOpen file - result = self.OpenXMLFile(plc_file) - if result: - return result - # Change XSD into class members - self._AddParamsMembers() - self.PluggedChilds = {} - # Keep track of the root plugin (i.e. project path) - self.ProjectPath = ProjectPath - self._setBuildPath(BuildPath) - # If dir have already be made, and file exist - if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()): - #Load the plugin.xml file into parameters members - result = self.LoadXMLParams() - if result: - return result - #Load and init all the childs - self.LoadChilds() - self.RefreshPluginsBlockLists() - - if os.path.exists(self._getBuildPath()): - self.EnableMethod("_Clean", True) - - if os.path.isfile(self._getIECrawcodepath()): - self.ShowMethod("_showIECcode", True) - - return None - - def CloseProject(self): - self.ClearPluggedChilds() - self.ResetAppFrame(None) - - def SaveProject(self): - if self.CheckProjectPathPerm(False): - self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) - result = self.PlugRequestSave() - if result: - self.logger.write_error(result) - - def SaveProjectAs(self, dosave=True): - # Ask user to choose a path with write permissions - if wx.Platform == '__WXMSW__': - path = os.getenv("USERPROFILE") - else: - path = os.getenv("HOME") - dirdialog = wx.DirDialog(self.AppFrame , _("Choose a directory to save project"), path, wx.DD_NEW_DIR_BUTTON) - answer = dirdialog.ShowModal() - dirdialog.Destroy() - if answer == wx.ID_OK: - newprojectpath = dirdialog.GetPath() - if os.path.isdir(newprojectpath): - self.ProjectPath = newprojectpath - if dosave: - self.SaveProject() - self._setBuildPath(self.BuildPath) - return True - return False - - # Update PLCOpenEditor Plugin Block types from loaded plugins - def RefreshPluginsBlockLists(self): - if getattr(self, "PluggedChilds", None) is not None: - self.ClearPluginTypes() - self.AddPluginTypesList(self.PluginsTypesFactory()) - if self.AppFrame is not None: - self.AppFrame.RefreshLibraryPanel() - self.AppFrame.RefreshEditor() - - # Update a PLCOpenEditor Pou variable location - def UpdateProjectVariableLocation(self, old_leading, new_leading): - self.Project.updateElementAddress(old_leading, new_leading) - self.BufferProject() - if self.AppFrame is not None: - self.AppFrame.RefreshTitle() - self.AppFrame.RefreshInstancesTree() - self.AppFrame.RefreshFileMenu() - self.AppFrame.RefreshEditMenu() - self.AppFrame.RefreshEditor() - - def GetVariableLocationTree(self): - ''' - This function is meant to be overridden by plugins. - - It should returns an list of dictionaries - - - IEC_type is an IEC type like BOOL/BYTE/SINT/... - - location is a string of this variable's location, like "%IX0.0.0" - ''' - children = [] - for child in self.IECSortedChilds(): - children.append(child.GetVariableLocationTree()) - return children - - def PluginPath(self): - return os.path.join(os.path.split(__file__)[0], "plugins") - - def PlugPath(self, PlugName=None): - return self.ProjectPath - - def PluginXmlFilePath(self, PlugName=None): - return os.path.join(self.PlugPath(PlugName), "beremiz.xml") - - def ParentsTypesFactory(self): - return self.PluginTypesFactory() - - def _setBuildPath(self, buildpath): - if CheckPathPerm(buildpath): - self.BuildPath = buildpath - else: - self.BuildPath = None - self.BuildPath = buildpath - self.DefaultBuildPath = None - if self._builder is not None: - self._builder.SetBuildPath(self._getBuildPath()) - - def _getBuildPath(self): - # BuildPath is defined by user - if self.BuildPath is not None: - return self.BuildPath - # BuildPath isn't defined by user but already created by default - if self.DefaultBuildPath is not None: - return self.DefaultBuildPath - # Create a build path in project folder if user has permissions - if CheckPathPerm(self.ProjectPath): - self.DefaultBuildPath = os.path.join(self.ProjectPath, "build") - # Create a build path in temp folder - else: - self.DefaultBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build") - - if not os.path.exists(self.DefaultBuildPath): - os.makedirs(self.DefaultBuildPath) - return self.DefaultBuildPath - - def _getExtraFilesPath(self): - return os.path.join(self._getBuildPath(), "extra_files") - - def _getIECcodepath(self): - # define name for IEC code file - return os.path.join(self._getBuildPath(), "plc.st") - - def _getIECgeneratedcodepath(self): - # define name for IEC generated code file - return os.path.join(self._getBuildPath(), "generated_plc.st") - - def _getIECrawcodepath(self): - # define name for IEC raw code file - return os.path.join(self.PlugPath(), "raw_plc.st") - - def GetLocations(self): - locations = [] - filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h") - if os.path.isfile(filepath): - # IEC2C compiler generate a list of located variables : LOCATED_VARIABLES.h - location_file = open(os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")) - # each line of LOCATED_VARIABLES.h declares a located variable - lines = [line.strip() for line in location_file.readlines()] - # This regular expression parses the lines genereated by IEC2C - LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P[A-Z]*),(?P[_A-Za-z0-9]*),(?P[QMI])(?:,(?P[XBWDL]))?,(?P[,0-9]*)\)") - for line in lines: - # If line match RE, - result = LOCATED_MODEL.match(line) - if result: - # Get the resulting dict - resdict = result.groupdict() - # rewrite string for variadic location as a tuple of integers - resdict['LOC'] = tuple(map(int,resdict['LOC'].split(','))) - # set located size to 'X' if not given - if not resdict['SIZE']: - resdict['SIZE'] = 'X' - # finally store into located variable list - locations.append(resdict) - return locations - - def _Generate_SoftPLC(self): - """ - Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C - @param buildpath: path where files should be created - """ - - # Update PLCOpenEditor Plugin Block types before generate ST code - self.RefreshPluginsBlockLists() - - self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")) - buildpath = self._getBuildPath() - # ask PLCOpenEditor controller to write ST/IL/SFC code file - program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath()) - if len(warnings) > 0: - self.logger.write_warning(_("Warnings in ST/IL/SFC code generator :\n")) - for warning in warnings: - self.logger.write_warning("%s\n"%warning) - if len(errors) > 0: - # Failed ! - self.logger.write_error(_("Error in ST/IL/SFC code generator :\n%s\n")%errors[0]) - return False - plc_file = open(self._getIECcodepath(), "w") - # Add ST Library from plugins - plc_file.write(self.PluginsSTLibraryFactory()) - if os.path.isfile(self._getIECrawcodepath()): - plc_file.write(open(self._getIECrawcodepath(), "r").read()) - plc_file.write("\n") - plc_file.close() - plc_file = open(self._getIECcodepath(), "r") - self.ProgramOffset = 0 - for line in plc_file.xreadlines(): - self.ProgramOffset += 1 - plc_file.close() - plc_file = open(self._getIECcodepath(), "a") - plc_file.write(open(self._getIECgeneratedcodepath(), "r").read()) - plc_file.close() - - self.logger.write(_("Compiling IEC Program into C code...\n")) - - # Now compile IEC code into many C files - # files are listed to stdout, and errors to stderr. - status, result, err_result = ProcessLogger( - self.logger, - "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%( - self.iec2c_path, - self.ieclib_path, - buildpath, - self._getIECcodepath()), - no_stdout=True, no_stderr=True).spin() - if status: - # Failed ! - - # parse iec2c's error message. if it contains a line number, - # then print those lines from the generated IEC file. - for err_line in err_result.split('\n'): - self.logger.write_warning(err_line + "\n") - - m_result = MATIEC_ERROR_MODEL.match(err_line) - if m_result is not None: - first_line, first_column, last_line, last_column, error = m_result.groups() - first_line, last_line = int(first_line), int(last_line) - - last_section = None - f = open(self._getIECcodepath()) - - for i, line in enumerate(f.readlines()): - i = i + 1 - if line[0] not in '\t \r\n': - last_section = line - - if first_line <= i <= last_line: - if last_section is not None: - self.logger.write_warning("In section: " + last_section) - last_section = None # only write section once - self.logger.write_warning("%04d: %s" % (i, line)) - - f.close() - - self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status) - return False - - # Now extract C files of stdout - C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ] - # remove those that are not to be compiled because included by others - C_files.remove("POUS.c") - if not C_files: - self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n")) - return False - # transform those base names to full names with path - C_files = map(lambda filename:os.path.join(buildpath, filename), C_files) - self.logger.write(_("Extracting Located Variables...\n")) - # Keep track of generated located variables for later use by self._Generate_C - self.PLCGeneratedLocatedVars = self.GetLocations() - # Keep track of generated C files for later use by self.PlugGenerate_C - self.PLCGeneratedCFiles = C_files - # compute CFLAGS for plc - self.plcCFLAGS = "\"-I"+self.ieclib_path+"\"" - return True - - def GetBuilder(self): - """ - Return a Builder (compile C code into machine code) - """ - # Get target, module and class name - targetname = self.GetTarget().getcontent()["name"] - modulename = "targets." + targetname - classname = targetname + "_target" - - # Get module reference - try : - targetmodule = getattr(__import__(modulename), targetname) - - except Exception, msg: - self.logger.write_error(_("Can't find module for target %s!\n")%targetname) - self.logger.write_error(str(msg)) - return None - - # Get target class - targetclass = getattr(targetmodule, classname) - - # if target already - if self._builder is None or not isinstance(self._builder,targetclass): - # Get classname instance - self._builder = targetclass(self) - return self._builder - - def ResetBuildMD5(self): - builder=self.GetBuilder() - if builder is not None: - builder.ResetBinaryCodeMD5() - self.EnableMethod("_Transfer", False) - - def GetLastBuildMD5(self): - builder=self.GetBuilder() - if builder is not None: - return builder.GetBinaryCodeMD5() - else: - return None - - ####################################################################### - # - # C CODE GENERATION METHODS - # - ####################################################################### - - def PlugGenerate_C(self, buildpath, locations): - """ - Return C code generated by iec2c compiler - when _generate_softPLC have been called - @param locations: ignored - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - - return ([(C_file_name, self.plcCFLAGS) - for C_file_name in self.PLCGeneratedCFiles ], - "", # no ldflags - False) # do not expose retreive/publish calls - - def ResetIECProgramsAndVariables(self): - """ - Reset variable and program list that are parsed from - CSV file generated by IEC2C compiler. - """ - self._ProgramList = None - self._VariablesList = None - self._IECPathToIdx = {} - self._Ticktime = 0 - self.TracedIECPath = [] - - def GetIECProgramsAndVariables(self): - """ - Parse CSV-like file VARIABLES.csv resulting from IEC2C compiler. - Each section is marked with a line staring with '//' - list of all variables used in various POUs - """ - if self._ProgramList is None or self._VariablesList is None: - try: - csvfile = os.path.join(self._getBuildPath(),"VARIABLES.csv") - # describes CSV columns - ProgramsListAttributeName = ["num", "C_path", "type"] - VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"] - self._ProgramList = [] - self._VariablesList = [] - self._IECPathToIdx = {} - - # Separate sections - ListGroup = [] - for line in open(csvfile,'r').xreadlines(): - strippedline = line.strip() - if strippedline.startswith("//"): - # Start new section - ListGroup.append([]) - elif len(strippedline) > 0 and len(ListGroup) > 0: - # append to this section - ListGroup[-1].append(strippedline) - - # first section contains programs - for line in ListGroup[0]: - # Split and Maps each field to dictionnary entries - attrs = dict(zip(ProgramsListAttributeName,line.strip().split(';'))) - # Truncate "C_path" to remove conf an ressources names - attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:]) - # Push this dictionnary into result. - self._ProgramList.append(attrs) - - # second section contains all variables - for line in ListGroup[1]: - # Split and Maps each field to dictionnary entries - attrs = dict(zip(VariablesListAttributeName,line.strip().split(';'))) - # Truncate "C_path" to remove conf an ressources names - parts = attrs["C_path"].split(".",2) - if len(parts) > 2: - attrs["C_path"] = '__'.join(parts[1:]) - else: - attrs["C_path"] = '__'.join(parts) - # Push this dictionnary into result. - self._VariablesList.append(attrs) - # Fill in IEC<->C translation dicts - IEC_path=attrs["IEC_path"] - Idx=int(attrs["num"]) - self._IECPathToIdx[IEC_path]=(Idx, attrs["type"]) - - # third section contains ticktime - if len(ListGroup) > 2: - self._Ticktime = int(ListGroup[2][0]) - - except Exception,e: - self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n")) - self.logger.write_error(traceback.format_exc()) - self.ResetIECProgramsAndVariables() - return False - - return True - - def Generate_plc_debugger(self): - """ - Generate trace/debug code out of PLC variable list - """ - self.GetIECProgramsAndVariables() - - # prepare debug code - debug_code = targets.code("plc_debug") % { - "buffer_size": reduce(lambda x, y: x + y, [DebugTypesSize.get(v["type"], 0) for v in self._VariablesList], 0), - "programs_declarations": - "\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]), - "extern_variables_declarations":"\n".join([ - {"EXT":"extern __IEC_%(type)s_p %(C_path)s;", - "IN":"extern __IEC_%(type)s_p %(C_path)s;", - "MEM":"extern __IEC_%(type)s_p %(C_path)s;", - "OUT":"extern __IEC_%(type)s_p %(C_path)s;", - "VAR":"extern __IEC_%(type)s_t %(C_path)s;"}[v["vartype"]]%v - for v in self._VariablesList if v["vartype"] != "FB" and v["C_path"].find('.')<0]), - "for_each_variable_do_code":"\n".join([ - {"EXT":" (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n", - "IN":" (*fp)((void*)&%(C_path)s,%(type)s_P_ENUM);\n", - "MEM":" (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n", - "OUT":" (*fp)((void*)&%(C_path)s,%(type)s_O_ENUM);\n", - "VAR":" (*fp)((void*)&%(C_path)s,%(type)s_ENUM);\n"}[v["vartype"]]%v - for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ]), - "find_variable_case_code":"\n".join([ - " case %(num)s:\n"%v+ - " *varp = (void*)&%(C_path)s;\n"%v+ - {"EXT":" return %(type)s_P_ENUM;\n", - "IN":" return %(type)s_P_ENUM;\n", - "MEM":" return %(type)s_O_ENUM;\n", - "OUT":" return %(type)s_O_ENUM;\n", - "VAR":" return %(type)s_ENUM;\n"}[v["vartype"]]%v - for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])} - - return debug_code - - def Generate_plc_common_main(self): - """ - Use plugins layout given in LocationCFilesAndCFLAGS to - generate glue code that dispatch calls to all plugins - """ - # filter location that are related to code that will be called - # in retreive, publish, init, cleanup - locstrs = map(lambda x:"_".join(map(str,x)), - [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls]) - - # Generate main, based on template - if self.BeremizRoot.getEnable_Plugins(): - plc_main_code = targets.code("plc_common_main") % { - "calls_prototypes":"\n".join([( - "int __init_%(s)s(int argc,char **argv);\n"+ - "void __cleanup_%(s)s(void);\n"+ - "void __retrieve_%(s)s(void);\n"+ - "void __publish_%(s)s(void);")%{'s':locstr} for locstr in locstrs]), - "retrieve_calls":"\n ".join([ - "__retrieve_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]), - "publish_calls":"\n ".join([ #Call publish in reverse order - "__publish_%s();"%locstr for locstr in locstrs]), - "init_calls":"\n ".join([ - "init_level=%d; "%(i+1)+ - "if((res = __init_%s(argc,argv))){"%locstr + - #"printf(\"%s\"); "%locstr + #for debug - "return res;}" for i,locstr in enumerate(locstrs)]), - "cleanup_calls":"\n ".join([ - "if(init_level >= %d) "%i+ - "__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]) - } - else: - plc_main_code = targets.code("plc_common_main") % { - "calls_prototypes":"\n", - "retrieve_calls":"\n", - "publish_calls":"\n", - "init_calls":"\n", - "cleanup_calls":"\n" - } - plc_main_code += targets.targetcode(self.GetTarget().getcontent()["name"]) - return plc_main_code - - - def _Build(self): - """ - Method called by user to (re)build SoftPLC and plugin tree - """ - if self.AppFrame is not None: - self.AppFrame.ClearErrors() - - buildpath = self._getBuildPath() - - # Eventually create build dir - if not os.path.exists(buildpath): - os.mkdir(buildpath) - # There is something to clean - self.EnableMethod("_Clean", True) - - self.logger.flush() - self.logger.write(_("Start build in %s\n") % buildpath) - - # Generate SoftPLC IEC code - IECGenRes = self._Generate_SoftPLC() - self.ShowMethod("_showIECcode", True) - - # If IEC code gen fail, bail out. - if not IECGenRes: - self.logger.write_error(_("IEC-61131-3 code generation failed !\n")) - self.ResetBuildMD5() - return False - - # Reset variable and program list that are parsed from - # CSV file generated by IEC2C compiler. - self.ResetIECProgramsAndVariables() - - # Generate C code and compilation params from plugin hierarchy - self.logger.write(_("Generating plugins C code\n")) - try: - self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C( - buildpath, - self.PLCGeneratedLocatedVars) - except Exception, exc: - self.logger.write_error(_("Plugins code generation failed !\n")) - self.logger.write_error(traceback.format_exc()) - self.ResetBuildMD5() - return False - - # Get temporary directory path - extrafilespath = self._getExtraFilesPath() - # Remove old directory - if os.path.exists(extrafilespath): - shutil.rmtree(extrafilespath) - # Recreate directory - os.mkdir(extrafilespath) - # Then write the files - for fname,fobject in ExtraFiles: - fpath = os.path.join(extrafilespath,fname) - open(fpath, "wb").write(fobject.read()) - # Now we can forget ExtraFiles (will close files object) - del ExtraFiles - - # Template based part of C code generation - # files are stacked at the beginning, as files of plugin tree root - for generator, filename, name in [ - # debugger code - (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"), - # init/cleanup/retrieve/publish, run and align code - (self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]: - try: - # Do generate - code = generator() - if code is None: - raise - code_path = os.path.join(buildpath,filename) - open(code_path, "w").write(code) - # Insert this file as first file to be compiled at root plugin - self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS)) - except Exception, exc: - self.logger.write_error(name+_(" generation failed !\n")) - self.logger.write_error(traceback.format_exc()) - self.ResetBuildMD5() - return False - - self.logger.write(_("C code generated successfully.\n")) - - # Get current or fresh builder - builder = self.GetBuilder() - if builder is None: - self.logger.write_error(_("Fatal : cannot get builder.\n")) - self.ResetBuildMD5() - return False - - # Build - try: - if not builder.build() : - self.logger.write_error(_("C Build failed.\n")) - return False - except Exception, exc: - self.logger.write_error(_("C Build crashed !\n")) - self.logger.write_error(traceback.format_exc()) - self.ResetBuildMD5() - return False - - self.logger.write(_("Successfully built.\n")) - # Update GUI status about need for transfer - self.CompareLocalAndRemotePLC() - return True - - def ShowError(self, logger, from_location, to_location): - chunk_infos = self.GetChunkInfos(from_location, to_location) - for infos, (start_row, start_col) in chunk_infos: - start = (from_location[0] - start_row, from_location[1] - start_col) - end = (to_location[0] - start_row, to_location[1] - start_col) - #print from_location, to_location, start_row, start_col, start, end - if self.AppFrame is not None: - self.AppFrame.ShowError(infos, start, end) - - def _showIECcode(self): - self._OpenView("IEC code") - - def _editIECrawcode(self): - self._OpenView("IEC raw code") - - def _OpenView(self, name=None): - if name == "IEC code": - plc_file = self._getIECcodepath() - - IEC_code_viewer = TextViewer(self.AppFrame.TabsOpened, "", None, None, instancepath=name) - #IEC_code_viewer.Enable(False) - IEC_code_viewer.SetTextSyntax("ALL") - IEC_code_viewer.SetKeywords(IEC_KEYWORDS) - try: - text = file(plc_file).read() - except: - text = '(* No IEC code have been generated at that time ! *)' - IEC_code_viewer.SetText(text = text) - IEC_code_viewer.SetIcon(self.AppFrame.GenerateBitmap("ST")) - - self.AppFrame.EditProjectElement(IEC_code_viewer, name) - - return IEC_code_viewer - - elif name == "IEC raw code": - controler = MiniTextControler(self._getIECrawcodepath()) - IEC_raw_code_viewer = TextViewer(self.AppFrame.TabsOpened, "", None, controler, instancepath=name) - #IEC_raw_code_viewer.Enable(False) - IEC_raw_code_viewer.SetTextSyntax("ALL") - IEC_raw_code_viewer.SetKeywords(IEC_KEYWORDS) - IEC_raw_code_viewer.RefreshView() - IEC_raw_code_viewer.SetIcon(self.AppFrame.GenerateBitmap("ST")) - - self.AppFrame.EditProjectElement(IEC_raw_code_viewer, name) - - return IEC_raw_code_viewer - - return None - - def _Clean(self): - if os.path.isdir(os.path.join(self._getBuildPath())): - self.logger.write(_("Cleaning the build directory\n")) - shutil.rmtree(os.path.join(self._getBuildPath())) - else: - self.logger.write_error(_("Build directory already clean\n")) - self.ShowMethod("_showIECcode", False) - self.EnableMethod("_Clean", False) - # kill the builder - self._builder = None - self.CompareLocalAndRemotePLC() - - ############# Real PLC object access ############# - def UpdateMethodsFromPLCStatus(self): - # Get PLC state : Running or Stopped - # TODO : use explicit status instead of boolean - status = None - if self._connector is not None: - status = self._connector.GetPLCstatus() - if status is None: - self._connector = None - status = "Disconnected" - if(self.previous_plcstate != status): - for args in { - "Started" : [("_Run", False), - ("_Stop", True)], - "Stopped" : [("_Run", True), - ("_Stop", False)], - "Empty" : [("_Run", False), - ("_Stop", False)], - "Broken" : [], - "Disconnected" :[("_Run", False), - ("_Stop", False), - ("_Transfer", False), - ("_Connect", True), - ("_Disconnect", False)], - }.get(status,[]): - self.ShowMethod(*args) - self.previous_plcstate = status - return True - return False - - def PullPLCStatusProc(self, event): - if self._connector is None: - self.StatusTimer.Stop() - if self.UpdateMethodsFromPLCStatus(): - - status = _(self.previous_plcstate) - {"Broken": self.logger.write_error, - None: lambda x: None}.get( - self.previous_plcstate, self.logger.write)(_("PLC is %s\n")%status) - self.AppFrame.RefreshAll() - - def RegisterDebugVarToConnector(self): - self.DebugTimer=None - Idxs = [] - self.TracedIECPath = [] - if self._connector is not None: - self.IECdebug_lock.acquire() - IECPathsToPop = [] - for IECPath,data_tuple in self.IECdebug_datas.iteritems(): - WeakCallableDict, data_log, status, fvalue = data_tuple - if len(WeakCallableDict) == 0: - # Callable Dict is empty. - # This variable is not needed anymore! - #print "Unused : " + IECPath - IECPathsToPop.append(IECPath) - elif IECPath != "__tick__": - # Convert - Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) - if Idx is not None: - if IEC_Type in DebugTypesSize: - Idxs.append((Idx, IEC_Type, fvalue, IECPath)) - else: - self.logger.write_warning(_("Debug : Unsuppoted type to debug %s\n")%IEC_Type) - else: - self.logger.write_warning(_("Debug : Unknown variable %s\n")%IECPath) - for IECPathToPop in IECPathsToPop: - self.IECdebug_datas.pop(IECPathToPop) - - if Idxs: - Idxs.sort() - self.TracedIECPath = zip(*Idxs)[3] - self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3])) - else: - self.TracedIECPath = [] - self._connector.SetTraceVariablesList([]) - self.IECdebug_lock.release() - - #for IEC_path, IECdebug_data in self.IECdebug_datas.iteritems(): - # print IEC_path, IECdebug_data[0].keys() - - def ReArmDebugRegisterTimer(self): - if self.DebugTimer is not None: - self.DebugTimer.cancel() - - # Timer to prevent rapid-fire when registering many variables - # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead - self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector]) - # Rearm anti-rapid-fire timer - self.DebugTimer.start() - - def GetDebugIECVariableType(self, IECPath): - Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None)) - return IEC_Type - - def SubscribeDebugIECVariable(self, IECPath, callableobj, *args, **kwargs): - """ - Dispatching use a dictionnary linking IEC variable paths - to a WeakKeyDictionary linking - weakly referenced callables to optionnal args - """ - if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath): - return None - - self.IECdebug_lock.acquire() - # If no entry exist, create a new one with a fresh WeakKeyDictionary - IECdebug_data = self.IECdebug_datas.get(IECPath, None) - if IECdebug_data is None: - IECdebug_data = [ - WeakKeyDictionary(), # Callables - [], # Data storage [(tick, data),...] - "Registered", # Variable status - None] # Forced value - self.IECdebug_datas[IECPath] = IECdebug_data - - IECdebug_data[0][callableobj]=(args, kwargs) - - self.IECdebug_lock.release() - - self.ReArmDebugRegisterTimer() - - return IECdebug_data[1] - - def UnsubscribeDebugIECVariable(self, IECPath, callableobj): - #print "Unsubscribe", IECPath, callableobj - self.IECdebug_lock.acquire() - IECdebug_data = self.IECdebug_datas.get(IECPath, None) - if IECdebug_data is not None: - IECdebug_data[0].pop(callableobj,None) - self.IECdebug_lock.release() - - self.ReArmDebugRegisterTimer() - - def UnsubscribeAllDebugIECVariable(self): - self.IECdebug_lock.acquire() - IECdebug_data = {} - self.IECdebug_lock.release() - - self.ReArmDebugRegisterTimer() - - def ForceDebugIECVariable(self, IECPath, fvalue): - if not self.IECdebug_datas.has_key(IECPath): - return - - self.IECdebug_lock.acquire() - - # If no entry exist, create a new one with a fresh WeakKeyDictionary - IECdebug_data = self.IECdebug_datas.get(IECPath, None) - IECdebug_data[2] = "Forced" - IECdebug_data[3] = fvalue - - self.IECdebug_lock.release() - - self.ReArmDebugRegisterTimer() - - def ReleaseDebugIECVariable(self, IECPath): - if not self.IECdebug_datas.has_key(IECPath): - return - - self.IECdebug_lock.acquire() - - # If no entry exist, create a new one with a fresh WeakKeyDictionary - IECdebug_data = self.IECdebug_datas.get(IECPath, None) - IECdebug_data[2] = "Registered" - IECdebug_data[3] = None - - self.IECdebug_lock.release() - - self.ReArmDebugRegisterTimer() - - def CallWeakcallables(self, IECPath, function_name, *cargs): - data_tuple = self.IECdebug_datas.get(IECPath, None) - if data_tuple is not None: - WeakCallableDict, data_log, status, fvalue = data_tuple - #data_log.append((debug_tick, value)) - for weakcallable,(args,kwargs) in WeakCallableDict.iteritems(): - #print weakcallable, value, args, kwargs - function = getattr(weakcallable, function_name, None) - if function is not None: - if status == "Forced" and cargs[1] == fvalue: - function(*(cargs + (True,) + args), **kwargs) - else: - function(*(cargs + args), **kwargs) - # This will block thread if more than one call is waiting - - def GetTicktime(self): - return self._Ticktime - - def RemoteExec(self, script, **kwargs): - if self._connector is None: - return -1, "No runtime connected!" - return self._connector.RemoteExec(script, **kwargs) - - def DebugThreadProc(self): - """ - This thread waid PLC debug data, and dispatch them to subscribers - """ - self.debug_break = False - debug_getvar_retry = 0 - while (not self.debug_break) and (self._connector is not None): - Trace = self._connector.GetTraceVariables() - if(Trace): - plc_status, debug_tick, debug_vars = Trace - else: - plc_status = None - debug_getvar_retry += 1 - #print debug_tick, debug_vars - if plc_status == "Started": - self.IECdebug_lock.acquire() - if len(debug_vars) == len(self.TracedIECPath): - if debug_getvar_retry > DEBUG_RETRIES_WARN: - self.logger.write(_("... debugger recovered\n")) - debug_getvar_retry = 0 - for IECPath,value in zip(self.TracedIECPath, debug_vars): - if value is not None: - self.CallWeakcallables(IECPath, "NewValue", debug_tick, value) - self.CallWeakcallables("__tick__", "NewDataAvailable") - self.IECdebug_lock.release() - if debug_getvar_retry == DEBUG_RETRIES_WARN: - self.logger.write(_("Waiting debugger to recover...\n")) - if debug_getvar_retry == DEBUG_RETRIES_REREGISTER: - # re-register debug registry to PLC - wx.CallAfter(self.RegisterDebugVarToConnector) - if debug_getvar_retry != 0: - # Be patient, tollerate PLC to come up before debugging - time.sleep(0.1) - else: - self.debug_break = True - self.logger.write(_("Debugger disabled\n")) - self.DebugThread = None - - def KillDebugThread(self): - tmp_debugthread = self.DebugThread - self.debug_break = True - if tmp_debugthread is not None: - self.logger.writeyield(_("Stopping debugger...\n")) - tmp_debugthread.join(timeout=5) - if tmp_debugthread.isAlive() and self.logger: - self.logger.write_warning(_("Couldn't stop debugger.\n")) - else: - self.logger.write(_("Debugger stopped.\n")) - self.DebugThread = None - - def _connect_debug(self): - if self.AppFrame: - self.AppFrame.ResetGraphicViewers() - self.RegisterDebugVarToConnector() - if self.DebugThread is None: - self.DebugThread = Thread(target=self.DebugThreadProc) - self.DebugThread.start() - - def _Run(self): - """ - Start PLC - """ - if self.GetIECProgramsAndVariables(): - self._connector.StartPLC() - self.logger.write(_("Starting PLC\n")) - self._connect_debug() - else: - self.logger.write_error(_("Couldn't start PLC !\n")) - wx.CallAfter(self.UpdateMethodsFromPLCStatus) - - def _Stop(self): - """ - Stop PLC - """ - if self._connector is not None and not self._connector.StopPLC(): - self.logger.write_error(_("Couldn't stop PLC !\n")) - - # debugthread should die on his own - #self.KillDebugThread() - - wx.CallAfter(self.UpdateMethodsFromPLCStatus) - - def _Connect(self): - # don't accept re-connetion is already connected - if self._connector is not None: - self.logger.write_error(_("Already connected. Please disconnect\n")) - return - - # Get connector uri - uri = self.\ - BeremizRoot.\ - getURI_location().\ - strip() - - # if uri is empty launch discovery dialog - if uri == "": - # Launch Service Discovery dialog - dialog = DiscoveryDialog(self.AppFrame) - answer = dialog.ShowModal() - uri = dialog.GetURI() - dialog.Destroy() - - # Nothing choosed or cancel button - if uri is None or answer == wx.ID_CANCEL: - self.logger.write_error(_("Connection canceled!\n")) - return - else: - self.\ - BeremizRoot.\ - setURI_location(uri) - - # Get connector from uri - try: - self._connector = connectors.ConnectorFactory(uri, self) - except Exception, msg: - self.logger.write_error(_("Exception while connecting %s!\n")%uri) - self.logger.write_error(traceback.format_exc()) - - # Did connection success ? - if self._connector is None: - # Oups. - self.logger.write_error(_("Connection failed to %s!\n")%uri) - else: - self.ShowMethod("_Connect", False) - self.ShowMethod("_Disconnect", True) - self.ShowMethod("_Transfer", True) - - self.CompareLocalAndRemotePLC() - - # Init with actual PLC status and print it - self.UpdateMethodsFromPLCStatus() - if self.previous_plcstate is not None: - status = _(self.previous_plcstate) - else: - status = "" - self.logger.write(_("PLC is %s\n")%status) - - # Start the status Timer - self.StatusTimer.Start(milliseconds=500, oneShot=False) - - if self.previous_plcstate=="Started": - if self.DebugAvailable() and self.GetIECProgramsAndVariables(): - self.logger.write(_("Debug connect matching running PLC\n")) - self._connect_debug() - else: - self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n")) - - def CompareLocalAndRemotePLC(self): - if self._connector is None: - return - # We are now connected. Update button status - MD5 = self.GetLastBuildMD5() - # Check remote target PLC correspondance to that md5 - if MD5 is not None: - if not self._connector.MatchMD5(MD5): -# self.logger.write_warning( -# _("Latest build does not match with target, please transfer.\n")) - self.EnableMethod("_Transfer", True) - else: -# self.logger.write( -# _("Latest build matches target, no transfer needed.\n")) - self.EnableMethod("_Transfer", True) - # warns controller that program match - self.ProgramTransferred() - #self.EnableMethod("_Transfer", False) - else: -# self.logger.write_warning( -# _("Cannot compare latest build to target. Please build.\n")) - self.EnableMethod("_Transfer", False) - - - def _Disconnect(self): - self._connector = None - self.StatusTimer.Stop() - wx.CallAfter(self.UpdateMethodsFromPLCStatus) - - def _Transfer(self): - # Get the last build PLC's - MD5 = self.GetLastBuildMD5() - - # Check if md5 file is empty : ask user to build PLC - if MD5 is None : - self.logger.write_error(_("Failed : Must build before transfer.\n")) - return False - - # Compare PLC project with PLC on target - if self._connector.MatchMD5(MD5): - self.logger.write( - _("Latest build already matches current target. Transfering anyway...\n")) - - # Get temprary directory path - extrafilespath = self._getExtraFilesPath() - extrafiles = [(name, open(os.path.join(extrafilespath, name), - 'rb').read()) \ - for name in os.listdir(extrafilespath) \ - if not name=="CVS"] - - # Send PLC on target - builder = self.GetBuilder() - if builder is not None: - data = builder.GetBinaryCode() - if data is not None : - if self._connector.NewPLC(MD5, data, extrafiles) and self.GetIECProgramsAndVariables(): - self.UnsubscribeAllDebugIECVariable() - self.ProgramTransferred() - if self.AppFrame is not None: - self.AppFrame.RefreshInstancesTree() - self.AppFrame.CloseObsoleteDebugTabs() - self.logger.write(_("Transfer completed successfully.\n")) - else: - self.logger.write_error(_("Transfer failed\n")) - else: - self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n")) - - wx.CallAfter(self.UpdateMethodsFromPLCStatus) - - PluginMethods = [ - {"bitmap" : opjimg("Build"), - "name" : _("Build"), - "tooltip" : _("Build project into build folder"), - "method" : "_Build"}, - {"bitmap" : opjimg("Clean"), - "name" : _("Clean"), - "enabled" : False, - "tooltip" : _("Clean project build folder"), - "method" : "_Clean"}, - {"bitmap" : opjimg("Run"), - "name" : _("Run"), - "shown" : False, - "tooltip" : _("Start PLC"), - "method" : "_Run"}, - {"bitmap" : opjimg("Stop"), - "name" : _("Stop"), - "shown" : False, - "tooltip" : _("Stop Running PLC"), - "method" : "_Stop"}, - {"bitmap" : opjimg("Connect"), - "name" : _("Connect"), - "tooltip" : _("Connect to the target PLC"), - "method" : "_Connect"}, - {"bitmap" : opjimg("Transfer"), - "name" : _("Transfer"), - "shown" : False, - "tooltip" : _("Transfer PLC"), - "method" : "_Transfer"}, - {"bitmap" : opjimg("Disconnect"), - "name" : _("Disconnect"), - "shown" : False, - "tooltip" : _("Disconnect from PLC"), - "method" : "_Disconnect"}, - {"bitmap" : opjimg("ShowIECcode"), - "name" : _("Show code"), - "shown" : False, - "tooltip" : _("Show IEC code generated by PLCGenerator"), - "method" : "_showIECcode"}, - {"bitmap" : opjimg("editIECrawcode"), - "name" : _("Raw IEC code"), - "tooltip" : _("Edit raw IEC code added to code generated by PLCGenerator"), - "method" : "_editIECrawcode"}, - ] diff -r 180e4a7d945c -r 1c23952dbde1 plugins/.cvsignore --- a/plugins/.cvsignore Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 plugins/__init__.py --- a/plugins/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -from os import listdir, path - -_base_path = path.split(__file__)[0] - -__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name.upper() != "CVS" or name.endswith(".py") and not name.startswith("__")] - -helps = [] -for name in __all__: - helpfilename = path.join(_base_path, name, "README") - if path.isfile(helpfilename): - helps.append(open(helpfilename).readline().strip()) - else: - helps.append(name) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/.cvsignore --- a/plugins/c_ext/.cvsignore Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/CFileEditor.py --- a/plugins/c_ext/CFileEditor.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,967 +0,0 @@ -import keyword - -import wx -import wx.grid -import wx.stc as stc -import wx.lib.buttons - -from controls import CustomGrid, CustomTable, EditorPanel - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - 'size2': 8, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - 'size2': 10, - } - - -def AppendMenu(parent, help, id, kind, text): - if wx.VERSION >= (2, 6, 0): - parent.Append(help=help, id=id, kind=kind, text=text) - else: - parent.Append(helpString=help, id=id, kind=kind, item=text) - - -[ID_CPPEDITOR, -] = [wx.NewId() for _init_ctrls in range(1)] - -CPP_KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class", - "const", "const_cast", "continue", "default", "delete", "do", "double", - "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", - "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "operator", "private", "protected", "public", "register", - "reinterpret_cast", "return", "short", "signed", "sizeof", "static", - "static_cast", "struct", "switch", "template", "this", "throw", "true", "try", - "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", - "void", "volatile", "wchar_t", "while"] - -def GetCursorPos(old, new): - old_length = len(old) - new_length = len(new) - common_length = min(old_length, new_length) - i = 0 - for i in xrange(common_length): - if old[i] != new[i]: - break - if old_length < new_length: - if common_length > 0 and old[i] != new[i]: - return i + new_length - old_length - else: - return i + new_length - old_length + 1 - elif old_length > new_length or i < min(old_length, new_length) - 1: - if common_length > 0 and old[i] != new[i]: - return i - else: - return i + 1 - else: - return None - -class CppEditor(stc.StyledTextCtrl): - - fold_symbols = 3 - - def __init__(self, parent, name, window, controler): - stc.StyledTextCtrl.__init__(self, parent, ID_CPPEDITOR, wx.DefaultPosition, - wx.Size(0, 0), 0) - - self.SetMarginType(1, stc.STC_MARGIN_NUMBER) - self.SetMarginWidth(1, 25) - - self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) - self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) - - self.SetLexer(stc.STC_LEX_CPP) - self.SetKeyWords(0, " ".join(CPP_KEYWORDS)) - - self.SetProperty("fold", "1") - self.SetProperty("tab.timmy.whinge.level", "1") - self.SetMargins(0,0) - - self.SetViewWhiteSpace(False) - #self.SetBufferedDraw(False) - #self.SetViewEOL(True) - #self.SetEOLMode(stc.STC_EOL_CRLF) - #self.SetUseAntiAliasing(True) - - self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) - self.SetEdgeColumn(78) - - # Setup a margin to hold fold markers - #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? - self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) - self.SetMarginMask(2, stc.STC_MASK_FOLDERS) - self.SetMarginSensitive(2, True) - self.SetMarginWidth(2, 12) - - if self.fold_symbols == 0: - # Arrow pointing right for contracted folders, arrow pointing down for expanded - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") - - elif self.fold_symbols == 1: - # Plus for contracted folders, minus for expanded - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") - - elif self.fold_symbols == 2: - # Like a flattened tree control using circular headers and curved joins - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") - - elif self.fold_symbols == 3: - # Like a flattened tree control using square headers - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") - self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") - - - self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) - self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) - self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) - - # Make some styles, The lexer defines what each style is used for, we - # just have to define what each style looks like. This set is adapted from - # Scintilla sample property files. - - # Global default styles for all languages - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) - self.StyleClearAll() # Reset all to be like the default - - # Global default styles for all languages - self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) - self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) - self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces) - self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") - self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") - - self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE') - self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056') - self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff') - self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056') - self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold') - self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF') - - # register some images for use in the AutoComplete box. - #self.RegisterImage(1, images.getSmilesBitmap()) - self.RegisterImage(1, - wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) - self.RegisterImage(2, - wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) - self.RegisterImage(3, - wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) - - # Indentation size - self.SetTabWidth(2) - self.SetUseTabs(0) - - self.Controler = controler - self.ParentWindow = window - - self.DisableEvents = True - self.Name = name - self.CurrentAction = None - - self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) - - self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_CPPEDITOR) - self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_CPPEDITOR) - - def OnModification(self, event): - if not self.DisableEvents: - mod_type = event.GetModificationType() - if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): - if mod_type&wx.stc.STC_MOD_BEFOREINSERT: - if self.CurrentAction == None: - self.StartBuffering() - elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: - self.Controler.EndBuffering() - self.StartBuffering() - self.CurrentAction = ("Add", event.GetPosition()) - wx.CallAfter(self.RefreshModel) - elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: - if self.CurrentAction == None: - self.StartBuffering() - elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: - self.Controler.EndBuffering() - self.StartBuffering() - self.CurrentAction = ("Delete", event.GetPosition()) - wx.CallAfter(self.RefreshModel) - event.Skip() - - def OnDoDrop(self, event): - self.ResetBuffer() - wx.CallAfter(self.RefreshModel) - event.Skip() - - # Buffer the last model state - def RefreshBuffer(self): - self.Controler.BufferCFile() - if self.ParentWindow is not None: - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def StartBuffering(self): - self.Controler.StartBuffering() - if self.ParentWindow is not None: - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def ResetBuffer(self): - if self.CurrentAction != None: - self.Controler.EndBuffering() - self.CurrentAction = None - - def RefreshView(self): - self.ResetBuffer() - self.DisableEvents = True - old_cursor_pos = self.GetCurrentPos() - old_text = self.GetText() - new_text = self.Controler.GetPartText(self.Name) - self.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.GotoPos(new_cursor_pos) - else: - self.GotoPos(old_cursor_pos) - self.ScrollToColumn(0) - self.EmptyUndoBuffer() - self.DisableEvents = False - - self.Colourise(0, -1) - - def DoGetBestSize(self): - return self.ParentWindow.GetPanelBestSize() - - def RefreshModel(self): - self.Controler.SetPartText(self.Name, self.GetText()) - - def OnKeyPressed(self, event): - if self.CallTipActive(): - self.CallTipCancel() - key = event.GetKeyCode() - - if key == 32 and event.ControlDown(): - pos = self.GetCurrentPos() - - # Tips - if event.ShiftDown(): - pass -## self.CallTipSetBackground("yellow") -## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' -## 'show some suff, maybe parameters..\n\n' -## 'fubar(param1, param2)') - # Code completion - else: - self.AutoCompSetIgnoreCase(False) # so this needs to match - - # Images are specified with a appended "?type" - self.AutoCompShow(0, " ".join([word + "?1" for word in CPP_KEYWORDS])) - else: - event.Skip() - - def OnKillFocus(self, event): - self.AutoCompCancel() - event.Skip() - - def OnUpdateUI(self, evt): - # check for matching braces - braceAtCaret = -1 - braceOpposite = -1 - charBefore = None - caretPos = self.GetCurrentPos() - - if caretPos > 0: - charBefore = self.GetCharAt(caretPos - 1) - styleBefore = self.GetStyleAt(caretPos - 1) - - # check before - if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: - braceAtCaret = caretPos - 1 - - # check after - if braceAtCaret < 0: - charAfter = self.GetCharAt(caretPos) - styleAfter = self.GetStyleAt(caretPos) - - if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: - braceAtCaret = caretPos - - if braceAtCaret >= 0: - braceOpposite = self.BraceMatch(braceAtCaret) - - if braceAtCaret != -1 and braceOpposite == -1: - self.BraceBadLight(braceAtCaret) - else: - self.BraceHighlight(braceAtCaret, braceOpposite) - #pt = self.PointFromPosition(braceOpposite) - #self.Refresh(True, wxRect(pt.x, pt.y, 5,5)) - #print pt - #self.Refresh(False) - - - def OnMarginClick(self, evt): - # fold and unfold as needed - if evt.GetMargin() == 2: - if evt.GetShift() and evt.GetControl(): - self.FoldAll() - else: - lineClicked = self.LineFromPosition(evt.GetPosition()) - - if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: - if evt.GetShift(): - self.SetFoldExpanded(lineClicked, True) - self.Expand(lineClicked, True, True, 1) - elif evt.GetControl(): - if self.GetFoldExpanded(lineClicked): - self.SetFoldExpanded(lineClicked, False) - self.Expand(lineClicked, False, True, 0) - else: - self.SetFoldExpanded(lineClicked, True) - self.Expand(lineClicked, True, True, 100) - else: - self.ToggleFold(lineClicked) - - - def FoldAll(self): - lineCount = self.GetLineCount() - expanding = True - - # find out if we are folding or unfolding - for lineNum in range(lineCount): - if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: - expanding = not self.GetFoldExpanded(lineNum) - break - - lineNum = 0 - - while lineNum < lineCount: - level = self.GetFoldLevel(lineNum) - if level & stc.STC_FOLDLEVELHEADERFLAG and \ - (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: - - if expanding: - self.SetFoldExpanded(lineNum, True) - lineNum = self.Expand(lineNum, True) - lineNum = lineNum - 1 - else: - lastChild = self.GetLastChild(lineNum, -1) - self.SetFoldExpanded(lineNum, False) - - if lastChild > lineNum: - self.HideLines(lineNum+1, lastChild) - - lineNum = lineNum + 1 - - - - def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): - lastChild = self.GetLastChild(line, level) - line = line + 1 - - while line <= lastChild: - if force: - if visLevels > 0: - self.ShowLines(line, line) - else: - self.HideLines(line, line) - else: - if doExpand: - self.ShowLines(line, line) - - if level == -1: - level = self.GetFoldLevel(line) - - if level & stc.STC_FOLDLEVELHEADERFLAG: - if force: - if visLevels > 1: - self.SetFoldExpanded(line, True) - else: - self.SetFoldExpanded(line, False) - - line = self.Expand(line, doExpand, force, visLevels-1) - - else: - if doExpand and self.GetFoldExpanded(line): - line = self.Expand(line, True, force, visLevels-1) - else: - line = self.Expand(line, False, force, visLevels-1) - else: - line = line + 1 - - return line - - def Cut(self): - self.ResetBuffer() - self.DisableEvents = True - self.CmdKeyExecute(wx.stc.STC_CMD_CUT) - self.DisableEvents = False - self.RefreshModel() - self.RefreshBuffer() - - def Copy(self): - self.CmdKeyExecute(wx.stc.STC_CMD_COPY) - - def Paste(self): - self.ResetBuffer() - self.DisableEvents = True - self.CmdKeyExecute(wx.stc.STC_CMD_PASTE) - self.DisableEvents = False - self.RefreshModel() - self.RefreshBuffer() - - -#------------------------------------------------------------------------------- -# Helper for VariablesGrid values -#------------------------------------------------------------------------------- - -class VariablesTable(CustomTable): - - def GetValue(self, row, col): - if row < self.GetNumberRows(): - if col == 0: - return row + 1 - else: - return str(self.data[row].get(self.GetColLabelValue(col, False), "")) - - def _updateColAttrs(self, grid): - """ - wxGrid -> update the column attributes to add the - appropriate renderer given the column name. - - Otherwise default to the default renderer. - """ - - typelist = None - accesslist = None - for row in range(self.GetNumberRows()): - for col in range(self.GetNumberCols()): - editor = None - renderer = None - colname = self.GetColLabelValue(col, False) - - if colname == "Name": - editor = wx.grid.GridCellTextEditor() - elif colname == "Class": - editor = wx.grid.GridCellChoiceEditor() - editor.SetParameters("input,memory,output") - elif colname == "Type": - pass - else: - grid.SetReadOnly(row, col, True) - - grid.SetCellEditor(row, col, editor) - grid.SetCellRenderer(row, col, renderer) - - grid.SetCellBackgroundColour(row, col, wx.WHITE) - self.ResizeRow(grid, row) - - -[ID_VARIABLESEDITOR, ID_VARIABLESEDITORVARIABLESGRID, - ID_VARIABLESEDITORADDVARIABLEBUTTON, ID_VARIABLESEDITORDELETEVARIABLEBUTTON, - ID_VARIABLESEDITORUPVARIABLEBUTTON, ID_VARIABLESEDITORDOWNVARIABLEBUTTON -] = [wx.NewId() for _init_ctrls in range(6)] - -class VariablesEditor(wx.Panel): - - if wx.VERSION < (2, 6, 0): - def Bind(self, event, function, id = None): - if id is not None: - event(self, id, function) - else: - event(self, function) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW) - parent.AddSizer(self.ButtonsSizer, 0, border=0, flag=wx.GROW) - - def _init_coll_ButtonsSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_coll_ButtonsSizer_Items(self, parent): - parent.AddWindow(self.AddVariableButton, 0, border=0, flag=wx.ALIGN_RIGHT) - parent.AddWindow(self.DeleteVariableButton, 0, border=0, flag=0) - parent.AddWindow(self.UpVariableButton, 0, border=0, flag=0) - parent.AddWindow(self.DownVariableButton, 0, border=0, flag=0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=4) - self.ButtonsSizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0) - - self._init_coll_MainSizer_Growables(self.MainSizer) - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_ButtonsSizer_Growables(self.ButtonsSizer) - self._init_coll_ButtonsSizer_Items(self.ButtonsSizer) - - self.SetSizer(self.MainSizer) - - def _init_ctrls(self, prnt): - wx.Panel.__init__(self, id=ID_VARIABLESEDITOR, name='', parent=prnt, - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - - self.VariablesGrid = CustomGrid(id=ID_VARIABLESEDITORVARIABLESGRID, - name='VariablesGrid', parent=self, pos=wx.Point(0, 0), - size=wx.Size(-1, -1), style=wx.VSCROLL) - if wx.VERSION >= (2, 5, 0): - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) - self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) - else: - wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange) - wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick) - wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown) - - self.AddVariableButton = wx.Button(id=ID_VARIABLESEDITORADDVARIABLEBUTTON, label='Add Variable', - name='AddVariableButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(122, 32), style=0) - - self.DeleteVariableButton = wx.Button(id=ID_VARIABLESEDITORDELETEVARIABLEBUTTON, label='Delete Variable', - name='DeleteVariableButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(122, 32), style=0) - - self.UpVariableButton = wx.Button(id=ID_VARIABLESEDITORUPVARIABLEBUTTON, label='^', - name='UpVariableButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(32, 32), style=0) - - self.DownVariableButton = wx.Button(id=ID_VARIABLESEDITORDOWNVARIABLEBUTTON, label='v', - name='DownVariableButton', parent=self, pos=wx.Point(0, 0), - size=wx.Size(32, 32), style=0) - - self._init_sizers() - - def __init__(self, parent, window, controler): - self._init_ctrls(parent) - - self.ParentWindow = window - self.Controler = controler - - self.VariablesDefaultValue = {"Name" : "", "Class" : "input", "Type" : ""} - self.Table = VariablesTable(self, [], ["#", "Name", "Class", "Type"]) - self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] - self.ColSizes = [40, 200, 150, 150] - self.VariablesGrid.SetTable(self.Table) - self.VariablesGrid.SetButtons({"Add": self.AddVariableButton, - "Delete": self.DeleteVariableButton, - "Up": self.UpVariableButton, - "Down": self.DownVariableButton}) - - def _AddVariable(new_row): - self.Table.InsertRow(new_row, self.VariablesDefaultValue.copy()) - self.RefreshModel() - self.RefreshView() - return new_row - setattr(self.VariablesGrid, "_AddRow", _AddVariable) - - def _DeleteVariable(row): - self.Table.RemoveRow(row) - self.RefreshModel() - self.RefreshView() - setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) - - def _MoveVariable(row, move): - new_row = self.Table.MoveRow(row, move) - if new_row != row: - self.RefreshModel() - self.RefreshView() - return new_row - setattr(self.VariablesGrid, "_MoveRow", _MoveVariable) - - self.VariablesGrid.SetRowLabelSize(0) - for col in range(self.Table.GetNumberCols()): - attr = wx.grid.GridCellAttr() - attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE) - self.VariablesGrid.SetColAttr(col, attr) - self.VariablesGrid.SetColSize(col, self.ColSizes[col]) - self.Table.ResetView(self.VariablesGrid) - - def RefreshModel(self): - self.Controler.SetVariables(self.Table.GetData()) - self.RefreshBuffer() - - # Buffer the last model state - def RefreshBuffer(self): - self.Controler.BufferCFile() - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def RefreshView(self): - self.Table.SetData(self.Controler.GetVariables()) - self.Table.ResetView(self.VariablesGrid) - self.VariablesGrid.RefreshButtons() - - def DoGetBestSize(self): - return self.ParentWindow.GetPanelBestSize() - - def OnVariablesGridCellChange(self, event): - self.RefreshModel() - wx.CallAfter(self.RefreshView) - event.Skip() - - def OnVariablesGridEditorShown(self, event): - row, col = event.GetRow(), event.GetCol() - if self.Table.GetColLabelValue(col) == "Type": - type_menu = wx.Menu(title='') - base_menu = wx.Menu(title='') - for base_type in self.Controler.GetBaseTypes(): - new_id = wx.NewId() - AppendMenu(base_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=base_type) - self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(base_type), id=new_id) - type_menu.AppendMenu(wx.NewId(), "Base Types", base_menu) - datatype_menu = wx.Menu(title='') - for datatype in self.Controler.GetDataTypes(basetypes=False, only_locatables=True): - new_id = wx.NewId() - AppendMenu(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(), "User Data Types", datatype_menu) - rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col)) - - self.VariablesGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.VariablesGrid.GetColLabelSize()) - type_menu.Destroy() - event.Veto() - else: - event.Skip() - - def GetVariableTypeFunction(self, base_type): - def VariableTypeFunction(event): - row = self.VariablesGrid.GetGridCursorRow() - self.Table.SetValueByName(row, "Type", base_type) - self.Table.ResetView(self.VariablesGrid) - self.RefreshModel() - self.RefreshView() - event.Skip() - return VariableTypeFunction - - def OnVariablesGridCellLeftClick(self, event): - if event.GetCol() == 0: - row = event.GetRow() - num = 0 - if self.Table.GetValueByName(row, "Class") == "input": - dir = "%I" - for i in xrange(row): - if self.Table.GetValueByName(i, "Class") == "input": - num += 1 - elif self.Table.GetValueByName(row, "Class") == "memory": - dir = "%M" - for i in xrange(row): - if self.Table.GetValueByName(i, "Class") == "memory": - num += 1 - else: - dir = "%Q" - for i in xrange(row): - if self.Table.GetValueByName(i, "Class") == "output": - num += 1 - data_type = self.Table.GetValueByName(row, "Type") - var_name = self.Table.GetValueByName(row, "Name") - base_location = ".".join(map(lambda x:str(x), self.Controler.GetCurrentLocation())) - location = "%s%s%s.%d"%(dir, self.Controler.GetSizeOfType(data_type), base_location, num) - data = wx.TextDataObject(str((location, "location", data_type, var_name, ""))) - dragSource = wx.DropSource(self.VariablesGrid) - dragSource.SetData(data) - dragSource.DoDragDrop() - event.Skip() - - -#------------------------------------------------------------------------------- -# SVGUIEditor Main Frame Class -#------------------------------------------------------------------------------- - -CFILE_PARTS = [ - ("Includes", CppEditor), - ("Variables", VariablesEditor), - ("Globals", CppEditor), - ("Init", CppEditor), - ("CleanUp", CppEditor), - ("Retrieve", CppEditor), - ("Publish", CppEditor), -] - -#---------------------------------------------------------------------- -# different icons for the collapsed/expanded states. -# Taken from standard Windows XP collapsed/expanded states. -#---------------------------------------------------------------------- - -def GetCollapsedIconData(): - return \ -'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ -\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ -\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\ -\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\ -\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\ -H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\ -\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\ -\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\ -\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\ -\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\ -zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\ -\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\ -~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\ -\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\ -\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\ -\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\ -0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\ -\x00\x00\x00IEND\xaeB`\x82' - -def GetCollapsedIconBitmap(): - return wx.BitmapFromImage(GetCollapsedIconImage()) - -def GetCollapsedIconImage(): - import cStringIO - stream = cStringIO.StringIO(GetCollapsedIconData()) - return wx.ImageFromStream(stream) - -#---------------------------------------------------------------------- -def GetExpandedIconData(): - return \ -'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ -\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ -\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\ -\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\ -\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\ -\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\ -\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\ -\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\ -\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\ -\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\ -\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\ -\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\ -\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\ -\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\ -\x05\x10\x81\xce\xc9\xa8\xf6>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\ -\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\ -`\x82' - -def GetExpandedIconBitmap(): - return wx.BitmapFromImage(GetExpandedIconImage()) - -def GetExpandedIconImage(): - import cStringIO - stream = cStringIO.StringIO(GetExpandedIconData()) - return wx.ImageFromStream(stream) - -class FoldPanelCaption(wx.lib.buttons.GenBitmapTextToggleButton): - - def GetBackgroundBrush(self, dc): - colBg = self.GetBackgroundColour() - brush = wx.Brush(colBg, wx.SOLID) - if self.style & wx.BORDER_NONE: - myAttr = self.GetDefaultAttributes() - parAttr = self.GetParent().GetDefaultAttributes() - myDef = colBg == myAttr.colBg - parDef = self.GetParent().GetBackgroundColour() == parAttr.colBg - if myDef and parDef: - if wx.Platform == "__WXMAC__": - brush.MacSetTheme(1) # 1 == kThemeBrushDialogBackgroundActive - elif wx.Platform == "__WXMSW__": - if self.DoEraseBackground(dc): - brush = None - elif myDef and not parDef: - colBg = self.GetParent().GetBackgroundColour() - brush = wx.Brush(colBg, wx.SOLID) - return brush - - def DrawLabel(self, dc, width, height, dx=0, dy=0): - bmp = self.bmpLabel - if bmp is not None: # if the bitmap is used - if self.bmpDisabled and not self.IsEnabled(): - bmp = self.bmpDisabled - if self.bmpFocus and self.hasFocus: - bmp = self.bmpFocus - if self.bmpSelected and not self.up: - bmp = self.bmpSelected - bw,bh = bmp.GetWidth(), bmp.GetHeight() - hasMask = bmp.GetMask() is not None - else: - bw = bh = 0 # no bitmap -> size is zero - - dc.SetFont(self.GetFont()) - if self.IsEnabled(): - dc.SetTextForeground(self.GetForegroundColour()) - else: - dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)) - - label = self.GetLabel() - tw, th = dc.GetTextExtent(label) # size of text - - if bmp is not None: - dc.DrawBitmap(bmp, width - bw - 2, (height-bh)/2, hasMask) # draw bitmap if available - - dc.DrawText(label, 2, (height-th)/2) # draw the text - - dc.SetPen(wx.Pen(self.GetForegroundColour())) - dc.SetBrush(wx.TRANSPARENT_BRUSH) - dc.DrawRectangle(0, 0, width, height) - -[ID_CFILEEDITOR, ID_CFILEEDITORMAINSPLITTER, - ID_CFILEEDITORCFILETREE, ID_CFILEEDITORPARTSOPENED, -] = [wx.NewId() for _init_ctrls in range(4)] - -class CFileEditor(EditorPanel): - - def _init_Editor(self, prnt): - self.Editor = wx.Panel(id=ID_CFILEEDITOR, parent=prnt, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - - self.Panels = {} - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2 * len(CFILE_PARTS) + 1, vgap=0) - self.MainSizer.AddGrowableCol(0) - - for idx, (name, panel_class) in enumerate(CFILE_PARTS): - button_id = wx.NewId() - button = FoldPanelCaption(id=button_id, name='FoldPanelCaption_%s' % name, - label=name, bitmap=GetCollapsedIconBitmap(), parent=self.Editor, pos=wx.Point(0, 0), - size=wx.Size(0, 20), style=wx.NO_BORDER|wx.ALIGN_LEFT) - button.SetBitmapSelected(GetExpandedIconBitmap()) - button.Bind(wx.EVT_BUTTON, self.GenPanelButtonCallback(name), id=button_id) - self.MainSizer.AddWindow(button, 0, border=0, flag=wx.TOP|wx.GROW) - - if panel_class == VariablesEditor: - panel = VariablesEditor(self.Editor, self.ParentWindow, self.Controler) - else: - panel = panel_class(self.Editor, name, self.ParentWindow, self.Controler) - self.MainSizer.AddWindow(panel, 0, border=0, flag=wx.BOTTOM|wx.GROW) - panel.Hide() - - self.Panels[name] = {"button": button, "panel": panel, "expanded": False, "row": 2 * idx + 1} - - self.Spacer = wx.Panel(self.Editor, -1) - self.SpacerExpanded = True - self.MainSizer.AddWindow(self.Spacer, 0, border=0, flag=wx.GROW) - - self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS)) - - self.Editor.SetSizer(self.MainSizer) - - def __init__(self, parent, controler, window): - EditorPanel.__init__(self, parent, "", window, controler) - - img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() - self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) - - def __del__(self): - self.Controler.OnCloseEditor(self) - - def GetTitle(self): - fullname = self.Controler.PlugFullName() - if not self.Controler.CFileIsSaved(): - return "~%s~" % fullname - return fullname - - def GetBufferState(self): - return self.Controler.GetBufferState() - - def Undo(self): - self.Controler.LoadPrevious() - self.RefreshView() - - def Redo(self): - self.Controler.LoadNext() - self.RefreshView() - - def HasNoModel(self): - return False - - def RefreshView(self): - for infos in self.Panels.itervalues(): - infos["panel"].RefreshView() - - def GenPanelButtonCallback(self, name): - def PanelButtonCallback(event): - self.TogglePanel(name) - return PanelButtonCallback - - def ExpandPanel(self, name): - infos = self.Panels.get(name, None) - if infos is not None and not infos["expanded"]: - infos["expanded"] = True - infos["button"].SetToggle(True) - infos["panel"].Show() - self.MainSizer.AddGrowableRow(infos["row"]) - - self.RefreshSizerLayout() - - def CollapsePanel(self, name): - infos = self.Panels.get(name, None) - if infos is not None and infos["expanded"]: - infos["expanded"] = False - infos["button"].SetToggle(False) - infos["panel"].Hide() - self.MainSizer.RemoveGrowableRow(infos["row"]) - - self.RefreshSizerLayout() - - def TogglePanel(self, name): - infos = self.Panels.get(name, None) - if infos is not None: - infos["expanded"] = not infos["expanded"] - infos["button"].SetToggle(infos["expanded"]) - if infos["expanded"]: - infos["panel"].Show() - self.MainSizer.AddGrowableRow(infos["row"]) - else: - infos["panel"].Hide() - self.MainSizer.RemoveGrowableRow(infos["row"]) - - self.RefreshSizerLayout() - - def RefreshSizerLayout(self): - expand_spacer = True - for infos in self.Panels.itervalues(): - expand_spacer = expand_spacer and not infos["expanded"] - - if self.SpacerExpanded != expand_spacer: - self.SpacerExpanded = expand_spacer - if expand_spacer: - self.Spacer.Show() - self.MainSizer.AddGrowableRow(2 * len(CFILE_PARTS)) - else: - self.Spacer.Hide() - self.MainSizer.RemoveGrowableRow(2 * len(CFILE_PARTS)) - - self.MainSizer.Layout() - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/README --- a/plugins/c_ext/README Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -C extension \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/__init__.py --- a/plugins/c_ext/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -from c_ext import * diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/c_ext.py --- a/plugins/c_ext/c_ext.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,315 +0,0 @@ -import wx -import os -from xml.dom import minidom -import cPickle - -from xmlclass import * - -from plugger import PlugTemplate, opjimg -from CFileEditor import CFileEditor -from PLCControler import PLCControler, UndoBuffer, LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY - -CFileClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "cext_xsd.xsd")) - -TYPECONVERSION = {"BOOL" : "X", "SINT" : "B", "INT" : "W", "DINT" : "D", "LINT" : "L", - "USINT" : "B", "UINT" : "W", "UDINT" : "D", "ULINT" : "L", "REAL" : "D", "LREAL" : "L", - "STRING" : "B", "BYTE" : "B", "WORD" : "W", "DWORD" : "D", "LWORD" : "L", "WSTRING" : "W"} - -class _Cfile: - XSD = """ - - - - - - - - - """ - EditorType = CFileEditor - - def __init__(self): - filepath = self.CFileName() - - self.CFile = CFileClasses["CFile"]() - if os.path.isfile(filepath): - xmlfile = open(filepath, 'r') - tree = minidom.parse(xmlfile) - xmlfile.close() - - for child in tree.childNodes: - if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "CFile": - self.CFile.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) - self.CreateCFileBuffer(True) - else: - self.CreateCFileBuffer(False) - self.OnPlugSave() - - def CFileName(self): - return os.path.join(self.PlugPath(), "cfile.xml") - - def GetBaseTypes(self): - return self.GetPlugRoot().GetBaseTypes() - - def GetDataTypes(self, basetypes = False, only_locatables = False): - return self.GetPlugRoot().GetDataTypes(basetypes=basetypes, only_locatables=only_locatables) - - def GetSizeOfType(self, type): - return TYPECONVERSION.get(self.GetPlugRoot().GetBaseType(type), None) - - def SetVariables(self, variables): - self.CFile.variables.setvariable([]) - for var in variables: - variable = CFileClasses["variables_variable"]() - variable.setname(var["Name"]) - variable.settype(var["Type"]) - variable.setclass(var["Class"]) - self.CFile.variables.appendvariable(variable) - - def GetVariables(self): - datas = [] - for var in self.CFile.variables.getvariable(): - datas.append({"Name" : var.getname(), "Type" : var.gettype(), "Class" : var.getclass()}) - return datas - - def GetVariableLocationTree(self): - '''See PlugTemplate.GetVariableLocationTree() for a description.''' - - current_location = ".".join(map(str, self.GetCurrentLocation())) - - vars = [] - input = memory = output = 0 - for var in self.CFile.variables.getvariable(): - var_size = self.GetSizeOfType(var.gettype()) - var_location = "" - if var.getclass() == "input": - var_class = LOCATION_VAR_INPUT - if var_size is not None: - var_location = "%%I%s%s.%d"%(var_size, current_location, input) - input += 1 - elif var.getclass() == "memory": - var_class = LOCATION_VAR_INPUT - if var_size is not None: - var_location = "%%M%s%s.%d"%(var_size, current_location, memory) - memory += 1 - else: - var_class = LOCATION_VAR_OUTPUT - if var_size is not None: - var_location = "%%Q%s%s.%d"%(var_size, current_location, output) - output += 1 - vars.append({"name": var.getname(), - "type": var_class, - "size": var_size, - "IEC_type": var.gettype(), - "var_name": var.getname(), - "location": var_location, - "description": "", - "children": []}) - - return {"name": self.BaseParams.getName(), - "type": LOCATION_PLUGIN, - "location": self.GetFullIEC_Channel(), - "children": vars} - - def SetPartText(self, name, text): - if name == "Includes": - self.CFile.includes.settext(text) - elif name == "Globals": - self.CFile.globals.settext(text) - elif name == "Init": - self.CFile.initFunction.settext(text) - elif name == "CleanUp": - self.CFile.cleanUpFunction.settext(text) - elif name == "Retrieve": - self.CFile.retrieveFunction.settext(text) - elif name == "Publish": - self.CFile.publishFunction.settext(text) - - def GetPartText(self, name): - if name == "Includes": - return self.CFile.includes.gettext() - elif name == "Globals": - return self.CFile.globals.gettext() - elif name == "Init": - return self.CFile.initFunction.gettext() - elif name == "CleanUp": - return self.CFile.cleanUpFunction.gettext() - elif name == "Retrieve": - return self.CFile.retrieveFunction.gettext() - elif name == "Publish": - return self.CFile.publishFunction.gettext() - return "" - - PluginMethods = [ - {"bitmap" : os.path.join("images", "EditCfile"), - "name" : _("Edit C File"), - "tooltip" : _("Edit C File"), - "method" : "_OpenView"}, - ] - - def PlugTestModified(self): - return self.ChangesToSave or not self.CFileIsSaved() - - def OnPlugSave(self): - filepath = self.CFileName() - - text = "\n" - extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", - "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", - "xsi:schemaLocation" : "cext_xsd.xsd"} - text += self.CFile.generateXMLText("CFile", 0, extras) - - xmlfile = open(filepath,"w") - xmlfile.write(text.encode("utf-8")) - xmlfile.close() - - self.MarkCFileAsSaved() - return True - - def PlugGenerate_C(self, buildpath, locations): - """ - Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(str, current_location)) - - text = "/* Code generated by Beremiz c_ext plugin */\n\n" - - # Adding includes - text += "/* User includes */\n" - text += self.CFile.includes.gettext() - text += "\n" - - text += """/* Beremiz c_ext plugin includes */ -#ifdef _WINDOWS_H - #include "iec_types.h" -#else - #include "iec_std_lib.h" -#endif - -""" - - # Adding variables - vars = [] - inputs = memories = outputs = 0 - for variable in self.CFile.variables.variable: - var = {"Name" : variable.getname(), "Type" : variable.gettype()} - if variable.getclass() == "input": - var["location"] = "__I%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, inputs) - inputs += 1 - elif variable.getclass() == "memory": - var["location"] = "__M%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, memories) - memories += 1 - else: - var["location"] = "__Q%s%s_%d"%(self.GetSizeOfType(var["Type"]), location_str, outputs) - outputs += 1 - vars.append(var) - text += "/* Beremiz c_ext plugin user variables definition */\n" - base_types = self.GetPlugRoot().GetBaseTypes() - for var in vars: - if var["Type"] in base_types: - prefix = "IEC_" - else: - prefix = "" - text += "%s%s beremiz%s;\n"%(prefix, var["Type"], var["location"]) - text += "%s%s *%s = &beremiz%s;\n"%(prefix, var["Type"], var["location"], var["location"]) - text += "/* User variables reference */\n" - for var in vars: - text += "#define %s beremiz%s\n"%(var["Name"], var["location"]) - text += "\n" - - # Adding user global variables and routines - text += "/* User internal user variables and routines */\n" - text += self.CFile.globals.gettext() - - # Adding Beremiz plugin functions - text += "/* Beremiz plugin functions */\n" - text += "int __init_%s(int argc,char **argv)\n{\n"%location_str - text += self.CFile.initFunction.gettext() - text += " return 0;\n" - text += "\n}\n\n" - - text += "void __cleanup_%s(void)\n{\n"%location_str - text += self.CFile.cleanUpFunction.gettext() - text += "\n}\n\n" - - text += "void __retrieve_%s(void)\n{\n"%location_str - text += self.CFile.retrieveFunction.gettext() - text += "\n}\n\n" - - text += "void __publish_%s(void)\n{\n"%location_str - text += self.CFile.publishFunction.gettext() - text += "\n}\n\n" - - Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str) - cfile = open(Gen_Cfile_path,'w') - cfile.write(text) - cfile.close() - - matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()) - - return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_flags))],str(self.CExtension.getLDFLAGS()),True - - -#------------------------------------------------------------------------------- -# Current Buffering Management Functions -#------------------------------------------------------------------------------- - - """ - Return a copy of the cfile model - """ - def Copy(self, model): - return cPickle.loads(cPickle.dumps(model)) - - def CreateCFileBuffer(self, saved): - self.Buffering = False - self.CFileBuffer = UndoBuffer(cPickle.dumps(self.CFile), saved) - - def BufferCFile(self): - self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) - - def StartBuffering(self): - self.Buffering = True - - def EndBuffering(self): - if self.Buffering: - self.CFileBuffer.Buffering(cPickle.dumps(self.CFile)) - self.Buffering = False - - def MarkCFileAsSaved(self): - self.EndBuffering() - self.CFileBuffer.CurrentSaved() - - def CFileIsSaved(self): - return self.CFileBuffer.IsCurrentSaved() and not self.Buffering - - def LoadPrevious(self): - self.EndBuffering() - self.CFile = cPickle.loads(self.CFileBuffer.Previous()) - - def LoadNext(self): - self.CFile = cPickle.loads(self.CFileBuffer.Next()) - - def GetBufferState(self): - first = self.CFileBuffer.IsFirst() and not self.Buffering - last = self.CFileBuffer.IsLast() - return not first, not last - -class RootClass: - - PlugChildsTypes = [("C_File",_Cfile, "C file")] - - def PlugGenerate_C(self, buildpath, locations): - return [],"",False - - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/c_ext/cext_xsd.xsd --- a/plugins/c_ext/cext_xsd.xsd Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Formatted text according to parts of XHTML 1.1 - - - - - - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/.cvsignore --- a/plugins/canfestival/.cvsignore Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -*.pyc diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/NetworkEditor.py --- a/plugins/canfestival/NetworkEditor.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -import os, sys -base_folder = os.path.split(sys.path[0])[0] -CanFestivalPath = os.path.join(base_folder, "CanFestival-3") - -import wx - -from subindextable import EditingPanel -from networkedit import NetworkEditorTemplate -from controls import EditorPanel - -[ID_NETWORKEDITOR, -] = [wx.NewId() for _init_ctrls in range(1)] - -[ID_NETWORKEDITORPLUGINMENUADDSLAVE, ID_NETWORKEDITORPLUGINMENUREMOVESLAVE, - ID_NETWORKEDITORPLUGINMENUMASTER, -] = [wx.NewId() for _init_coll_PluginMenu_Items in range(3)] - -[ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE, - ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, - ID_NETWORKEDITORMASTERMENUADD, -] = [wx.NewId() for _init_coll_MasterMenu_Items in range(5)] - -[ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT, - ID_NETWORKEDITORADDMENUPDOTRANSMIT, ID_NETWORKEDITORADDMENUPDORECEIVE, - ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE, -] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] - -class NetworkEditor(EditorPanel, NetworkEditorTemplate): - - ID = ID_NETWORKEDITOR - - def _init_coll_MainSizer_Items(self, parent): - parent.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL) - - def _init_coll_MainSizer_Growables(self, parent): - parent.AddGrowableCol(0) - parent.AddGrowableRow(0) - - def _init_sizers(self): - self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0) - - self._init_coll_MainSizer_Items(self.MainSizer) - self._init_coll_MainSizer_Growables(self.MainSizer) - - self.Editor.SetSizer(self.MainSizer) - - def _init_Editor(self, prnt): - self.Editor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0), - size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL) - - NetworkEditorTemplate._init_ctrls(self, self.Editor) - - self._init_sizers() - - def __init__(self, parent, controler, window): - EditorPanel.__init__(self, parent, "", window, controler) - NetworkEditorTemplate.__init__(self, controler, window, False) - - img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() - self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) - - self.RefreshNetworkNodes() - self.RefreshBufferState() - - def __del__(self): - self.Controler.OnCloseEditor(self) - - def GetPluginMenuItems(self): - add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), - (wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)), - (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_NETWORKEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)), - (wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), - (wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), - (wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] - - profile = self.Manager.GetCurrentProfileName() - if profile not in ("None", "DS-301"): - other_profile_text = _("%s Profile") % profile - add_menu.append((wx.ITEM_SEPARATOR, None)) - for text, indexes in self.Manager.GetCurrentSpecificMenu(): - add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) - else: - other_profile_text = _('Other Profile') - - master_menu = [(wx.ITEM_NORMAL, (_('Node infos'), ID_NETWORKEDITORMASTERMENUNODEINFOS, '', self.OnNodeInfosMenu)), - (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)), - (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), - (wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), - (wx.ITEM_SEPARATOR, None), - (add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))] - - return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORPLUGINMENUADDSLAVE, '', self.OnAddSlaveMenu)), - (wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORPLUGINMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)), - (wx.ITEM_SEPARATOR, None), - (master_menu, (_('Master'), ID_NETWORKEDITORPLUGINMENUMASTER))] - - def RefreshMainMenu(self): - pass - - def RefreshPluginMenu(self, plugin_menu): - plugin_menu.Enable(ID_NETWORKEDITORPLUGINMENUMASTER, self.NetworkNodes.GetSelection() == 0) - - def GetTitle(self): - fullname = self.Controler.PlugFullName() - if not self.Manager.CurrentIsSaved(): - return "~%s~" % fullname - return fullname - - def RefreshView(self): - self.RefreshCurrentIndexList() - - def RefreshBufferState(self): - NetworkEditorTemplate.RefreshBufferState(self) - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def OnNodeSelectedChanged(self, event): - NetworkEditorTemplate.OnNodeSelectedChanged(self, event) - wx.CallAfter(self.ParentWindow.RefreshPluginMenu) - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/README --- a/plugins/canfestival/README Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -CANOpen \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/SlaveEditor.py --- a/plugins/canfestival/SlaveEditor.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,83 +0,0 @@ -import os, sys -base_folder = os.path.split(sys.path[0])[0] -CanFestivalPath = os.path.join(base_folder, "CanFestival-3") - -import wx - -from subindextable import EditingPanel -from nodeeditor import NodeEditorTemplate -from controls import EditorPanel - -[ID_SLAVEEDITORPLUGINMENUNODEINFOS, ID_SLAVEEDITORPLUGINMENUDS301PROFILE, - ID_SLAVEEDITORPLUGINMENUDS302PROFILE, ID_SLAVEEDITORPLUGINMENUDSOTHERPROFILE, - ID_SLAVEEDITORPLUGINMENUADD, -] = [wx.NewId() for _init_coll_PluginMenu_Items in range(5)] - -[ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT, - ID_SLAVEEDITORADDMENUPDOTRANSMIT, ID_SLAVEEDITORADDMENUPDORECEIVE, - ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE, -] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)] - -class SlaveEditor(EditorPanel, NodeEditorTemplate): - - def _init_Editor(self, prnt): - self.Editor = EditingPanel(prnt, self, self.Controler, self.Editable) - - def __init__(self, parent, controler, window, editable=True): - self.Editable = editable - EditorPanel.__init__(self, parent, "", window, controler) - NodeEditorTemplate.__init__(self, controler, window, False) - - img = wx.Bitmap(os.path.join(CanFestivalPath, "objdictgen", "networkedit.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() - self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) - - def __del__(self): - self.Controler.OnCloseEditor(self) - - def GetPluginMenuItems(self): - if self.Editable: - add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)), - (wx.ITEM_NORMAL, (_('SDO Client'), ID_SLAVEEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)), - (wx.ITEM_NORMAL, (_('PDO Transmit'), ID_SLAVEEDITORADDMENUPDOTRANSMIT, '', self.OnAddPDOTransmitMenu)), - (wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)), - (wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)), - (wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))] - - profile = self.Controler.GetCurrentProfileName() - if profile not in ("None", "DS-301"): - other_profile_text = _("%s Profile") % profile - add_menu.append((wx.ITEM_SEPARATOR, None)) - for text, indexes in self.Manager.GetCurrentSpecificMenu(): - add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text)))) - else: - other_profile_text = _('Other Profile') - - return [(wx.ITEM_NORMAL, (_('Node infos'), ID_SLAVEEDITORPLUGINMENUNODEINFOS, '', self.OnNodeInfosMenu)), - (wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORPLUGINMENUDS301PROFILE, '', self.OnCommunicationMenu)), - (wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORPLUGINMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)), - (wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORPLUGINMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)), - (wx.ITEM_SEPARATOR, None), - (add_menu, (_('Add'), ID_SLAVEEDITORPLUGINMENUADD))] - return [] - - def RefreshPluginMenu(self, plugin_menu): - plugin_menu.Enable(ID_SLAVEEDITORPLUGINMENUDSOTHERPROFILE, False) - - def GetTitle(self): - fullname = self.Controler.PlugFullName() - if not self.Controler.CurrentIsSaved(): - return "~%s~" % fullname - return fullname - - def RefreshView(self): - self.Editor.RefreshIndexList() - - def RefreshCurrentIndexList(self): - self.RefreshView() - - def RefreshBufferState(self): - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/__init__.py --- a/plugins/canfestival/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -from canfestival import * diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/canfestival.py --- a/plugins/canfestival/canfestival.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,484 +0,0 @@ -import os, sys -base_folder = os.path.split(sys.path[0])[0] -CanFestivalPath = os.path.join(base_folder, "CanFestival-3") -sys.path.append(os.path.join(CanFestivalPath, "objdictgen")) - -from nodelist import NodeList -from nodemanager import NodeManager -import config_utils, gen_cfile, eds_utils -from networkedit import networkedit -from objdictedit import objdictedit -import canfestival_config as local_canfestival_config -from plugger import PlugTemplate -from commondialogs import CreateNodeDialog -import wx - -from SlaveEditor import SlaveEditor -from NetworkEditor import NetworkEditor - -from gnosis.xml.pickle import * -from gnosis.xml.pickle.util import setParanoia -setParanoia(0) - -if wx.Platform == '__WXMSW__': - DEFAULT_SETTINGS = { - "CAN_Driver": "can_tcp_win32", - "CAN_Device": "127.0.0.1", - "CAN_Baudrate": "125K", - "Slave_NodeId": 2, - "Master_NodeId": 1, - } -else: - DEFAULT_SETTINGS = { - "CAN_Driver": "../CanFestival-3/drivers/can_socket/libcanfestival_can_socket.so", - "CAN_Device": "vcan0", - "CAN_Baudrate": "125K", - "Slave_NodeId": 2, - "Master_NodeId": 1, - } - -#-------------------------------------------------- -# SLAVE -#-------------------------------------------------- - -class _SlavePlug(NodeManager): - XSD = """ - - - - - - - - - - - - - - - - - - - """ % DEFAULT_SETTINGS - - EditorType = SlaveEditor - - def __init__(self): - # TODO change netname when name change - NodeManager.__init__(self) - odfilepath = self.GetSlaveODPath() - if(os.path.isfile(odfilepath)): - self.OpenFileInCurrent(odfilepath) - else: - self.FilePath = "" - dialog = CreateNodeDialog(None, wx.OK) - dialog.Type.Enable(False) - dialog.GenSYNC.Enable(False) - if dialog.ShowModal() == wx.ID_OK: - name, id, nodetype, description = dialog.GetValues() - profile, filepath = dialog.GetProfile() - NMT = dialog.GetNMTManagement() - options = dialog.GetOptions() - self.CreateNewNode(name, # Name - will be changed at build time - id, # NodeID - will be changed at build time - "slave", # Type - description,# description - profile, # profile - filepath, # prfile filepath - NMT, # NMT - options) # options - else: - self.CreateNewNode("SlaveNode", # Name - will be changed at build time - 0x00, # NodeID - will be changed at build time - "slave", # Type - "", # description - "None", # profile - "", # prfile filepath - "heartbeat", # NMT - []) # options - dialog.Destroy() - self.OnPlugSave() - - def GetSlaveODPath(self): - return os.path.join(self.PlugPath(), 'slave.od') - - def GetCanDevice(self): - return self.CanFestivalSlaveNode.getCan_Device() - - def _OpenView(self): - PlugTemplate._OpenView(self) - if self._View is not None: - self._View.SetBusId(self.GetCurrentLocation()) - - PluginMethods = [ - {"bitmap" : os.path.join("images", "NetworkEdit"), - "name" : "Edit slave", - "tooltip" : "Edit CanOpen slave with ObjdictEdit", - "method" : "_OpenView"}, - ] - - def OnPlugClose(self): - if self._View: - self._View.Close() - - def PlugTestModified(self): - return self.ChangesToSave or self.OneFileHasChanged() - - def OnPlugSave(self): - return self.SaveCurrentInFile(self.GetSlaveODPath()) - - def SetParamsAttribute(self, path, value): - result = PlugTemplate.SetParamsAttribute(self, path, value) - - # Filter IEC_Channel and Name, that have specific behavior - if path == "BaseParams.IEC_Channel" and self._View is not None: - self._View.SetBusId(self.GetCurrentLocation()) - - return result - - def PlugGenerate_C(self, buildpath, locations): - """ - Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - prefix = "_".join(map(str, current_location)) - Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) - # Create a new copy of the model - slave = self.GetCurrentNodeCopy() - slave.SetNodeName("OD_%s"%prefix) - # allow access to local OD from Slave PLC - pointers = config_utils.LocalODPointers(locations, current_location, slave) - res = gen_cfile.GenerateFile(Gen_OD_path, slave, pointers) - if res : - raise Exception, res - res = eds_utils.GenerateEDSFile(os.path.join(buildpath, "Slave_%s.eds"%prefix), slave) - if res : - raise Exception, res - return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False - - def LoadPrevious(self): - self.LoadCurrentPrevious() - - def LoadNext(self): - self.LoadCurrentNext() - - def GetBufferState(self): - return self.GetCurrentBufferState() - -#-------------------------------------------------- -# MASTER -#-------------------------------------------------- - -class MiniNodeManager(NodeManager): - - def __init__(self, parent, filepath, fullname): - NodeManager.__init__(self) - - self.OpenFileInCurrent(filepath) - - self.Parent = parent - self.Fullname = fullname - - def OnCloseEditor(self, view): - self.Parent.OnCloseEditor(view) - - def PlugFullName(self): - return self.Fullname - - def GetBufferState(self): - return self.GetCurrentBufferState() - -class _NodeListPlug(NodeList): - XSD = """ - - - - - - - - - - - """ % DEFAULT_SETTINGS - - EditorType = NetworkEditor - - def __init__(self): - manager = NodeManager() - NodeList.__init__(self, manager) - self.LoadProject(self.PlugPath()) - self.SetNetworkName(self.BaseParams.getName()) - - def GetCanDevice(self): - return self.CanFestivalNode.getCan_Device() - - def SetParamsAttribute(self, path, value): - result = PlugTemplate.SetParamsAttribute(self, path, value) - - # Filter IEC_Channel and Name, that have specific behavior - if path == "BaseParams.IEC_Channel" and self._View is not None: - self._View.SetBusId(self.GetCurrentLocation()) - elif path == "BaseParams.Name": - self.SetNetworkName(value) - - return result - - def _OpenView(self): - PlugTemplate._OpenView(self) - if self._View is not None: - self._View.SetBusId(self.GetCurrentLocation()) - - _GeneratedView = None - def _ShowMasterGenerated(self): - if self._GeneratedView is None: - buildpath = self._getBuildPath() - # Eventually create build dir - if not os.path.exists(buildpath): - self.GetPlugRoot().logger.write_error(_("Error: No PLC built\n")) - return - - masterpath = os.path.join(buildpath, "MasterGenerated.od") - if not os.path.exists(masterpath): - self.GetPlugRoot().logger.write_error(_("Error: No Master generated\n")) - return - - app_frame = self.GetPlugRoot().AppFrame - - manager = MiniNodeManager(self, masterpath, self.PlugFullName() + ".generated_master") - self._GeneratedView = SlaveEditor(app_frame.TabsOpened, manager, app_frame, False) - - app_frame.EditProjectElement(self._GeneratedView, "MasterGenerated") - - def _CloseGenerateView(self): - if self._GeneratedView is not None: - app_frame = self.GetPlugRoot().AppFrame - if app_frame is not None: - app_frame.DeletePage(self._GeneratedView) - - PluginMethods = [ - {"bitmap" : os.path.join("images", "NetworkEdit"), - "name" : _("Edit network"), - "tooltip" : _("Edit CanOpen Network with NetworkEdit"), - "method" : "_OpenView"}, - {"bitmap" : os.path.join("images", "ShowMaster"), - "name" : _("Show Master"), - "tooltip" : _("Show Master generated by config_utils"), - "method" : "_ShowMasterGenerated"} - ] - - def OnCloseEditor(self, view): - PlugTemplate.OnCloseEditor(self, view) - if self._GeneratedView == view: - self._GeneratedView = None - - def OnPlugClose(self): - PlugTemplate.OnPlugClose(self) - self._CloseGenerateView() - return True - - def PlugTestModified(self): - return self.ChangesToSave or self.HasChanged() - - def OnPlugSave(self): - self.SetRoot(self.PlugPath()) - return self.SaveProject() is None - - def PlugGenerate_C(self, buildpath, locations): - """ - Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - self._CloseGenerateView() - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - prefix = "_".join(map(str, current_location)) - Gen_OD_path = os.path.join(buildpath, "OD_%s.c"%prefix ) - # Create a new copy of the model with DCF loaded with PDO mappings for desired location - try: - master, pointers = config_utils.GenerateConciseDCF(locations, current_location, self, self.CanFestivalNode.getSync_TPDOs(),"OD_%s"%prefix) - except config_utils.PDOmappingException, e: - raise Exception, e.message - # Do generate C file. - res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers) - if res : - raise Exception, res - - file = open(os.path.join(buildpath, "MasterGenerated.od"), "w") - dump(master, file) - file.close() - - return [(Gen_OD_path,local_canfestival_config.getCFLAGS(CanFestivalPath))],"",False - - def LoadPrevious(self): - self.Manager.LoadCurrentPrevious() - - def LoadNext(self): - self.Manager.LoadCurrentNext() - - def GetBufferState(self): - return self.Manager.GetCurrentBufferState() - -class RootClass: - XSD = """ - - - - - - - - - """ % DEFAULT_SETTINGS - - PlugChildsTypes = [("CanOpenNode",_NodeListPlug, "CanOpen Master"), - ("CanOpenSlave",_SlavePlug, "CanOpen Slave")] - def GetParamsAttributes(self, path = None): - infos = PlugTemplate.GetParamsAttributes(self, path = None) - for element in infos: - if element["name"] == "CanFestivalInstance": - for child in element["children"]: - if child["name"] == "CAN_Driver": - DLL_LIST= getattr(local_canfestival_config,"DLL_LIST",None) - if DLL_LIST is not None: - child["type"] = DLL_LIST - return infos - - def GetCanDriver(self): - can_driver = self.CanFestivalInstance.getCAN_Driver() - if sys.platform == 'win32': - if self.CanFestivalInstance.getDebug_mode() and os.path.isfile(os.path.join("%s"%(can_driver + '_DEBUG.dll'))): - can_driver += '_DEBUG.dll' - else: - can_driver += '.dll' - return can_driver - - def PlugGenerate_C(self, buildpath, locations): - - format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())), - "candriver" : self.GetCanDriver(), - "nodes_includes" : "", - "board_decls" : "", - "nodes_init" : "", - "nodes_open" : "", - "nodes_stop" : "", - "nodes_close" : "", - "nodes_send_sync" : "", - "nodes_proceed_sync" : "", - "slavebootups" : "", - "slavebootup_register" : "", - "post_sync" : "", - "post_sync_register" : "", - } - for child in self.IECSortedChilds(): - childlocstr = "_".join(map(str,child.GetCurrentLocation())) - nodename = "OD_%s" % childlocstr - - # Try to get Slave Node - child_data = getattr(child, "CanFestivalSlaveNode", None) - if child_data is None: - # Not a slave -> master - child_data = getattr(child, "CanFestivalNode") - # Apply sync setting - format_dict["nodes_init"] += 'NODE_MASTER_INIT(%s, %s)\n '%( - nodename, - child_data.getNodeId()) - if child_data.getSync_TPDOs(): - format_dict["nodes_send_sync"] += 'NODE_SEND_SYNC(%s)\n '%(nodename) - format_dict["nodes_proceed_sync"] += 'NODE_PROCEED_SYNC(%s)\n '%(nodename) - - # initialize and declare node boot status variables for post_SlaveBootup lookup - SlaveIDs = child.GetSlaveIDs() - if len(SlaveIDs) == 0: - # define post_SlaveBootup lookup functions - format_dict["slavebootups"] += ( - "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n"%(nodename)) - else: - for id in SlaveIDs: - format_dict["slavebootups"] += ( - "int %s_slave_%d_booted = 0;\n"%(nodename, id)) - # define post_SlaveBootup lookup functions - format_dict["slavebootups"] += ( - "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+ - " switch(nodeId){\n") - # one case per declared node, mark node as booted - for id in SlaveIDs: - format_dict["slavebootups"] += ( - " case %d:\n"%(id)+ - " %s_slave_%d_booted = 1;\n"%(nodename, id)+ - " break;\n") - format_dict["slavebootups"] += ( - " default:\n"+ - " break;\n"+ - " }\n"+ - " if( ") - # expression to test if all declared nodes booted - format_dict["slavebootups"] += " && ".join(["%s_slave_%d_booted"%(nodename, id) for id in SlaveIDs]) - format_dict["slavebootups"] += " )\n" + ( - " Master_post_SlaveBootup(d,nodeId);\n"+ - "}\n") - # register previously declared func as post_SlaveBootup callback for that node - format_dict["slavebootup_register"] += ( - "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n"%(nodename,nodename)) - else: - # Slave node - align = child_data.getSync_Align() - align_ratio=child_data.getSync_Align_Ratio() - if align > 0: - format_dict["post_sync"] += ( - "static int %s_CalCount = 0;\n"%(nodename)+ - "static void %s_post_sync(CO_Data* d){\n"%(nodename)+ - " if(%s_CalCount < %d){\n"%(nodename, align)+ - " %s_CalCount++;\n"%(nodename)+ - " align_tick(-1);\n"+ - " }else{\n"+ - " align_tick(%d);\n"%(align_ratio)+ - " }\n"+ - "}\n") - format_dict["post_sync_register"] += ( - "%s_Data.post_sync = %s_post_sync;\n"%(nodename,nodename)) - format_dict["nodes_init"] += 'NODE_SLAVE_INIT(%s, %s)\n '%( - nodename, - child_data.getNodeId()) - - # Include generated OD headers - format_dict["nodes_includes"] += '#include "%s.h"\n'%(nodename) - # Declare CAN channels according user filled config - format_dict["board_decls"] += 'BOARD_DECL(%s, "%s", "%s")\n'%( - nodename, - child.GetCanDevice(), - child_data.getCAN_Baudrate()) - format_dict["nodes_open"] += 'NODE_OPEN(%s)\n '%(nodename) - format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n '%(nodename) - format_dict["nodes_stop"] += 'NODE_STOP(%s)\n '%(nodename) - - filename = os.path.join(os.path.split(__file__)[0],"cf_runtime.c") - cf_main = open(filename).read() % format_dict - cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict) - f = open(cf_main_path,'w') - f.write(cf_main) - f.close() - - return [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True - - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/cf_runtime.c --- a/plugins/canfestival/cf_runtime.c Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ - -#include "canfestival.h" - -/* CanFestival nodes generated OD headers*/ -%(nodes_includes)s - -#define BOARD_DECL(nodename, busname, baudrate)\ - s_BOARD nodename##Board = {busname, baudrate}; - -/* CAN channels declaration */ -%(board_decls)s - -/* Keep track of init level to cleanup correctly */ -static int init_level=0; -/* Retrieve PLC cycle time */ -extern int common_ticktime__; - -/* Called once all NetworkEdit declares slaves have booted*/ -static void Master_post_SlaveBootup(CO_Data* d, UNS8 nodeId) -{ - /* Put the master in operational mode */ - setState(d, Operational); - - /* Ask slave node to go in operational mode */ - masterSendNMTstateChange (d, 0, NMT_Start_Node); -} - -/* Per master node slavebootup callbacks. Checks that - * every node have booted before calling Master_post_SlaveBootup */ -%(slavebootups)s - -/* One slave node post_sync callback. - * Used to align PLC tick-time on CANopen SYNC - */ -%(post_sync)s - -#define NODE_FORCE_SYNC(nodename) \ - /* Artificially force sync state to 1 so that it is not started */\ - nodename##_Data.CurrentCommunicationState.csSYNC = -1;\ - /* Force sync period to common_ticktime__ so that other node can read it*/\ - *nodename##_Data.COB_ID_Sync = 0x40000080;\ - *nodename##_Data.Sync_Cycle_Period = common_ticktime__ * 1000; - -#define NODE_INIT(nodename, nodeid) \ - /* Defining the node Id */\ - setNodeId(&nodename##_Data, nodeid);\ - /* init */\ - setState(&nodename##_Data, Initialisation); - -#define NODE_MASTER_INIT(nodename, nodeid) \ - NODE_FORCE_SYNC(nodename) \ - NODE_INIT(nodename, nodeid) - -#define NODE_SLAVE_INIT(nodename, nodeid) \ - NODE_INIT(nodename, nodeid) - -void InitNodes(CO_Data* d, UNS32 id) -{ - %(slavebootup_register)s - %(post_sync_register)s - %(nodes_init)s -} - -#define NODE_STOP(nodename) \ - if(init_level-- > 0)\ - {\ - masterSendNMTstateChange(&nodename##_Data, 0, NMT_Reset_Node);\ - setState(&nodename##_Data, Stopped);\ - } - -void Exit(CO_Data* d, UNS32 id) -{ - %(nodes_stop)s -} - -#define NODE_CLOSE(nodename) \ - if(init_level_c-- > 0)\ - {\ - canClose(&nodename##_Data);\ - } - -void __cleanup_%(locstr)s(void) -{ - // Stop timer thread - if(init_level-- > 0){ - int init_level_c = init_level; - StopTimerLoop(&Exit); - %(nodes_close)s - } - - TimerCleanup(); -} - -#ifndef stderr -#define fprintf(...) -#define fflush(...) -#endif - -#define NODE_OPEN(nodename)\ - if(!canOpen(&nodename##Board,&nodename##_Data)){\ - fprintf(stderr,"Cannot open CAN intefrace %%s at speed %%s\n for CANopen node \"" #nodename "\"",nodename##Board.busname, nodename##Board.baudrate);\ - fflush(stderr);\ - return -1;\ - }\ - init_level++; - -/*************************** INIT *****************************************/ -int __init_%(locstr)s(int argc,char **argv) -{ -#ifndef NOT_USE_DYNAMIC_LOADING - if( !LoadCanDriver("%(candriver)s") ){ - fprintf(stderr, "Cannot load CAN interface library for CanFestival (%(candriver)s)\n");\ - fflush(stderr);\ - return -1;\ - } -#endif - - TimerInit(); - - %(nodes_open)s - - // Start timer thread - StartTimerLoop(&InitNodes); - init_level++; - return 0; -} - -#define NODE_SEND_SYNC(nodename)\ - sendSYNCMessage(&nodename##_Data); - -void __retrieve_%(locstr)s(void) -{ - /* Locks the stack, so that no changes occurs while PLC access variables - * TODO : implement buffers to avoid such a big lock - * */ - EnterMutex(); - /* Send Sync */ - %(nodes_send_sync)s -} - -#define NODE_PROCEED_SYNC(nodename)\ - proceedSYNC(&nodename##_Data); - -void __publish_%(locstr)s(void) -{ - /* Process sync event */ - %(nodes_proceed_sync)s - LeaveMutex(); -} - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/config_utils.py --- a/plugins/canfestival/config_utils.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,737 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -#This file is part of Beremiz, a Integrated Development Environment for -#programming IEC 61131-3 automates supporting plcopen standard and CanFestival. -# -#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 types import * - -# Translation between IEC types and Can Open types -IECToCOType = {"BOOL":0x01, "SINT":0x02, "INT":0x03,"DINT":0x04,"LINT":0x10, - "USINT":0x05,"UINT":0x06,"UDINT":0x07,"ULINT":0x1B,"REAL":0x08, - "LREAL":0x11,"STRING":0x09,"BYTE":0x05,"WORD":0x06,"DWORD":0x07, - "LWORD":0x1B,"WSTRING":0x0B} - -# Constants for PDO types -RPDO = 1 -TPDO = 2 - -SlavePDOType = {"I" : TPDO, "Q" : RPDO} -InvertPDOType = {RPDO : TPDO, TPDO : RPDO} -PDOTypeBaseIndex = {RPDO : 0x1400, TPDO : 0x1800} -PDOTypeBaseCobId = {RPDO : 0x200, TPDO : 0x180} - -VariableIncrement = 0x100 -VariableStartIndex = {TPDO : 0x2000, RPDO : 0x4000} -VariableDirText = {TPDO : "__I", RPDO : "__Q"} -VariableTypeOffset = dict(zip(["","X","B","W","D","L"], range(6))) - -TrashVariables = [(1, 0x01), (8, 0x05), (16, 0x06), (32, 0x07), (64, 0x1B)] - -#------------------------------------------------------------------------------- -# Specific exception for PDO mapping errors -#------------------------------------------------------------------------------- - -class PDOmappingException(Exception): - pass - - -def LE_to_BE(value, size): - """ - Convert Little Endian to Big Endian - @param value: value expressed in integer - @param size: number of bytes generated - @return: a string containing the value converted - """ - - data = ("%" + str(size * 2) + "." + str(size * 2) + "X") % value - list_car = [data[i:i+2] for i in xrange(0, len(data), 2)] - list_car.reverse() - return "".join([chr(int(car, 16)) for car in list_car]) - - -def GetNodePDOIndexes(node, type, parameters = False): - """ - Find the PDO indexes of a node - @param node: node - @param type: type of PDO searched (RPDO or TPDO or both) - @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) - @return: a list of indexes found - """ - - indexes = [] - if type & RPDO: - indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF]) - if type & TPDO: - indexes.extend([idx for idx in node.GetIndexes() if 0x1800 <= idx <= 0x19FF]) - if not parameters: - return [idx + 0x200 for idx in indexes] - else: - return indexes - - -def SearchNodePDOMapping(loc_infos, node): - """ - Find the PDO indexes of a node - @param node: node - @param type: type of PDO searched (RPDO or TPDO or both) - @param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False) - @return: a list of indexes found - """ - - model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) - - for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]): - values = node.GetEntry(PDOidx) - if values != None: - for subindex, mapping in enumerate(values): - if subindex != 0 and mapping & 0xFFFFFF00 == model: - return PDOidx, subindex - return None - - -def GeneratePDOMappingDCF(idx, cobid, transmittype, pdomapping): - """ - Build concise DCF value for configuring a PDO - @param idx: index of PDO parameters - @param cobid: PDO generated COB ID - @param transmittype : PDO transmit type - @param pdomapping: list of PDO mappings - @return: a tuple of value and number of parameters to add to DCF - """ - - # Create entry for RPDO or TPDO parameters and Disable PDO - dcfdata = LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4) - # Set Transmit type synchrone - dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x02, 1) + LE_to_BE(0x01, 4) + LE_to_BE(transmittype, 1) - # Re-Enable PDO - # ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------ - dcfdata += LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4) - nbparams = 3 - if len(pdomapping) > 0: - dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(0x00, 1) + LE_to_BE(0x01, 4) + LE_to_BE(len(pdomapping), 1) - nbparams += 1 - # Map Variables - for subindex, (name, loc_infos) in enumerate(pdomapping): - value = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8) + loc_infos["size"] - dcfdata += LE_to_BE(idx + 0x200, 2) + LE_to_BE(subindex + 1, 1) + LE_to_BE(0x04, 4) + LE_to_BE(value, 4) - nbparams += 1 - return dcfdata, nbparams - -class ConciseDCFGenerator: - - def __init__(self, nodelist, nodename): - # Dictionary of location informations classed by name - self.IECLocations = {} - # Dictionary of location that have not been mapped yet - self.LocationsNotMapped = {} - # Dictionary of location informations classed by name - self.MasterMapping = {} - # List of COB IDs available - self.ListCobIDAvailable = range(0x180, 0x580) - # Dictionary of mapping value where unexpected variables are stored - self.TrashVariables = {} - # Dictionary of pointed variables - self.PointedVariables = {} - - self.NodeList = nodelist - self.Manager = self.NodeList.Manager - self.MasterNode = self.Manager.GetCurrentNodeCopy() - self.MasterNode.SetNodeName(nodename) - self.PrepareMasterNode() - - def GetPointedVariables(self): - return self.PointedVariables - - def RemoveUsedNodeCobId(self, node): - """ - Remove all PDO COB ID used by the given node from the list of available COB ID - @param node: node - @return: a tuple of number of RPDO and TPDO for the node - """ - - # Get list of all node TPDO and RPDO indexes - nodeRpdoIndexes = GetNodePDOIndexes(node, RPDO, True) - nodeTpdoIndexes = GetNodePDOIndexes(node, TPDO, True) - - # Mark all the COB ID of the node already mapped PDO as not available - for PdoIdx in nodeRpdoIndexes + nodeTpdoIndexes: - pdo_cobid = node.GetEntry(PdoIdx, 0x01) - # Extract COB ID, if PDO isn't active - if pdo_cobid > 0x600 : - pdo_cobid -= 0x80000000 - # Remove COB ID from the list of available COB ID - if pdo_cobid in self.ListCobIDAvailable: - self.ListCobIDAvailable.remove(pdo_cobid) - - return len(nodeRpdoIndexes), len(nodeTpdoIndexes) - - - def PrepareMasterNode(self): - """ - Add mandatory entries for DCF generation into MasterNode. - """ - - # Adding DCF entry into Master node - if not self.MasterNode.IsEntry(0x1F22): - self.MasterNode.AddEntry(0x1F22, 1, "") - self.Manager.AddSubentriesToCurrent(0x1F22, 127, self.MasterNode) - - # Adding trash mappable variables for unused mapped datas - idxTrashVariables = 0x2000 + self.MasterNode.GetNodeID() - # Add an entry for storing unexpected all variable - self.Manager.AddMapVariableToCurrent(idxTrashVariables, self.MasterNode.GetNodeName()+"_trashvariables", 3, len(TrashVariables), self.MasterNode) - for subidx, (size, typeidx) in enumerate(TrashVariables): - # Add a subentry for storing unexpected variable of this size - self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, "TRASH%d" % size, "name", None, self.MasterNode) - self.Manager.SetCurrentEntry(idxTrashVariables, subidx + 1, typeidx, "type", None, self.MasterNode) - # Store the mapping value for this entry - self.TrashVariables[size] = (idxTrashVariables << 16) + ((subidx + 1) << 8) + size - - RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(self.MasterNode) - - # Store the indexes of the first RPDO and TPDO available for MasterNode - self.CurrentPDOParamsIdx = {RPDO : 0x1400 + RPDOnumber, TPDO : 0x1800 + TPDOnumber} - - # Prepare MasterNode with all nodelist slaves - for idx, (nodeid, nodeinfos) in enumerate(self.NodeList.SlaveNodes.items()): - node = nodeinfos["Node"] - node.SetNodeID(nodeid) - - RPDOnumber, TPDOnumber = self.RemoveUsedNodeCobId(node) - - # Get Slave's default SDO server parameters - RSDO_cobid = node.GetEntry(0x1200,0x01) - if not RSDO_cobid: - RSDO_cobid = 0x600 + nodeid - TSDO_cobid = node.GetEntry(0x1200,0x02) - if not TSDO_cobid: - TSDO_cobid = 0x580 + nodeid - - # Configure Master's SDO parameters entries - self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode) - self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid) - self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid) - self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid) - - - def GetMasterNode(self): - """ - Return MasterNode. - """ - return self.MasterNode - - def AddParamsToDCF(self, nodeid, data, nbparams): - """ - Add entry to DCF, for the requested nodeID - @param nodeid: id of the slave (int) - @param data: data to add to slave DCF (string) - @param nbparams: number of params added to slave DCF (int) - """ - # Get current DCF for slave - nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid) - - # Extract data and number of params in current DCF - if nodeDCF != None and nodeDCF != '': - tmpnbparams = [i for i in nodeDCF[:4]] - tmpnbparams.reverse() - nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16) - data = nodeDCF[4:] + data - - # Build new DCF - dcf = LE_to_BE(nbparams, 0x04) + data - # Set new DCF for slave - self.MasterNode.SetEntry(0x1F22, nodeid, dcf) - - def GetEmptyPDO(self, nodeid, pdotype, start_index=None): - """ - Search a not configured PDO for a slave - @param node: the slave node object - @param pdotype: type of PDO to generated (RPDO or TPDO) - @param start_index: Index where search must start (default: None) - @return tuple of PDO index, COB ID and number of subindex defined - """ - # If no start_index defined, start with PDOtype base index - if start_index is None: - index = PDOTypeBaseIndex[pdotype] - else: - index = start_index - - # Search for all PDO possible index until find a configurable PDO - # starting from start_index - while index < PDOTypeBaseIndex[pdotype] + 0x200: - values = self.NodeList.GetSlaveNodeEntry(nodeid, index + 0x200) - if values != None and values[0] > 0: - # Check that all subindex upper than 0 equal 0 => configurable PDO - if reduce(lambda x, y: x and y, map(lambda x: x == 0, values[1:]), True): - cobid = self.NodeList.GetSlaveNodeEntry(nodeid, index, 1) - # If no COB ID defined in PDO, generate a new one (not used) - if cobid == 0: - if len(self.ListCobIDAvailable) == 0: - return None - # Calculate COB ID from standard values - if index < PDOTypeBaseIndex[pdotype] + 4: - cobid = PDOTypeBaseCobId[pdotype] + 0x100 * (index - PDOTypeBaseIndex[pdotype]) + nodeid - if cobid not in self.ListCobIDAvailable: - cobid = self.ListCobIDAvailable.pop(0) - return index, cobid, values[0] - index += 1 - return None - - def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs): - """ - Record a new mapping request for a slave, and add related slave config to the DCF - @param nodeid: id of the slave (int) - @param pdotype: type of PDO to generated (RPDO or TPDO) - @param pdomapping: list od variables to map with PDO - """ - # Add an entry to MasterMapping - self.MasterMapping[pdocobid] = {"type" : InvertPDOType[pdotype], - "mapping" : [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]} - - # Return the data to add to DCF - if sync_TPDOs: - return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping) - else: - return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping) - return 0, "" - - def GenerateDCF(self, locations, current_location, sync_TPDOs): - """ - Generate Concise DCF of MasterNode for the locations list given - @param locations: list of locations to be mapped - @param current_location: tuple of the located prefixes not to be considered - @param sync_TPDOs: indicate if TPDO must be synchronous - """ - - #------------------------------------------------------------------------------- - # Verify that locations correspond to real slave variables - #------------------------------------------------------------------------------- - - # Get list of locations check if exists and mappables -> put them in IECLocations - for location in locations: - COlocationtype = IECToCOType[location["IEC_TYPE"]] - name = location["NAME"] - if name in self.IECLocations: - if self.IECLocations[name]["type"] != COlocationtype: - raise PDOmappingException, _("Type conflict for location \"%s\"") % name - else: - # Get only the part of the location that concern this node - loc = location["LOC"][len(current_location):] - # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) - if len(loc) not in (2, 3, 4): - raise PDOmappingException, _("Bad location size : %s") % str(loc) - elif len(loc) == 2: - continue - - direction = location["DIR"] - - sizelocation = location["SIZE"] - - # Extract and check nodeid - nodeid, index, subindex = loc[:3] - - # Check Id is in slave node list - if nodeid not in self.NodeList.SlaveNodes.keys(): - raise PDOmappingException, _("Non existing node ID : %d (variable %s)") % (nodeid,name) - - # Get the model for this node (made from EDS) - node = self.NodeList.SlaveNodes[nodeid]["Node"] - - # Extract and check index and subindex - if not node.IsEntry(index, subindex): - raise PDOmappingException, _("No such index/subindex (%x,%x) in ID : %d (variable %s)") % (index,subindex,nodeid,name) - - # Get the entry info - subentry_infos = node.GetSubentryInfos(index, subindex) - - # If a PDO mappable - if subentry_infos and subentry_infos["pdo"]: - if sizelocation == "X" and len(loc) > 3: - numbit = loc[3] - elif sizelocation != "X" and len(loc) > 3: - raise PDOmappingException, _("Cannot set bit offset for non bool '%s' variable (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex) - else: - numbit = None - - if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype: - raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) - - typeinfos = node.GetEntryInfos(COlocationtype) - self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction], - "nodeid": nodeid, "index": index,"subindex": subindex, - "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation} - else: - raise PDOmappingException, _("Not PDO mappable variable : '%s' (ID:%d,Idx:%x,sIdx:%x))") % (name,nodeid,index,subindex) - - #------------------------------------------------------------------------------- - # Search for locations already mapped - #------------------------------------------------------------------------------- - - for name, locationinfos in self.IECLocations.items(): - node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"] - - # Search if slave has a PDO mapping this locations - result = SearchNodePDOMapping(locationinfos, node) - if result != None: - index, subindex = result - # Get COB ID of the PDO - cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1) - - # Add PDO to MasterMapping - if cobid not in self.MasterMapping.keys(): - # Verify that PDO transmit type is conform to sync_TPDOs - transmittype = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 2) - if sync_TPDOs and transmittype != 0x01 or transmittype != 0xFF: - if sync_TPDOs: - # Change TransmitType to SYNCHRONE - data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0x01, []) - else: - # Change TransmitType to ASYCHRONE - data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, []) - - # Add entry to slave dcf to change transmit type of - self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams) - - mapping = [None] - values = node.GetEntry(index) - # Store the size of each entry mapped in PDO - for value in values[1:]: - if value != 0: - mapping.append(value % 0x100) - self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping} - - # Indicate that this PDO entry must be saved - if locationinfos["bit"] is not None: - if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType): - self.MasterMapping[cobid]["mapping"][subindex] = [1] * self.MasterMapping[cobid]["mapping"][subindex] - if locationinfos["bit"] < len(self.MasterMapping[cobid]["mapping"][subindex]): - self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name) - else: - self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name) - - else: - # Add location to those that haven't been mapped yet - if locationinfos["nodeid"] not in self.LocationsNotMapped.keys(): - self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []} - self.LocationsNotMapped[locationinfos["nodeid"]][locationinfos["pdotype"]].append((name, locationinfos)) - - #------------------------------------------------------------------------------- - # Build concise DCF for the others locations - #------------------------------------------------------------------------------- - - for nodeid, locations in self.LocationsNotMapped.items(): - node = self.NodeList.SlaveNodes[nodeid]["Node"] - - # Initialize number of params and data to add to node DCF - nbparams = 0 - dataparams = "" - - # Generate the best PDO mapping for each type of PDO - for pdotype in (TPDO, RPDO): - if len(locations[pdotype]) > 0: - pdosize = 0 - pdomapping = [] - result = self.GetEmptyPDO(nodeid, pdotype) - if result is None: - raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid - pdoindex, pdocobid, pdonbparams = result - for name, loc_infos in locations[pdotype]: - pdosize += loc_infos["size"] - # If pdo's size > 64 bits - if pdosize > 64 or len(pdomapping) >= pdonbparams: - # Generate a new PDO Mapping - data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs) - dataparams += data - nbparams += nbaddedparams - pdosize = loc_infos["size"] - pdomapping = [(name, loc_infos)] - result = self.GetEmptyPDO(nodeid, pdotype, pdoindex + 1) - if result is None: - raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid - pdoindex, pdocobid, pdonbparams = result - else: - pdomapping.append((name, loc_infos)) - # If there isn't locations yet but there is still a PDO to generate - if len(pdomapping) > 0: - # Generate a new PDO Mapping - data, nbaddedparams = self.AddPDOMapping(nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs) - dataparams += data - nbparams += nbaddedparams - - # Add number of params and data to node DCF - self.AddParamsToDCF(nodeid, dataparams, nbparams) - - #------------------------------------------------------------------------------- - # Master Node Configuration - #------------------------------------------------------------------------------- - - # Generate Master's Configuration from informations stored in MasterMapping - for cobid, pdo_infos in self.MasterMapping.items(): - # Get next PDO index in MasterNode for this PDO type - current_idx = self.CurrentPDOParamsIdx[pdo_infos["type"]] - - # Search if there is already a PDO in MasterNode with this cob id - for idx in GetNodePDOIndexes(self.MasterNode, pdo_infos["type"], True): - if self.MasterNode.GetEntry(idx, 1) == cobid: - current_idx = idx - - # Add a PDO to MasterNode if not PDO have been found - if current_idx == self.CurrentPDOParamsIdx[pdo_infos["type"]]: - addinglist = [current_idx, current_idx + 0x200] - self.Manager.ManageEntriesOfCurrent(addinglist, [], self.MasterNode) - self.MasterNode.SetEntry(current_idx, 0x01, cobid) - - # Increment the number of PDO for this PDO type - self.CurrentPDOParamsIdx[pdo_infos["type"]] += 1 - - # Change the transmit type of the PDO - if sync_TPDOs: - self.MasterNode.SetEntry(current_idx, 0x02, 0x01) - else: - self.MasterNode.SetEntry(current_idx, 0x02, 0xFF) - - mapping = [] - for item in pdo_infos["mapping"]: - if isinstance(item, ListType): - mapping.extend(item) - else: - mapping.append(item) - - # Add some subentries to PDO mapping if there is not enough - if len(mapping) > 1: - self.Manager.AddSubentriesToCurrent(current_idx + 0x200, len(mapping) - 1, self.MasterNode) - - # Generate MasterNode's PDO mapping - for subindex, variable in enumerate(mapping): - if subindex == 0: - continue - new_index = False - - if isinstance(variable, (IntType, LongType)): - # If variable is an integer then variable is unexpected - self.MasterNode.SetEntry(current_idx + 0x200, subindex, self.TrashVariables[variable]) - else: - typeidx, varname = variable - variable_infos = self.IECLocations[varname] - - # Calculate base index for storing variable - mapvariableidx = VariableStartIndex[variable_infos["pdotype"]] + \ - VariableTypeOffset[variable_infos["sizelocation"]] * VariableIncrement + \ - variable_infos["nodeid"] - - # Generate entry name - indexname = "%s%s%s_%d"%(VariableDirText[variable_infos["pdotype"]], - variable_infos["sizelocation"], - '_'.join(map(str,current_location)), - variable_infos["nodeid"]) - - # Search for an entry that has an empty subindex - while mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: - # Entry doesn't exist - if not self.MasterNode.IsEntry(mapvariableidx): - # Add entry to MasterNode - self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode) - new_index = True - nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00) - else: - # Get Number of subentries already defined - nbsubentries = self.MasterNode.GetEntry(mapvariableidx, 0x00) - # if entry is full, go to next entry possible or stop now - if nbsubentries == 0xFF: - mapvariableidx += 8 * VariableIncrement - else: - break - - # Verify that a not full entry has been found - if mapvariableidx < VariableStartIndex[variable_infos["pdotype"]] + 0x2000: - # Generate subentry name - if variable_infos["bit"] != None: - subindexname = "%(index)d_%(subindex)d_%(bit)d"%variable_infos - else: - subindexname = "%(index)d_%(subindex)d"%variable_infos - # If entry have just been created, no subentry have to be added - if not new_index: - self.Manager.AddSubentriesToCurrent(mapvariableidx, 1, self.MasterNode) - nbsubentries += 1 - # Add informations to the new subentry created - self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"name" : subindexname}) - self.MasterNode.SetMappingEntry(mapvariableidx, nbsubentries, values = {"type" : typeidx}) - - # Set value of the PDO mapping - typeinfos = self.Manager.GetEntryInfos(typeidx) - if typeinfos != None: - value = (mapvariableidx << 16) + ((nbsubentries) << 8) + typeinfos["size"] - self.MasterNode.SetEntry(current_idx + 0x200, subindex, value) - - # Add variable to pointed variables - self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s"%(indexname, subindexname) - -def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename): - """ - Fills a CanFestival network editor model, with DCF with requested PDO mappings. - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @param nodelist: CanFestival network editor model - @return: a modified copy of the given CanFestival network editor model - """ - - dcfgenerator = ConciseDCFGenerator(nodelist, nodename) - dcfgenerator.GenerateDCF(locations, current_location, sync_TPDOs) - masternode,pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables() - # allow access to local OD from Master PLC - pointers.update(LocalODPointers(locations, current_location, masternode)) - return masternode,pointers - -def LocalODPointers(locations, current_location, slave): - IECLocations = {} - pointers = {} - for location in locations: - COlocationtype = IECToCOType[location["IEC_TYPE"]] - name = location["NAME"] - if name in IECLocations: - if IECLocations[name] != COlocationtype: - raise PDOmappingException, _("Type conflict for location \"%s\"") % name - else: - # Get only the part of the location that concern this node - loc = location["LOC"][len(current_location):] - # loc correspond to (ID, INDEX, SUBINDEX [,BIT]) - if len(loc) not in (2, 3, 4): - raise PDOmappingException, _("Bad location size : %s") % str(loc) - elif len(loc) != 2: - continue - - # Extract and check nodeid - index, subindex = loc[:2] - - # Extract and check index and subindex - if not slave.IsEntry(index, subindex): - raise PDOmappingException, _("No such index/subindex (%x,%x) (variable %s)") % (index, subindex, name) - - # Get the entry info - subentry_infos = slave.GetSubentryInfos(index, subindex) - if subentry_infos["type"] != COlocationtype: - raise PDOmappingException, _("Invalid type \"%s\"-> %d != %d for location\"%s\"") % (location["IEC_TYPE"], COlocationtype, subentry_infos["type"] , name) - - IECLocations[name] = COlocationtype - pointers[(index, subindex)] = name - return pointers - -if __name__ == "__main__": - import os, sys, getopt - - def usage(): - print """ -Usage of config_utils.py test : - - %s [options] - -Options: - --help (-h) - Displays help informations for config_utils - - --reset (-r) - Reset the reference result of config_utils test. - Use with caution. Be sure that config_utils - is currently working properly. -"""%sys.argv[0] - - # Boolean that indicate if reference result must be redefined - reset = False - - # Extract command options - try: - opts, args = getopt.getopt(sys.argv[1:], "hr", ["help","reset"]) - except getopt.GetoptError: - # print help information and exit: - usage() - sys.exit(2) - - # Test each option - for o, a in opts: - if o in ("-h", "--help"): - usage() - sys.exit() - elif o in ("-r", "--reset"): - reset = True - - # Extract workspace base folder - base_folder = sys.path[0] - for i in xrange(3): - base_folder = os.path.split(base_folder)[0] - # Add CanFestival folder to search pathes - sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen")) - - from nodemanager import * - from nodelist import * - - # Open the test nodelist contained into test_config folder - manager = NodeManager() - nodelist = NodeList(manager) - result = nodelist.LoadProject("test_config") - - # List of locations, we try to map for test - locations = [{"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24576_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24576,1)}, - {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_2","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,2)}, - {"IEC_TYPE":"INT","NAME":"__IW0_1_64_25601_3","DIR":"I","SIZE":"W","LOC":(0,1,64,25601,3)}, - {"IEC_TYPE":"INT","NAME":"__QW0_1_64_25617_2","DIR":"Q","SIZE":"W","LOC":(0,1,64,25617,1)}, - {"IEC_TYPE":"BYTE","NAME":"__IB0_1_64_24578_1","DIR":"I","SIZE":"B","LOC":(0,1,64,24578,1)}, - {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_1","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,1)}, - {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_2","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,2)}, - {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_3","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,3)}, - {"IEC_TYPE":"UDINT","NAME":"__ID0_1_64_25638_4","DIR":"I","SIZE":"D","LOC":(0,1,64,25638,4)}, - {"IEC_TYPE":"UDINT","NAME":"__ID0_1_4096_0","DIR":"I","SIZE":"D","LOC":(0,1,4096,0)}] - - # Generate MasterNode configuration - try: - masternode, pointedvariables = GenerateConciseDCF(locations, (0, 1), nodelist, True, "TestNode") - except ValueError, message: - print "%s\nTest Failed!"%message - sys.exit() - - import pprint - # Get Text corresponding to MasterNode - result_node = masternode.PrintString() - result_vars = pprint.pformat(pointedvariables) - result = result_node + "\n********POINTERS*********\n" + result_vars + "\n" - - # If reset has been choosen - if reset: - # Write Text into reference result file - testfile = open("test_config/result.txt", "w") - testfile.write(result) - testfile.close() - - print "Reset Successful!" - else: - import os - - testfile = open("test_config/result_tmp.txt", "w") - testfile.write(result) - testfile.close() - - os.system("diff test_config/result.txt test_config/result_tmp.txt") - os.remove("test_config/result_tmp.txt") diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/test_config/eds/PEAK MicroMod.eds --- a/plugins/canfestival/test_config/eds/PEAK MicroMod.eds Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1289 +0,0 @@ -[FileInfo] -CreatedBy=ESAcademy -ModifiedBy=ESAcademy -Description=PEAK MicroMod CANopenIA Generic -CreationTime=09:41PM -CreationDate=05-05-2003 -ModificationTime=05:05PM -ModificationDate=03-23-2005 -FileName=C:\CANopenCT\Tests\PEAK MicroMod.eds -FileVersion=1 -FileRevision=1 -EDSVersion=4 - -[DeviceInfo] -VendorName=PEAK System Technik -VendorNumber=0x00000175 -ProductName=PEAK MicroMod CANopenIA Generic -ProductNumber=0x00100000 -RevisionNumber=0x00010001 -OrderCode=na -BaudRate_10=0 -BaudRate_20=0 -BaudRate_50=1 -BaudRate_125=1 -BaudRate_250=1 -BaudRate_500=1 -BaudRate_800=1 -BaudRate_1000=1 -SimpleBootUpMaster=0 -SimpleBootUpSlave=1 -Granularity=0 -DynamicChannelsSupported=0 -CompactPDO=0 -GroupMessaging=0 -NrOfRXPDO=4 -NrOfTXPDO=4 -LSS_Supported=0 - -[DummyUsage] -Dummy0001=0 -Dummy0002=0 -Dummy0003=0 -Dummy0004=0 -Dummy0005=1 -Dummy0006=1 -Dummy0007=1 - -[Comments] -Lines=0 - -[MandatoryObjects] -SupportedObjects=3 -1=0x1000 -2=0x1001 -3=0x1018 - -[1000] -ParameterName=Device Type -ObjectType=0x7 -DataType=0x0007 -AccessType=ro -DefaultValue=0x000F0191 -PDOMapping=0 - -[1001] -ParameterName=Error Register -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=0 -PDOMapping=0 - -[1018] -ParameterName=Identity Object -ObjectType=0x9 -SubNumber=4 - -[1018sub0] -ParameterName=number of entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=3 -PDOMapping=0 - -[1018sub1] -ParameterName=Vendor ID -ObjectType=0x7 -DataType=0x0007 -AccessType=ro -DefaultValue=0x00000175 -PDOMapping=0 - -[1018sub2] -ParameterName=Product Code -ObjectType=0x7 -DataType=0x0007 -AccessType=ro -DefaultValue=0x00100000 -PDOMapping=0 - -[1018sub3] -ParameterName=Revision number -ObjectType=0x7 -DataType=0x0007 -AccessType=ro -DefaultValue=0x00010001 -PDOMapping=0 - -[OptionalObjects] -SupportedObjects=41 -1=0x1002 -2=0x1005 -3=0x1008 -4=0x1009 -5=0x100A -6=0x100C -7=0x100D -8=0x1010 -9=0x1011 -10=0x1016 -11=0x1017 -12=0x1020 -13=0x1400 -14=0x1401 -15=0x1402 -16=0x1403 -17=0x1600 -18=0x1601 -19=0x1602 -20=0x1603 -21=0x1800 -22=0x1801 -23=0x1802 -24=0x1803 -25=0x1A00 -26=0x1A01 -27=0x1A02 -28=0x1A03 -29=0x1F50 -30=0x6000 -31=0x6002 -32=0x6200 -33=0x6202 -34=0x6206 -35=0x6207 -36=0x6401 -37=0x6411 -38=0x6423 -39=0x6426 -40=0x6443 -41=0x6444 - -[1002] -ParameterName=PEAK Status Register -ObjectType=0x7 -DataType=0x0007 -AccessType=ro -PDOMapping=0 - -[1005] -ParameterName=COB-ID SYNC -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x00000080 -PDOMapping=0 - -[1008] -ParameterName=Manufacturer Device Name -ObjectType=0x7 -DataType=0x0009 -AccessType=const -PDOMapping=0 - -[1009] -ParameterName=Manufacturer Hardware Version -ObjectType=0x7 -DataType=0x0009 -AccessType=const -PDOMapping=0 - -[100a] -ParameterName=Manufacturer Software Version -ObjectType=0x7 -DataType=0x0009 -AccessType=const -PDOMapping=0 - -[100c] -ParameterName=Guard Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[100d] -ParameterName=Life Time Factor -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0x00 -PDOMapping=0 - -[1010] -ParameterName=Store Parameter Field -ObjectType=0x8 -SubNumber=2 - -[1010sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1010sub1] -ParameterName=Save all Parameters -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 - -[1011] -ParameterName=Restore Default Parameters -ObjectType=0x8 -SubNumber=2 - -[1011sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[1011sub1] -ParameterName=Restore all Default Parameters -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 - -[1016] -ParameterName=Consumer Heartbeat Time -ObjectType=0x8 -SubNumber=4 - -[1016sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=3 -PDOMapping=0 -LowLimit=0x1 - -[1016sub1] -ParameterName=Consumer Heartbeat Time -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1016sub2] -ParameterName=Consumer Heartbeat Time -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1016sub3] -ParameterName=Consumer Heartbeat Time -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1017] -ParameterName=Producer Heartbeat Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1020] -ParameterName=Verify Configuration -ObjectType=0x8 -SubNumber=3 - -[1020sub0] -ParameterName=Number of entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1020sub1] -ParameterName=Configuration date -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 - -[1020sub2] -ParameterName=Configuration time -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -PDOMapping=0 - -[1400] -ParameterName=Receive PDO Communication Parameter -ObjectType=0x9 -SubNumber=3 - -[1400sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1400sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x200 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1400sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1401] -ParameterName=Receive PDO Communication Parameter -ObjectType=0x9 -SubNumber=3 - -[1401sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 - -[1401sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x300 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1401sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1402] -ParameterName=Receive PDO Communication Parameter -ObjectType=0x9 -SubNumber=3 - -[1402sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1402sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x80000400 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1402sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1403] -ParameterName=Receive PDO Communication Parameter -ObjectType=0x9 -SubNumber=3 - -[1403sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=2 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1403sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x80000500 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1403sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1600] -ParameterName=Receive PDO Mapping Parameter -ObjectType=0x9 -SubNumber=2 - -[1600sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=1 -PDOMapping=0 - -[1600sub1] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x62000108 -PDOMapping=0 - -[1601] -ParameterName=Receive PDO Mapping Parameter -ObjectType=0x9 -SubNumber=5 - -[1601sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=4 -PDOMapping=0 - -[1601sub1] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64110110 -PDOMapping=0 - -[1601sub2] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64110210 -PDOMapping=0 - -[1601sub3] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64110310 -PDOMapping=0 - -[1601sub4] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64110410 -PDOMapping=0 - -[1602] -ParameterName=Receive PDO Mapping Parameter -ObjectType=0x9 -SubNumber=1 - -[1602sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1603] -ParameterName=Receive PDO Mapping Parameter -ObjectType=0x9 -SubNumber=1 - -[1603sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1800] -ParameterName=Transmit PDO Communication Parameter -ObjectType=0x9 -SubNumber=5 - -[1800sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=5 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1800sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x180 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1800sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1800sub3] -ParameterName=Inhibit Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0x0000 -PDOMapping=0 - -[1800sub5] -ParameterName=Event Timer -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1801] -ParameterName=Transmit PDO Communication Parameter -ObjectType=0x9 -SubNumber=5 - -[1801sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=5 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1801sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x280 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1801sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1801sub3] -ParameterName=Inhibit Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0x0000 -PDOMapping=0 - -[1801sub5] -ParameterName=Event Timer -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1802] -ParameterName=Transmit PDO Communication Parameter -ObjectType=0x9 -SubNumber=5 - -[1802sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=5 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1802sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x380 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1802sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1802sub3] -ParameterName=Inhibit Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0x0000 -PDOMapping=0 - -[1802sub5] -ParameterName=Event Timer -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1803] -ParameterName=Transmit PDO Communication Parameter -ObjectType=0x9 -SubNumber=5 - -[1803sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=5 -PDOMapping=0 -LowLimit=0x02 -HighLimit=0x05 - -[1803sub1] -ParameterName=COB-ID -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=$NODEID+0x80000480 -PDOMapping=0 -LowLimit=0x00000001 -HighLimit=0xFFFFFFFF - -[1803sub2] -ParameterName=Transmission Type -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=255 -PDOMapping=0 - -[1803sub3] -ParameterName=Inhibit Time -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0x0000 -PDOMapping=0 - -[1803sub5] -ParameterName=Event Timer -ObjectType=0x7 -DataType=0x0006 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1a00] -ParameterName=Transmit PDO Mapping Parameter -ObjectType=0x9 -SubNumber=2 - -[1a00sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=1 -PDOMapping=0 - -[1a00sub1] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x60000108 -PDOMapping=0 - -[1a01] -ParameterName=Transmit PDO Mapping Parameter -ObjectType=0x9 -SubNumber=5 - -[1a01sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=4 -PDOMapping=0 - -[1a01sub1] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010110 -PDOMapping=0 - -[1a01sub2] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010210 -PDOMapping=0 - -[1a01sub3] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010310 -PDOMapping=0 - -[1a01sub4] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010410 -PDOMapping=0 - -[1a02] -ParameterName=Transmit PDO Mapping Parameter -ObjectType=0x9 -SubNumber=5 - -[1a02sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=4 -PDOMapping=0 - -[1a02sub1] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010510 -PDOMapping=0 - -[1a02sub2] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010610 -PDOMapping=0 - -[1a02sub3] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010710 -PDOMapping=0 - -[1a02sub4] -ParameterName=PDO Mapping Entry -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0x64010810 -PDOMapping=0 - -[1a03] -ParameterName=Transmit PDO Mapping Parameter -ObjectType=0x9 -SubNumber=1 - -[1a03sub0] -ParameterName=Number of Entries -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[1f50] -ParameterName=Download Program Data -ObjectType=0x8 -SubNumber=2 - -[1f50sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=3 -PDOMapping=0 - -[1f50sub3] -ParameterName=Download Program Data - HW Settings -ObjectType=0x7 -DataType=0x000F -AccessType=rw -PDOMapping=0 - -[6000] -ParameterName=Read Digital Input 8-bit -ObjectType=0x8 -SubNumber=2 - -[6000sub0] -ParameterName=Number of Elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6000sub1] -ParameterName=DigInput8_1 -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -PDOMapping=1 - -[6002] -ParameterName=Polarity Digital Input -ObjectType=0x8 -SubNumber=2 - -[6002sub0] -ParameterName=Number of Elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6002sub1] -ParameterName=Polarity8_1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6200] -ParameterName=Write Digital Output 8-bit -ObjectType=0x8 -SubNumber=2 - -[6200sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6200sub1] -ParameterName=DigOutput8_1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rww -PDOMapping=1 - -[6202] -ParameterName=Polarity Digital Output -ObjectType=0x8 -SubNumber=2 - -[6202sub0] -ParameterName=Number of Elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6202sub1] -ParameterName=Polarity8_1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6206] -ParameterName=Error Mode Digital Output -ObjectType=0x8 -SubNumber=2 - -[6206sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6206sub1] -ParameterName=Error Mode 1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6207] -ParameterName=Error Value Digital Output -ObjectType=0x8 -SubNumber=2 - -[6207sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=1 -PDOMapping=0 - -[6207sub1] -ParameterName=Error Value 1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6401] -ParameterName=Read Analog Input 16-bit -ObjectType=0x8 -SubNumber=9 - -[6401sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=8 -PDOMapping=0 - -[6401sub1] -ParameterName=AnalogInput16_1 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub2] -ParameterName=AnalogInput16_2 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub3] -ParameterName=AnalogInput16_3 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub4] -ParameterName=AnalogInput16_4 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub5] -ParameterName=AnalogInput16_5 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub6] -ParameterName=AnalogInput16_6 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub7] -ParameterName=AnalogInput16_7 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6401sub8] -ParameterName=AnalogInput16_8 -ObjectType=0x7 -DataType=0x0003 -AccessType=ro -PDOMapping=1 - -[6411] -ParameterName=Write Analog Output 16-bit -ObjectType=0x8 -SubNumber=5 - -[6411sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=4 -PDOMapping=0 - -[6411sub1] -ParameterName=AnalogOutput16_1 -ObjectType=0x7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 - -[6411sub2] -ParameterName=AnalogOutput16_2 -ObjectType=0x7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 - -[6411sub3] -ParameterName=AnalogOutput16_3 -ObjectType=0x7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 - -[6411sub4] -ParameterName=AnalogOutput16_4 -ObjectType=0x7 -DataType=0x0003 -AccessType=rww -PDOMapping=1 - -[6423] -ParameterName=Analog Input Global Interrupt -ObjectType=0x7 -DataType=0x0001 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426] -ParameterName=Analog Input Interrupt Delta -ObjectType=0x8 -SubNumber=9 - -[6426sub0] -ParameterName=NrOfObjects -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=8 -PDOMapping=0 - -[6426sub1] -ParameterName=Analog Input Delta 1 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub2] -ParameterName=Analog Input Delta 2 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub3] -ParameterName=Analog Input Delta 3 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub4] -ParameterName=Analog Input Delta 4 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub5] -ParameterName=Analog Input Delta 5 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub6] -ParameterName=Analog Input Delta 6 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub7] -ParameterName=Analog Input Delta 7 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6426sub8] -ParameterName=Analog Input Delta 8 -ObjectType=0x7 -DataType=0x0007 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6443] -ParameterName=Error Mode Analog Output -ObjectType=0x8 -SubNumber=5 - -[6443sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=4 -PDOMapping=0 - -[6443sub1] -ParameterName=Error Mode 1 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6443sub2] -ParameterName=Error Mode 2 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6443sub3] -ParameterName=Error Mode 3 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6443sub4] -ParameterName=Error Mode 4 -ObjectType=0x7 -DataType=0x0005 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6444] -ParameterName=Error Value Analog Output -ObjectType=0x8 -SubNumber=5 - -[6444sub0] -ParameterName=Number of elements -ObjectType=0x7 -DataType=0x0005 -AccessType=ro -DefaultValue=4 -PDOMapping=0 - -[6444sub1] -ParameterName=Error Value 1 -ObjectType=0x7 -DataType=0x0004 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6444sub2] -ParameterName=Error Value 2 -ObjectType=0x7 -DataType=0x0004 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6444sub3] -ParameterName=Error Value 3 -ObjectType=0x7 -DataType=0x0004 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[6444sub4] -ParameterName=Error Value 4 -ObjectType=0x7 -DataType=0x0004 -AccessType=rw -DefaultValue=0 -PDOMapping=0 - -[ManufacturerObjects] -SupportedObjects=0 diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/test_config/master.od --- a/plugins/canfestival/test_config/master.od Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,314 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Read Inputs - - - - - - - Read Inputs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -master - -TestMaster - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/test_config/nodelist.cpj --- a/plugins/canfestival/test_config/nodelist.cpj Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -[TOPOLOGY] -NetName=None -Nodes=0x01 -Node64Present=0x01 -Node64Name=micromod -Node64DCFName=PEAK MicroMod.eds -EDSBaseName=eds diff -r 180e4a7d945c -r 1c23952dbde1 plugins/canfestival/test_config/result.txt --- a/plugins/canfestival/test_config/result.txt Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,257 +0,0 @@ -1000 (Device Type): 12E -1001 (Error Register): 0 -1005 (SYNC COB ID): 40000080 -1006 (Communication / Cycle Period): C350 -1016 (Consumer Heartbeat Time): -1016 01 (Consumer Heartbeat Time): 4005DC -1018 (Identity): -1018 01 (Vendor ID): 0 -1018 02 (Product Code): 0 -1018 03 (Revision Number): 0 -1018 04 (Serial Number): 0 -1280 (Client SDO 1 Parameter): -1280 01 (COB ID Client to Server (Transmit SDO)): 640 -1280 02 (COB ID Server to Client (Receive SDO)): 5C0 -1280 03 (Node ID of the SDO Server): 40 -1400 (Receive PDO 1 Parameter): -1400 01 (COB ID used by PDO): 1C0 -1400 02 (Transmission Type): 1 -1400 03 (Inhibit Time): 0 -1400 04 (Compatibility Entry): 0 -1400 05 (Event Timer): 0 -1401 (Receive PDO 2 Parameter): -1401 01 (COB ID used by PDO): 2C0 -1401 02 (Transmission Type): 1 -1401 03 (Inhibit Time): 0 -1401 04 (Compatibility Entry): 0 -1401 05 (Event Timer): 0 -1402 (Receive PDO 3 Parameter): -1402 01 (COB ID used by PDO): 182 -1402 02 (Transmission Type): 1 -1402 03 (Inhibit Time): 0 -1402 04 (Compatibility Entry): 0 -1402 05 (Event Timer): 0 -1403 (Receive PDO 4 Parameter): -1403 01 (COB ID used by PDO): 183 -1403 02 (Transmission Type): 1 -1403 03 (Inhibit Time): 0 -1403 04 (Compatibility Entry): 0 -1403 05 (Event Timer): 0 -1404 (Receive PDO 5 Parameter): -1404 01 (COB ID used by PDO): 181 -1404 02 (Transmission Type): 1 -1404 03 (Inhibit Time): 0 -1404 04 (Compatibility Entry): 0 -1404 05 (Event Timer): 0 -1600 (Receive PDO 1 Mapping): -1600 01 (PDO 1 Mapping for an application object 1): 22400108 -1600 02 (PDO 1 Mapping for an application object 2): 0 -1601 (Receive PDO 2 Mapping): -1601 01 (PDO 2 Mapping for an application object 1): 20000310 -1601 02 (PDO 2 Mapping for an application object 2): 23400110 -1601 03 (PDO 2 Mapping for an application object 3): 23400210 -1601 04 (PDO 2 Mapping for an application object 4): 20000310 -1602 (Receive PDO 3 Mapping): -1602 01 (PDO 3 Mapping for an application object 1): 24400120 -1602 02 (PDO 3 Mapping for an application object 2): 24400220 -1603 (Receive PDO 4 Mapping): -1603 01 (PDO 4 Mapping for an application object 1): 24400320 -1604 (Receive PDO 5 Mapping): -1604 01 (PDO 5 Mapping for an application object 1): 22400208 -1604 02 (PDO 5 Mapping for an application object 2): 24400420 -1800 (Transmit PDO 1 Parameter): -1800 01 (COB ID used by PDO): {True:"$NODEID+0x%X80"%(base+1),False:0x80000000}[base<4] -1800 02 (Transmission Type): 0 -1800 03 (Inhibit Time): 0 -1800 04 (Compatibility Entry): 0 -1800 05 (Event Timer): 0 -1801 (Transmit PDO 2 Parameter): -1801 01 (COB ID used by PDO): 340 -1801 02 (Transmission Type): 1 -1801 03 (Inhibit Time): 0 -1801 04 (Compatibility Entry): 0 -1801 05 (Event Timer): 0 -1A00 (Transmit PDO 1 Mapping): -1A00 01 (PDO 1 Mapping for a process data variable 1): 10010008 -1A01 (Transmit PDO 2 Mapping): -1A01 01 (PDO 2 Mapping for a process data variable 1): 43400110 -1A01 02 (PDO 2 Mapping for a process data variable 2): 20000310 -1A01 03 (PDO 2 Mapping for a process data variable 3): 20000310 -1A01 04 (PDO 2 Mapping for a process data variable 4): 20000310 -1F22 (Concise DCF): -1F22 01 (Concise DCF for Node 1): -1F22 02 (Concise DCF for Node 2): -1F22 03 (Concise DCF for Node 3): -1F22 04 (Concise DCF for Node 4): -1F22 05 (Concise DCF for Node 5): -1F22 06 (Concise DCF for Node 6): -1F22 07 (Concise DCF for Node 7): -1F22 08 (Concise DCF for Node 8): -1F22 09 (Concise DCF for Node 9): -1F22 0A (Concise DCF for Node 10): -1F22 0B (Concise DCF for Node 11): -1F22 0C (Concise DCF for Node 12): -1F22 0D (Concise DCF for Node 13): -1F22 0E (Concise DCF for Node 14): -1F22 0F (Concise DCF for Node 15): -1F22 10 (Concise DCF for Node 16): -1F22 11 (Concise DCF for Node 17): -1F22 12 (Concise DCF for Node 18): -1F22 13 (Concise DCF for Node 19): -1F22 14 (Concise DCF for Node 20): -1F22 15 (Concise DCF for Node 21): -1F22 16 (Concise DCF for Node 22): -1F22 17 (Concise DCF for Node 23): -1F22 18 (Concise DCF for Node 24): -1F22 19 (Concise DCF for Node 25): -1F22 1A (Concise DCF for Node 26): -1F22 1B (Concise DCF for Node 27): -1F22 1C (Concise DCF for Node 28): -1F22 1D (Concise DCF for Node 29): -1F22 1E (Concise DCF for Node 30): -1F22 1F (Concise DCF for Node 31): -1F22 20 (Concise DCF for Node 32): -1F22 21 (Concise DCF for Node 33): -1F22 22 (Concise DCF for Node 34): -1F22 23 (Concise DCF for Node 35): -1F22 24 (Concise DCF for Node 36): -1F22 25 (Concise DCF for Node 37): -1F22 26 (Concise DCF for Node 38): -1F22 27 (Concise DCF for Node 39): -1F22 28 (Concise DCF for Node 40): -1F22 29 (Concise DCF for Node 41): -1F22 2A (Concise DCF for Node 42): -1F22 2B (Concise DCF for Node 43): -1F22 2C (Concise DCF for Node 44): -1F22 2D (Concise DCF for Node 45): -1F22 2E (Concise DCF for Node 46): -1F22 2F (Concise DCF for Node 47): -1F22 30 (Concise DCF for Node 48): -1F22 31 (Concise DCF for Node 49): -1F22 32 (Concise DCF for Node 50): -1F22 33 (Concise DCF for Node 51): -1F22 34 (Concise DCF for Node 52): -1F22 35 (Concise DCF for Node 53): -1F22 36 (Concise DCF for Node 54): -1F22 37 (Concise DCF for Node 55): -1F22 38 (Concise DCF for Node 56): -1F22 39 (Concise DCF for Node 57): -1F22 3A (Concise DCF for Node 58): -1F22 3B (Concise DCF for Node 59): -1F22 3C (Concise DCF for Node 60): -1F22 3D (Concise DCF for Node 61): -1F22 3E (Concise DCF for Node 62): -1F22 3F (Concise DCF for Node 63): -1F22 40 (Concise DCF for Node 64): 23 arg defined -1F22 40, arg 1: 1800 01 00000004 800001C0 -1F22 40, arg 2: 1800 02 00000001 01 -1F22 40, arg 3: 1800 01 00000004 000001C0 -1F22 40, arg 4: 1801 01 00000004 800002C0 -1F22 40, arg 5: 1801 02 00000001 01 -1F22 40, arg 6: 1801 01 00000004 000002C0 -1F22 40, arg 7: 1401 01 00000004 80000340 -1F22 40, arg 8: 1401 02 00000001 01 -1F22 40, arg 9: 1401 01 00000004 00000340 -1F22 40, arg 10: 1804 01 00000004 80000181 -1F22 40, arg 11: 1804 02 00000001 01 -1F22 40, arg 12: 1804 01 00000004 00000181 -1F22 40, arg 13: 1A04 01 00000004 60020108 -1F22 40, arg 14: 1A04 02 00000004 64260120 -1F22 40, arg 15: 1805 01 00000004 80000182 -1F22 40, arg 16: 1805 02 00000001 01 -1F22 40, arg 17: 1805 01 00000004 00000182 -1F22 40, arg 18: 1A05 01 00000004 64260220 -1F22 40, arg 19: 1A05 02 00000004 64260320 -1F22 40, arg 20: 1806 01 00000004 80000183 -1F22 40, arg 21: 1806 02 00000001 01 -1F22 40, arg 22: 1806 01 00000004 00000183 -1F22 40, arg 23: 1A06 01 00000004 64260420 -1F22 41 (Concise DCF for Node 65): -1F22 42 (Concise DCF for Node 66): -1F22 43 (Concise DCF for Node 67): -1F22 44 (Concise DCF for Node 68): -1F22 45 (Concise DCF for Node 69): -1F22 46 (Concise DCF for Node 70): -1F22 47 (Concise DCF for Node 71): -1F22 48 (Concise DCF for Node 72): -1F22 49 (Concise DCF for Node 73): -1F22 4A (Concise DCF for Node 74): -1F22 4B (Concise DCF for Node 75): -1F22 4C (Concise DCF for Node 76): -1F22 4D (Concise DCF for Node 77): -1F22 4E (Concise DCF for Node 78): -1F22 4F (Concise DCF for Node 79): -1F22 50 (Concise DCF for Node 80): -1F22 51 (Concise DCF for Node 81): -1F22 52 (Concise DCF for Node 82): -1F22 53 (Concise DCF for Node 83): -1F22 54 (Concise DCF for Node 84): -1F22 55 (Concise DCF for Node 85): -1F22 56 (Concise DCF for Node 86): -1F22 57 (Concise DCF for Node 87): -1F22 58 (Concise DCF for Node 88): -1F22 59 (Concise DCF for Node 89): -1F22 5A (Concise DCF for Node 90): -1F22 5B (Concise DCF for Node 91): -1F22 5C (Concise DCF for Node 92): -1F22 5D (Concise DCF for Node 93): -1F22 5E (Concise DCF for Node 94): -1F22 5F (Concise DCF for Node 95): -1F22 60 (Concise DCF for Node 96): -1F22 61 (Concise DCF for Node 97): -1F22 62 (Concise DCF for Node 98): -1F22 63 (Concise DCF for Node 99): -1F22 64 (Concise DCF for Node 100): -1F22 65 (Concise DCF for Node 101): -1F22 66 (Concise DCF for Node 102): -1F22 67 (Concise DCF for Node 103): -1F22 68 (Concise DCF for Node 104): -1F22 69 (Concise DCF for Node 105): -1F22 6A (Concise DCF for Node 106): -1F22 6B (Concise DCF for Node 107): -1F22 6C (Concise DCF for Node 108): -1F22 6D (Concise DCF for Node 109): -1F22 6E (Concise DCF for Node 110): -1F22 6F (Concise DCF for Node 111): -1F22 70 (Concise DCF for Node 112): -1F22 71 (Concise DCF for Node 113): -1F22 72 (Concise DCF for Node 114): -1F22 73 (Concise DCF for Node 115): -1F22 74 (Concise DCF for Node 116): -1F22 75 (Concise DCF for Node 117): -1F22 76 (Concise DCF for Node 118): -1F22 77 (Concise DCF for Node 119): -1F22 78 (Concise DCF for Node 120): -1F22 79 (Concise DCF for Node 121): -1F22 7A (Concise DCF for Node 122): -1F22 7B (Concise DCF for Node 123): -1F22 7C (Concise DCF for Node 124): -1F22 7D (Concise DCF for Node 125): -1F22 7E (Concise DCF for Node 126): -1F22 7F (Concise DCF for Node 127): -2000 (Read Inputs): 0 -2240 (beremiz__IB0_1_64): -2240 01 (24576_1): 0 -2240 02 (24578_1): 0 -2340 (beremiz__IW0_1_64): -2340 01 (25601_2): 0 -2340 02 (25601_3): 0 -2440 (beremiz__ID0_1_64): -2440 01 (25638_2): 0 -2440 02 (25638_3): 0 -2440 03 (25638_4): 0 -2440 04 (25638_1): 0 -4340 (beremiz__QW0_1_64): -4340 01 (25617_1): 0 - -********POINTERS********* -{(4096, 0): '__ID0_1_4096_0', - (8768, 1): '__IB0_1_64_24576_1', - (8768, 2): '__IB0_1_64_24578_1', - (9024, 1): '__IW0_1_64_25601_2', - (9024, 2): '__IW0_1_64_25601_3', - (9280, 1): '__ID0_1_64_25638_2', - (9280, 2): '__ID0_1_64_25638_3', - (9280, 3): '__ID0_1_64_25638_4', - (9280, 4): '__ID0_1_64_25638_1', - (17216, 1): '__QW0_1_64_25617_1'} diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/PythonEditor.py --- a/plugins/python/PythonEditor.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,505 +0,0 @@ -import wx, wx.grid -import wx.stc as stc -import keyword - -from controls import EditorPanel - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - 'size2': 8, - } -elif wx.Platform == '__WXMAC__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Monaco', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 12, - 'size2': 10, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - 'size2': 10, - } - -[ID_PYTHONEDITOR, -] = [wx.NewId() for _init_ctrls in range(1)] - -def GetCursorPos(old, new): - old_length = len(old) - new_length = len(new) - common_length = min(old_length, new_length) - i = 0 - for i in xrange(common_length): - if old[i] != new[i]: - break - if old_length < new_length: - if common_length > 0 and old[i] != new[i]: - return i + new_length - old_length - else: - return i + new_length - old_length + 1 - elif old_length > new_length or i < min(old_length, new_length) - 1: - if common_length > 0 and old[i] != new[i]: - return i - else: - return i + 1 - else: - return None - -class PythonEditor(EditorPanel): - - fold_symbols = 3 - - def _init_Editor(self, prnt): - self.Editor = stc.StyledTextCtrl(id=ID_PYTHONEDITOR, parent=prnt, - name="TextViewer", pos=wx.DefaultPosition, - size=wx.DefaultSize, style=0) - - self.Editor.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) - self.Editor.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) - - self.Editor.SetLexer(stc.STC_LEX_PYTHON) - self.Editor.SetKeyWords(0, " ".join(keyword.kwlist)) - - self.Editor.SetProperty("fold", "1") - self.Editor.SetProperty("tab.timmy.whinge.level", "1") - self.Editor.SetMargins(0,0) - - self.Editor.SetViewWhiteSpace(False) - - self.Editor.SetEdgeMode(stc.STC_EDGE_BACKGROUND) - self.Editor.SetEdgeColumn(78) - - # Set up the numbers in the margin for margin #1 - self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) - # Reasonable value for, say, 4-5 digits using a mono font (40 pix) - self.Editor.SetMarginWidth(1, 40) - - # Setup a margin to hold fold markers - self.Editor.SetMarginType(2, stc.STC_MARGIN_SYMBOL) - self.Editor.SetMarginMask(2, stc.STC_MASK_FOLDERS) - self.Editor.SetMarginSensitive(2, True) - self.Editor.SetMarginWidth(2, 12) - - if self.fold_symbols == 0: - # Arrow pointing right for contracted folders, arrow pointing down for expanded - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") - - elif self.fold_symbols == 1: - # Plus for contracted folders, minus for expanded - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") - - elif self.fold_symbols == 2: - # Like a flattened tree control using circular headers and curved joins - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") - - elif self.fold_symbols == 3: - # Like a flattened tree control using square headers - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") - self.Editor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") - - - self.Editor.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) - self.Editor.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) - self.Editor.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) - - # Global default style - if wx.Platform == '__WXMSW__': - self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New') - elif wx.Platform == '__WXMAC__': - # TODO: if this looks fine on Linux too, remove the Mac-specific case - # and use this whenever OS != MSW. - self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Monaco') - else: - defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() - self.Editor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) - - # Clear styles and revert to default. - self.Editor.StyleClearAll() - - # Following style specs only indicate differences from default. - # The rest remains unchanged. - - # Line numbers in margin - self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') - # Highlighted brace - self.Editor.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') - # Unmatched brace - self.Editor.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') - # Indentation guide - self.Editor.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") - - # Python styles - self.Editor.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') - # Comments - self.Editor.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') - self.Editor.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') - # Numbers - self.Editor.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') - # Strings and characters - self.Editor.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') - self.Editor.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') - # Keywords - self.Editor.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') - # Triple quotes - self.Editor.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') - self.Editor.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') - # Class names - self.Editor.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') - # Function names - self.Editor.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') - # Operators - self.Editor.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') - # Identifiers. I leave this as not bold because everything seems - # to be an identifier if it doesn't match the above criterae - self.Editor.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') - - # Caret color - self.Editor.SetCaretForeground("BLUE") - # Selection background - self.Editor.SetSelBackground(1, '#66CCFF') - - self.Editor.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) - self.Editor.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) - - # register some images for use in the AutoComplete box. - #self.RegisterImage(1, images.getSmilesBitmap()) - self.Editor.RegisterImage(1, - wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) - self.Editor.RegisterImage(2, - wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) - self.Editor.RegisterImage(3, - wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) - - # Indentation and tab stuff - self.Editor.SetIndent(4) # Proscribed indent size for wx - self.Editor.SetIndentationGuides(True) # Show indent guides - self.Editor.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space - self.Editor.SetTabIndents(True) # Tab key indents - self.Editor.SetTabWidth(4) # Proscribed tab size for wx - self.Editor.SetUseTabs(False) # Use spaces rather than tabs, or - # TabTimmy will complain! - # White space - self.Editor.SetViewWhiteSpace(False) # Don't view white space - - # EOL: Since we are loading/saving ourselves, and the - # strings will always have \n's in them, set the STC to - # edit them that way. - self.Editor.SetEOLMode(wx.stc.STC_EOL_LF) - self.Editor.SetViewEOL(False) - - # No right-edge mode indicator - self.Editor.SetEdgeMode(stc.STC_EDGE_NONE) - - self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) - - self.Editor.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) - self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) - self.Editor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR) - - - def __init__(self, parent, controler, window): - EditorPanel.__init__(self, parent, "", window, controler) - - self.DisableEvents = False - self.CurrentAction = None - - img = wx.Bitmap(self.Controler.GetIconPath("Cfile.png"), wx.BITMAP_TYPE_PNG).ConvertToImage() - self.SetIcon(wx.BitmapFromImage(img.Rescale(16, 16))) - - def __del__(self): - self.Controler.OnCloseEditor(self) - - def GetTitle(self): - fullname = self.Controler.PlugFullName() - if not self.Controler.PythonIsSaved(): - return "~%s~" % fullname - return fullname - - def GetBufferState(self): - return self.Controler.GetBufferState() - - def Undo(self): - self.Controler.LoadPrevious() - self.RefreshView() - - def Redo(self): - self.Controler.LoadNext() - self.RefreshView() - - def HasNoModel(self): - return False - - def OnModification(self, event): - if not self.DisableEvents: - mod_type = event.GetModificationType() - if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): - if mod_type&wx.stc.STC_MOD_BEFOREINSERT: - if self.CurrentAction is None: - self.StartBuffering() - elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: - self.Controler.EndBuffering() - self.StartBuffering() - self.CurrentAction = ("Add", event.GetPosition()) - wx.CallAfter(self.RefreshModel) - elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: - if self.CurrentAction == None: - self.StartBuffering() - elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: - self.Controler.EndBuffering() - self.StartBuffering() - self.CurrentAction = ("Delete", event.GetPosition()) - wx.CallAfter(self.RefreshModel) - event.Skip() - - def OnDoDrop(self, event): - self.ResetBuffer() - wx.CallAfter(self.RefreshModel) - event.Skip() - - # Buffer the last model state - def RefreshBuffer(self): - self.Controler.BufferPython() - if self.ParentWindow is not None: - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def StartBuffering(self): - self.Controler.StartBuffering() - if self.ParentWindow is not None: - self.ParentWindow.RefreshTitle() - self.ParentWindow.RefreshFileMenu() - self.ParentWindow.RefreshEditMenu() - self.ParentWindow.RefreshPageTitles() - - def ResetBuffer(self): - if self.CurrentAction != None: - self.Controler.EndBuffering() - self.CurrentAction = None - - def RefreshView(self): - self.ResetBuffer() - self.DisableEvents = True - old_cursor_pos = self.Editor.GetCurrentPos() - old_text = self.Editor.GetText() - new_text = self.Controler.GetPythonCode() - self.Editor.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.Editor.GotoPos(new_cursor_pos) - else: - self.Editor.GotoPos(old_cursor_pos) - self.Editor.ScrollToColumn(0) - self.Editor.EmptyUndoBuffer() - self.DisableEvents = False - - self.Editor.Colourise(0, -1) - - def RefreshModel(self): - self.Controler.SetPythonCode(self.Editor.GetText()) - - def OnKeyPressed(self, event): - if self.Editor.CallTipActive(): - self.Editor.CallTipCancel() - key = event.GetKeyCode() - - if key == 32 and event.ControlDown(): - pos = self.Editor.GetCurrentPos() - - # Tips - if event.ShiftDown(): - pass -## self.CallTipSetBackground("yellow") -## self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' -## 'show some suff, maybe parameters..\n\n' -## 'fubar(param1, param2)') - # Code completion - else: - self.Editor.AutoCompSetIgnoreCase(False) # so this needs to match - - # Images are specified with a appended "?type" - self.Editor.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) - else: - event.Skip() - - def OnKillFocus(self, event): - self.Editor.AutoCompCancel() - event.Skip() - - def OnUpdateUI(self, evt): - # check for matching braces - braceAtCaret = -1 - braceOpposite = -1 - charBefore = None - caretPos = self.Editor.GetCurrentPos() - - if caretPos > 0: - charBefore = self.Editor.GetCharAt(caretPos - 1) - styleBefore = self.Editor.GetStyleAt(caretPos - 1) - - # check before - if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: - braceAtCaret = caretPos - 1 - - # check after - if braceAtCaret < 0: - charAfter = self.Editor.GetCharAt(caretPos) - styleAfter = self.Editor.GetStyleAt(caretPos) - - if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: - braceAtCaret = caretPos - - if braceAtCaret >= 0: - braceOpposite = self.Editor.BraceMatch(braceAtCaret) - - if braceAtCaret != -1 and braceOpposite == -1: - self.Editor.BraceBadLight(braceAtCaret) - else: - self.Editor.BraceHighlight(braceAtCaret, braceOpposite) - #pt = self.Editor.PointFromPosition(braceOpposite) - #self.Editor.Refresh(True, wxRect(pt.x, pt.y, 5,5)) - #print pt - #self.Editor.Refresh(False) - - - def OnMarginClick(self, evt): - # fold and unfold as needed - if evt.GetMargin() == 2: - if evt.GetShift() and evt.GetControl(): - self.FoldAll() - else: - lineClicked = self.Editor.LineFromPosition(evt.GetPosition()) - - if self.Editor.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: - if evt.GetShift(): - self.Editor.SetFoldExpanded(lineClicked, True) - self.Expand(lineClicked, True, True, 1) - elif evt.GetControl(): - if self.Editor.GetFoldExpanded(lineClicked): - self.Editor.SetFoldExpanded(lineClicked, False) - self.Expand(lineClicked, False, True, 0) - else: - self.Editor.SetFoldExpanded(lineClicked, True) - self.Expand(lineClicked, True, True, 100) - else: - self.Editor.ToggleFold(lineClicked) - - - def FoldAll(self): - lineCount = self.Editor.GetLineCount() - expanding = True - - # find out if we are folding or unfolding - for lineNum in range(lineCount): - if self.Editor.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: - expanding = not self.Editor.GetFoldExpanded(lineNum) - break - - lineNum = 0 - - while lineNum < lineCount: - level = self.Editor.GetFoldLevel(lineNum) - if level & stc.STC_FOLDLEVELHEADERFLAG and \ - (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: - - if expanding: - self.Editor.SetFoldExpanded(lineNum, True) - lineNum = self.Expand(lineNum, True) - lineNum = lineNum - 1 - else: - lastChild = self.Editor.GetLastChild(lineNum, -1) - self.Editor.SetFoldExpanded(lineNum, False) - - if lastChild > lineNum: - self.Editor.HideLines(lineNum+1, lastChild) - - lineNum = lineNum + 1 - - - - def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): - lastChild = self.Editor.GetLastChild(line, level) - line = line + 1 - - while line <= lastChild: - if force: - if visLevels > 0: - self.Editor.ShowLines(line, line) - else: - self.Editor.HideLines(line, line) - else: - if doExpand: - self.Editor.ShowLines(line, line) - - if level == -1: - level = self.Editor.GetFoldLevel(line) - - if level & stc.STC_FOLDLEVELHEADERFLAG: - if force: - if visLevels > 1: - self.Editor.SetFoldExpanded(line, True) - else: - self.Editor.SetFoldExpanded(line, False) - - line = self.Expand(line, doExpand, force, visLevels-1) - - else: - if doExpand and self.Editor.GetFoldExpanded(line): - line = self.Expand(line, True, force, visLevels-1) - else: - line = self.Expand(line, False, force, visLevels-1) - else: - line = line + 1 - - return line - - def Cut(self): - self.ResetBuffer() - self.DisableEvents = True - self.Editor.CmdKeyExecute(wx.stc.STC_CMD_CUT) - self.DisableEvents = False - self.RefreshModel() - self.RefreshBuffer() - - def Copy(self): - self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY) - - def Paste(self): - self.ResetBuffer() - self.DisableEvents = True - self.Editor.CmdKeyExecute(wx.stc.STC_CMD_PASTE) - self.DisableEvents = False - self.RefreshModel() - self.RefreshBuffer() diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/README --- a/plugins/python/README Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -Asynchronous Python Interpreter diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/__init__.py --- a/plugins/python/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -from python import * diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/__init__.py --- a/plugins/python/modules/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -from os import listdir, path - -_base_path = path.split(__file__)[0] - -__all__ = [name for name in listdir(_base_path) if path.isdir(path.join(_base_path, name)) and name.upper() != "CVS" or name.endswith(".py") and not name.startswith("__")] - -helps = [] -for name in __all__: - helpfilename = path.join(_base_path, name, "README") - if path.isfile(helpfilename): - helps.append(open(helpfilename).readline().strip()) - else: - helps.append(name) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/README --- a/plugins/python/modules/svgui/README Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -SVGUI HMI \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/__init__.py --- a/plugins/python/modules/svgui/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -from svgui import * diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/livesvg.js --- a/plugins/python/modules/svgui/livesvg.js Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -// import Nevow.Athena -// import Divmod.Base - -function updateAttr(id, param, value) { - Nevow.Athena.Widget.fromAthenaID(1).callRemote('HMIexec', 'setattr', id, param, value); -} - -var svguiWidgets = new Array(); - -var currentObject = null; -function setCurrentObject(obj) { - currentObject = obj; -} -function isCurrentObject(obj) { - return currentObject == obj; -} - -function getSVGElementById(id) { - return document.getElementById(id); -} - -function blockSVGElementDrag(element) { - element.addEventListener("draggesture", function(event){event.stopPropagation()}, true); -} - -LiveSVGPage.LiveSVGWidget = Nevow.Athena.Widget.subclass('LiveSVGPage.LiveSVGWidget'); -LiveSVGPage.LiveSVGWidget.methods( - - function handleEvent(self, evt) { - if (currentObject != null) { - currentObject.handleEvent(evt); - } - }, - - function receiveData(self, data){ - dataReceived = json_parse(data); - gadget = svguiWidgets[dataReceived.id] - if (gadget) { - gadget.updateValues(json_parse(dataReceived.kwargs)); - } - //console.log("OBJET : " + dataReceived.back_id + " STATE : " + newState); - }, - - function init(self, arg1){ - //console.log("Object received : " + arg1); - for (ind in arg1) { - gad = json_parse(arg1[ind]); - args = json_parse(gad.kwargs); - gadget = new svguilib[gad.__class__](self, gad.id, args); - svguiWidgets[gadget.id]=gadget; - //console.log('GADGET :' + gadget); - } - var elements = document.getElementsByTagName("svg"); - for (var i = 0; i < elements.length; i++) { - elements[i].addEventListener("mouseup", self, false); - } - //console.log("SVGUIWIDGETS : " + svguiWidgets); - } -); diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pous.xml --- a/plugins/python/modules/svgui/pous.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1428 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'createSVGUIControl("textControl", back_id="' - - - - - - - back_id - - - - - - - '")' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - BOOL#1 - - - - - - - - - - - ID - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - set_text - - - - - - - 'setAttr(' - - - - - - - ',"text","' - - - - - - - '")' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'createSVGUIControl("button",back_id="' - - - - - - - '",sele_id="' - - - - - - - ',active=True)' - - - - - - - BOOL#1 - - - - - - - back_id - - - - - - - sele_id - - - - - - - set_state - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - state_in - - - - - - - - - - - state_out - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - 'setAttr(' - - - - - - - ',"state",' - - - - - - - ')' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - 'int(getAttr(' - - - - - - - ',"state",False))' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '",toggle=' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - toggle - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'createSVGUIControl("button",back_id="' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - '",sele_id="' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - '",toggle=True,active=False)' - - - - - - - BOOL#1 - - - - - - - back_id - - - - - - - sele_id - - - - - - - 'setAttr(' - - - - - - - ',"state",' - - - - - - - ')' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ID - - - - - - - - - - - - - - - - - state_in - - - - - - - - - - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/__init__.py --- a/plugins/python/modules/svgui/pyjs/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -from pyjs import * - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/build.py --- a/plugins/python/modules/svgui/pyjs/build.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,724 +0,0 @@ -#!/usr/bin/env python - -import sys -import os -import shutil -from copy import copy -from os.path import join, dirname, basename, abspath, split, isfile, isdir -from optparse import OptionParser -import pyjs -from cStringIO import StringIO -try: - # Python 2.5 and above - from hashlib import md5 -except: - import md5 -import re - -usage = """ - usage: %prog [options] - -This is the command line builder for the pyjamas project, which can -be used to build Ajax applications from Python. -For more information, see the website at http://pyjs.org/ -""" - -# GWT1.2 Impl | GWT1.2 Output | Pyjamas 0.2 Platform | Pyjamas 0.2 Output -# -------------+-----------------------+----------------------+---------------------- -# IE6 | ie6 | IE6 | ie6 -# Opera | opera | Opera | opera -# Safari | safari | Safari | safari -# -- | gecko1_8 | Mozilla | mozilla -# -- | gecko | OldMoz | oldmoz -# Standard | all | (default code) | all -# Mozilla | gecko1_8, gecko | -- | -- -# Old | safari, gecko, opera | -- | -- - -version = "%prog pyjamas version 2006-08-19" - -# these names in lowercase need match the strings -# returned by "provider$user.agent" in order to be selected corretly -app_platforms = ['IE6', 'Opera', 'OldMoz', 'Safari', 'Mozilla'] - -# usually defaults to e.g. /usr/share/pyjamas -_data_dir = os.path.join(pyjs.prefix, "share/pyjamas") - - -# .cache.html files produces look like this -CACHE_HTML_PAT=re.compile('^[a-z]*.[0-9a-f]{32}\.cache\.html$') - -# ok these are the three "default" library directories, containing -# the builtins (str, List, Dict, ord, round, len, range etc.) -# the main pyjamas libraries (pyjamas.ui, pyjamas.Window etc.) -# and the contributed addons - -for p in ["library/builtins", - "library", - "addons"]: - p = os.path.join(_data_dir, p) - if os.path.isdir(p): - pyjs.path.append(p) - - -def read_boilerplate(data_dir, filename): - return open(join(data_dir, "builder/boilerplate", filename)).read() - -def copy_boilerplate(data_dir, filename, output_dir): - filename = join(data_dir, "builder/boilerplate", filename) - shutil.copy(filename, output_dir) - - -# taken and modified from python2.4 -def copytree_exists(src, dst, symlinks=False): - if not os.path.exists(src): - return - - names = os.listdir(src) - try: - os.mkdir(dst) - except: - pass - - errors = [] - for name in names: - if name.startswith('CVS'): - continue - if name.startswith('.git'): - continue - if name.startswith('.svn'): - continue - - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if symlinks and os.path.islink(srcname): - linkto = os.readlink(srcname) - os.symlink(linkto, dstname) - elif isdir(srcname): - copytree_exists(srcname, dstname, symlinks) - else: - shutil.copy2(srcname, dstname) - except (IOError, os.error), why: - errors.append((srcname, dstname, why)) - if errors: - print errors - -def check_html_file(source_file, dest_path): - """ Checks if a base HTML-file is available in the PyJamas - output directory. - If the HTML-file isn't available, it will be created. - - If a CSS-file with the same name is available - in the output directory, a reference to this CSS-file - is included. - - If no CSS-file is found, this function will look for a special - CSS-file in the output directory, with the name - "pyjamas_default.css", and if found it will be referenced - in the generated HTML-file. - - [thank you to stef mientki for contributing this function] - """ - - base_html = """\ - - - - - %(css)s - %(title)s - - - - - -""" - - filename = os.path.split ( source_file )[1] - mod_name = os.path.splitext ( filename )[0] - file_name = os.path.join ( dest_path, mod_name + '.html' ) - - # if html file in output directory exists, leave it alone. - if os.path.exists ( file_name ): - return 0 - - if os.path.exists ( - os.path.join ( dest_path, mod_name + '.css' ) ) : - css = "" - elif os.path.exists ( - os.path.join ( dest_path, 'pyjamas_default.css' ) ) : - css = "" - - else: - css = '' - - title = 'PyJamas Auto-Generated HTML file ' + mod_name - - base_html = base_html % {'modulename': mod_name, 'title': title, 'css': css} - - fh = open (file_name, 'w') - fh.write (base_html) - fh.close () - - return 1 - - -def build(app_name, output, js_includes=(), debug=False, dynamic=0, - data_dir=None, cache_buster=False, optimize=False): - - # make sure the output directory is always created in the current working - # directory or at the place given if it is an absolute path. - output = os.path.abspath(output) - msg = "Building '%(app_name)s' to output directory '%(output)s'" % locals() - if debug: - msg += " with debugging statements" - print msg - - # check the output directory - if os.path.exists(output) and not os.path.isdir(output): - print >>sys.stderr, "Output destination %s exists and is not a directory" % output - return - if not os.path.isdir(output): - try: - print "Creating output directory" - os.mkdir(output) - except StandardError, e: - print >>sys.stderr, "Exception creating output directory %s: %s" % (output, e) - - ## public dir - for p in pyjs.path: - pub_dir = join(p, 'public') - if isdir(pub_dir): - print "Copying: public directory of library %r" % p - copytree_exists(pub_dir, output) - - ## AppName.html - can be in current or public directory - html_input_filename = app_name + ".html" - html_output_filename = join(output, basename(html_input_filename)) - if os.path.isfile(html_input_filename): - if not os.path.isfile(html_output_filename) or \ - os.path.getmtime(html_input_filename) > \ - os.path.getmtime(html_output_filename): - try: - shutil.copy(html_input_filename, html_output_filename) - except: - print >>sys.stderr, "Warning: Missing module HTML file %s" % html_input_filename - - print "Copying: %(html_input_filename)s" % locals() - - if check_html_file(html_input_filename, output): - print >>sys.stderr, "Warning: Module HTML file %s has been auto-generated" % html_input_filename - - ## pygwt.js - - print "Copying: pygwt.js" - - pygwt_js_template = read_boilerplate(data_dir, "pygwt.js") - pygwt_js_output = open(join(output, "pygwt.js"), "w") - - print >>pygwt_js_output, pygwt_js_template - - pygwt_js_output.close() - - ## Images - - print "Copying: Images and History" - copy_boilerplate(data_dir, "corner_dialog_topleft_black.png", output) - copy_boilerplate(data_dir, "corner_dialog_topright_black.png", output) - copy_boilerplate(data_dir, "corner_dialog_bottomright_black.png", output) - copy_boilerplate(data_dir, "corner_dialog_bottomleft_black.png", output) - copy_boilerplate(data_dir, "corner_dialog_edge_black.png", output) - copy_boilerplate(data_dir, "corner_dialog_topleft.png", output) - copy_boilerplate(data_dir, "corner_dialog_topright.png", output) - copy_boilerplate(data_dir, "corner_dialog_bottomright.png", output) - copy_boilerplate(data_dir, "corner_dialog_bottomleft.png", output) - copy_boilerplate(data_dir, "corner_dialog_edge.png", output) - copy_boilerplate(data_dir, "tree_closed.gif", output) - copy_boilerplate(data_dir, "tree_open.gif", output) - copy_boilerplate(data_dir, "tree_white.gif", output) - copy_boilerplate(data_dir, "history.html", output) - - - ## all.cache.html - app_files = generateAppFiles(data_dir, js_includes, app_name, debug, - output, dynamic, cache_buster, optimize) - - ## AppName.nocache.html - - print "Creating: %(app_name)s.nocache.html" % locals() - - home_nocache_html_template = read_boilerplate(data_dir, "home.nocache.html") - home_nocache_html_output = open(join(output, app_name + ".nocache.html"), - "w") - - # the selector templ is added to the selectScript function - select_tmpl = """O(["true","%s"],"%s");""" - script_selectors = StringIO() - - for platform, file_prefix in app_files: - print >> script_selectors, select_tmpl % (platform, file_prefix) - - print >>home_nocache_html_output, home_nocache_html_template % dict( - app_name = app_name, - script_selectors = script_selectors.getvalue(), - ) - - home_nocache_html_output.close() - - print "Done. You can run your app by opening '%(html_output_filename)s' in a browser" % locals() - - -def generateAppFiles(data_dir, js_includes, app_name, debug, output, dynamic, - cache_buster, optimize): - - all_cache_html_template = read_boilerplate(data_dir, "all.cache.html") - mod_cache_html_template = read_boilerplate(data_dir, "mod.cache.html") - - # clean out the old ones first - for name in os.listdir(output): - if CACHE_HTML_PAT.match(name): - p = join(output, name) - print "Deleting existing app file %s" % p - os.unlink(p) - - app_files = [] - tmpl = read_boilerplate(data_dir, "all.cache.html") - parser = pyjs.PlatformParser("platform") - app_headers = '' - scripts = [''%script \ - for script in js_includes] - app_body = '\n'.join(scripts) - - mod_code = {} - mod_libs = {} - modules = {} - app_libs = {} - early_app_libs = {} - app_code = {} - overrides = {} - pover = {} - app_modnames = {} - mod_levels = {} - - # First, generate all the code. - # Second, (dynamic only), post-analyse the places where modules - # haven't changed - # Third, write everything out. - - for platform in app_platforms: - - mod_code[platform] = {} - mod_libs[platform] = {} - modules[platform] = [] - pover[platform] = {} - app_libs[platform] = '' - early_app_libs[platform] = '' - app_code[platform] = {} - app_modnames[platform] = {} - - # Application.Platform.cache.html - - parser.setPlatform(platform) - app_translator = pyjs.AppTranslator( - parser=parser, dynamic=dynamic, optimize=optimize) - early_app_libs[platform], appcode = \ - app_translator.translate(None, is_app=False, - debug=debug, - library_modules=['dynamicajax.js', - '_pyjs.js', 'sys', - 'pyjslib']) - pover[platform].update(app_translator.overrides.items()) - for mname, name in app_translator.overrides.items(): - pd = overrides.setdefault(mname, {}) - pd[platform] = name - - print appcode - #mod_code[platform][app_name] = appcode - - # platform.Module.cache.js - - modules_done = ['pyjslib', 'sys', '_pyjs.js'] - #modules_to_do = [app_name] + app_translator.library_modules - modules_to_do = [app_name] + app_translator.library_modules - - dependencies = {} - - deps = map(pyjs.strip_py, modules_to_do) - for d in deps: - sublist = add_subdeps(dependencies, d) - modules_to_do += sublist - deps = uniquify(deps) - #dependencies[app_name] = deps - - modules[platform] = modules_done + modules_to_do - - while modules_to_do: - - #print "modules to do", modules_to_do - - mn = modules_to_do.pop() - mod_name = pyjs.strip_py(mn) - - if mod_name in modules_done: - continue - - modules_done.append(mod_name) - - mod_cache_name = "%s.%s.cache.js" % (platform.lower(), mod_name) - - parser.setPlatform(platform) - mod_translator = pyjs.AppTranslator(parser=parser, optimize=optimize) - mod_libs[platform][mod_name], mod_code[platform][mod_name] = \ - mod_translator.translate(mod_name, - is_app=False, - debug=debug) - pover[platform].update(mod_translator.overrides.items()) - for mname, name in mod_translator.overrides.items(): - pd = overrides.setdefault(mname, {}) - pd[platform] = name - - mods = mod_translator.library_modules - modules_to_do += mods - modules[platform] += mods - - deps = map(pyjs.strip_py, mods) - sd = subdeps(mod_name) - if len(sd) > 1: - deps += sd[:-1] - while mod_name in deps: - deps.remove(mod_name) - - #print - #print - #print "modname preadd:", mod_name, deps - #print - #print - for d in deps: - sublist = add_subdeps(dependencies, d) - modules_to_do += sublist - modules_to_do += add_subdeps(dependencies, mod_name) - #print "modname:", mod_name, deps - deps = uniquify(deps) - #print "modname:", mod_name, deps - dependencies[mod_name] = deps - - # work out the dependency ordering of the modules - - mod_levels[platform] = make_deps(None, dependencies, modules_done) - - # now write everything out - - for platform in app_platforms: - - early_app_libs_ = early_app_libs[platform] - app_libs_ = app_libs[platform] - app_code_ = app_code[platform] - #modules_ = filter_mods(app_name, modules[platform]) - mods = flattenlist(mod_levels[platform]) - mods.reverse() - modules_ = filter_mods(None, mods) - - for mod_name in modules_: - - mod_code_ = mod_code[platform][mod_name] - - mod_name = pyjs.strip_py(mod_name) - - override_name = "%s.%s" % (platform.lower(), mod_name) - if pover[platform].has_key(override_name): - mod_cache_name = "%s.cache.js" % (override_name) - else: - mod_cache_name = "%s.cache.js" % (mod_name) - - print "Creating: " + mod_cache_name - - modlevels = make_deps(None, dependencies, dependencies[mod_name]) - - modnames = [] - - for md in modlevels: - mnames = map(lambda x: "'%s'" % x, md) - mnames = "new pyjslib.List([\n\t\t\t%s])" % ',\n\t\t\t'.join(mnames) - modnames.append(mnames) - - modnames.reverse() - modnames = "new pyjslib.List([\n\t\t%s\n\t])" % ',\n\t\t'.join(modnames) - - # convert the overrides - - overnames = map(lambda x: "'%s': '%s'" % x, pover[platform].items()) - overnames = "new pyjslib.Dict({\n\t\t%s\n\t})" % ',\n\t\t'.join(overnames) - - if dynamic: - mod_cache_html_output = open(join(output, mod_cache_name), "w") - else: - mod_cache_html_output = StringIO() - - print >>mod_cache_html_output, mod_cache_html_template % dict( - mod_name = mod_name, - app_name = app_name, - modnames = modnames, - overrides = overnames, - mod_libs = mod_libs[platform][mod_name], - dynamic = dynamic, - mod_code = mod_code_, - ) - - if dynamic: - mod_cache_html_output.close() - else: - mod_cache_html_output.seek(0) - app_libs_ += mod_cache_html_output.read() - - # write out the dependency ordering of the modules - - app_modnames = [] - - for md in mod_levels[platform]: - mnames = map(lambda x: "'%s'" % x, md) - mnames = "new pyjslib.List([\n\t\t\t%s])" % ',\n\t\t\t'.join(mnames) - app_modnames.append(mnames) - - app_modnames.reverse() - app_modnames = "new pyjslib.List([\n\t\t%s\n\t])" % ',\n\t\t'.join(app_modnames) - - # convert the overrides - - overnames = map(lambda x: "'%s': '%s'" % x, pover[platform].items()) - overnames = "new pyjslib.Dict({\n\t\t%s\n\t})" % ',\n\t\t'.join(overnames) - - #print "platform names", platform, overnames - #print pover - - # now write app.allcache including dependency-ordered list of - # library modules - - file_contents = all_cache_html_template % dict( - app_name = app_name, - early_app_libs = early_app_libs_, - app_libs = app_libs_, - app_code = app_code_, - app_body = app_body, - overrides = overnames, - platform = platform.lower(), - dynamic = dynamic, - app_modnames = app_modnames, - app_headers = app_headers - ) - if cache_buster: - digest = md5.new(file_contents).hexdigest() - file_name = "%s.%s.%s" % (platform.lower(), app_name, digest) - else: - file_name = "%s.%s" % (platform.lower(), app_name) - file_name += ".cache.html" - out_path = join(output, file_name) - out_file = open(out_path, 'w') - out_file.write(file_contents) - out_file.close() - app_files.append((platform.lower(), file_name)) - print "Created app file %s:%s: %s" % ( - app_name, platform, out_path) - - return app_files - -def flattenlist(ll): - res = [] - for l in ll: - res += l - return res - -# creates sub-dependencies e.g. pyjamas.ui.Widget -# creates pyjamas.ui.Widget, pyjamas.ui and pyjamas. -def subdeps(m): - d = [] - m = m.split(".") - for i in range(0, len(m)): - d.append('.'.join(m[:i+1])) - return d - -import time - -def add_subdeps(deps, mod_name): - sd = subdeps(mod_name) - if len(sd) == 1: - return [] - #print "subdeps", mod_name, sd - #print "deps", deps - res = [] - for i in range(0, len(sd)-1): - parent = sd[i] - child = sd[i+1] - l = deps.get(child, []) - l.append(parent) - deps[child] = l - if parent not in res: - res.append(parent) - #print deps - return res - -# makes unique and preserves list order -def uniquify(md): - res = [] - for m in md: - if m not in res: - res.append(m) - return res - -def filter_mods(app_name, md): - while 'sys' in md: - md.remove('sys') - while 'pyjslib' in md: - md.remove('pyjslib') - while app_name in md: - md.remove(app_name) - md = filter(lambda x: not x.endswith('.js'), md) - md = map(pyjs.strip_py, md) - - return uniquify(md) - -def filter_deps(app_name, deps): - - res = {} - for (k, l) in deps.items(): - mods = filter_mods(k, l) - while k in mods: - mods.remove(k) - res[k] = mods - return res - -def has_nodeps(mod, deps): - if not deps.has_key(mod) or not deps[mod]: - return True - return False - -def nodeps_list(mod_list, deps): - res = [] - for mod in mod_list: - if has_nodeps(mod, deps): - res.append(mod) - return res - -# this function takes a dictionary of dependent modules and -# creates a list of lists. the first list will be modules -# that have no dependencies; the second list will be those -# modules that have the first list as dependencies; the -# third will be those modules that have the first and second... -# etc. - - -def make_deps(app_name, deps, mod_list): - print "Calculating Dependencies ..." - mod_list = filter_mods(app_name, mod_list) - deps = filter_deps(app_name, deps) - - if not mod_list: - return [] - - #print mod_list - #print deps - - ordered_deps = [] - last_len = -1 - while deps: - l_deps = len(deps) - #print l_deps - if l_deps==last_len: - for m, dl in deps.items(): - for d in dl: - if m in deps.get(d, []): - raise Exception('Circular Imports found: \n%s %s -> %s %s' - % (m, dl, d, deps[d])) - #raise Exception('Could not calculate dependencies: \n%s' % deps) - break - last_len = l_deps - #print "modlist", mod_list - nodeps = nodeps_list(mod_list, deps) - #print "nodeps", nodeps - mod_list = filter(lambda x: x not in nodeps, mod_list) - newdeps = {} - for k in deps.keys(): - depslist = deps[k] - depslist = filter(lambda x: x not in nodeps, depslist) - if depslist: - newdeps[k] = depslist - #print "newdeps", newdeps - deps = newdeps - ordered_deps.append(nodeps) - #time.sleep(0) - - if mod_list: - ordered_deps.append(mod_list) # last dependencies - usually the app(s) - - ordered_deps.reverse() - - return ordered_deps - -def main(): - global app_platforms - - parser = OptionParser(usage = usage, version = version) - parser.add_option("-o", "--output", dest="output", - help="directory to which the webapp should be written") - parser.add_option("-j", "--include-js", dest="js_includes", action="append", - help="javascripts to load into the same frame as the rest of the script") - parser.add_option("-I", "--library_dir", dest="library_dirs", - action="append", help="additional paths appended to PYJSPATH") - parser.add_option("-D", "--data_dir", dest="data_dir", - help="path for data directory") - parser.add_option("-m", "--dynamic-modules", action="store_true", - dest="dynamic", default=False, - help="Split output into separate dynamically-loaded modules (experimental)") - parser.add_option("-P", "--platforms", dest="platforms", - help="platforms to build for, comma-separated") - parser.add_option("-d", "--debug", action="store_true", dest="debug") - parser.add_option("-O", "--optimize", action="store_true", - dest="optimize", default=False, - help="Optimize generated code (removes all print statements)", - ) - parser.add_option("-c", "--cache_buster", action="store_true", - dest="cache_buster", - help="Enable browser cache-busting (MD5 hash added to output filenames)") - - parser.set_defaults(output = "output", js_includes=[], library_dirs=[], - platforms=(','.join(app_platforms)), - data_dir=os.path.join(sys.prefix, "share/pyjamas"), - dynamic=False, - cache_buster=False, - debug=False) - (options, args) = parser.parse_args() - if len(args) != 1: - parser.error("incorrect number of arguments") - - data_dir = abspath(options.data_dir) - - app_path = args[0] - if app_path.endswith('.py'): - app_path = abspath(app_path) - if not isfile(app_path): - parser.error("Application file not found %r" % app_path) - app_path, app_name = split(app_path) - app_name = app_name[:-3] - pyjs.path.append(app_path) - elif os.path.sep in app_path: - parser.error("Not a valid module declaration %r" % app_path) - else: - app_name = app_path - - for d in options.library_dirs: - pyjs.path.append(abspath(d)) - - if options.platforms: - app_platforms = options.platforms.split(',') - - # this is mostly for getting boilerplate stuff - data_dir = os.path.abspath(options.data_dir) - - build(app_name, options.output, options.js_includes, - options.debug, options.dynamic and 1 or 0, data_dir, - options.cache_buster, options.optimize) - -if __name__ == "__main__": - main() - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/jsonrpc/README.txt --- a/plugins/python/modules/svgui/pyjs/jsonrpc/README.txt Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -These classes are intended for use server-side. - -e.g. in a django view.py : - - from pyjs.jsonrpc.django import JSONService, jsonremote - - jsonservice = JSONRPCService() - - @jsonremote(jsonservice) - def test(request, echo_param): - return "echoing the param back: %s" % echo_param - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/jsonrpc/django/jsonrpc.py --- a/plugins/python/modules/svgui/pyjs/jsonrpc/django/jsonrpc.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,226 +0,0 @@ -# jsonrpc.py -# original code: http://trac.pyworks.org/pyjamas/wiki/DjangoWithPyJamas -# also from: http://www.pimentech.fr/technologies/outils -from django.utils import simplejson -from django.http import HttpResponse -import sys - -from pyjs.jsonrpc import JSONRPCServiceBase -# JSONRPCService and jsonremote are used in combination to drastically -# simplify the provision of JSONRPC services. use as follows: -# -# jsonservice = JSONRPCService() -# -# @jsonremote(jsonservice) -# def test(request, echo_param): -# return "echoing the param back: %s" % echo_param -# -# dump jsonservice into urlpatterns: -# (r'^service1/$', 'djangoapp.views.jsonservice'), - -class JSONRPCService(JSONRPCServiceBase): - - def __call__(self, request, extra=None): - return self.process(request.raw_post_data) - -def jsonremote(service): - """Make JSONRPCService a decorator so that you can write : - - from jsonrpc import JSONRPCService - chatservice = JSONRPCService() - - @jsonremote(chatservice) - def login(request, user_name): - (...) - """ - def remotify(func): - if isinstance(service, JSONRPCService): - service.add_method(func.__name__, func) - else: - emsg = 'Service "%s" not found' % str(service.__name__) - raise NotImplementedError, emsg - return func - return remotify - - -# FormProcessor provides a mechanism for turning Django Forms into JSONRPC -# Services. If you have an existing Django app which makes prevalent -# use of Django Forms it will save you rewriting the app. -# use as follows. in djangoapp/views.py : -# -# class SimpleForm(forms.Form): -# testfield = forms.CharField(max_length=100) -# -# class SimpleForm2(forms.Form): -# testfield = forms.CharField(max_length=20) -# -# processor = FormProcessor({'processsimpleform': SimpleForm, -# 'processsimpleform2': SimpleForm2}) -# -# this will result in a JSONRPC service being created with two -# RPC functions. dump "processor" into urlpatterns to make it -# part of the app: -# (r'^formsservice/$', 'djangoapp.views.processor'), - -from django import forms - -def builderrors(form): - d = {} - for error in form.errors.keys(): - if error not in d: - d[error] = [] - for errorval in form.errors[error]: - d[error].append(unicode(errorval)) - return d - - -# contains the list of arguments in each field -field_names = { - 'CharField': ['max_length', 'min_length'], - 'IntegerField': ['max_value', 'min_value'], - 'FloatField': ['max_value', 'min_value'], - 'DecimalField': ['max_value', 'min_value', 'max_digits', 'decimal_places'], - 'DateField': ['input_formats'], - 'DateTimeField': ['input_formats'], - 'TimeField': ['input_formats'], - 'RegexField': ['max_length', 'min_length'], # sadly we can't get the expr - 'EmailField': ['max_length', 'min_length'], - 'URLField': ['max_length', 'min_length', 'verify_exists', 'user_agent'], - 'ChoiceField': ['choices'], - 'FilePathField': ['path', 'match', 'recursive', 'choices'], - 'IPAddressField': ['max_length', 'min_length'], - } - -def describe_field_errors(field): - res = {} - field_type = field.__class__.__name__ - msgs = {} - for n, m in field.error_messages.items(): - msgs[n] = unicode(m) - res['error_messages'] = msgs - if field_type in ['ComboField', 'MultiValueField', 'SplitDateTimeField']: - res['fields'] = map(describe_field, field.fields) - return res - -def describe_fields_errors(fields, field_names): - res = {} - if not field_names: - field_names = fields.keys() - for name in field_names: - field = fields[name] - res[name] = describe_field_errors(field) - return res - -def describe_field(field): - res = {} - field_type = field.__class__.__name__ - for fname in field_names.get(field_type, []) + \ - ['help_text', 'label', 'initial', 'required']: - res[fname] = getattr(field, fname) - if field_type in ['ComboField', 'MultiValueField', 'SplitDateTimeField']: - res['fields'] = map(describe_field, field.fields) - return res - -def describe_fields(fields, field_names): - res = {} - if not field_names: - field_names = fields.keys() - for name in field_names: - field = fields[name] - res[name] = describe_field(field) - return res - -class FormProcessor(JSONRPCService): - def __init__(self, forms, _formcls=None): - - if _formcls is None: - JSONRPCService.__init__(self) - for k in forms.keys(): - s = FormProcessor({}, forms[k]) - self.add_method(k, s.__process) - else: - JSONRPCService.__init__(self, forms) - self.formcls = _formcls - - def __process(self, request, params, command=None): - - f = self.formcls(params) - - if command is None: # just validate - if not f.is_valid(): - return {'success':False, 'errors': builderrors(f)} - return {'success':True} - - elif command.has_key('describe_errors'): - field_names = command['describe_errors'] - return describe_fields_errors(f.fields, field_names) - - elif command.has_key('describe'): - field_names = command['describe'] - return describe_fields(f.fields, field_names) - - elif command.has_key('save'): - if not f.is_valid(): - return {'success':False, 'errors': builderrors(f)} - instance = f.save() # XXX: if you want more, over-ride save. - return {'success': True, 'instance': json_convert(instance) } - - elif command.has_key('html'): - return {'success': True, 'html': f.as_table()} - - return "unrecognised command" - - - - -# The following is incredibly convenient for saving vast amounts of -# coding, avoiding doing silly things like this: -# jsonresult = {'field1': djangoobject.field1, -# 'field2': djangoobject.date.strftime('%Y.%M'), -# ..... } -# -# The date/time flatten function is there because JSONRPC doesn't -# support date/time objects or formats, so conversion to a string -# is the most logical choice. pyjamas, being python, can easily -# be used to parse the string result at the other end. -# -# use as follows: -# -# jsonservice = JSONRPCService() -# -# @jsonremote(jsonservice) -# def list_some_model(request, start=0, count=10): -# l = SomeDjangoModelClass.objects.filter() -# res = json_convert(l[start:end]) -# -# @jsonremote(jsonservice) -# def list_another_model(request, start=0, count=10): -# l = AnotherDjangoModelClass.objects.filter() -# res = json_convert(l[start:end]) -# -# dump jsonservice into urlpatterns to make the two RPC functions, -# list_some_model and list_another_model part of the django app: -# (r'^service1/$', 'djangoapp.views.jsonservice'), - -from django.core.serializers import serialize -import datetime -from datetime import date - -def dict_datetimeflatten(item): - d = {} - for k, v in item.items(): - k = str(k) - if isinstance(v, datetime.date): - d[k] = str(v) - elif isinstance(v, dict): - d[k] = dict_datetimeflatten(v) - else: - d[k] = v - return d - -def json_convert(l, fields=None): - res = [] - for item in serialize('python', l, fields=fields): - res.append(dict_datetimeflatten(item)) - return res - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/jsonrpc/jsonrpc.py --- a/plugins/python/modules/svgui/pyjs/jsonrpc/jsonrpc.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -import gluon.contrib.simplejson as simplejson -import types -import sys - -class JSONRPCServiceBase: - - def __init__(self): - self.methods={} - - def response(self, id, result): - return simplejson.dumps({'version': '1.1', 'id':id, - 'result':result, 'error':None}) - def error(self, id, code, message): - return simplejson.dumps({'id': id, - 'version': '1.1', - 'error': {'name': 'JSONRPCError', - 'code': code, - 'message': message - } - }) - - def add_method(self, name, method): - self.methods[name] = method - - def process(self, data): - data = simplejson.loads(data) - id, method, params = data["id"], data["method"], data["params"] - if method in self.methods: - try: - result =self.methods[method](*params) - return self.response(id, result) - except BaseException: - etype, eval, etb = sys.exc_info() - return self.error(id, 100, '%s: %s' %(etype.__name__, eval)) - except: - etype, eval, etb = sys.exc_info() - return self.error(id, 100, 'Exception %s: %s' %(etype, eval)) - else: - return self.error(id, 100, 'method "%s" does not exist' % method) - - def listmethods(self): - return self.methods.keys() - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/jsonrpc/web2py/jsonrpc.py --- a/plugins/python/modules/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,11 +0,0 @@ -from pyjs.jsonrpc import JSONRPCServiceBase - -class JSONRPCService(JSONRPCServiceBase): - - def serve(self): - return self.process(request.body.read()) - - def __call__(self,func): - self.methods[func.__name__]=func - return func - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/lib/_pyjs.js --- a/plugins/python/modules/svgui/pyjs/lib/_pyjs.js Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,160 +0,0 @@ -function pyjs_extend(klass, base) { - function klass_object_inherit() {} - klass_object_inherit.prototype = base.prototype; - klass_object = new klass_object_inherit(); - for (var i in base.prototype.__class__) { - v = base.prototype.__class__[i]; - if (typeof v == "function" && (v.class_method || v.static_method || v.unbound_method)) - { - klass_object[i] = v; - } - } - - function klass_inherit() {} - klass_inherit.prototype = klass_object; - klass.prototype = new klass_inherit(); - klass_object.constructor = klass; - klass.prototype.__class__ = klass_object; - - for (var i in base.prototype) { - v = base.prototype[i]; - if (typeof v == "function" && v.instance_method) - { - klass.prototype[i] = v; - } - } -} - -/* creates a class, derived from bases, with methods and variables */ -function pyjs_type(clsname, bases, methods) -{ - var fn_cls = function() {}; - fn_cls.__name__ = clsname; - var fn = function() { - var instance = new fn_cls(); - if(instance.__init__) instance.__init__.apply(instance, arguments); - return instance; - } - fn_cls.__initialize__ = function() { - if (fn_cls.__was_initialized__) return; - fn_cls.__was_initialized__ = true; - fn_cls.__extend_baseclasses(); - fn_cls.prototype.__class__.__new__ = fn; - fn_cls.prototype.__class__.__name__ = clsname; - } - fn_cls.__extend_baseclasses = function() { - var bi; - for (bi in fn_cls.__baseclasses) - { - var b = fn_cls.__baseclasses[bi]; - if (b.__was_initialized__) - { - continue; - } - b.__initialize__(); - } - for (bi in fn_cls.__baseclasses) - { - var b = fn_cls.__baseclasses[bi]; - pyjs_extend(fn_cls, b); - } - } - if (!bases) { - bases = [pyjslib.__Object]; - } - fn_cls.__baseclasses = bases; - - fn_cls.__initialize__(); - - for (k in methods) { - var mth = methods[k]; - var mtype = typeof mth; - if (mtype == "function" ) { - fn_cls.prototype[k] = mth; - fn_cls.prototype.__class__[k] = function () { - return fn_cls.prototype[k].call.apply( - fn_cls.prototype[k], arguments); - }; - fn_cls.prototype.__class__[k].unbound_method = true; - fn_cls.prototype.instance_method = true; - fn_cls.prototype.__class__[k].__name__ = k; - fn_cls.prototype[k].__name__ = k; - } else { - fn_cls.prototype.__class__[k] = mth; - } - } - return fn; -} -function pyjs_kwargs_call(obj, func, star_args, args) -{ - var call_args; - - if (star_args) - { - if (!pyjslib.isIteratable(star_args)) - { - throw (pyjslib.TypeError(func.__name__ + "() arguments after * must be a sequence" + pyjslib.repr(star_args))); - } - call_args = Array(); - var __i = star_args.__iter__(); - var i = 0; - try { - while (true) { - call_args[i]=__i.next(); - i++; - } - } catch (e) { - if (e != pyjslib.StopIteration) { - throw e; - } - } - - if (args) - { - var n = star_args.length; - for (var i=0; i < args.length; i++) { - call_args[n+i]=args[i]; - } - } - } - else - { - call_args = args; - } - return func.apply(obj, call_args); -} - -function pyjs_kwargs_function_call(func, star_args, args) -{ - return pyjs_kwargs_call(null, func, star_args, args); -} - -function pyjs_kwargs_method_call(obj, method_name, star_args, args) -{ - var method = obj[method_name]; - if (method.parse_kwargs) - { - args = method.parse_kwargs.apply(null, args); - } - return pyjs_kwargs_call(obj, method, star_args, args); -} - -//String.prototype.__getitem__ = String.prototype.charAt; -//String.prototype.upper = String.prototype.toUpperCase; -//String.prototype.lower = String.prototype.toLowerCase; -//String.prototype.find=pyjslib.String_find; -//String.prototype.join=pyjslib.String_join; -//String.prototype.isdigit=pyjslib.String_isdigit; -//String.prototype.__iter__=pyjslib.String___iter__; -// -//String.prototype.__replace=String.prototype.replace; -//String.prototype.replace=pyjslib.String_replace; -// -//String.prototype.split=pyjslib.String_split; -//String.prototype.strip=pyjslib.String_strip; -//String.prototype.lstrip=pyjslib.String_lstrip; -//String.prototype.rstrip=pyjslib.String_rstrip; -//String.prototype.startswith=pyjslib.String_startswith; - -var str = String; - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/lib/json.js --- a/plugins/python/modules/svgui/pyjs/lib/json.js Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,293 +0,0 @@ -json_parse = (function () { - -// This is a function that can parse a JSON text, producing a JavaScript -// data structure. It is a simple, recursive descent parser. It does not use -// eval or regular expressions, so it can be used as a model for implementing -// a JSON parser in other languages. - -// We are defining the function inside of another function to avoid creating -// global variables. - - var at, // The index of the current character - ch, // The current character - escapee = { - '"': '"', - '\\': '\\', - '/': '/', - b: '\b', - f: '\f', - n: '\n', - r: '\r', - t: '\t' - }, - text, - - error = function (m) { - -// Call error when something is wrong. - - throw { - name: 'SyntaxError', - message: m, - at: at, - text: text - }; - }, - - next = function (c) { - -// If a c parameter is provided, verify that it matches the current character. - - if (c && c !== ch) { - error("Expected '" + c + "' instead of '" + ch + "'"); - } - -// Get the next character. When there are no more characters, -// return the empty string. - - ch = text.charAt(at); - at += 1; - return ch; - }, - - number = function () { - -// Parse a number value. - - var number, - string = ''; - - if (ch === '-') { - string = '-'; - next('-'); - } - while (ch >= '0' && ch <= '9') { - string += ch; - next(); - } - if (ch === '.') { - string += '.'; - while (next() && ch >= '0' && ch <= '9') { - string += ch; - } - } - if (ch === 'e' || ch === 'E') { - string += ch; - next(); - if (ch === '-' || ch === '+') { - string += ch; - next(); - } - while (ch >= '0' && ch <= '9') { - string += ch; - next(); - } - } - number = +string; - if (isNaN(number)) { - error("Bad number"); - } else { - return number; - } - }, - - string = function () { - -// Parse a string value. - - var hex, - i, - string = '', - uffff; - -// When parsing for string values, we must look for " and \ characters. - - if (ch === '"') { - while (next()) { - if (ch === '"') { - next(); - return string; - } else if (ch === '\\') { - next(); - if (ch === 'u') { - uffff = 0; - for (i = 0; i < 4; i += 1) { - hex = parseInt(next(), 16); - if (!isFinite(hex)) { - break; - } - uffff = uffff * 16 + hex; - } - string += String.fromCharCode(uffff); - } else if (typeof escapee[ch] === 'string') { - string += escapee[ch]; - } else { - break; - } - } else { - string += ch; - } - } - } - error("Bad string"); - }, - - white = function () { - -// Skip whitespace. - - while (ch && ch <= ' ') { - next(); - } - }, - - word = function () { - -// true, false, or null. - - switch (ch) { - case 't': - next('t'); - next('r'); - next('u'); - next('e'); - return true; - case 'f': - next('f'); - next('a'); - next('l'); - next('s'); - next('e'); - return false; - case 'n': - next('n'); - next('u'); - next('l'); - next('l'); - return null; - } - error("Unexpected '" + ch + "'"); - }, - - value, // Place holder for the value function. - - array = function () { - -// Parse an array value. - - var array = []; - - if (ch === '[') { - next('['); - white(); - if (ch === ']') { - next(']'); - return array; // empty array - } - while (ch) { - array.push(value()); - white(); - if (ch === ']') { - next(']'); - return array; - } - next(','); - white(); - } - } - error("Bad array"); - }, - - object = function () { - -// Parse an object value. - - var key, - object = {}; - - if (ch === '{') { - next('{'); - white(); - if (ch === '}') { - next('}'); - return object; // empty object - } - while (ch) { - key = string(); - white(); - next(':'); - if (Object.hasOwnProperty.call(object, key)) { - error('Duplicate key "' + key + '"'); - } - object[key] = value(); - white(); - if (ch === '}') { - next('}'); - return object; - } - next(','); - white(); - } - } - error("Bad object"); - }; - - value = function () { - -// Parse a JSON value. It could be an object, an array, a string, a number, -// or a word. - - white(); - switch (ch) { - case '{': - return object(); - case '[': - return array(); - case '"': - return string(); - case '-': - return number(); - default: - return ch >= '0' && ch <= '9' ? number() : word(); - } - }; - -// Return the json_parse function. It will have access to all of the above -// functions and variables. - - return function (source, reviver) { - var result; - - text = source; - at = 0; - ch = ' '; - result = value(); - white(); - if (ch) { - error("Syntax error"); - } - -// If there is a reviver function, we recursively walk the new structure, -// passing each name/value pair to the reviver function for possible -// transformation, starting with a temporary root object that holds the result -// in an empty key. If there is not a reviver function, we simply return the -// result. - - return typeof reviver === 'function' ? (function walk(holder, key) { - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - }({'': result}, '')) : result; - }; -}()); diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/lib/pyjslib.py --- a/plugins/python/modules/svgui/pyjs/lib/pyjslib.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1365 +0,0 @@ -# Copyright 2006 James Tauber and contributors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -# iteration from Bob Ippolito's Iteration in JavaScript - -from __pyjamas__ import JS - -# must declare import _before_ importing sys - -def import_module(path, parent_module, module_name, dynamic=1, async=False): - """ - """ - - JS(""" - var cache_file; - - if (module_name == "sys" || module_name == 'pyjslib') - { - /*module_load_request[module_name] = 1;*/ - return; - } - - if (path == null) - { - path = './'; - } - - var override_name = sys.platform + "." + module_name; - if (((sys.overrides != null) && - (sys.overrides.has_key(override_name)))) - { - cache_file = sys.overrides.__getitem__(override_name) ; - } - else - { - cache_file = module_name ; - } - - cache_file = (path + cache_file + '.cache.js' ) ; - - //alert("cache " + cache_file + " " + module_name + " " + parent_module); - - /* already loaded? */ - if (module_load_request[module_name]) - { - if (module_load_request[module_name] >= 3 && parent_module != null) - { - //onload_fn = parent_module + '.' + module_name + ' = ' + module_name + ';'; - //pyjs_eval(onload_fn); /* set up the parent-module namespace */ - } - return; - } - if (typeof (module_load_request[module_name]) == 'undefined') - { - module_load_request[module_name] = 1; - } - - /* following a load, this first executes the script - * "preparation" function MODULENAME_loaded_fn() - * and then sets up the loaded module in the namespace - * of the parent. - */ - - onload_fn = ''; // module_name + "_loaded_fn();" - - if (parent_module != null) - { - //onload_fn += parent_module + '.' + module_name + ' = ' + module_name + ';'; - /*pmod = parent_module + '.' + module_name; - onload_fn += 'alert("' + pmod + '"+' + pmod+');';*/ - } - - - if (dynamic) - { - /* this one tacks the script onto the end of the DOM - */ - - pyjs_load_script(cache_file, onload_fn, async); - - /* this one actually RUNS the script (eval) into the page. - my feeling is that this would be better for non-async - but i can't get it to work entirely yet. - */ - /*pyjs_ajax_eval(cache_file, onload_fn, async);*/ - } - else - { - if (module_name != "pyjslib" && - module_name != "sys") - pyjs_eval(onload_fn); - } - - """) - -JS(""" -function import_wait(proceed_fn, parent_mod, dynamic) { - - var data = ''; - var element = $doc.createElement("div"); - $doc.body.appendChild(element); - function write_dom(txt) { - element.innerHTML = txt + '
'; - } - - var timeoutperiod = 1; - if (dynamic) - var timeoutperiod = 1; - - var wait = function() { - - var status = ''; - for (l in module_load_request) - { - var m = module_load_request[l]; - if (l == "sys" || l == 'pyjslib') - continue; - status += l + m + " "; - } - - //write_dom( " import wait " + wait_count + " " + status + " parent_mod " + parent_mod); - wait_count += 1; - - if (status == '') - { - setTimeout(wait, timeoutperiod); - return; - } - - for (l in module_load_request) - { - var m = module_load_request[l]; - if (l == "sys" || l == 'pyjslib') - { - module_load_request[l] = 4; - continue; - } - if ((parent_mod != null) && (l == parent_mod)) - { - if (m == 1) - { - setTimeout(wait, timeoutperiod); - return; - } - if (m == 2) - { - /* cheat and move app on to next stage */ - module_load_request[l] = 3; - } - } - if (m == 1 || m == 2) - { - setTimeout(wait, timeoutperiod); - return; - } - if (m == 3) - { - //alert("waited for module " + l + ": loaded"); - module_load_request[l] = 4; - mod_fn = modules[l]; - } - } - //alert("module wait done"); - - if (proceed_fn.importDone) - proceed_fn.importDone(proceed_fn); - else - proceed_fn(); - } - - wait(); -} -""") - -class Object: - pass - -object = Object - -class Modload: - - def __init__(self, path, app_modlist, app_imported_fn, dynamic, - parent_mod): - self.app_modlist = app_modlist - self.app_imported_fn = app_imported_fn - self.path = path - self.idx = 0; - self.dynamic = dynamic - self.parent_mod = parent_mod - - def next(self): - - for i in range(len(self.app_modlist[self.idx])): - app = self.app_modlist[self.idx][i] - import_module(self.path, self.parent_mod, app, self.dynamic, True); - self.idx += 1 - - if self.idx >= len(self.app_modlist): - import_wait(self.app_imported_fn, self.parent_mod, self.dynamic) - else: - import_wait(getattr(self, "next"), self.parent_mod, self.dynamic) - -def get_module(module_name): - ev = "__mod = %s;" % module_name - JS("pyjs_eval(ev);") - return __mod - -def preload_app_modules(path, app_modnames, app_imported_fn, dynamic, - parent_mod=None): - - loader = Modload(path, app_modnames, app_imported_fn, dynamic, parent_mod) - loader.next() - -import sys - -class BaseException: - - name = "BaseException" - - def __init__(self, *args): - self.args = args - - def __str__(self): - if len(self.args) is 0: - return '' - elif len(self.args) is 1: - return repr(self.args[0]) - return repr(self.args) - - def toString(self): - return str(self) - -class Exception(BaseException): - - name = "Exception" - -class TypeError(BaseException): - name = "TypeError" - -class StandardError(Exception): - name = "StandardError" - -class LookupError(StandardError): - name = "LookupError" - - def toString(self): - return self.name + ": " + self.args[0] - -class KeyError(LookupError): - name = "KeyError" - -class AttributeError(StandardError): - - name = "AttributeError" - - def toString(self): - return "AttributeError: %s of %s" % (self.args[1], self.args[0]) - -JS(""" -pyjslib.StopIteration = function () { }; -pyjslib.StopIteration.prototype = new Error(); -pyjslib.StopIteration.name = 'StopIteration'; -pyjslib.StopIteration.message = 'StopIteration'; - -pyjslib.String_find = function(sub, start, end) { - var pos=this.indexOf(sub, start); - if (pyjslib.isUndefined(end)) return pos; - - if (pos + sub.length>end) return -1; - return pos; -} - -pyjslib.String_join = function(data) { - var text=""; - - if (pyjslib.isArray(data)) { - return data.join(this); - } - else if (pyjslib.isIteratable(data)) { - var iter=data.__iter__(); - try { - text+=iter.next(); - while (true) { - var item=iter.next(); - text+=this + item; - } - } - catch (e) { - if (e != pyjslib.StopIteration) throw e; - } - } - - return text; -} - -pyjslib.String_isdigit = function() { - return (this.match(/^\d+$/g) != null); -} - -pyjslib.String_replace = function(old, replace, count) { - var do_max=false; - var start=0; - var new_str=""; - var pos=0; - - if (!pyjslib.isString(old)) return this.__replace(old, replace); - if (!pyjslib.isUndefined(count)) do_max=true; - - while (start= s.length) { - throw pyjslib.StopIteration; - } - return s.substring(i++, i, 1); - }, - '__iter__': function() { - return this; - } - }; -} - -pyjslib.String_strip = function(chars) { - return this.lstrip(chars).rstrip(chars); -} - -pyjslib.String_lstrip = function(chars) { - if (pyjslib.isUndefined(chars)) return this.replace(/^\s+/, ""); - - return this.replace(new RegExp("^[" + chars + "]+"), ""); -} - -pyjslib.String_rstrip = function(chars) { - if (pyjslib.isUndefined(chars)) return this.replace(/\s+$/, ""); - - return this.replace(new RegExp("[" + chars + "]+$"), ""); -} - -pyjslib.String_startswith = function(prefix, start) { - if (pyjslib.isUndefined(start)) start = 0; - - if (this.substring(start, prefix.length) == prefix) return true; - return false; -} - -pyjslib.abs = Math.abs; - -""") - -class Class: - def __init__(self, name): - self.name = name - - def __str___(self): - return self.name - -def eq(a,b): - JS(""" - if (pyjslib.hasattr(a, "__cmp__")) { - return a.__cmp__(b) == 0; - } else if (pyjslib.hasattr(b, "__cmp__")) { - return b.__cmp__(a) == 0; - } - return a == b; - """) - -def cmp(a,b): - if hasattr(a, "__cmp__"): - return a.__cmp__(b) - elif hasattr(b, "__cmp__"): - return -b.__cmp__(a) - if a > b: - return 1 - elif b > a: - return -1 - else: - return 0 - -def bool(v): - # this needs to stay in native code without any dependencies here, - # because this is used by if and while, we need to prevent - # recursion - JS(""" - if (!v) return false; - switch(typeof v){ - case 'boolean': - return v; - case 'object': - if (v.__nonzero__){ - return v.__nonzero__(); - }else if (v.__len__){ - return v.__len__()>0; - } - return true; - } - return Boolean(v); - """) - -class List: - def __init__(self, data=None): - JS(""" - this.l = []; - this.extend(data); - """) - - def append(self, item): - JS(""" this.l[this.l.length] = item;""") - - def extend(self, data): - JS(""" - if (pyjslib.isArray(data)) { - n = this.l.length; - for (var i=0; i < data.length; i++) { - this.l[n+i]=data[i]; - } - } - else if (pyjslib.isIteratable(data)) { - var iter=data.__iter__(); - var i=this.l.length; - try { - while (true) { - var item=iter.next(); - this.l[i++]=item; - } - } - catch (e) { - if (e != pyjslib.StopIteration) throw e; - } - } - """) - - def remove(self, value): - JS(""" - var index=this.index(value); - if (index<0) return false; - this.l.splice(index, 1); - return true; - """) - - def index(self, value, start=0): - JS(""" - var length=this.l.length; - for (var i=start; i= 0 - - def __iter__(self): - JS(""" - var i = 0; - var l = this.l; - return { - 'next': function() { - if (i >= l.length) { - throw pyjslib.StopIteration; - } - return l[i++]; - }, - '__iter__': function() { - return this; - } - }; - """) - - def reverse(self): - JS(""" this.l.reverse();""") - - def sort(self, compareFunc=None, keyFunc=None, reverse=False): - if not compareFunc: - global cmp - compareFunc = cmp - if keyFunc and reverse: - def thisSort1(a,b): - return -compareFunc(keyFunc(a), keyFunc(b)) - self.l.sort(thisSort1) - elif keyFunc: - def thisSort2(a,b): - return compareFunc(keyFunc(a), keyFunc(b)) - self.l.sort(thisSort2) - elif reverse: - def thisSort3(a,b): - return -compareFunc(a, b) - self.l.sort(thisSort3) - else: - self.l.sort(compareFunc) - - def getArray(self): - """ - Access the javascript Array that is used internally by this list - """ - return self.l - - def __str__(self): - return repr(self) - -list = List - -class Tuple: - def __init__(self, data=None): - JS(""" - this.l = []; - this.extend(data); - """) - - def append(self, item): - JS(""" this.l[this.l.length] = item;""") - - def extend(self, data): - JS(""" - if (pyjslib.isArray(data)) { - n = this.l.length; - for (var i=0; i < data.length; i++) { - this.l[n+i]=data[i]; - } - } - else if (pyjslib.isIteratable(data)) { - var iter=data.__iter__(); - var i=this.l.length; - try { - while (true) { - var item=iter.next(); - this.l[i++]=item; - } - } - catch (e) { - if (e != pyjslib.StopIteration) throw e; - } - } - """) - - def remove(self, value): - JS(""" - var index=this.index(value); - if (index<0) return false; - this.l.splice(index, 1); - return true; - """) - - def index(self, value, start=0): - JS(""" - var length=this.l.length; - for (var i=start; i= 0 - - def __iter__(self): - JS(""" - var i = 0; - var l = this.l; - return { - 'next': function() { - if (i >= l.length) { - throw pyjslib.StopIteration; - } - return l[i++]; - }, - '__iter__': function() { - return this; - } - }; - """) - - def reverse(self): - JS(""" this.l.reverse();""") - - def sort(self, compareFunc=None, keyFunc=None, reverse=False): - if not compareFunc: - global cmp - compareFunc = cmp - if keyFunc and reverse: - def thisSort1(a,b): - return -compareFunc(keyFunc(a), keyFunc(b)) - self.l.sort(thisSort1) - elif keyFunc: - def thisSort2(a,b): - return compareFunc(keyFunc(a), keyFunc(b)) - self.l.sort(thisSort2) - elif reverse: - def thisSort3(a,b): - return -compareFunc(a, b) - self.l.sort(thisSort3) - else: - self.l.sort(compareFunc) - - def getArray(self): - """ - Access the javascript Array that is used internally by this list - """ - return self.l - - def __str__(self): - return repr(self) - -tuple = Tuple - - -class Dict: - def __init__(self, data=None): - JS(""" - this.d = {}; - - if (pyjslib.isArray(data)) { - for (var i in data) { - var item=data[i]; - this.__setitem__(item[0], item[1]); - //var sKey=pyjslib.hash(item[0]); - //this.d[sKey]=item[1]; - } - } - else if (pyjslib.isIteratable(data)) { - var iter=data.__iter__(); - try { - while (true) { - var item=iter.next(); - this.__setitem__(item.__getitem__(0), item.__getitem__(1)); - } - } - catch (e) { - if (e != pyjslib.StopIteration) throw e; - } - } - else if (pyjslib.isObject(data)) { - for (var key in data) { - this.__setitem__(key, data[key]); - } - } - """) - - def __setitem__(self, key, value): - JS(""" - var sKey = pyjslib.hash(key); - this.d[sKey]=[key, value]; - """) - - def __getitem__(self, key): - JS(""" - var sKey = pyjslib.hash(key); - var value=this.d[sKey]; - if (pyjslib.isUndefined(value)){ - throw pyjslib.KeyError(key); - } - return value[1]; - """) - - def __nonzero__(self): - JS(""" - for (var i in this.d){ - return true; - } - return false; - """) - - def __len__(self): - JS(""" - var size=0; - for (var i in this.d) size++; - return size; - """) - - def has_key(self, key): - return self.__contains__(key) - - def __delitem__(self, key): - JS(""" - var sKey = pyjslib.hash(key); - delete this.d[sKey]; - """) - - def __contains__(self, key): - JS(""" - var sKey = pyjslib.hash(key); - return (pyjslib.isUndefined(this.d[sKey])) ? false : true; - """) - - def keys(self): - JS(""" - var keys=new pyjslib.List(); - for (var key in this.d) { - keys.append(this.d[key][0]); - } - return keys; - """) - - def values(self): - JS(""" - var values=new pyjslib.List(); - for (var key in this.d) values.append(this.d[key][1]); - return values; - """) - - def items(self): - JS(""" - var items = new pyjslib.List(); - for (var key in this.d) { - var kv = this.d[key]; - items.append(new pyjslib.List(kv)) - } - return items; - """) - - def __iter__(self): - return self.keys().__iter__() - - def iterkeys(self): - return self.__iter__() - - def itervalues(self): - return self.values().__iter__(); - - def iteritems(self): - return self.items().__iter__(); - - def setdefault(self, key, default_value): - if not self.has_key(key): - self[key] = default_value - - def get(self, key, default_=None): - if not self.has_key(key): - return default_ - return self[key] - - def update(self, d): - for k,v in d.iteritems(): - self[k] = v - - def getObject(self): - """ - Return the javascript Object which this class uses to store - dictionary keys and values - """ - return self.d - - def copy(self): - return Dict(self.items()) - - def __str__(self): - return repr(self) - -dict = Dict - -# taken from mochikit: range( [start,] stop[, step] ) -def range(): - JS(""" - var start = 0; - var stop = 0; - var step = 1; - - if (arguments.length == 2) { - start = arguments[0]; - stop = arguments[1]; - } - else if (arguments.length == 3) { - start = arguments[0]; - stop = arguments[1]; - step = arguments[2]; - } - else if (arguments.length>0) stop = arguments[0]; - - return { - 'next': function() { - if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) throw pyjslib.StopIteration; - var rval = start; - start += step; - return rval; - }, - '__iter__': function() { - return this; - } - } - """) - -def slice(object, lower, upper): - JS(""" - if (pyjslib.isString(object)) { - if (lower < 0) { - lower = object.length + lower; - } - if (upper < 0) { - upper = object.length + upper; - } - if (pyjslib.isNull(upper)) upper=object.length; - return object.substring(lower, upper); - } - if (pyjslib.isObject(object) && object.slice) - return object.slice(lower, upper); - - return null; - """) - -def str(text): - JS(""" - if (pyjslib.hasattr(text,"__str__")) { - return text.__str__(); - } - return String(text); - """) - -def ord(x): - if(isString(x) and len(x) is 1): - JS(""" - return x.charCodeAt(0); - """) - else: - JS(""" - throw pyjslib.TypeError(); - """) - return None - -def chr(x): - JS(""" - return String.fromCharCode(x) - """) - -def is_basetype(x): - JS(""" - var t = typeof(x); - return t == 'boolean' || - t == 'function' || - t == 'number' || - t == 'string' || - t == 'undefined' - ; - """) - -def get_pyjs_classtype(x): - JS(""" - if (pyjslib.hasattr(x, "__class__")) - if (pyjslib.hasattr(x.__class__, "__new__")) - var src = x.__class__.__name__; - return src; - return null; - """) - -def repr(x): - """ Return the string representation of 'x'. - """ - JS(""" - if (x === null) - return "null"; - - if (x === undefined) - return "undefined"; - - var t = typeof(x); - - //alert("repr typeof " + t + " : " + x); - - if (t == "boolean") - return x.toString(); - - if (t == "function") - return ""; - - if (t == "number") - return x.toString(); - - if (t == "string") { - if (x.indexOf("'") == -1) - return "'" + x + "'"; - if (x.indexOf('"') == -1) - return '"' + x + '"'; - var s = x.replace(new RegExp('"', "g"), '\\\\"'); - return '"' + s + '"'; - }; - - if (t == "undefined") - return "undefined"; - - // If we get here, x is an object. See if it's a Pyjamas class. - - if (!pyjslib.hasattr(x, "__init__")) - return "<" + x.toString() + ">"; - - // Handle the common Pyjamas data types. - - var constructor = "UNKNOWN"; - - constructor = pyjslib.get_pyjs_classtype(x); - - //alert("repr constructor: " + constructor); - - if (constructor == "Tuple") { - var contents = x.getArray(); - var s = "("; - for (var i=0; i < contents.length; i++) { - s += pyjslib.repr(contents[i]); - if (i < contents.length - 1) - s += ", "; - }; - s += ")" - return s; - }; - - if (constructor == "List") { - var contents = x.getArray(); - var s = "["; - for (var i=0; i < contents.length; i++) { - s += pyjslib.repr(contents[i]); - if (i < contents.length - 1) - s += ", "; - }; - s += "]" - return s; - }; - - if (constructor == "Dict") { - var keys = new Array(); - for (var key in x.d) - keys.push(key); - - var s = "{"; - for (var i=0; i return the class name. - // Note that we replace underscores with dots so that the name will - // (hopefully!) look like the original Python name. - - //var s = constructor.replace(new RegExp('_', "g"), '.'); - return "<" + constructor + " object>"; - """) - -def float(text): - JS(""" - return parseFloat(text); - """) - -def int(text, radix=0): - JS(""" - return parseInt(text, radix); - """) - -def len(object): - JS(""" - if (object==null) return 0; - if (pyjslib.isObject(object) && object.__len__) return object.__len__(); - return object.length; - """) - -def isinstance(object_, classinfo): - if pyjslib.isUndefined(object_): - return False - if not pyjslib.isObject(object_): - - return False - if _isinstance(classinfo, Tuple): - for ci in classinfo: - if isinstance(object_, ci): - return True - return False - else: - return _isinstance(object_, classinfo) - -def _isinstance(object_, classinfo): - if not pyjslib.isObject(object_): - return False - JS(""" - if (object_.__class__){ - var res = object_ instanceof classinfo.constructor; - return res; - } - return false; - """) - -def getattr(obj, name, default_): - JS(""" - if ((!pyjslib.isObject(obj))||(pyjslib.isUndefined(obj[name]))){ - if (pyjslib.isUndefined(default_)){ - throw pyjslib.AttributeError(obj, name); - }else{ - return default_; - } - } - if (!pyjslib.isFunction(obj[name])) return obj[name]; - var fnwrap = function() { - var args = []; - for (var i = 0; i < arguments.length; i++) { - args.push(arguments[i]); - } - return obj[name].apply(obj,args); - } - fnwrap.__name__ = name; - return fnwrap; - """) - -def setattr(obj, name, value): - JS(""" - if (!pyjslib.isObject(obj)) return null; - - obj[name] = value; - - """) - -def hasattr(obj, name): - JS(""" - if (!pyjslib.isObject(obj)) return false; - if (pyjslib.isUndefined(obj[name])) return false; - - return true; - """) - -def dir(obj): - JS(""" - var properties=new pyjslib.List(); - for (property in obj) properties.append(property); - return properties; - """) - -def filter(obj, method, sequence=None): - # object context is LOST when a method is passed, hence object must be passed separately - # to emulate python behaviour, should generate this code inline rather than as a function call - items = [] - if sequence is None: - sequence = method - method = obj - - for item in sequence: - if method(item): - items.append(item) - else: - for item in sequence: - if method.call(obj, item): - items.append(item) - - return items - - -def map(obj, method, sequence=None): - items = [] - - if sequence is None: - sequence = method - method = obj - - for item in sequence: - items.append(method(item)) - else: - for item in sequence: - items.append(method.call(obj, item)) - - return items - - -def enumerate(sequence): - enumeration = [] - nextIndex = 0 - for item in sequence: - enumeration.append([nextIndex, item]) - nextIndex = nextIndex + 1 - return enumeration - - -def min(*sequence): - minValue = None - for item in sequence: - if minValue is None: - minValue = item - elif item < minValue: - minValue = item - return minValue - - -def max(*sequence): - maxValue = None - for item in sequence: - if maxValue is None: - maxValue = item - elif item > maxValue: - maxValue = item - return maxValue - - -next_hash_id = 0 - -def hash(obj): - JS(""" - if (obj == null) return null; - - if (obj.$H) return obj.$H; - if (obj.__hash__) return obj.__hash__(); - if (obj.constructor == String || obj.constructor == Number || obj.constructor == Date) return obj; - - obj.$H = ++pyjslib.next_hash_id; - return obj.$H; - """) - - -# type functions from Douglas Crockford's Remedial Javascript: http://www.crockford.com/javascript/remedial.html -def isObject(a): - JS(""" - return (a != null && (typeof a == 'object')) || pyjslib.isFunction(a); - """) - -def isFunction(a): - JS(""" - return typeof a == 'function'; - """) - -def isString(a): - JS(""" - return typeof a == 'string'; - """) - -def isNull(a): - JS(""" - return typeof a == 'object' && !a; - """) - -def isArray(a): - JS(""" - return pyjslib.isObject(a) && a.constructor == Array; - """) - -def isUndefined(a): - JS(""" - return typeof a == 'undefined'; - """) - -def isIteratable(a): - JS(""" - return pyjslib.isString(a) || (pyjslib.isObject(a) && a.__iter__); - """) - -def isNumber(a): - JS(""" - return typeof a == 'number' && isFinite(a); - """) - -def toJSObjects(x): - """ - Convert the pyjs pythonic List and Dict objects into javascript Object and Array - objects, recursively. - """ - if isArray(x): - JS(""" - var result = []; - for(var k=0; k < x.length; k++) { - var v = x[k]; - var tv = pyjslib.toJSObjects(v); - result.push(tv); - } - return result; - """) - if isObject(x): - if isinstance(x, Dict): - JS(""" - var o = x.getObject(); - var result = {}; - for (var i in o) { - result[o[i][0].toString()] = o[i][1]; - } - return pyjslib.toJSObjects(result) - """) - elif isinstance(x, List): - return toJSObjects(x.l) - elif hasattr(x, '__class__'): - # we do not have a special implementation for custom - # classes, just pass it on - return x - if isObject(x): - JS(""" - var result = {}; - for(var k in x) { - var v = x[k]; - var tv = pyjslib.toJSObjects(v) - result[k] = tv; - } - return result; - """) - return x - -def printFunc(objs): - JS(""" - if ($wnd.console==undefined) return; - var s = ""; - for(var i=0; i < objs.length; i++) { - if(s != "") s += " "; - s += objs[i]; - } - console.debug(s) - """) - -def type(clsname, bases=None, methods=None): - """ creates a class, derived from bases, with methods and variables - """ - - JS(" var mths = {}; ") - if methods: - for k in methods.keys(): - mth = methods[k] - JS(" mths[k] = mth; ") - - JS(" var bss = null; ") - if bases: - JS("bss = bases.l;") - JS(" return pyjs_type(clsname, bss, mths); ") - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/lib/sys.py --- a/plugins/python/modules/svgui/pyjs/lib/sys.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -# the platform name (PyV8, smjs, Mozilla, IE6, Opera, Safari etc.) -platform = '' # to be updated by app, on compile - -# a dictionary of module override names (platform-specific) -overrides = None # to be updated by app, on compile - -# the remote path for loading modules -loadpath = None - -stacktrace = None - -appname = None - -def setloadpath(lp): - global loadpath - loadpath = lp - -def setappname(an): - global appname - appname = an - -def getloadpath(): - global loadpath - return loadpath - -def addoverride(module_name, path): - global overrides - overrides[module_name] = path - -def addstack(linedebug): - JS(""" - if (pyjslib.bool((sys.stacktrace === null))) { - sys.stacktrace = new pyjslib.List([]); - } - sys.stacktrace.append(linedebug); - """) -def popstack(): - JS(""" - sys.stacktrace.pop() - """) - -def printstack(): - JS(""" - var res = ''; - - var __l = sys.stacktrace.__iter__(); - try { - while (true) { - var l = __l.next(); - res += ( l + '\\n' ) ; - } - } catch (e) { - if (e != pyjslib.StopIteration) { - throw e; - } - } - - return res; - """) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/pyjs/pyjs.py --- a/plugins/python/modules/svgui/pyjs/pyjs.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1777 +0,0 @@ -#!/usr/bin/env python -# Copyright 2006 James Tauber and contributors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -import sys -from types import StringType -import compiler -from compiler import ast -import os -import copy - -# the standard location for builtins (e.g. pyjslib) can be -# over-ridden by changing this. it defaults to sys.prefix -# so that on a system-wide install of pyjamas the builtins -# can be found in e.g. {sys.prefix}/share/pyjamas -# -# over-rides can be done by either explicitly modifying -# pyjs.prefix or by setting an environment variable, PYJSPREFIX. - -prefix = sys.prefix - -if os.environ.has_key('PYJSPREFIX'): - prefix = os.environ['PYJSPREFIX'] - -# pyjs.path is the list of paths, just like sys.path, from which -# library modules will be searched for, for compile purposes. -# obviously we don't want to use sys.path because that would result -# in compiling standard python modules into javascript! - -path = [os.path.abspath('')] - -if os.environ.has_key('PYJSPATH'): - for p in os.environ['PYJSPATH'].split(os.pathsep): - p = os.path.abspath(p) - if os.path.isdir(p): - path.append(p) - -# this is the python function used to wrap native javascript -NATIVE_JS_FUNC_NAME = "JS" - -UU = "" - -PYJSLIB_BUILTIN_FUNCTIONS=("cmp", - "map", - "filter", - "dir", - "getattr", - "setattr", - "hasattr", - "int", - "float", - "str", - "repr", - "range", - "len", - "hash", - "abs", - "ord", - "chr", - "enumerate", - "min", - "max", - "bool", - "type", - "isinstance") - -PYJSLIB_BUILTIN_CLASSES=("BaseException", - "Exception", - "StandardError", - "StopIteration", - "AttributeError", - "TypeError", - "KeyError", - "LookupError", - "list", - "dict", - "object", - "tuple", - ) - -def pyjs_builtin_remap(name): - # XXX HACK! - if name == 'list': - name = 'List' - if name == 'object': - name = '__Object' - if name == 'dict': - name = 'Dict' - if name == 'tuple': - name = 'Tuple' - return name - -# XXX: this is a hack: these should be dealt with another way -# however, console is currently the only global name which is causing -# problems. -PYJS_GLOBAL_VARS=("console") - -# This is taken from the django project. -# Escape every ASCII character with a value less than 32. -JS_ESCAPES = ( - ('\\', r'\x5C'), - ('\'', r'\x27'), - ('"', r'\x22'), - ('>', r'\x3E'), - ('<', r'\x3C'), - ('&', r'\x26'), - (';', r'\x3B') - ) + tuple([('%c' % z, '\\x%02X' % z) for z in range(32)]) - -def escapejs(value): - """Hex encodes characters for use in JavaScript strings.""" - for bad, good in JS_ESCAPES: - value = value.replace(bad, good) - return value - -def uuprefix(name, leave_alone=0): - name = name.split(".") - name = name[:leave_alone] + map(lambda x: "__%s" % x, name[leave_alone:]) - return '.'.join(name) - -class Klass: - - klasses = {} - - def __init__(self, name, name_): - self.name = name - self.name_ = name_ - self.klasses[name] = self - self.functions = set() - - def set_base(self, base_name): - self.base = self.klasses.get(base_name) - - def add_function(self, function_name): - self.functions.add(function_name) - - -class TranslationError(Exception): - def __init__(self, message, node): - self.message = "line %s:\n%s\n%s" % (node.lineno, message, node) - - def __str__(self): - return self.message - -def strip_py(name): - return name - -def mod_var_name_decl(raw_module_name): - """ function to get the last component of the module e.g. - pyjamas.ui.DOM into the "namespace". i.e. doing - "import pyjamas.ui.DOM" actually ends up with _two_ - variables - one pyjamas.ui.DOM, the other just "DOM". - but "DOM" is actually local, hence the "var" prefix. - - for PyV8, this might end up causing problems - we'll have - to see: gen_mod_import and mod_var_name_decl might have - to end up in a library-specific module, somewhere. - """ - name = raw_module_name.split(".") - if len(name) == 1: - return '' - child_name = name[-1] - return "var %s = %s;\n" % (child_name, raw_module_name) - -def gen_mod_import(parentName, importName, dynamic=1): - #pyjs_ajax_eval("%(n)s.cache.js", null, true); - return """ - pyjslib.import_module(sys.loadpath, '%(p)s', '%(n)s', %(d)d, false); - """ % ({'p': parentName, 'd': dynamic, 'n': importName}) + \ - mod_var_name_decl(importName) - -class Translator: - - def __init__(self, mn, module_name, raw_module_name, src, debug, mod, output, - dynamic=0, optimize=False, - findFile=None): - - if module_name: - self.module_prefix = module_name + "." - else: - self.module_prefix = "" - self.raw_module_name = raw_module_name - src = src.replace("\r\n", "\n") - src = src.replace("\n\r", "\n") - src = src.replace("\r", "\n") - self.src = src.split("\n") - self.debug = debug - self.imported_modules = [] - self.imported_modules_as = [] - self.imported_js = set() - self.top_level_functions = set() - self.top_level_classes = set() - self.top_level_vars = set() - self.local_arg_stack = [[]] - self.output = output - self.imported_classes = {} - self.method_imported_globals = set() - self.method_self = None - self.nextTupleAssignID = 1 - self.dynamic = dynamic - self.optimize = optimize - self.findFile = findFile - - if module_name.find(".") >= 0: - vdec = '' - else: - vdec = 'var ' - print >>self.output, UU+"%s%s = function (__mod_name__) {" % (vdec, module_name) - - print >>self.output, " if("+module_name+".__was_initialized__) return;" - print >>self.output, " "+UU+module_name+".__was_initialized__ = true;" - print >>self.output, UU+"if (__mod_name__ == null) __mod_name__ = '%s';" % (mn) - print >>self.output, UU+"%s.__name__ = __mod_name__;" % (raw_module_name) - - decl = mod_var_name_decl(raw_module_name) - if decl: - print >>self.output, decl - - - if self.debug: - haltException = self.module_prefix + "HaltException" - print >>self.output, haltException + ' = function () {' - print >>self.output, ' this.message = "Program Halted";' - print >>self.output, ' this.name = "' + haltException + '";' - print >>self.output, '}' - print >>self.output, '' - print >>self.output, haltException + ".prototype.__str__ = function()" - print >>self.output, '{' - print >>self.output, 'return this.message ;' - print >>self.output, '}' - - print >>self.output, haltException + ".prototype.toString = function()" - print >>self.output, '{' - print >>self.output, 'return this.name + ": \\"" + this.message + "\\"";' - print >>self.output, '}' - - isHaltFunction = self.module_prefix + "IsHaltException" - print >>self.output, """ - %s = function (s) { - var suffix="HaltException"; - if (s.length < suffix.length) { - //alert(s + " " + suffix); - return false; - } else { - var ss = s.substring(s.length, (s.length - suffix.length)); - //alert(s + " " + suffix + " " + ss); - return ss == suffix; - } - } - """ % isHaltFunction - for child in mod.node: - if isinstance(child, ast.Function): - self.top_level_functions.add(child.name) - elif isinstance(child, ast.Class): - self.top_level_classes.add(child.name) - - for child in mod.node: - if isinstance(child, ast.Function): - self._function(child, False) - elif isinstance(child, ast.Class): - self._class(child) - elif isinstance(child, ast.Import): - importName = child.names[0][0] - if importName == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter - pass - elif importName.endswith('.js'): - self.imported_js.add(importName) - else: - self.add_imported_module(strip_py(importName)) - elif isinstance(child, ast.From): - if child.modname == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter - pass - else: - self.add_imported_module(child.modname) - self._from(child) - elif isinstance(child, ast.Discard): - self._discard(child, None) - elif isinstance(child, ast.Assign): - self._assign(child, None, True) - elif isinstance(child, ast.AugAssign): - self._augassign(child, None) - elif isinstance(child, ast.If): - self._if(child, None) - elif isinstance(child, ast.For): - self._for(child, None) - elif isinstance(child, ast.While): - self._while(child, None) - elif isinstance(child, ast.Subscript): - self._subscript_stmt(child, None) - elif isinstance(child, ast.Global): - self._global(child, None) - elif isinstance(child, ast.Printnl): - self._print(child, None) - elif isinstance(child, ast.Print): - self._print(child, None) - elif isinstance(child, ast.TryExcept): - self._tryExcept(child, None) - elif isinstance(child, ast.Raise): - self._raise(child, None) - elif isinstance(child, ast.Stmt): - self._stmt(child, None) - else: - raise TranslationError("unsupported type (in __init__)", child) - - # Initialize all classes for this module - #print >> self.output, "__"+self.modpfx()+\ - # "classes_initialize = function() {\n" - #for className in self.top_level_classes: - # print >> self.output, "\t"+UU+self.modpfx()+"__"+className+"_initialize();" - #print >> self.output, "};\n" - - print >> self.output, "return this;\n" - print >> self.output, "}; /* end %s */ \n" % module_name - - def module_imports(self): - return self.imported_modules + self.imported_modules_as - - def add_local_arg(self, varname): - local_vars = self.local_arg_stack[-1] - if varname not in local_vars: - local_vars.append(varname) - - def add_imported_module(self, importName): - - if importName in self.imported_modules: - return - self.imported_modules.append(importName) - name = importName.split(".") - if len(name) != 1: - # add the name of the module to the namespace, - # but don't add the short name to imported_modules - # because then the short name would be attempted to be - # added to the dependencies, and it's half way up the - # module import directory structure! - child_name = name[-1] - self.imported_modules_as.append(child_name) - print >> self.output, gen_mod_import(self.raw_module_name, - strip_py(importName), - self.dynamic) - - def _default_args_handler(self, node, arg_names, current_klass, - output=None): - if len(node.defaults): - output = output or self.output - default_pos = len(arg_names) - len(node.defaults) - if arg_names and arg_names[0] == self.method_self: - default_pos -= 1 - for default_node in node.defaults: - if isinstance(default_node, ast.Const): - default_value = self._const(default_node) - elif isinstance(default_node, ast.Name): - default_value = self._name(default_node, current_klass) - elif isinstance(default_node, ast.UnarySub): - default_value = self._unarysub(default_node, current_klass) - else: - raise TranslationError("unsupported type (in _method)", default_node) - - default_name = arg_names[default_pos] - default_pos += 1 - print >> output, " if (typeof %s == 'undefined') %s=%s;" % (default_name, default_name, default_value) - - def _varargs_handler(self, node, varargname, arg_names, current_klass): - print >>self.output, " var", varargname, '= new pyjslib.Tuple();' - print >>self.output, " for(var __va_arg="+str(len(arg_names))+"; __va_arg < arguments.length; __va_arg++) {" - print >>self.output, " var __arg = arguments[__va_arg];" - print >>self.output, " "+varargname+".append(__arg);" - print >>self.output, " }" - - def _kwargs_parser(self, node, function_name, arg_names, current_klass): - if len(node.defaults) or node.kwargs: - default_pos = len(arg_names) - len(node.defaults) - if arg_names and arg_names[0] == self.method_self: - default_pos -= 1 - print >>self.output, function_name+'.parse_kwargs = function (', ", ".join(["__kwargs"]+arg_names), ") {" - for default_node in node.defaults: - default_value = self.expr(default_node, current_klass) -# if isinstance(default_node, ast.Const): -# default_value = self._const(default_node) -# elif isinstance(default_node, ast.Name): -# default_value = self._name(default_node) -# elif isinstance(default_node, ast.UnarySub): -# default_value = self._unarysub(default_node, current_klass) -# else: -# raise TranslationError("unsupported type (in _method)", default_node) - - default_name = arg_names[default_pos] - print >>self.output, " if (typeof %s == 'undefined')"%(default_name) - print >>self.output, " %s=__kwargs.%s;"% (default_name, default_name) - default_pos += 1 - - #self._default_args_handler(node, arg_names, current_klass) - if node.kwargs: arg_names += ["pyjslib.Dict(__kwargs)"] - print >>self.output, " var __r = "+"".join(["[", ", ".join(arg_names), "]"])+";" - if node.varargs: - self._varargs_handler(node, "__args", arg_names, current_klass) - print >>self.output, " __r.push.apply(__r, __args.getArray())" - print >>self.output, " return __r;" - print >>self.output, "};" - - def _function(self, node, local=False): - if local: - function_name = node.name - self.add_local_arg(function_name) - else: - function_name = UU + self.modpfx() + node.name - - arg_names = list(node.argnames) - normal_arg_names = list(arg_names) - if node.kwargs: kwargname = normal_arg_names.pop() - if node.varargs: varargname = normal_arg_names.pop() - declared_arg_names = list(normal_arg_names) - if node.kwargs: declared_arg_names.append(kwargname) - - function_args = "(" + ", ".join(declared_arg_names) + ")" - print >>self.output, "%s = function%s {" % (function_name, function_args) - self._default_args_handler(node, normal_arg_names, None) - - local_arg_names = normal_arg_names + declared_arg_names - - if node.varargs: - self._varargs_handler(node, varargname, declared_arg_names, None) - local_arg_names.append(varargname) - - # stack of local variable names for this function call - self.local_arg_stack.append(local_arg_names) - - for child in node.code: - self._stmt(child, None) - - # remove the top local arg names - self.local_arg_stack.pop() - - # we need to return null always, so it is not undefined - lastStmt = [p for p in node.code][-1] - if not isinstance(lastStmt, ast.Return): - if not self._isNativeFunc(lastStmt): - print >>self.output, " return null;" - - print >>self.output, "};" - print >>self.output, "%s.__name__ = '%s';\n" % (function_name, node.name) - - - self._kwargs_parser(node, function_name, normal_arg_names, None) - - - def _return(self, node, current_klass): - expr = self.expr(node.value, current_klass) - # in python a function call always returns None, so we do it - # here too - print >>self.output, " return " + expr + ";" - - - def _break(self, node, current_klass): - print >>self.output, " break;" - - - def _continue(self, node, current_klass): - print >>self.output, " continue;" - - - def _callfunc(self, v, current_klass): - - if isinstance(v.node, ast.Name): - if v.node.name in self.top_level_functions: - call_name = self.modpfx() + v.node.name - elif v.node.name in self.top_level_classes: - call_name = self.modpfx() + v.node.name - elif self.imported_classes.has_key(v.node.name): - call_name = self.imported_classes[v.node.name] + '.' + v.node.name - elif v.node.name in PYJSLIB_BUILTIN_FUNCTIONS: - call_name = 'pyjslib.' + v.node.name - elif v.node.name in PYJSLIB_BUILTIN_CLASSES: - name = pyjs_builtin_remap(v.node.name) - call_name = 'pyjslib.' + name - elif v.node.name == "callable": - call_name = "pyjslib.isFunction" - else: - call_name = v.node.name - call_args = [] - elif isinstance(v.node, ast.Getattr): - attr_name = v.node.attrname - - if isinstance(v.node.expr, ast.Name): - call_name = self._name2(v.node.expr, current_klass, attr_name) - call_args = [] - elif isinstance(v.node.expr, ast.Getattr): - call_name = self._getattr2(v.node.expr, current_klass, attr_name) - call_args = [] - elif isinstance(v.node.expr, ast.CallFunc): - call_name = self._callfunc(v.node.expr, current_klass) + "." + v.node.attrname - call_args = [] - elif isinstance(v.node.expr, ast.Subscript): - call_name = self._subscript(v.node.expr, current_klass) + "." + v.node.attrname - call_args = [] - elif isinstance(v.node.expr, ast.Const): - call_name = self.expr(v.node.expr, current_klass) + "." + v.node.attrname - call_args = [] - else: - raise TranslationError("unsupported type (in _callfunc)", v.node.expr) - else: - raise TranslationError("unsupported type (in _callfunc)", v.node) - - call_name = strip_py(call_name) - - kwargs = [] - star_arg_name = None - if v.star_args: - star_arg_name = self.expr(v.star_args, current_klass) - - for ch4 in v.args: - if isinstance(ch4, ast.Keyword): - kwarg = ch4.name + ":" + self.expr(ch4.expr, current_klass) - kwargs.append(kwarg) - else: - arg = self.expr(ch4, current_klass) - call_args.append(arg) - - if kwargs: - fn_args = ", ".join(['{' + ', '.join(kwargs) + '}']+call_args) - else: - fn_args = ", ".join(call_args) - - if kwargs or star_arg_name: - if not star_arg_name: - star_arg_name = 'null' - try: call_this, method_name = call_name.rsplit(".", 1) - except ValueError: - # Must be a function call ... - return ("pyjs_kwargs_function_call("+call_name+", " - + star_arg_name - + ", ["+fn_args+"]" - + ")" ) - else: - return ("pyjs_kwargs_method_call("+call_this+", '"+method_name+"', " - + star_arg_name - + ", ["+fn_args+"]" - + ")") - else: - return call_name + "(" + ", ".join(call_args) + ")" - - def _print(self, node, current_klass): - if self.optimize: - return - call_args = [] - for ch4 in node.nodes: - arg = self.expr(ch4, current_klass) - call_args.append(arg) - - print >>self.output, "pyjslib.printFunc([", ', '.join(call_args), "],", int(isinstance(node, ast.Printnl)), ");" - - def _tryExcept(self, node, current_klass): - if len(node.handlers) != 1: - raise TranslationError("except statements in this form are" + - " not supported", node) - - expr = node.handlers[0][0] - as_ = node.handlers[0][1] - if as_: - errName = as_.name - else: - errName = 'err' - - # XXX TODO: check that this should instead be added as a _separate_ - # local scope, temporary to the function. oh dearie me. - self.add_local_arg(errName) - - print >>self.output, " try {" - for stmt in node.body.nodes: - self._stmt(stmt, current_klass) - print >> self.output, " } catch(%s) {" % errName - if expr: - l = [] - if isinstance(expr, ast.Tuple): - for x in expr.nodes: - l.append("(%(err)s.__name__ == %(expr)s.__name__)" % dict (err=errName, expr=self.expr(x, current_klass))) - else: - l = [ " (%(err)s.__name__ == %(expr)s.__name__) " % dict (err=errName, expr=self.expr(expr, current_klass)) ] - print >> self.output, " if(%s) {" % '||\n\t\t'.join(l) - for stmt in node.handlers[0][2]: - self._stmt(stmt, current_klass) - if expr: - #print >> self.output, "} else { throw(%s); } " % errName - print >> self.output, "}" - if node.else_ != None: - print >>self.output, " } finally {" - for stmt in node.else_: - self._stmt(stmt, current_klass) - print >>self.output, " }" - - # XXX: change use_getattr to True to enable "strict" compilation - # but incurring a 100% performance penalty. oops. - def _getattr(self, v, current_klass, use_getattr=False): - attr_name = v.attrname - if isinstance(v.expr, ast.Name): - obj = self._name(v.expr, current_klass, return_none_for_module=True) - if obj == None and v.expr.name in self.module_imports(): - # XXX TODO: distinguish between module import classes - # and variables. right now, this is a hack to get - # the sys module working. - #if v.expr.name == 'sys': - return v.expr.name+'.'+attr_name - #return v.expr.name+'.__'+attr_name+'.prototype.__class__' - if not use_getattr or attr_name == '__class__' or \ - attr_name == '__name__': - return obj + "." + attr_name - return "pyjslib.getattr(%s, '%s')" % (obj, attr_name) - elif isinstance(v.expr, ast.Getattr): - return self._getattr(v.expr, current_klass) + "." + attr_name - elif isinstance(v.expr, ast.Subscript): - return self._subscript(v.expr, self.modpfx()) + "." + attr_name - elif isinstance(v.expr, ast.CallFunc): - return self._callfunc(v.expr, self.modpfx()) + "." + attr_name - else: - raise TranslationError("unsupported type (in _getattr)", v.expr) - - - def modpfx(self): - return strip_py(self.module_prefix) - - def _name(self, v, current_klass, top_level=False, - return_none_for_module=False): - - if v.name == 'ilikesillynamesfornicedebugcode': - print top_level, current_klass, repr(v) - print self.top_level_vars - print self.top_level_functions - print self.local_arg_stack - print "error..." - - local_var_names = None - las = len(self.local_arg_stack) - if las > 0: - local_var_names = self.local_arg_stack[-1] - - if v.name == "True": - return "true" - elif v.name == "False": - return "false" - elif v.name == "None": - return "null" - elif v.name == '__name__' and current_klass is None: - return self.modpfx() + v.name - elif v.name == self.method_self: - return "this" - elif v.name in self.top_level_functions: - return UU+self.modpfx() + v.name - elif v.name in self.method_imported_globals: - return UU+self.modpfx() + v.name - elif not current_klass and las == 1 and v.name in self.top_level_vars: - return UU+self.modpfx() + v.name - elif v.name in local_var_names: - return v.name - elif self.imported_classes.has_key(v.name): - return UU+self.imported_classes[v.name] + '.__' + v.name + ".prototype.__class__" - elif v.name in self.top_level_classes: - return UU+self.modpfx() + "__" + v.name + ".prototype.__class__" - elif v.name in self.module_imports() and return_none_for_module: - return None - elif v.name in PYJSLIB_BUILTIN_CLASSES: - return "pyjslib." + pyjs_builtin_remap( v.name ) - elif current_klass: - if v.name not in local_var_names and \ - v.name not in self.top_level_vars and \ - v.name not in PYJS_GLOBAL_VARS and \ - v.name not in self.top_level_functions: - - cls_name = current_klass - if hasattr(cls_name, "name"): - cls_name_ = cls_name.name_ - cls_name = cls_name.name - else: - cls_name_ = current_klass + "_" # XXX ??? - name = UU+cls_name_ + ".prototype.__class__." \ - + v.name - if v.name == 'listener': - name = 'listener+' + name - return name - - return v.name - - def _name2(self, v, current_klass, attr_name): - obj = v.name - - if obj in self.method_imported_globals: - call_name = UU+self.modpfx() + obj + "." + attr_name - elif self.imported_classes.has_key(obj): - #attr_str = "" - #if attr_name != "__init__": - attr_str = ".prototype.__class__." + attr_name - call_name = UU+self.imported_classes[obj] + '.__' + obj + attr_str - elif obj in self.module_imports(): - call_name = obj + "." + attr_name - elif obj[0] == obj[0].upper(): # XXX HACK ALERT - call_name = UU + self.modpfx() + "__" + obj + ".prototype.__class__." + attr_name - else: - call_name = UU+self._name(v, current_klass) + "." + attr_name - - return call_name - - - def _getattr2(self, v, current_klass, attr_name): - if isinstance(v.expr, ast.Getattr): - call_name = self._getattr2(v.expr, current_klass, v.attrname + "." + attr_name) - elif isinstance(v.expr, ast.Name) and v.expr.name in self.module_imports(): - call_name = UU+v.expr.name + '.__' +v.attrname+".prototype.__class__."+attr_name - else: - obj = self.expr(v.expr, current_klass) - call_name = obj + "." + v.attrname + "." + attr_name - - return call_name - - - def _class(self, node): - """ - Handle a class definition. - - In order to translate python semantics reasonably well, the following - structure is used: - - A special object is created for the class, which inherits attributes - from the superclass, or Object if there's no superclass. This is the - class object; the object which you refer to when specifying the - class by name. Static, class, and unbound methods are copied - from the superclass object. - - A special constructor function is created with the same name as the - class, which is used to create instances of that class. - - A javascript class (e.g. a function with a prototype attribute) is - created which is the javascript class of created instances, and - which inherits attributes from the class object. Bound methods are - copied from the superclass into this class rather than inherited, - because the class object contains unbound, class, and static methods - that we don't necessarily want to inherit. - - The type of a method can now be determined by inspecting its - static_method, unbound_method, class_method, or instance_method - attribute; only one of these should be true. - - Much of this work is done in pyjs_extend, is pyjslib.py - """ - class_name = self.modpfx() + uuprefix(node.name, 1) - class_name_ = self.modpfx() + uuprefix(node.name) - current_klass = Klass(class_name, class_name_) - init_method = None - for child in node.code: - if isinstance(child, ast.Function): - current_klass.add_function(child.name) - if child.name == "__init__": - init_method = child - - - if len(node.bases) == 0: - base_class = "pyjslib.__Object" - elif len(node.bases) == 1: - if isinstance(node.bases[0], ast.Name): - if self.imported_classes.has_key(node.bases[0].name): - base_class_ = self.imported_classes[node.bases[0].name] + '.__' + node.bases[0].name - base_class = self.imported_classes[node.bases[0].name] + '.' + node.bases[0].name - else: - base_class_ = self.modpfx() + "__" + node.bases[0].name - base_class = self.modpfx() + node.bases[0].name - elif isinstance(node.bases[0], ast.Getattr): - # the bases are not in scope of the class so do not - # pass our class to self._name - base_class_ = self._name(node.bases[0].expr, None) + \ - ".__" + node.bases[0].attrname - base_class = self._name(node.bases[0].expr, None) + \ - "." + node.bases[0].attrname - else: - raise TranslationError("unsupported type (in _class)", node.bases[0]) - - current_klass.set_base(base_class) - else: - raise TranslationError("more than one base (in _class)", node) - - print >>self.output, UU+class_name_ + " = function () {" - # call superconstructor - #if base_class: - # print >>self.output, " __" + base_class + ".call(this);" - print >>self.output, "}" - - if not init_method: - init_method = ast.Function([], "__init__", ["self"], [], 0, None, []) - #self._method(init_method, current_klass, class_name) - - # Generate a function which constructs the object - clsfunc = ast.Function([], - node.name, - init_method.argnames[1:], - init_method.defaults, - init_method.flags, - None, - [ast.Discard(ast.CallFunc(ast.Name("JS"), [ast.Const( -# I attempted lazy initialization, but then you can't access static class members -# " if(!__"+base_class+".__was_initialized__)"+ -# " __" + class_name + "_initialize();\n" + - " var instance = new " + UU + class_name_ + "();\n" + - " if(instance.__init__) instance.__init__.apply(instance, arguments);\n" + - " return instance;" - )]))]) - - self._function(clsfunc, False) - print >>self.output, UU+class_name_ + ".__initialize__ = function () {" - print >>self.output, " if("+UU+class_name_+".__was_initialized__) return;" - print >>self.output, " "+UU+class_name_+".__was_initialized__ = true;" - cls_obj = UU+class_name_ + '.prototype.__class__' - - if class_name == "pyjslib.__Object": - print >>self.output, " "+cls_obj+" = {};" - else: - if base_class and base_class not in ("object", "pyjslib.__Object"): - print >>self.output, " if(!"+UU+base_class_+".__was_initialized__)" - print >>self.output, " "+UU+base_class_+".__initialize__();" - print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+base_class_+");" - else: - print >>self.output, " pyjs_extend(" + UU+class_name_ + ", "+UU+"pyjslib.__Object);" - - print >>self.output, " "+cls_obj+".__new__ = "+UU+class_name+";" - print >>self.output, " "+cls_obj+".__name__ = '"+UU+node.name+"';" - - for child in node.code: - if isinstance(child, ast.Pass): - pass - elif isinstance(child, ast.Function): - self._method(child, current_klass, class_name, class_name_) - elif isinstance(child, ast.Assign): - self.classattr(child, current_klass) - elif isinstance(child, ast.Discard) and isinstance(child.expr, ast.Const): - # Probably a docstring, turf it - pass - else: - raise TranslationError("unsupported type (in _class)", child) - print >>self.output, "}" - - print >> self.output, class_name_+".__initialize__();" - - - def classattr(self, node, current_klass): - self._assign(node, current_klass, True) - - def _raise(self, node, current_klass): - if node.expr2: - raise TranslationError("More than one expression unsupported", - node) - print >> self.output, "throw (%s);" % self.expr( - node.expr1, current_klass) - - def _method(self, node, current_klass, class_name, class_name_): - # reset global var scope - self.method_imported_globals = set() - - arg_names = list(node.argnames) - - classmethod = False - staticmethod = False - if node.decorators: - for d in node.decorators: - if d.name == "classmethod": - classmethod = True - elif d.name == "staticmethod": - staticmethod = True - - if staticmethod: - staticfunc = ast.Function([], class_name_+"."+node.name, node.argnames, node.defaults, node.flags, node.doc, node.code, node.lineno) - self._function(staticfunc, True) - print >>self.output, " " + UU+class_name_ + ".prototype.__class__." + node.name + " = " + class_name_+"."+node.name+";"; - print >>self.output, " " + UU+class_name_ + ".prototype.__class__." + node.name + ".static_method = true;"; - return - else: - if len(arg_names) == 0: - raise TranslationError("methods must take an argument 'self' (in _method)", node) - self.method_self = arg_names[0] - - #if not classmethod and arg_names[0] != "self": - # raise TranslationError("first arg not 'self' (in _method)", node) - - normal_arg_names = arg_names[1:] - if node.kwargs: kwargname = normal_arg_names.pop() - if node.varargs: varargname = normal_arg_names.pop() - declared_arg_names = list(normal_arg_names) - if node.kwargs: declared_arg_names.append(kwargname) - - function_args = "(" + ", ".join(declared_arg_names) + ")" - - if classmethod: - fexpr = UU + class_name_ + ".prototype.__class__." + node.name - else: - fexpr = UU + class_name_ + ".prototype." + node.name - print >>self.output, " "+fexpr + " = function" + function_args + " {" - - # default arguments - self._default_args_handler(node, normal_arg_names, current_klass) - - local_arg_names = normal_arg_names + declared_arg_names - - if node.varargs: - self._varargs_handler(node, varargname, declared_arg_names, current_klass) - local_arg_names.append(varargname) - - - # stack of local variable names for this function call - self.local_arg_stack.append(local_arg_names) - - for child in node.code: - self._stmt(child, current_klass) - - # remove the top local arg names - self.local_arg_stack.pop() - - print >>self.output, " };" - - self._kwargs_parser(node, fexpr, normal_arg_names, current_klass) - - if classmethod: - # Have to create a version on the instances which automatically passes the - # class as "self" - altexpr = UU + class_name_ + ".prototype." + node.name - print >>self.output, " "+altexpr + " = function() {" - print >>self.output, " return " + fexpr + ".apply(this.__class__, arguments);" - print >>self.output, " };" - print >>self.output, " "+fexpr+".class_method = true;" - print >>self.output, " "+altexpr+".instance_method = true;" - else: - # For instance methods, we need an unbound version in the class object - altexpr = UU + class_name_ + ".prototype.__class__." + node.name - print >>self.output, " "+altexpr + " = function() {" - print >>self.output, " return " + fexpr + ".call.apply("+fexpr+", arguments);" - print >>self.output, " };" - print >>self.output, " "+altexpr+".unbound_method = true;" - print >>self.output, " "+fexpr+".instance_method = true;" - print >>self.output, " "+altexpr+".__name__ = '%s';" % node.name - - print >>self.output, UU + class_name_ + ".prototype.%s.__name__ = '%s';" % \ - (node.name, node.name) - - if node.kwargs or len(node.defaults): - print >>self.output, " "+altexpr + ".parse_kwargs = " + fexpr + ".parse_kwargs;" - - self.method_self = None - self.method_imported_globals = set() - - def _isNativeFunc(self, node): - if isinstance(node, ast.Discard): - if isinstance(node.expr, ast.CallFunc): - if isinstance(node.expr.node, ast.Name) and \ - node.expr.node.name == NATIVE_JS_FUNC_NAME: - return True - return False - - def _stmt(self, node, current_klass): - debugStmt = self.debug and not self._isNativeFunc(node) - if debugStmt: - print >>self.output, ' try {' - - if isinstance(node, ast.Return): - self._return(node, current_klass) - elif isinstance(node, ast.Break): - self._break(node, current_klass) - elif isinstance(node, ast.Continue): - self._continue(node, current_klass) - elif isinstance(node, ast.Assign): - self._assign(node, current_klass) - elif isinstance(node, ast.AugAssign): - self._augassign(node, current_klass) - elif isinstance(node, ast.Discard): - self._discard(node, current_klass) - elif isinstance(node, ast.If): - self._if(node, current_klass) - elif isinstance(node, ast.For): - self._for(node, current_klass) - elif isinstance(node, ast.While): - self._while(node, current_klass) - elif isinstance(node, ast.Subscript): - self._subscript_stmt(node, current_klass) - elif isinstance(node, ast.Global): - self._global(node, current_klass) - elif isinstance(node, ast.Pass): - pass - elif isinstance(node, ast.Function): - self._function(node, True) - elif isinstance(node, ast.Printnl): - self._print(node, current_klass) - elif isinstance(node, ast.Print): - self._print(node, current_klass) - elif isinstance(node, ast.TryExcept): - self._tryExcept(node, current_klass) - elif isinstance(node, ast.Raise): - self._raise(node, current_klass) - else: - raise TranslationError("unsupported type (in _stmt)", node) - - if debugStmt: - - lt = self.get_line_trace(node) - - haltException = self.module_prefix + "HaltException" - isHaltFunction = self.module_prefix + "IsHaltException" - - print >>self.output, ' } catch (__err) {' - print >>self.output, ' if (' + isHaltFunction + '(__err.name)) {' - print >>self.output, ' throw __err;' - print >>self.output, ' } else {' - print >>self.output, " st = sys.printstack() + "\ - + '"%s"' % lt + "+ '\\n' ;" - print >>self.output, ' alert("' + "Error in " \ - + lt + '"' \ - + '+"\\n"+__err.name+": "+__err.message'\ - + '+"\\n\\nStack trace:\\n"' \ - + '+st' \ - + ');' - print >>self.output, ' debugger;' - - print >>self.output, ' throw new ' + self.module_prefix + "HaltException();" - print >>self.output, ' }' - print >>self.output, ' }' - - - def get_line_trace(self, node): - lineNum = "Unknown" - srcLine = "" - if hasattr(node, "lineno"): - if node.lineno != None: - lineNum = node.lineno - srcLine = self.src[min(lineNum, len(self.src))-1] - srcLine = srcLine.replace('\\', '\\\\') - srcLine = srcLine.replace('"', '\\"') - srcLine = srcLine.replace("'", "\\'") - - return self.raw_module_name + ".py, line " \ - + str(lineNum) + ":"\ - + "\\n" \ - + " " + srcLine - - def _augassign(self, node, current_klass): - v = node.node - if isinstance(v, ast.Getattr): - # XXX HACK! don't allow += on return result of getattr. - # TODO: create a temporary variable or something. - lhs = self._getattr(v, current_klass, False) - else: - lhs = self._name(node.node, current_klass) - op = node.op - rhs = self.expr(node.expr, current_klass) - print >>self.output, " " + lhs + " " + op + " " + rhs + ";" - - - def _assign(self, node, current_klass, top_level = False): - if len(node.nodes) != 1: - tempvar = '__temp'+str(node.lineno) - tnode = ast.Assign([ast.AssName(tempvar, "OP_ASSIGN", node.lineno)], node.expr, node.lineno) - self._assign(tnode, current_klass, top_level) - for v in node.nodes: - tnode2 = ast.Assign([v], ast.Name(tempvar, node.lineno), node.lineno) - self._assign(tnode2, current_klass, top_level) - return - - local_var_names = None - if len(self.local_arg_stack) > 0: - local_var_names = self.local_arg_stack[-1] - - def _lhsFromAttr(v, current_klass): - attr_name = v.attrname - if isinstance(v.expr, ast.Name): - obj = v.expr.name - lhs = self._name(v.expr, current_klass) + "." + attr_name - elif isinstance(v.expr, ast.Getattr): - lhs = self._getattr(v, current_klass) - elif isinstance(v.expr, ast.Subscript): - lhs = self._subscript(v.expr, current_klass) + "." + attr_name - else: - raise TranslationError("unsupported type (in _assign)", v.expr) - return lhs - - def _lhsFromName(v, top_level, current_klass): - if top_level: - if current_klass: - lhs = UU+current_klass.name_ + ".prototype.__class__." \ - + v.name - else: - self.top_level_vars.add(v.name) - vname = self.modpfx() + v.name - if not self.modpfx() and v.name not in\ - self.method_imported_globals: - lhs = "var " + vname - else: - lhs = UU + vname - self.add_local_arg(v.name) - else: - if v.name in local_var_names: - lhs = v.name - elif v.name in self.method_imported_globals: - lhs = self.modpfx() + v.name - else: - lhs = "var " + v.name - self.add_local_arg(v.name) - return lhs - - dbg = 0 - v = node.nodes[0] - if isinstance(v, ast.AssAttr): - lhs = _lhsFromAttr(v, current_klass) - if v.flags == "OP_ASSIGN": - op = "=" - else: - raise TranslationError("unsupported flag (in _assign)", v) - - elif isinstance(v, ast.AssName): - lhs = _lhsFromName(v, top_level, current_klass) - if v.flags == "OP_ASSIGN": - op = "=" - else: - raise TranslationError("unsupported flag (in _assign)", v) - elif isinstance(v, ast.Subscript): - if v.flags == "OP_ASSIGN": - obj = self.expr(v.expr, current_klass) - if len(v.subs) != 1: - raise TranslationError("must have one sub (in _assign)", v) - idx = self.expr(v.subs[0], current_klass) - value = self.expr(node.expr, current_klass) - print >>self.output, " " + obj + ".__setitem__(" + idx + ", " + value + ");" - return - else: - raise TranslationError("unsupported flag (in _assign)", v) - elif isinstance(v, (ast.AssList, ast.AssTuple)): - uniqueID = self.nextTupleAssignID - self.nextTupleAssignID += 1 - tempName = "__tupleassign" + str(uniqueID) + "__" - print >>self.output, " var " + tempName + " = " + \ - self.expr(node.expr, current_klass) + ";" - for index,child in enumerate(v.getChildNodes()): - rhs = tempName + ".__getitem__(" + str(index) + ")" - - if isinstance(child, ast.AssAttr): - lhs = _lhsFromAttr(child, current_klass) - elif isinstance(child, ast.AssName): - lhs = _lhsFromName(child, top_level, current_klass) - elif isinstance(child, ast.Subscript): - if child.flags == "OP_ASSIGN": - obj = self.expr(child.expr, current_klass) - if len(child.subs) != 1: - raise TranslationError("must have one sub " + - "(in _assign)", child) - idx = self.expr(child.subs[0], current_klass) - value = self.expr(node.expr, current_klass) - print >>self.output, " " + obj + ".__setitem__(" \ - + idx + ", " + rhs + ");" - continue - print >>self.output, " " + lhs + " = " + rhs + ";" - return - else: - raise TranslationError("unsupported type (in _assign)", v) - - rhs = self.expr(node.expr, current_klass) - if dbg: - print "b", repr(node.expr), rhs - print >>self.output, " " + lhs + " " + op + " " + rhs + ";" - - - def _discard(self, node, current_klass): - - if isinstance(node.expr, ast.CallFunc): - debugStmt = self.debug and not self._isNativeFunc(node) - if debugStmt and isinstance(node.expr.node, ast.Name) and \ - node.expr.node.name == 'import_wait': - debugStmt = False - if debugStmt: - st = self.get_line_trace(node) - print >>self.output, "sys.addstack('%s');\n" % st - if isinstance(node.expr.node, ast.Name) and node.expr.node.name == NATIVE_JS_FUNC_NAME: - if len(node.expr.args) != 1: - raise TranslationError("native javascript function %s must have one arg" % NATIVE_JS_FUNC_NAME, node.expr) - if not isinstance(node.expr.args[0], ast.Const): - raise TranslationError("native javascript function %s must have constant arg" % NATIVE_JS_FUNC_NAME, node.expr) - raw_js = node.expr.args[0].value - print >>self.output, raw_js - else: - expr = self._callfunc(node.expr, current_klass) - print >>self.output, " " + expr + ";" - - if debugStmt: - print >>self.output, "sys.popstack();\n" - - elif isinstance(node.expr, ast.Const): - if node.expr.value is not None: # Empty statements generate ignore None - print >>self.output, self._const(node.expr) - else: - raise TranslationError("unsupported type (in _discard)", node.expr) - - - def _if(self, node, current_klass): - for i in range(len(node.tests)): - test, consequence = node.tests[i] - if i == 0: - keyword = "if" - else: - keyword = "else if" - - self._if_test(keyword, test, consequence, current_klass) - - if node.else_: - keyword = "else" - test = None - consequence = node.else_ - - self._if_test(keyword, test, consequence, current_klass) - - - def _if_test(self, keyword, test, consequence, current_klass): - if test: - expr = self.expr(test, current_klass) - - print >>self.output, " " + keyword + " (pyjslib.bool(" + expr + ")) {" - else: - print >>self.output, " " + keyword + " {" - - if isinstance(consequence, ast.Stmt): - for child in consequence.nodes: - self._stmt(child, current_klass) - else: - raise TranslationError("unsupported type (in _if_test)", consequence) - - print >>self.output, " }" - - - def _from(self, node): - for name in node.names: - # look up "hack" in AppTranslator as to how findFile gets here - module_name = node.modname + "." + name[0] - try: - ff = self.findFile(module_name + ".py") - except Exception: - ff = None - if ff: - self.add_imported_module(module_name) - else: - self.imported_classes[name[0]] = node.modname - - - def _compare(self, node, current_klass): - lhs = self.expr(node.expr, current_klass) - - if len(node.ops) != 1: - raise TranslationError("only one ops supported (in _compare)", node) - - op = node.ops[0][0] - rhs_node = node.ops[0][1] - rhs = self.expr(rhs_node, current_klass) - - if op == "==": - return "pyjslib.eq(%s, %s)" % (lhs, rhs) - if op == "in": - return rhs + ".__contains__(" + lhs + ")" - elif op == "not in": - return "!" + rhs + ".__contains__(" + lhs + ")" - elif op == "is": - op = "===" - elif op == "is not": - op = "!==" - - return "(" + lhs + " " + op + " " + rhs + ")" - - - def _not(self, node, current_klass): - expr = self.expr(node.expr, current_klass) - - return "!(" + expr + ")" - - def _or(self, node, current_klass): - expr = "("+(") || (".join([self.expr(child, current_klass) for child in node.nodes]))+')' - return expr - - def _and(self, node, current_klass): - expr = "("+(") && (".join([self.expr(child, current_klass) for child in node.nodes]))+")" - return expr - - def _for(self, node, current_klass): - assign_name = "" - assign_tuple = "" - - # based on Bob Ippolito's Iteration in Javascript code - if isinstance(node.assign, ast.AssName): - assign_name = node.assign.name - self.add_local_arg(assign_name) - if node.assign.flags == "OP_ASSIGN": - op = "=" - elif isinstance(node.assign, ast.AssTuple): - op = "=" - i = 0 - for child in node.assign: - child_name = child.name - if assign_name == "": - assign_name = "temp_" + child_name - self.add_local_arg(child_name) - assign_tuple += """ - var %(child_name)s %(op)s %(assign_name)s.__getitem__(%(i)i); - """ % locals() - i += 1 - else: - raise TranslationError("unsupported type (in _for)", node.assign) - - if isinstance(node.list, ast.Name): - list_expr = self._name(node.list, current_klass) - elif isinstance(node.list, ast.Getattr): - list_expr = self._getattr(node.list, current_klass) - elif isinstance(node.list, ast.CallFunc): - list_expr = self._callfunc(node.list, current_klass) - else: - raise TranslationError("unsupported type (in _for)", node.list) - - lhs = "var " + assign_name - iterator_name = "__" + assign_name - - print >>self.output, """ - var %(iterator_name)s = %(list_expr)s.__iter__(); - try { - while (true) { - %(lhs)s %(op)s %(iterator_name)s.next(); - %(assign_tuple)s - """ % locals() - for node in node.body.nodes: - self._stmt(node, current_klass) - print >>self.output, """ - } - } catch (e) { - if (e.__name__ != pyjslib.StopIteration.__name__) { - throw e; - } - } - """ % locals() - - - def _while(self, node, current_klass): - test = self.expr(node.test, current_klass) - print >>self.output, " while (pyjslib.bool(" + test + ")) {" - if isinstance(node.body, ast.Stmt): - for child in node.body.nodes: - self._stmt(child, current_klass) - else: - raise TranslationError("unsupported type (in _while)", node.body) - print >>self.output, " }" - - - def _const(self, node): - if isinstance(node.value, int): - return str(node.value) - elif isinstance(node.value, float): - return str(node.value) - elif isinstance(node.value, basestring): - v = node.value - if isinstance(node.value, unicode): - v = v.encode('utf-8') - return "String('%s')" % escapejs(v) - elif node.value is None: - return "null" - else: - raise TranslationError("unsupported type (in _const)", node) - - def _unaryadd(self, node, current_klass): - return self.expr(node.expr, current_klass) - - def _unarysub(self, node, current_klass): - return "-" + self.expr(node.expr, current_klass) - - def _add(self, node, current_klass): - return self.expr(node.left, current_klass) + " + " + self.expr(node.right, current_klass) - - def _sub(self, node, current_klass): - return self.expr(node.left, current_klass) + " - " + self.expr(node.right, current_klass) - - def _div(self, node, current_klass): - return self.expr(node.left, current_klass) + " / " + self.expr(node.right, current_klass) - - def _mul(self, node, current_klass): - return self.expr(node.left, current_klass) + " * " + self.expr(node.right, current_klass) - - def _mod(self, node, current_klass): - if isinstance(node.left, ast.Const) and isinstance(node.left.value, StringType): - self.imported_js.add("sprintf.js") # Include the sprintf functionality if it is used - return "sprintf("+self.expr(node.left, current_klass) + ", " + self.expr(node.right, current_klass)+")" - return self.expr(node.left, current_klass) + " % " + self.expr(node.right, current_klass) - - def _invert(self, node, current_klass): - return "~" + self.expr(node.expr, current_klass) - - def _bitand(self, node, current_klass): - return " & ".join([self.expr(child, current_klass) for child in node.nodes]) - - def _bitshiftleft(self, node, current_klass): - return self.expr(node.left, current_klass) + " << " + self.expr(node.right, current_klass) - - def _bitshiftright(self, node, current_klass): - return self.expr(node.left, current_klass) + " >>> " + self.expr(node.right, current_klass) - - def _bitxor(self,node, current_klass): - return " ^ ".join([self.expr(child, current_klass) for child in node.nodes]) - - def _bitor(self, node, current_klass): - return " | ".join([self.expr(child, current_klass) for child in node.nodes]) - - def _subscript(self, node, current_klass): - if node.flags == "OP_APPLY": - if len(node.subs) == 1: - return self.expr(node.expr, current_klass) + ".__getitem__(" + self.expr(node.subs[0], current_klass) + ")" - else: - raise TranslationError("must have one sub (in _subscript)", node) - else: - raise TranslationError("unsupported flag (in _subscript)", node) - - def _subscript_stmt(self, node, current_klass): - if node.flags == "OP_DELETE": - print >>self.output, " " + self.expr(node.expr, current_klass) + ".__delitem__(" + self.expr(node.subs[0], current_klass) + ");" - else: - raise TranslationError("unsupported flag (in _subscript)", node) - - def _list(self, node, current_klass): - return "new pyjslib.List([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])" - - def _dict(self, node, current_klass): - items = [] - for x in node.items: - key = self.expr(x[0], current_klass) - value = self.expr(x[1], current_klass) - items.append("[" + key + ", " + value + "]") - return "new pyjslib.Dict([" + ", ".join(items) + "])" - - def _tuple(self, node, current_klass): - return "new pyjslib.Tuple([" + ", ".join([self.expr(x, current_klass) for x in node.nodes]) + "])" - - def _lambda(self, node, current_klass): - if node.varargs: - raise TranslationError("varargs are not supported in Lambdas", node) - if node.kwargs: - raise TranslationError("kwargs are not supported in Lambdas", node) - res = cStringIO.StringIO() - arg_names = list(node.argnames) - function_args = ", ".join(arg_names) - for child in node.getChildNodes(): - expr = self.expr(child, None) - print >> res, "function (%s){" % function_args - self._default_args_handler(node, arg_names, None, - output=res) - print >> res, 'return %s;}' % expr - return res.getvalue() - - def _slice(self, node, current_klass): - if node.flags == "OP_APPLY": - lower = "null" - upper = "null" - if node.lower != None: - lower = self.expr(node.lower, current_klass) - if node.upper != None: - upper = self.expr(node.upper, current_klass) - return "pyjslib.slice(" + self.expr(node.expr, current_klass) + ", " + lower + ", " + upper + ")" - else: - raise TranslationError("unsupported flag (in _slice)", node) - - def _global(self, node, current_klass): - for name in node.names: - self.method_imported_globals.add(name) - - def expr(self, node, current_klass): - if isinstance(node, ast.Const): - return self._const(node) - # @@@ not sure if the parentheses should be here or in individual operator functions - JKT - elif isinstance(node, ast.Mul): - return " ( " + self._mul(node, current_klass) + " ) " - elif isinstance(node, ast.Add): - return " ( " + self._add(node, current_klass) + " ) " - elif isinstance(node, ast.Sub): - return " ( " + self._sub(node, current_klass) + " ) " - elif isinstance(node, ast.Div): - return " ( " + self._div(node, current_klass) + " ) " - elif isinstance(node, ast.Mod): - return self._mod(node, current_klass) - elif isinstance(node, ast.UnaryAdd): - return self._unaryadd(node, current_klass) - elif isinstance(node, ast.UnarySub): - return self._unarysub(node, current_klass) - elif isinstance(node, ast.Not): - return self._not(node, current_klass) - elif isinstance(node, ast.Or): - return self._or(node, current_klass) - elif isinstance(node, ast.And): - return self._and(node, current_klass) - elif isinstance(node, ast.Invert): - return self._invert(node, current_klass) - elif isinstance(node, ast.Bitand): - return "("+self._bitand(node, current_klass)+")" - elif isinstance(node,ast.LeftShift): - return self._bitshiftleft(node, current_klass) - elif isinstance(node, ast.RightShift): - return self._bitshiftright(node, current_klass) - elif isinstance(node, ast.Bitxor): - return "("+self._bitxor(node, current_klass)+")" - elif isinstance(node, ast.Bitor): - return "("+self._bitor(node, current_klass)+")" - elif isinstance(node, ast.Compare): - return self._compare(node, current_klass) - elif isinstance(node, ast.CallFunc): - return self._callfunc(node, current_klass) - elif isinstance(node, ast.Name): - return self._name(node, current_klass) - elif isinstance(node, ast.Subscript): - return self._subscript(node, current_klass) - elif isinstance(node, ast.Getattr): - return self._getattr(node, current_klass) - elif isinstance(node, ast.List): - return self._list(node, current_klass) - elif isinstance(node, ast.Dict): - return self._dict(node, current_klass) - elif isinstance(node, ast.Tuple): - return self._tuple(node, current_klass) - elif isinstance(node, ast.Slice): - return self._slice(node, current_klass) - elif isinstance(node, ast.Lambda): - return self._lambda(node, current_klass) - else: - raise TranslationError("unsupported type (in expr)", node) - - - -import cStringIO - -def translate(file_name, module_name, debug=False): - f = file(file_name, "r") - src = f.read() - f.close() - output = cStringIO.StringIO() - mod = compiler.parseFile(file_name) - t = Translator(module_name, module_name, module_name, src, debug, mod, output) - return output.getvalue() - - -class PlatformParser: - def __init__(self, platform_dir = "", verbose=True): - self.platform_dir = platform_dir - self.parse_cache = {} - self.platform = "" - self.verbose = verbose - - def setPlatform(self, platform): - self.platform = platform - - def parseModule(self, module_name, file_name): - - importing = False - if not self.parse_cache.has_key(file_name): - importing = True - mod = compiler.parseFile(file_name) - self.parse_cache[file_name] = mod - else: - mod = self.parse_cache[file_name] - - override = False - platform_file_name = self.generatePlatformFilename(file_name) - if self.platform and os.path.isfile(platform_file_name): - mod = copy.deepcopy(mod) - mod_override = compiler.parseFile(platform_file_name) - self.merge(mod, mod_override) - override = True - - if self.verbose: - if override: - print "Importing %s (Platform %s)" % (module_name, self.platform) - elif importing: - print "Importing %s" % (module_name) - - return mod, override - - def generatePlatformFilename(self, file_name): - (module_name, extension) = os.path.splitext(os.path.basename(file_name)) - platform_file_name = module_name + self.platform + extension - - return os.path.join(os.path.dirname(file_name), self.platform_dir, platform_file_name) - - def merge(self, tree1, tree2): - for child in tree2.node: - if isinstance(child, ast.Function): - self.replaceFunction(tree1, child.name, child) - elif isinstance(child, ast.Class): - self.replaceClassMethods(tree1, child.name, child) - - return tree1 - - def replaceFunction(self, tree, function_name, function_node): - # find function to replace - for child in tree.node: - if isinstance(child, ast.Function) and child.name == function_name: - self.copyFunction(child, function_node) - return - raise TranslationError("function not found: " + function_name, function_node) - - def replaceClassMethods(self, tree, class_name, class_node): - # find class to replace - old_class_node = None - for child in tree.node: - if isinstance(child, ast.Class) and child.name == class_name: - old_class_node = child - break - - if not old_class_node: - raise TranslationError("class not found: " + class_name, class_node) - - # replace methods - for function_node in class_node.code: - if isinstance(function_node, ast.Function): - found = False - for child in old_class_node.code: - if isinstance(child, ast.Function) and child.name == function_node.name: - found = True - self.copyFunction(child, function_node) - break - - if not found: - raise TranslationError("class method not found: " + class_name + "." + function_node.name, function_node) - - def copyFunction(self, target, source): - target.code = source.code - target.argnames = source.argnames - target.defaults = source.defaults - target.doc = source.doc # @@@ not sure we need to do this any more - -def dotreplace(fname): - path, ext = os.path.splitext(fname) - return path.replace(".", "/") + ext - -class AppTranslator: - - def __init__(self, library_dirs=[], parser=None, dynamic=False, - optimize=False, verbose=True): - self.extension = ".py" - self.optimize = optimize - self.library_modules = [] - self.overrides = {} - self.library_dirs = path + library_dirs - self.dynamic = dynamic - self.verbose = verbose - - if not parser: - self.parser = PlatformParser() - else: - self.parser = parser - - self.parser.dynamic = dynamic - - def findFile(self, file_name): - if os.path.isfile(file_name): - return file_name - - for library_dir in self.library_dirs: - file_name = dotreplace(file_name) - full_file_name = os.path.join( - os.path.abspath(os.path.dirname(__file__)), library_dir, file_name) - if os.path.isfile(full_file_name): - return full_file_name - - fnameinit, ext = os.path.splitext(file_name) - fnameinit = fnameinit + "/__init__.py" - - full_file_name = os.path.join( - os.path.abspath(os.path.dirname(__file__)), library_dir, fnameinit) - if os.path.isfile(full_file_name): - return full_file_name - - raise Exception("file not found: " + file_name) - - def _translate(self, module_name, is_app=True, debug=False, - imported_js=set()): - if module_name not in self.library_modules: - self.library_modules.append(module_name) - - file_name = self.findFile(module_name + self.extension) - - output = cStringIO.StringIO() - - f = file(file_name, "r") - src = f.read() - f.close() - - mod, override = self.parser.parseModule(module_name, file_name) - if override: - override_name = "%s.%s" % (self.parser.platform.lower(), - module_name) - self.overrides[override_name] = override_name - if is_app: - mn = '__main__' - else: - mn = module_name - t = Translator(mn, module_name, module_name, - src, debug, mod, output, self.dynamic, self.optimize, - self.findFile) - - module_str = output.getvalue() - imported_js.update(set(t.imported_js)) - imported_modules_str = "" - for module in t.imported_modules: - if module not in self.library_modules: - self.library_modules.append(module) - #imported_js.update(set(t.imported_js)) - #imported_modules_str += self._translate( - # module, False, debug=debug, imported_js=imported_js) - - return imported_modules_str + module_str - - - def translate(self, module_name, is_app=True, debug=False, - library_modules=[]): - app_code = cStringIO.StringIO() - lib_code = cStringIO.StringIO() - imported_js = set() - self.library_modules = [] - self.overrides = {} - for library in library_modules: - if library.endswith(".js"): - imported_js.add(library) - continue - self.library_modules.append(library) - if self.verbose: - print 'Including LIB', library - print >> lib_code, '\n//\n// BEGIN LIB '+library+'\n//\n' - print >> lib_code, self._translate( - library, False, debug=debug, imported_js=imported_js) - - print >> lib_code, "/* initialize static library */" - print >> lib_code, "%s%s();\n" % (UU, library) - - print >> lib_code, '\n//\n// END LIB '+library+'\n//\n' - if module_name: - print >> app_code, self._translate( - module_name, is_app, debug=debug, imported_js=imported_js) - for js in imported_js: - path = self.findFile(js) - if os.path.isfile(path): - if self.verbose: - print 'Including JS', js - print >> lib_code, '\n//\n// BEGIN JS '+js+'\n//\n' - print >> lib_code, file(path).read() - print >> lib_code, '\n//\n// END JS '+js+'\n//\n' - else: - print >>sys.stderr, 'Warning: Unable to find imported javascript:', js - return lib_code.getvalue(), app_code.getvalue() - -usage = """ - usage: %s file_name [module_name] -""" - -def main(): - import sys - if len(sys.argv)<2: - print >> sys.stderr, usage % sys.argv[0] - sys.exit(1) - file_name = os.path.abspath(sys.argv[1]) - if not os.path.isfile(file_name): - print >> sys.stderr, "File not found %s" % file_name - sys.exit(1) - if len(sys.argv) > 2: - module_name = sys.argv[2] - else: - module_name = None - print translate(file_name, module_name), - -if __name__ == "__main__": - main() - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/svgui.py --- a/plugins/python/modules/svgui/svgui.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -import wx -import os, sys, shutil - -from plugger import opjimg -from plugins.python import PythonCodeTemplate - -from pyjs import translate - -from docutils import * - -class RootClass: - - PluginMethods = [ - {"bitmap" : os.path.join("images","ImportSVG"), - "name" : _("Import SVG"), - "tooltip" : _("Import SVG"), - "method" : "_ImportSVG"}, - {"bitmap" : os.path.join("images","ImportSVG"), - "name" : _("Inkscape"), - "tooltip" : _("Create HMI"), - "method" : "_StartInkscape"}, - ] - - def PluginPath(self): - return os.path.join(self.PlugParent.PluginPath(), "modules", self.PlugType) - - def _getSVGpath(self): - # define name for IEC raw code file - return os.path.join(self.PlugPath(), "gui.svg") - - def _getSVGUIserverpath(self): - return os.path.join(os.path.dirname(__file__), "svgui_server.py") - - def PlugGenerate_C(self, buildpath, locations): - """ - Return C code generated by iec2c compiler - when _generate_softPLC have been called - @param locations: ignored - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - res = ([], "", False) - - svgfile=self._getSVGpath() - if os.path.exists(svgfile): - res += (("gui.svg", file(svgfile,"rb")),) - - svguiserverfile = open(self._getSVGUIserverpath(), 'r') - svguiservercode = svguiserverfile.read() - svguiserverfile.close() - - svguilibpath = os.path.join(self._getBuildPath(), "svguilib.js") - svguilibfile = open(svguilibpath, 'w') - svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "sys.py"), "sys")) - svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "_pyjs.js"), 'r').read()) - svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "pyjslib.py"), "pyjslib")) - svguilibfile.write(translate(os.path.join(os.path.dirname(__file__), "svguilib.py"), "svguilib")) - svguilibfile.write("pyjslib();\nsvguilib();\n") - svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "pyjs", "lib", "json.js"), 'r').read()) - svguilibfile.write(open(os.path.join(os.path.dirname(__file__), "livesvg.js"), 'r').read()) - svguilibfile.close() - jsmodules = {"LiveSVGPage": "svguilib.js"} - res += (("svguilib.js", file(svguilibpath,"rb")),) - - runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) - runtimefile = open(runtimefile_path, 'w') - runtimefile.write(svguiservercode % {"svgfile" : "gui.svg"}) - runtimefile.write(""" -def _runtime_%(location)s_begin(): - website.LoadHMI(%(svgui_class)s, %(jsmodules)s) - -def _runtime_%(location)s_cleanup(): - website.UnLoadHMI() - -""" % {"location": location_str, - "svgui_class": "SVGUI_HMI", - "jsmodules" : str(jsmodules), - }) - runtimefile.close() - - res += (("runtime_%s.py"%location_str, file(runtimefile_path,"rb")),) - - return res - - def _ImportSVG(self): - dialog = wx.FileDialog(self.GetPlugRoot().AppFrame, _("Choose a SVG file"), os.getcwd(), "", _("SVG files (*.svg)|*.svg|All files|*.*"), wx.OPEN) - if dialog.ShowModal() == wx.ID_OK: - svgpath = dialog.GetPath() - if os.path.isfile(svgpath): - shutil.copy(svgpath, self._getSVGpath()) - else: - self.GetPlugRoot().logger.write_error(_("No such SVG file: %s\n")%svgpath) - dialog.Destroy() - - def _StartInkscape(self): - svgfile = self._getSVGpath() - open_inkscape = True - if not self.GetPlugRoot().CheckProjectPathPerm(): - dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, - _("You don't have write permissions.\nOpen Inkscape anyway ?"), - _("Open Inkscape"), - wx.YES_NO|wx.ICON_QUESTION) - open_inkscape = dialog.ShowModal() == wx.ID_YES - dialog.Destroy() - if open_inkscape: - if not os.path.isfile(svgfile): - svgfile = None - open_svg(svgfile) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/svgui_server.py --- a/plugins/python/modules/svgui/svgui_server.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -import os - -from nevow import rend, appserver, inevow, tags, loaders, athena -import simplejson as json - -svgfile = '%(svgfile)s' - -svguiWidgets = {} - -currentId = 0 -def getNewId(): - global currentId - currentId += 1 - return currentId - -class SvguiWidget: - - def __init__(self, classname, id, **kwargs): - self.classname = classname - self.id = id - self.attrs = kwargs.copy() - self.inputs = {} - self.outputs = {} - self.inhibit = False - self.changed = False - - def setinput(self, attrname, value): - self.inputs[attrname] = value - - def getinput(self, attrname, default=None): - if not self.inputs.has_key(attrname): - self.inputs[attrname] = default - return self.inputs[attrname] - - def setoutput(self, attrname, value): - if self.outputs.get(attrname) != value: - self.outputs[attrname] = value - self.changed = True - self.RefreshInterface() - - def updateoutputs(self, **kwargs): - for attrname, value in kwargs.iteritems(): - if self.outputs.get(attrname) != value: - self.outputs[attrname] = value - self.changed = True - self.RefreshInterface() - - def RefreshInterface(self): - interface = website.getHMI() - if isinstance(interface, SVGUI_HMI) and self.changed and not self.inhibit: - self.changed = False - d = interface.sendData(self) - if d is not None: - self.inhibit = True - d.addCallback(self.InterfaceRefreshed) - - def InterfaceRefreshed(self, result): - self.inhibit = False - if self.changed: - self.RefreshInterface() - -def get_object_init_state(obj): - # Convert objects to a dictionary of their representation - attrs = obj.attrs.copy() - attrs.update(obj.inputs) - d = { '__class__': obj.classname, - 'id': obj.id, - 'kwargs': json.dumps(attrs), - } - return d - -def get_object_current_state(obj): - # Convert objects to a dictionary of their representation - d = { '__class__': obj.classname, - 'id': obj.id, - 'kwargs': json.dumps(obj.outputs), - } - return d - -class SVGUI_HMI(website.PLCHMI): - jsClass = u"LiveSVGPage.LiveSVGWidget" - - docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ - tags.xml(loaders.xmlfile(os.path.join(WorkingDir, svgfile))), - ]) - - def HMIinitialisation(self): - gadgets = [] - for gadget in svguiWidgets.values(): - gadgets.append(unicode(json.dumps(gadget, default=get_object_init_state, indent=2), 'ascii')) - d = self.callRemote('init', gadgets) - d.addCallback(self.HMIinitialised) - - def sendData(self,data): - if self.initialised: - return self.callRemote('receiveData',unicode(json.dumps(data, default=get_object_current_state, indent=2), 'ascii')) - return None - - def setattr(self, id, attrname, value): - svguiWidgets[id].setinput(attrname, value) - -def createSVGUIControl(*args, **kwargs): - id = getNewId() - gad = SvguiWidget(args[0], id, **kwargs) - svguiWidgets[id] = gad - gadget = [unicode(json.dumps(gad, default=get_object_init_state, indent=2), 'ascii')] - interface = website.getHMI() - if isinstance(interface, SVGUI_HMI) and interface.initialised: - interface.callRemote('init', gadget) - return id - -def setAttr(id, attrname, value): - gad = svguiWidgets.get(id, None) - if gad is not None: - gad.setoutput(attrname, value) - -def updateAttr(id, **kwargs): - gad = svguiWidgets.get(id, None) - if gad is not None: - gad.updateoutput(**kwargs) - -def getAttr(id, attrname, default=None): - gad = svguiWidgets.get(id, None) - if gad is not None: - return gad.getinput(attrname, default) - return default - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/svgui/svguilib.py --- a/plugins/python/modules/svgui/svguilib.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ - -class button: - - def __init__(self, parent, id, args): - self.parent = parent - self.id = id - self.back_elt = getSVGElementById(args.back_id) - self.sele_elt = getSVGElementById(args.sele_id) - self.toggle = args.toggle - self.active = args.active - if args.state != undefined: - self.state = args.state - else: - self.state = False - self.dragging = False - if self.toggle: - self.up = not self.state - else: - self.up = True - - # Add event on each element of the button - if self.active: - self.back_elt.addEventListener("mouseup", self, False) - self.back_elt.addEventListener("mousedown", self, False) - self.back_elt.addEventListener("mouseover", self, False) - self.back_elt.addEventListener("mouseout", self, False) - - self.sele_elt.addEventListener("mouseup", self, False) - self.sele_elt.addEventListener("mousedown", self, False) - self.sele_elt.addEventListener("mouseover", self, False) - self.sele_elt.addEventListener("mouseout", self, False) - - blockSVGElementDrag(self.back_elt) - blockSVGElementDrag(self.sele_elt) - - self.updateElements() - - # method to display the current state of interface - def updateElements(self): - if self.up: - self.sele_elt.setAttribute("display", "none") - self.back_elt.removeAttribute("display") - else: - self.sele_elt.removeAttribute("display") - self.back_elt.setAttribute("display", "none") - - def updateValues(self, values): - if values.state != self.state: - self.state = values.state - self.up = not self.state - updateAttr(self.id, 'state', self.state) - self.updateElements() - - def handleEvent(self, evt): - # Quand le bouton de la souris est presse - if evt.type == "mousedown": - evt.stopPropagation() - setCurrentObject(self) - - self.dragging = True - - if self.toggle: - self.up = self.state - else: - self.up = False - self.state = True - updateAttr(self.id, 'state', self.state) - self.updateElements() - - if isCurrentObject(self) and self.dragging: - # Quand le bouton est survole - if evt.type == "mouseover" and self.toggle: - self.up = self.state - self.updateElements() - - # Quand le curseur quitte la zone du bouton - elif evt.type == "mouseout" and self.toggle: - self.up = not self.state - self.updateElements() - - # Quand le bouton de la souris est relache - elif evt.type == "mouseup": - evt.stopPropagation() - if self.toggle and self.up == self.state: - self.state = not self.state - updateAttr(self.id, 'state', self.state) - elif not self.toggle: - self.up = True - self.state = False - updateAttr(self.id, 'state', self.state) - self.updateElements() - self.dragging = False - -class textControl: - - def __init__(self, parent, id, args): - self.parent = parent - self.id = id - self.back_elt = getSVGElementById(args.back_id) - if args.text != undefined: - self.text = args.text - else: - self.text = "" - self.updateElements() - - def updateValues(self, values): - if values.text != self.value: - self.text = values.text - updateAttr(self.id, 'text', self.text) - self.updateElements() - - def updateElements(self): - self.back_elt.firstChild.firstChild.textContent = self.text - - def handleEvent(self, evt): - pass - \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/wxglade_hmi/README --- a/plugins/python/modules/wxglade_hmi/README Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -WxGlade HMI \ No newline at end of file diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/wxglade_hmi/__init__.py --- a/plugins/python/modules/wxglade_hmi/__init__.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -from wxglade_hmi import * diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/modules/wxglade_hmi/wxglade_hmi.py --- a/plugins/python/modules/wxglade_hmi/wxglade_hmi.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -import wx -import os, sys -from xml.dom import minidom - -from plugger import opjimg -from plugins.python import PythonCodeTemplate - -class RootClass(PythonCodeTemplate): - - PluginMethods = [ - {"bitmap" : opjimg("editWXGLADE"), - "name" : _("WXGLADE GUI"), - "tooltip" : _("Edit a WxWidgets GUI with WXGlade"), - "method" : "_editWXGLADE"}, - ] - - def _getWXGLADEpath(self): - # define name for IEC raw code file - return os.path.join(self.PlugPath(), "hmi.wxg") - - def launch_wxglade(self, options, wait=False): - from wxglade import __file__ as fileName - path = os.path.dirname(fileName) - glade = os.path.join(path, 'wxglade.py') - if wx.Platform == '__WXMSW__': - glade = "\"%s\""%glade - mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] - os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options) - - - def PlugGenerate_C(self, buildpath, locations): - """ - Return C code generated by iec2c compiler - when _generate_softPLC have been called - @param locations: ignored - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) - runtimefile = open(runtimefile_path, 'w') - - hmi_frames = {} - - wxgfile_path=self._getWXGLADEpath() - if os.path.exists(wxgfile_path): - wxgfile = open(wxgfile_path, 'r') - wxgtree = minidom.parse(wxgfile) - wxgfile.close() - - for node in wxgtree.childNodes[1].childNodes: - if node.nodeType == wxgtree.ELEMENT_NODE: - hmi_frames[node._attrs["name"].value] = node._attrs["class"].value - - hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py") - if wx.Platform == '__WXMSW__': - wxgfile_path = "\"%s\""%wxgfile_path - wxghmipyfile_path = "\"%s\""%hmipyfile_path - else: - wxghmipyfile_path = hmipyfile_path - self.launch_wxglade(['-o', wxghmipyfile_path, '-g', 'python', wxgfile_path], wait=True) - - hmipyfile = open(hmipyfile_path, 'r') - runtimefile.write(hmipyfile.read()) - hmipyfile.close() - - runtimefile.write(self.GetPythonCode()) - runtimefile.write(""" -%(declare)s - -def _runtime_%(location)s_begin(): - global %(global)s - - def OnCloseFrame(evt): - wx.MessageBox(_("Please stop PLC to close")) - - %(init)s - -def _runtime_%(location)s_cleanup(): - global %(global)s - - %(cleanup)s - -""" % {"location": location_str, - "declare": "\n".join(map(lambda x:"%s = None" % x, hmi_frames.keys())), - "global": ",".join(hmi_frames.keys()), - "init": "\n".join(map(lambda x: """ - %(name)s = %(class)s(None) - %(name)s.Bind(wx.EVT_CLOSE, OnCloseFrame) - %(name)s.Show() -""" % {"name": x[0], "class": x[1]}, - hmi_frames.items())), - "cleanup": "\n ".join(map(lambda x:"%s.Destroy()" % x, hmi_frames.keys()))}) - runtimefile.close() - - return [], "", False, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) - - def _editWXGLADE(self): - wxg_filename = self._getWXGLADEpath() - open_wxglade = True - if not self.GetPlugRoot().CheckProjectPathPerm(): - dialog = wx.MessageDialog(self.GetPlugRoot().AppFrame, - _("You don't have write permissions.\nOpen wxGlade anyway ?"), - _("Open wxGlade"), - wx.YES_NO|wx.ICON_QUESTION) - open_wxglade = dialog.ShowModal() == wx.ID_YES - dialog.Destroy() - if open_wxglade: - if not os.path.exists(wxg_filename): - hmi_name = self.BaseParams.getName() - open(wxg_filename,"w").write(""" - - - - frame_1 - - - """ % {"name": hmi_name, "class": "Class_%s" % hmi_name}) - if wx.Platform == '__WXMSW__': - wxg_filename = "\"%s\""%wxg_filename - self.launch_wxglade([wxg_filename]) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/plc_python.c --- a/plugins/python/plc_python.c Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -/* - * Python Asynchronous execution code - * - * PLC put python commands in a fifo, respecting execution order - * with the help of C pragmas inserted in python_eval FB code - * - * Buffer content is read asynchronously, (from non real time part), - * commands are executed and result stored for later use by PLC. - * - * In this implementation, fifo is a list of pointer to python_eval - * function blocks structures. Some local variables have been added in - * python_eval interface. We use those local variables as buffer and state - * flags. - * - * */ - -#include "iec_types_all.h" -#include "POUS.h" -#include - -/* The fifo (fixed size, as number of FB is fixed) */ -static PYTHON_EVAL* EvalFBs[%(python_eval_fb_count)d]; -/* Producer and consumer cursors */ -static int Current_PLC_EvalFB; -static int Current_Python_EvalFB; - -/* A global IEC-Python gateway state, for use inside python_eval FBs*/ -static int PythonState; -#define PYTHON_LOCKED_BY_PYTHON 0 -#define PYTHON_LOCKED_BY_PLC 1 -#define PYTHON_MUSTWAKEUP 2 -#define PYTHON_FINISHED 4 - -/* Each python_eval FunctionBlock have it own state */ -#define PYTHON_FB_FREE 0 -#define PYTHON_FB_REQUESTED 1 -#define PYTHON_FB_PROCESSING 2 -#define PYTHON_FB_ANSWERED 3 - -int WaitPythonCommands(void); -void UnBlockPythonCommands(void); -int TryLockPython(void); -void UnLockPython(void); -void LockPython(void); - -int __init_%(location)s() -{ - int i; - /* Initialize cursors */ - Current_Python_EvalFB = 0; - Current_PLC_EvalFB = 0; - PythonState = PYTHON_LOCKED_BY_PYTHON; - for(i = 0; i < %(python_eval_fb_count)d; i++) - EvalFBs[i] = NULL; - return 0; -} - -void __cleanup_%(location)s() -{ - PythonState = PYTHON_FINISHED; - UnBlockPythonCommands(); -} - -void __retrieve_%(location)s() -{ - /* Check Python thread is not being - * modifying internal python_eval data */ - PythonState = TryLockPython() ? - PYTHON_LOCKED_BY_PLC : - PYTHON_LOCKED_BY_PYTHON; - /* If python thread _is_ in, then PythonState remains PYTHON_LOCKED_BY_PYTHON - * and python_eval will no do anything */ -} - -void __publish_%(location)s() -{ - if(PythonState & PYTHON_LOCKED_BY_PLC){ - /* If runnig PLC did push something in the fifo*/ - if(PythonState & PYTHON_MUSTWAKEUP){ - /* WakeUp python thread */ - UnBlockPythonCommands(); - } - UnLockPython(); - } -} -/** - * Called by the PLC, each time a python_eval - * FB instance is executed - */ -void __PythonEvalFB(int poll, PYTHON_EVAL* data__) -{ - /* detect rising edge on TRIG to trigger evaluation */ - if(((__GET_VAR(data__->TRIG) && !__GET_VAR(data__->TRIGM1)) || - /* polling is equivalent to trig on value rather than on rising edge*/ - (poll && __GET_VAR(data__->TRIG) )) && - /* trig only if not already trigged */ - __GET_VAR(data__->TRIGGED) == 0){ - /* mark as trigged */ - __SET_VAR(data__->, TRIGGED, 1); - /* make a safe copy of the code */ - __SET_VAR(data__->, PREBUFFER, __GET_VAR(data__->CODE)); - } - /* retain value for next rising edge detection */ - __SET_VAR(data__->, TRIGM1, __GET_VAR(data__->TRIG)); - - /* python thread is not in ? */ - if( PythonState & PYTHON_LOCKED_BY_PLC){ - /* if some answer are waiting, publish*/ - if(__GET_VAR(data__->STATE) == PYTHON_FB_ANSWERED){ - /* Copy buffer content into result*/ - __SET_VAR(data__->, RESULT, __GET_VAR(data__->BUFFER)); - /* signal result presece to PLC*/ - __SET_VAR(data__->, ACK, 1); - /* Mark as free */ - __SET_VAR(data__->, STATE, PYTHON_FB_FREE); - /* mark as not trigged */ - if(!poll) - __SET_VAR(data__->, TRIGGED, 0); - /*printf("__PythonEvalFB pop %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ - }else if(poll){ - /* when in polling, no answer == ack down */ - __SET_VAR(data__->, ACK, 0); - } - /* got the order to act ?*/ - if(__GET_VAR(data__->TRIGGED) == 1 && - /* and not already being processed */ - __GET_VAR(data__->STATE) == PYTHON_FB_FREE) - { - /* Enter the block in the fifo - * Don't have to check if fifo cell is free - * as fifo size == FB count, and a FB cannot - * be requested twice */ - EvalFBs[Current_PLC_EvalFB] = data__; - /* copy into BUFFER local*/ - __SET_VAR(data__->, BUFFER, __GET_VAR(data__->PREBUFFER)); - /* Set ACK pin to low so that we can set a rising edge on result */ - if(!poll){ - /* when not polling, a new answer imply reseting ack*/ - __SET_VAR(data__->, ACK, 0); - }else{ - /* when in polling, acting reset trigger */ - __SET_VAR(data__->, TRIGGED, 0); - } - /* Mark FB busy */ - __SET_VAR(data__->, STATE, PYTHON_FB_REQUESTED); - /* Have to wakeup python thread in case he was asleep */ - PythonState |= PYTHON_MUSTWAKEUP; - /*printf("__PythonEvalFB push %%d - %%*s\n",Current_PLC_EvalFB, data__->BUFFER.len, data__->BUFFER.body);*/ - /* Get a new line */ - Current_PLC_EvalFB = (Current_PLC_EvalFB + 1) %% %(python_eval_fb_count)d; - } - } -} - -char* PythonIterator(char* result) -{ - char* next_command; - PYTHON_EVAL* data__; - //printf("PythonIterator result %%s\n", result); - /*emergency exit*/ - if(PythonState & PYTHON_FINISHED) return NULL; - /* take python mutex to prevent changing PLC data while PLC running */ - LockPython(); - /* Get current FB */ - data__ = EvalFBs[Current_Python_EvalFB]; - if(data__ && /* may be null at first run */ - __GET_VAR(data__->STATE) == PYTHON_FB_PROCESSING){ /* some answer awaited*/ - /* If result not None */ - if(result){ - /* Get results len */ - __SET_VAR(data__->, BUFFER, strlen(result), .len); - /* prevent results overrun */ - if(__GET_VAR(data__->BUFFER, .len) > STR_MAX_LEN) - { - __SET_VAR(data__->, BUFFER, STR_MAX_LEN, .len ); - /* TODO : signal error */ - } - /* Copy results to buffer */ - strncpy((char*)__GET_VAR(data__->BUFFER, .body), result, __GET_VAR(data__->BUFFER,.len)); - }else{ - __SET_VAR(data__->, BUFFER, 0, .len); - } - /* remove block from fifo*/ - EvalFBs[Current_Python_EvalFB] = NULL; - /* Mark block as answered */ - __SET_VAR(data__->, STATE, PYTHON_FB_ANSWERED); - /* Get a new line */ - Current_Python_EvalFB = (Current_Python_EvalFB + 1) %% %(python_eval_fb_count)d; - //printf("PythonIterator ++ Current_Python_EvalFB %%d\n", Current_Python_EvalFB); - } - /* while next slot is empty */ - while(((data__ = EvalFBs[Current_Python_EvalFB]) == NULL) || - /* or doesn't contain command */ - __GET_VAR(data__->STATE) != PYTHON_FB_REQUESTED) - { - UnLockPython(); - /* wait next FB to eval */ - //printf("PythonIterator wait\n"); - if(WaitPythonCommands()) return NULL; - /*emergency exit*/ - if(PythonState & PYTHON_FINISHED) return NULL; - LockPython(); - } - /* Mark block as processing */ - __SET_VAR(data__->, STATE, PYTHON_FB_PROCESSING); - //printf("PythonIterator\n"); - /* make BUFFER a null terminated string */ - __SET_VAR(data__->, BUFFER, 0, .body[__GET_VAR(data__->BUFFER, .len)]); - /* next command is BUFFER */ - next_command = (char*)__GET_VAR(data__->BUFFER, .body); - /* free python mutex */ - UnLockPython(); - /* return the next command to eval */ - return next_command; -} - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/pous.xml --- a/plugins/python/pous.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,457 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - N - - - - - - - TRIG - - - - - - - CODE - - - - - - - - - - - ACK - - - - - - - - - - - RESULT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - COUNTER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USINT#1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - USINT#0 - - - - - - - - - - - COUNTER - - - - - - - - - - diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/python.py --- a/plugins/python/python.py Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -import wx -import os -import modules -from plugger import PlugTemplate, opjimg -from PLCControler import UndoBuffer -from PythonEditor import PythonEditor - -from xml.dom import minidom -from xmlclass import * -import cPickle - -PythonClasses = GenerateClassesFromXSD(os.path.join(os.path.dirname(__file__), "python_xsd.xsd")) - -class PythonCodeTemplate: - - EditorType = PythonEditor - - def __init__(self): - - self.PluginMethods.insert(0, - {"bitmap" : opjimg("editPYTHONcode"), - "name" : _("Edit Python File"), - "tooltip" : _("Edit Python File"), - "method" : "_OpenView"}, - ) - - filepath = self.PythonFileName() - - self.PythonCode = PythonClasses["Python"]() - if os.path.isfile(filepath): - xmlfile = open(filepath, 'r') - tree = minidom.parse(xmlfile) - xmlfile.close() - - for child in tree.childNodes: - if child.nodeType == tree.ELEMENT_NODE and child.nodeName == "Python": - self.PythonCode.loadXMLTree(child, ["xmlns", "xmlns:xsi", "xsi:schemaLocation"]) - self.CreatePythonBuffer(True) - else: - self.CreatePythonBuffer(False) - self.OnPlugSave() - - def PluginPath(self): - return os.path.join(self.PlugParent.PluginPath(), "modules", self.PlugType) - - def PythonFileName(self): - return os.path.join(self.PlugPath(), "python.xml") - - def GetFilename(self): - if self.PythonBuffer.IsCurrentSaved(): - return "python" - else: - return "~python~" - - def SetPythonCode(self, text): - self.PythonCode.settext(text) - - def GetPythonCode(self): - return self.PythonCode.gettext() - - def PlugTestModified(self): - return self.ChangesToSave or not self.PythonIsSaved() - - def OnPlugSave(self): - filepath = self.PythonFileName() - - text = "\n" - extras = {"xmlns":"http://www.w3.org/2001/XMLSchema", - "xmlns:xsi":"http://www.w3.org/2001/XMLSchema-instance", - "xsi:schemaLocation" : "python_xsd.xsd"} - text += self.PythonCode.generateXMLText("Python", 0, extras) - - xmlfile = open(filepath,"w") - xmlfile.write(text.encode("utf-8")) - xmlfile.close() - - self.MarkPythonAsSaved() - return True - -#------------------------------------------------------------------------------- -# Current Buffering Management Functions -#------------------------------------------------------------------------------- - - """ - Return a copy of the project - """ - def Copy(self, model): - return cPickle.loads(cPickle.dumps(model)) - - def CreatePythonBuffer(self, saved): - self.Buffering = False - self.PythonBuffer = UndoBuffer(cPickle.dumps(self.PythonCode), saved) - - def BufferPython(self): - self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) - - def StartBuffering(self): - self.Buffering = True - - def EndBuffering(self): - if self.Buffering: - self.PythonBuffer.Buffering(cPickle.dumps(self.PythonCode)) - self.Buffering = False - - def MarkPythonAsSaved(self): - self.EndBuffering() - self.PythonBuffer.CurrentSaved() - - def PythonIsSaved(self): - return self.PythonBuffer.IsCurrentSaved() and not self.Buffering - - def LoadPrevious(self): - self.EndBuffering() - self.PythonCode = cPickle.loads(self.PythonBuffer.Previous()) - - def LoadNext(self): - self.PythonCode = cPickle.loads(self.PythonBuffer.Next()) - - def GetBufferState(self): - first = self.PythonBuffer.IsFirst() and not self.Buffering - last = self.PythonBuffer.IsLast() - return not first, not last - -def _GetClassFunction(name): - def GetRootClass(): - __import__("plugins.python.modules." + name) - return getattr(modules, name).RootClass - return GetRootClass - -class RootClass(PythonCodeTemplate): - - # For root object, available Childs Types are modules of the modules packages. - PlugChildsTypes = [(name, _GetClassFunction(name), help) for name, help in zip(modules.__all__,modules.helps)] - - def PluginPath(self): - return os.path.join(self.PlugParent.PluginPath(), self.PlugType) - - def PlugGenerate_C(self, buildpath, locations): - """ - Generate C code - @param current_location: Tupple containing plugin IEC location : %I0.0.4.5 => (0,0,4,5) - @param locations: List of complete variables locations \ - [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...) - "NAME" : name of the variable (generally "__IW0_1_2" style) - "DIR" : direction "Q","I" or "M" - "SIZE" : size "X", "B", "W", "D", "L" - "LOC" : tuple of interger for IEC location (0,1,2,...) - }, ...] - @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND - """ - current_location = self.GetCurrentLocation() - # define a unique name for the generated C file - location_str = "_".join(map(lambda x:str(x), current_location)) - - plugin_root = self.GetPlugRoot() - plugin_root.GetIECProgramsAndVariables() - - plc_python_filepath = os.path.join(os.path.split(__file__)[0], "plc_python.c") - plc_python_file = open(plc_python_filepath, 'r') - plc_python_code = plc_python_file.read() - plc_python_file.close() - python_eval_fb_list = [] - for v in plugin_root._VariablesList: - if v["vartype"] == "FB" and v["type"] in ["PYTHON_EVAL","PYTHON_POLL"]: - python_eval_fb_list.append(v) - python_eval_fb_count = max(1, len(python_eval_fb_list)) - - # prepare python code - plc_python_code = plc_python_code % { - "python_eval_fb_count": python_eval_fb_count, - "location": location_str} - - Gen_Pythonfile_path = os.path.join(buildpath, "python_%s.c"%location_str) - pythonfile = open(Gen_Pythonfile_path,'w') - pythonfile.write(plc_python_code) - pythonfile.close() - - runtimefile_path = os.path.join(buildpath, "runtime_%s.py"%location_str) - runtimefile = open(runtimefile_path, 'w') - runtimefile.write(self.GetPythonCode()) - runtimefile.close() - - matiec_flags = '"-I%s"'%os.path.abspath(self.GetPlugRoot().GetIECLibPath()) - - return [(Gen_Pythonfile_path, matiec_flags)], "", True, ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")) diff -r 180e4a7d945c -r 1c23952dbde1 plugins/python/python_xsd.xsd --- a/plugins/python/python_xsd.xsd Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ - - - - - - - Formatted text according to parts of XHTML 1.1 - - - - - - - diff -r 180e4a7d945c -r 1c23952dbde1 runtime/PLCObject.py --- a/runtime/PLCObject.py Thu May 03 19:02:34 2012 +0200 +++ b/runtime/PLCObject.py Mon May 07 18:47:29 2012 +0200 @@ -109,7 +109,7 @@ self._stopPLC = self._stopPLC_real else: - # If python plugin is not enabled, we reuse _PythonIterator + # If python confnode is not enabled, we reuse _PythonIterator # as a call that block pythonthread until StopPLC self.PythonIteratorLock = Lock() self.PythonIteratorLock.acquire() diff -r 180e4a7d945c -r 1c23952dbde1 targets/LPC/__init__.py --- a/targets/LPC/__init__.py Thu May 03 19:02:34 2012 +0200 +++ b/targets/LPC/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -6,9 +6,9 @@ class LPC_target(toolchain_makefile): #extension = ".ld" #DebugEnabled = False - def __init__(self, PluginsRootInstance): + def __init__(self, ConfigTreeRootInstance): self.binmd5key = None - toolchain_makefile.__init__(self, PluginsRootInstance) + toolchain_makefile.__init__(self, ConfigTreeRootInstance) def _GetBinMD5FileName(self): return os.path.join(self.buildpath, "lastbuildPLCbin.md5") @@ -64,7 +64,7 @@ f.write(self.binmd5key) f.close() try: - self.PluginsRootInstance.logger.write( + self.ConfigTreeRootInstance.logger.write( _("Binary is %s bytes long\n")% str(os.path.getsize( os.path.join(self.buildpath, "ArmPLC_rom.bin")))) diff -r 180e4a7d945c -r 1c23952dbde1 targets/Xenomai/__init__.py --- a/targets/Xenomai/__init__.py Thu May 03 19:02:34 2012 +0200 +++ b/targets/Xenomai/__init__.py Mon May 07 18:47:29 2012 +0200 @@ -4,14 +4,14 @@ extension = ".so" def getXenoConfig(self, flagsname): """ Get xeno-config from target parameters """ - xeno_config=self.PluginsRootInstance.GetTarget().getcontent()["value"].getXenoConfig() + xeno_config=self.ConfigTreeRootInstance.GetTarget().getcontent()["value"].getXenoConfig() if xeno_config: from wxPopen import ProcessLogger - status, result, err_result = ProcessLogger(self.PluginsRootInstance.logger, + status, result, err_result = ProcessLogger(self.ConfigTreeRootInstance.logger, xeno_config + " --skin=native --"+flagsname, no_stdout=True).spin() if status: - self.PluginsRootInstance.logger.write_error(_("Unable to get Xenomai's %s \n")%flagsname) + self.ConfigTreeRootInstance.logger.write_error(_("Unable to get Xenomai's %s \n")%flagsname) return [result.strip()] return [] diff -r 180e4a7d945c -r 1c23952dbde1 targets/toolchain_gcc.py --- a/targets/toolchain_gcc.py Thu May 03 19:02:34 2012 +0200 +++ b/targets/toolchain_gcc.py Mon May 07 18:47:29 2012 +0200 @@ -10,23 +10,23 @@ It cannot be used as this and should be inherited in a target specific class such as target_linux or target_win32 """ - def __init__(self, PluginsRootInstance): - self.PluginsRootInstance = PluginsRootInstance + def __init__(self, ConfigTreeRootInstance): + self.ConfigTreeRootInstance = ConfigTreeRootInstance self.buildpath = None - self.SetBuildPath(self.PluginsRootInstance._getBuildPath()) + self.SetBuildPath(self.ConfigTreeRootInstance._getBuildPath()) def getBuilderCFLAGS(self): """ Returns list of builder specific CFLAGS """ - return [self.PluginsRootInstance.GetTarget().getcontent()["value"].getCFLAGS()] + return [self.ConfigTreeRootInstance.GetTarget().getcontent()["value"].getCFLAGS()] def getBuilderLDFLAGS(self): """ Returns list of builder specific LDFLAGS """ - return self.PluginsRootInstance.LDFLAGS + \ - [self.PluginsRootInstance.GetTarget().getcontent()["value"].getLDFLAGS()] + return self.ConfigTreeRootInstance.LDFLAGS + \ + [self.ConfigTreeRootInstance.GetTarget().getcontent()["value"].getLDFLAGS()] def GetBinaryCode(self): try: @@ -56,7 +56,7 @@ def SetBuildPath(self, buildpath): if self.buildpath != buildpath: self.buildpath = buildpath - self.exe = self.PluginsRootInstance.GetProjectName() + self.extension + self.exe = self.ConfigTreeRootInstance.GetProjectName() + self.extension self.exe_path = os.path.join(self.buildpath, self.exe) self.md5key = None self.srcmd5 = {} @@ -89,7 +89,7 @@ def build(self): # Retrieve toolchain user parameters - toolchain_params = self.PluginsRootInstance.GetTarget().getcontent()["value"] + toolchain_params = self.ConfigTreeRootInstance.GetTarget().getcontent()["value"] self.compiler = toolchain_params.getCompiler() self.linker = toolchain_params.getLinker() @@ -99,11 +99,11 @@ obns = [] objs = [] relink = False - for Location, CFilesAndCFLAGS, DoCalls in self.PluginsRootInstance.LocationCFilesAndCFLAGS: + for Location, CFilesAndCFLAGS, DoCalls in self.ConfigTreeRootInstance.LocationCFilesAndCFLAGS: if Location: - self.PluginsRootInstance.logger.write(_("Plugin : ") + self.PluginsRootInstance.GetChildByIECLocation(Location).GetCurrentName() + " " + str(Location)+"\n") + self.ConfigTreeRootInstance.logger.write(_("ConfNode : ") + self.ConfigTreeRootInstance.GetChildByIECLocation(Location).GetCurrentName() + " " + str(Location)+"\n") else: - self.PluginsRootInstance.logger.write(_("PLC :\n")) + self.ConfigTreeRootInstance.logger.write(_("PLC :\n")) for CFile, CFLAGS in CFilesAndCFLAGS: if CFile.endswith(".c"): @@ -114,21 +114,21 @@ match = self.check_and_update_hash_and_deps(bn) if match: - self.PluginsRootInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n") + self.ConfigTreeRootInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n") else: relink = True - self.PluginsRootInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n") + self.ConfigTreeRootInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n") status, result, err_result = ProcessLogger( - self.PluginsRootInstance.logger, + self.ConfigTreeRootInstance.logger, "\"%s\" -c \"%s\" -o \"%s\" %s %s"% (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS) ).spin() if status : self.srcmd5.pop(bn) - self.PluginsRootInstance.logger.write_error(_("C compilation of %s failed.\n")%bn) + self.ConfigTreeRootInstance.logger.write_error(_("C compilation of %s failed.\n")%bn) return False obns.append(obn) objs.append(objectfilename) @@ -138,7 +138,7 @@ ######### GENERATE library FILE ######################################## # Link all the object files into one binary file - self.PluginsRootInstance.logger.write(_("Linking :\n")) + self.ConfigTreeRootInstance.logger.write(_("Linking :\n")) if relink: objstring = [] @@ -147,10 +147,10 @@ ALLldflags = ' '.join(self.getBuilderLDFLAGS()) - self.PluginsRootInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n") + self.ConfigTreeRootInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n") status, result, err_result = ProcessLogger( - self.PluginsRootInstance.logger, + self.ConfigTreeRootInstance.logger, "\"%s\" %s -o \"%s\" %s"% (self.linker, listobjstring, @@ -162,7 +162,7 @@ return False else: - self.PluginsRootInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") + self.ConfigTreeRootInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n") # Calculate md5 key and get data for the new created PLC data=self.GetBinaryCode() diff -r 180e4a7d945c -r 1c23952dbde1 targets/toolchain_makefile.py --- a/targets/toolchain_makefile.py Thu May 03 19:02:34 2012 +0200 +++ b/targets/toolchain_makefile.py Mon May 07 18:47:29 2012 +0200 @@ -7,11 +7,11 @@ includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*') class toolchain_makefile(): - def __init__(self, PluginsRootInstance): - self.PluginsRootInstance = PluginsRootInstance + def __init__(self, ConfigTreeRootInstance): + self.ConfigTreeRootInstance = ConfigTreeRootInstance self.md5key = None self.buildpath = None - self.SetBuildPath(self.PluginsRootInstance._getBuildPath()) + self.SetBuildPath(self.ConfigTreeRootInstance._getBuildPath()) def SetBuildPath(self, buildpath): if self.buildpath != buildpath: @@ -60,7 +60,7 @@ srcfiles= [] cflags = [] wholesrcdata = "" - for Location, CFilesAndCFLAGS, DoCalls in self.PluginsRootInstance.LocationCFilesAndCFLAGS: + for Location, CFilesAndCFLAGS, DoCalls in self.ConfigTreeRootInstance.LocationCFilesAndCFLAGS: # Get CFiles list to give it to makefile for CFile, CFLAGS in CFilesAndCFLAGS: CFileName = os.path.basename(CFile) @@ -72,7 +72,7 @@ oldmd5 = self.md5key self.md5key = hashlib.md5(wholesrcdata).hexdigest() - props = self.PluginsRootInstance.GetProjectProperties() + props = self.ConfigTreeRootInstance.GetProjectProperties() self.md5key += '#'.join([props[key] for key in ['companyName', 'projectName', 'productName']]) @@ -88,21 +88,21 @@ "md5": '"'+self.md5key+'"' } - target = self.PluginsRootInstance.GetTarget().getcontent()["value"] + target = self.ConfigTreeRootInstance.GetTarget().getcontent()["value"] command = target.getCommand().split(' ') +\ [target.getBuildPath()] +\ [arg % beremizcommand for arg in target.getArguments().split(' ')] +\ target.getRule().split(' ') # Call Makefile to build PLC code and link it with target specific code - status, result, err_result = ProcessLogger(self.PluginsRootInstance.logger, + status, result, err_result = ProcessLogger(self.ConfigTreeRootInstance.logger, command).spin() if status : self.md5key = None - self.PluginsRootInstance.logger.write_error(_("C compilation failed.\n")) + self.ConfigTreeRootInstance.logger.write_error(_("C compilation failed.\n")) return False return True else : - self.PluginsRootInstance.logger.write(_("Source didn't change, no build.\n")) + self.ConfigTreeRootInstance.logger.write(_("Source didn't change, no build.\n")) return True diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_master/canopen@canfestival/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/baseplugin.xml --- a/tests/canopen_master/canopen@canfestival/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/confnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_master/canopen@canfestival/confnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/master@CanOpenNode/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_master/canopen@canfestival/master@CanOpenNode/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/master@CanOpenNode/baseplugin.xml --- a/tests/canopen_master/canopen@canfestival/master@CanOpenNode/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/master@CanOpenNode/confnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_master/canopen@canfestival/master@CanOpenNode/confnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/master@CanOpenNode/plugin.xml --- a/tests/canopen_master/canopen@canfestival/master@CanOpenNode/plugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_master/canopen@canfestival/plugin.xml --- a/tests/canopen_master/canopen@canfestival/plugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_slave/canopen@canfestival/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/baseplugin.xml --- a/tests/canopen_slave/canopen@canfestival/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/confnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_slave/canopen@canfestival/confnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/plugin.xml --- a/tests/canopen_slave/canopen@canfestival/plugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/baseplugin.xml --- a/tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/confnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/confnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/plugin.xml --- a/tests/canopen_slave/canopen@canfestival/slave@CanOpenSlave/plugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/python/python@python/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/python/python@python/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/python/python@python/baseplugin.xml --- a/tests/python/python@python/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/svgui/python@python/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/svgui/python@python/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/svgui/python@python/baseplugin.xml --- a/tests/svgui/python@python/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/svgui/python@python/svgui@svgui/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/svgui/python@python/svgui@svgui/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/svgui/python@python/svgui@svgui/baseplugin.xml --- a/tests/svgui/python@python/svgui@svgui/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/wxGlade/python@python/HMIFrame@wxglade_hmi/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/wxGlade/python@python/HMIFrame@wxglade_hmi/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/wxGlade/python@python/HMIFrame@wxglade_hmi/baseplugin.xml --- a/tests/wxGlade/python@python/HMIFrame@wxglade_hmi/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - - diff -r 180e4a7d945c -r 1c23952dbde1 tests/wxGlade/python@python/baseconfnode.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/wxGlade/python@python/baseconfnode.xml Mon May 07 18:47:29 2012 +0200 @@ -0,0 +1,2 @@ + + diff -r 180e4a7d945c -r 1c23952dbde1 tests/wxGlade/python@python/baseplugin.xml --- a/tests/wxGlade/python@python/baseplugin.xml Thu May 03 19:02:34 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ - -