--- a/Beremiz.py Mon Aug 21 20:17:19 2017 +0000
+++ b/Beremiz.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,12 +23,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import os, sys, getopt
+import os
+import sys
+import getopt
import time
import __builtin__
import util.paths as paths
+
class BeremizIDELauncher:
def __init__(self):
self.updateinfo_url = None
@@ -40,7 +42,7 @@
self.splashPath = self.Bpath("images", "splash.png")
def Bpath(self, *args):
- return os.path.join(self.app_dir,*args)
+ return os.path.join(self.app_dir, *args)
def ShowSplashScreen(self):
from wx.lib.agw.advancedsplash import AdvancedSplash
@@ -53,21 +55,20 @@
self.splash.Show()
self.splash.ProcessEvent(wx.PaintEvent())
else:
- for i in range(0,30):
+ for i in range(0, 30):
wx.Yield()
- time.sleep(0.01);
-
+ time.sleep(0.01)
def Usage(self):
print "Usage:"
- print "%s [Options] [Projectpath] [Buildpath]"%sys.argv[0]
+ print "%s [Options] [Projectpath] [Buildpath]" % sys.argv[0]
print ""
print "Supported options:"
print "-h --help Print this help"
print "-u --updatecheck URL Retrieve update information by checking URL"
print "-e --extend PathToExtension Extend IDE functionality by loading at start additional extensions"
print ""
- print ""
+ print ""
def SetCmdOptions(self):
self.shortCmdOpts = "hu:e:"
@@ -108,7 +109,7 @@
def CreateApplication(self):
if os.path.exists("BEREMIZ_DEBUG"):
__builtin__.__dict__["BMZ_DBG"] = True
- else :
+ else:
__builtin__.__dict__["BMZ_DBG"] = False
global wxversion, wx
@@ -157,10 +158,10 @@
def updateinfoproc():
global updateinfo
- try :
+ try:
import urllib2
- updateinfo = urllib2.urlopen(self.updateinfo_url,None).read()
- except :
+ updateinfo = urllib2.urlopen(self.updateinfo_url, None).read()
+ except Exception:
updateinfo = _("update info unavailable.")
from threading import Thread
@@ -178,7 +179,7 @@
import version
import tempfile
logpath = tempfile.gettempdir()+os.sep+'Beremiz'
- BeremizIDE.AddExceptHook(logpath,version.app_version)
+ BeremizIDE.AddExceptHook(logpath, version.app_version)
def ShowUI(self):
self.frame = BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath)
@@ -190,6 +191,7 @@
self.ProcessCommandLineArgs()
self.CreateApplication()
+
if __name__ == '__main__':
beremiz = BeremizIDELauncher()
beremiz.Start()
--- a/BeremizIDE.py Mon Aug 21 20:17:19 2017 +0000
+++ b/BeremizIDE.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,26 +24,32 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys
+import os
+import sys
import tempfile
import shutil
import random
import time
import version
+
+from types import ListType
+
+import wx.lib.buttons
+import wx.lib.statbmp
+import wx.stc
+import cPickle
+import types
+import time
+import re
+import platform
+import time
+import traceback
+import commands
+import threading
+from threading import Lock, Timer, currentThread
+from time import time as gettime
+
import util.paths as paths
-from types import ListType
-
-beremiz_dir = paths.AbsDir(__file__)
-
-def Bpath(*args):
- return os.path.join(beremiz_dir,*args)
-
-
-
-import wx.lib.buttons, wx.lib.statbmp, wx.stc
-import cPickle
-import types, time, re, platform, time, traceback, commands
-
from docutil import OpenHtmlFrame
from editors.EditorPanel import EditorPanel
from editors.Viewer import Viewer
@@ -57,27 +63,63 @@
from controls import EnhancedStatusBar as esb
from dialogs.AboutDialog import ShowAboutDialog
-from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY, ITEM_PROJECT, ITEM_RESOURCE
+from PLCControler import \
+ LOCATION_CONFNODE, \
+ LOCATION_MODULE, \
+ LOCATION_GROUP, \
+ LOCATION_VAR_INPUT, \
+ LOCATION_VAR_OUTPUT, \
+ LOCATION_VAR_MEMORY, \
+ ITEM_PROJECT, \
+ ITEM_RESOURCE
+
from ProjectController import ProjectController, GetAddMenuItems, MATIEC_ERROR_MODEL, ITEM_CONFNODE
+from IDEFrame import \
+ TITLE,\
+ EDITORTOOLBAR,\
+ FILEMENU,\
+ EDITMENU,\
+ DISPLAYMENU,\
+ PROJECTTREE,\
+ POUINSTANCEVARIABLESPANEL,\
+ LIBRARYTREE,\
+ SCALING,\
+ PAGETITLES,\
+ IDEFrame, \
+ AppendMenu,\
+ EncodeFileSystemPath, \
+ DecodeFileSystemPath
+
+from util.BitmapLibrary import GetBitmap
+
+
+beremiz_dir = paths.AbsDir(__file__)
+
+
+def Bpath(*args):
+ return os.path.join(beremiz_dir, *args)
+
MAX_RECENT_PROJECTS = 9
+
if wx.Platform == '__WXMSW__':
faces = {
- 'mono' : 'Courier New',
- 'size' : 8,
+ 'mono': 'Courier New',
+ 'size': 8,
}
else:
faces = {
- 'mono' : 'Courier',
- 'size' : 10,
+ 'mono': 'Courier',
+ 'size': 10,
}
-from threading import Lock,Timer,currentThread
+
MainThread = currentThread().ident
REFRESH_PERIOD = 0.1
-from time import time as gettime
+
+
class LogPseudoFile:
""" Base class for file like objects to facilitate StdOut for the Shell."""
def __init__(self, output, risecall):
@@ -96,15 +138,15 @@
self.LastRefreshTime = gettime()
self.LastRefreshTimer = None
- def write(self, s, style = None):
+ def write(self, s, style=None):
if self.lock.acquire():
- self.stack.append((s,style))
+ self.stack.append((s, style))
self.lock.release()
current_time = gettime()
self.TimerAccessLock.acquire()
if self.LastRefreshTimer:
self.LastRefreshTimer.cancel()
- self.LastRefreshTimer=None
+ self.LastRefreshTimer = None
self.TimerAccessLock.release()
if current_time - self.LastRefreshTime > REFRESH_PERIOD and self.RefreshLock.acquire(False):
self._should_write()
@@ -133,11 +175,12 @@
self.YieldLock.release()
def _write(self):
- if self.output :
+ if self.output:
self.output.Freeze()
self.lock.acquire()
for s, style in self.stack:
- if style is None : style=self.black_white
+ if style is None:
+ style = self.black_white
if style != self.black_white:
self.output.StartStyling(self.output.GetLength(), 0xff)
@@ -159,7 +202,7 @@
self.LastRefreshTime = gettime()
try:
self.RefreshLock.release()
- except:
+ except Exception:
pass
newtime = time.time()
if newtime - self.rising_timer > 1:
@@ -167,10 +210,10 @@
self.rising_timer = newtime
def write_warning(self, s):
- self.write(s,self.red_white)
+ self.write(s, self.red_white)
def write_error(self, s):
- self.write(s,self.red_yellow)
+ self.write(s, self.red_yellow)
def writeyield(self, s):
self.write(s)
@@ -187,21 +230,9 @@
def isatty(self):
return False
+
ID_FILEMENURECENTPROJECTS = wx.NewId()
-from IDEFrame import TITLE,\
- EDITORTOOLBAR,\
- FILEMENU,\
- EDITMENU,\
- DISPLAYMENU,\
- PROJECTTREE,\
- POUINSTANCEVARIABLESPANEL,\
- LIBRARYTREE,\
- SCALING,\
- PAGETITLES,\
- IDEFrame, AppendMenu,\
- EncodeFileSystemPath, DecodeFileSystemPath
-from util.BitmapLibrary import GetBitmap
class Beremiz(IDEFrame):
@@ -213,29 +244,29 @@
def _init_coll_FileMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_NEW,
- kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N')
+ kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N')
AppendMenu(parent, help='', id=wx.ID_OPEN,
- kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O')
+ kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O')
parent.AppendMenu(ID_FILEMENURECENTPROJECTS, _("&Recent Projects"), self.RecentProjectsMenu)
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_SAVE,
- kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S')
+ kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S')
AppendMenu(parent, help='', id=wx.ID_SAVEAS,
- kind=wx.ITEM_NORMAL, text=_(u'Save as') + '\tCTRL+SHIFT+S')
+ kind=wx.ITEM_NORMAL, text=_(u'Save as') + '\tCTRL+SHIFT+S')
AppendMenu(parent, help='', id=wx.ID_CLOSE,
- kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W')
+ kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W')
AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL,
- kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W')
+ kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
- kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P')
AppendMenu(parent, help='', id=wx.ID_PREVIEW,
- kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P')
AppendMenu(parent, help='', id=wx.ID_PRINT,
- kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_EXIT,
- kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q')
+ kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q')
self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
@@ -263,7 +294,7 @@
self._RecursiveAddMenuItems(new_menu, children)
else:
AppendMenu(menu, help=help, id=new_id,
- kind=wx.ITEM_NORMAL, text=text)
+ kind=wx.ITEM_NORMAL, text=text)
self.Bind(wx.EVT_MENU, self.GetAddConfNodeFunction(name),
id=new_id)
@@ -272,15 +303,18 @@
self._RecursiveAddMenuItems(parent, GetAddMenuItems())
def _init_coll_HelpMenu_Items(self, parent):
- handler=lambda event: {
- wx.MessageBox(version.GetCommunityHelpMsg(), _(u'Community support'), wx.OK | wx.ICON_INFORMATION)
- }
+ def handler(event):
+ return wx.MessageBox(
+ version.GetCommunityHelpMsg(),
+ _(u'Community support'),
+ wx.OK | wx.ICON_INFORMATION)
+
id = wx.NewId()
- parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support'))
+ parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support'))
self.Bind(wx.EVT_MENU, handler, id=id)
-
+
parent.Append(help='', id=wx.ID_ABOUT,
- kind=wx.ITEM_NORMAL, text=_(u'About'))
+ kind=wx.ITEM_NORMAL, text=_(u'About'))
self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
def _init_coll_ConnectionStatusBar_Fields(self, parent):
@@ -299,26 +333,26 @@
inspectorID = wx.NewId()
self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=inspectorID)
- accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), inspectorID)]
+ accels = [wx.AcceleratorEntry(wx.ACCEL_CTRL | wx.ACCEL_ALT, ord('I'), inspectorID)]
keyID = wx.NewId()
self.Bind(wx.EVT_MENU, self.SwitchFullScrMode, id=keyID)
accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, wx.WXK_F12, keyID)]
- for method,shortcut in [("Stop", wx.WXK_F4),
- ("Run", wx.WXK_F5),
- ("Transfer", wx.WXK_F6),
- ("Connect", wx.WXK_F7),
- ("Build", wx.WXK_F11)]:
- def OnMethodGen(obj,meth):
+ for method, shortcut in [("Stop", wx.WXK_F4),
+ ("Run", wx.WXK_F5),
+ ("Transfer", wx.WXK_F6),
+ ("Connect", wx.WXK_F7),
+ ("Build", wx.WXK_F11)]:
+ def OnMethodGen(obj, meth):
def OnMethod(evt):
if obj.CTR is not None:
- obj.CTR.CallMethod('_'+meth)
+ obj.CTR.CallMethod('_'+meth)
wx.CallAfter(self.RefreshStatusToolBar)
return OnMethod
newid = wx.NewId()
- self.Bind(wx.EVT_MENU, OnMethodGen(self,method), id=newid)
- accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut,newid)]
+ self.Bind(wx.EVT_MENU, OnMethodGen(self, method), id=newid)
+ accels += [wx.AcceleratorEntry(wx.ACCEL_NORMAL, shortcut, newid)]
self.SetAcceleratorTable(wx.AcceleratorTable(accels))
@@ -349,29 +383,29 @@
self.MainTabs["LogConsole"] = (self.LogConsole, _("Console"))
self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"])
- #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT)
+ # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogConsole), wx.RIGHT)
self.LogViewer = LogViewer(self.BottomNoteBook, self)
self.MainTabs["LogViewer"] = (self.LogViewer, _("PLC Log"))
self.BottomNoteBook.AddPage(*self.MainTabs["LogViewer"])
- #self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT)
+ # self.BottomNoteBook.Split(self.BottomNoteBook.GetPageIndex(self.LogViewer), wx.RIGHT)
StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
- wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
+ wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
StatusToolBar.SetToolBitmapSize(wx.Size(25, 25))
StatusToolBar.Realize()
self.Panes["StatusToolBar"] = StatusToolBar
self.AUIManager.AddPane(StatusToolBar, wx.aui.AuiPaneInfo().
- Name("StatusToolBar").Caption(_("Status ToolBar")).
- ToolbarPane().Top().Position(1).
- LeftDockable(False).RightDockable(False))
+ Name("StatusToolBar").Caption(_("Status ToolBar")).
+ ToolbarPane().Top().Position(1).
+ LeftDockable(False).RightDockable(False))
self.AUIManager.Update()
self.ConnectionStatusBar = esb.EnhancedStatusBar(self, style=wx.ST_SIZEGRIP)
self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar)
- self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range = 100)
- self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2)
+ self.ProgressStatusBar = wx.Gauge(self.ConnectionStatusBar, -1, range=100)
+ self.ConnectionStatusBar.AddWidget(self.ProgressStatusBar, esb.ESB_EXACT_FIT, esb.ESB_EXACT_FIT, 2)
self.ProgressStatusBar.Hide()
self.SetStatusBar(self.ConnectionStatusBar)
@@ -383,15 +417,14 @@
# commands invoked by build process by default are
# found here.
os.environ["PATH"] = os.getcwd()+';'+os.environ["PATH"]
-
-
+
def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
# Add beremiz's icon in top left corner of the frame
self.icon = wx.Icon(Bpath("images", "brz.ico"), wx.BITMAP_TYPE_ICO)
self.__init_execute_path()
-
+
IDEFrame.__init__(self, parent, debug)
- self.Log = LogPseudoFile(self.LogConsole,self.SelectTab)
+ self.Log = LogPseudoFile(self.LogConsole, self.SelectTab)
self.local_runtime = None
self.runtime_port = None
@@ -405,17 +438,17 @@
# Icons for location items
for imgname, itemtype in [
- ("CONFIGURATION", LOCATION_CONFNODE),
- ("RESOURCE", LOCATION_MODULE),
- ("PROGRAM", LOCATION_GROUP),
- ("VAR_INPUT", LOCATION_VAR_INPUT),
- ("VAR_OUTPUT", LOCATION_VAR_OUTPUT),
- ("VAR_LOCAL", LOCATION_VAR_MEMORY)]:
+ ("CONFIGURATION", LOCATION_CONFNODE),
+ ("RESOURCE", LOCATION_MODULE),
+ ("PROGRAM", LOCATION_GROUP),
+ ("VAR_INPUT", LOCATION_VAR_INPUT),
+ ("VAR_OUTPUT", LOCATION_VAR_OUTPUT),
+ ("VAR_LOCAL", LOCATION_VAR_MEMORY)]:
self.LocationImageDict[itemtype] = self.LocationImageList.Add(GetBitmap(imgname))
# Icons for other items
for imgname, itemtype in [
- ("Extension", ITEM_CONFNODE)]:
+ ("Extension", ITEM_CONFNODE)]:
self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
if projectOpen is not None:
@@ -461,23 +494,24 @@
else:
self.SetTitle(name)
- def StartLocalRuntime(self, taskbaricon = True):
+ def StartLocalRuntime(self, taskbaricon=True):
if (self.local_runtime is None) or (self.local_runtime.exitcode is not None):
# create temporary directory for runtime working directory
self.local_runtime_tmpdir = tempfile.mkdtemp()
# choose an arbitrary random port for runtime
self.runtime_port = int(random.random() * 1000) + 61131
# launch local runtime
- self.local_runtime = ProcessLogger(self.Log,
- "\"%s\" \"%s\" -p %s -i localhost %s %s"%(
+ self.local_runtime = ProcessLogger(
+ self.Log,
+ "\"%s\" \"%s\" -p %s -i localhost %s %s" % (
sys.executable,
Bpath("Beremiz_service.py"),
self.runtime_port,
- {False : "-x 0", True :"-x 1"}[taskbaricon],
+ {False: "-x 0", True: "-x 1"}[taskbaricon],
self.local_runtime_tmpdir),
no_gui=False,
- timeout=500, keyword = self.local_runtime_tmpdir,
- cwd = self.local_runtime_tmpdir)
+ timeout=500, keyword=self.local_runtime_tmpdir,
+ cwd=self.local_runtime_tmpdir)
self.local_runtime.spin()
return self.runtime_port
@@ -531,17 +565,19 @@
if result is not None:
first_line, first_column, last_line, last_column, error = result.groups()
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.
+ (int(first_line), int(first_column)),
+ (int(last_line), int(last_column)))
+
def CheckSaveBeforeClosing(self, title=_("Close Project")):
+ """Function displaying an Error dialog in PLCOpenEditor.
+
+ :returns: False if closing cancelled.
+ """
if self.CTR.ProjectTestModified():
dialog = wx.MessageDialog(self,
_("There are changes, do you want to save?"),
title,
- wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+ wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
if answer == wx.ID_YES:
@@ -584,6 +620,7 @@
# Twisted reactor needs to be stopped only before quit,
# since it cannot be restarted
ToDoBeforeQuit = []
+
def AddToDoBeforeQuit(self, Thing):
self.ToDoBeforeQuit.append(Thing)
@@ -599,7 +636,7 @@
self.SaveLastState()
- for Thing in self.ToDoBeforeQuit :
+ for Thing in self.ToDoBeforeQuit:
Thing()
self.ToDoBeforeQuit = []
@@ -657,7 +694,7 @@
try:
recent_projects = map(DecodeFileSystemPath,
self.GetConfigEntry("RecentProjects", []))
- except:
+ except Exception:
recent_projects = []
while self.RecentProjectsMenu.GetMenuItemCount() > len(recent_projects):
@@ -715,10 +752,10 @@
if self.CTR is not None:
for confnode_method in self.CTR.StatusMethods:
- if "method" in confnode_method and confnode_method.get("shown",True):
+ if "method" in confnode_method and confnode_method.get("shown", True):
id = wx.NewId()
- StatusToolBar.AddSimpleTool(id,
- GetBitmap(confnode_method.get("bitmap", "Unknown")),
+ StatusToolBar.AddSimpleTool(
+ id, GetBitmap(confnode_method.get("bitmap", "Unknown")),
confnode_method["tooltip"])
self.Bind(wx.EVT_MENU, self.GetMenuCallBackFunction(confnode_method["method"]), id=id)
@@ -807,7 +844,7 @@
try:
recent_projects = map(DecodeFileSystemPath,
self.GetConfigEntry("RecentProjects", []))
- except:
+ except Exception:
recent_projects = []
if projectpath in recent_projects:
recent_projects.remove(projectpath)
@@ -827,10 +864,10 @@
try:
defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder"))
- except:
+ except Exception:
defaultpath = os.path.expanduser("~")
- dialog = wx.DirDialog(self , _("Choose an empty directory for new project"), defaultpath)
+ dialog = wx.DirDialog(self, _("Choose an empty directory for new project"), defaultpath)
if dialog.ShowModal() == wx.ID_OK:
projectpath = dialog.GetPath()
self.Config.Write("lastopenedfolder",
@@ -863,11 +900,11 @@
try:
defaultpath = DecodeFileSystemPath(self.Config.Read("lastopenedfolder"))
- except:
+ except Exception:
defaultpath = os.path.expanduser("~")
- dialog = wx.DirDialog(self , _("Choose a project"), defaultpath, style=wx.DEFAULT_DIALOG_STYLE|
- wx.RESIZE_BORDER)
+ dialog = wx.DirDialog(self, _("Choose a project"), defaultpath,
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
if dialog.ShowModal() == wx.ID_OK:
self.OpenProject(dialog.GetPath())
dialog.Destroy()
@@ -932,7 +969,7 @@
self.Close()
def OnAboutMenu(self, event):
- info = version.GetAboutDialogInfo()
+ info = version.GetAboutDialogInfo()
ShowAboutDialog(self, info)
def OnProjectTreeItemBeginEdit(self, event):
@@ -1015,8 +1052,9 @@
self.ProjectTree.SelectItem(root)
self.ResetSelectedItem()
else:
- return self.RecursiveProjectTreeItemSelection(root,
- [(word, ITEM_CONFNODE) for word in tagname.split(".")])
+ return self.RecursiveProjectTreeItemSelection(
+ root,
+ [(word, ITEM_CONFNODE) for word in tagname.split(".")])
elif words[0] == "R":
return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)])
elif not os.path.exists(words[0]):
@@ -1043,19 +1081,20 @@
def DeleteConfNode(self, confnode):
if self.CTR.CheckProjectPathPerm():
- dialog = wx.MessageDialog(self,
+ dialog = wx.MessageDialog(
+ self,
_("Really delete node '%s'?") % confnode.CTNName(),
_("Remove %s node") % confnode.CTNType,
- wx.YES_NO|wx.NO_DEFAULT)
+ wx.YES_NO | wx.NO_DEFAULT)
if dialog.ShowModal() == wx.ID_YES:
confnode.CTNRemove()
del confnode
self._Refresh(TITLE, FILEMENU, PROJECTTREE)
dialog.Destroy()
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Highlights showing functions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
def ShowHighlight(self, infos, start, end, highlight_type):
config_name = self.Controler.GetProjectMainConfigurationName()
@@ -1068,16 +1107,17 @@
else:
IDEFrame.ShowHighlight(self, infos, start, end, highlight_type)
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Exception Handler
-#-------------------------------------------------------------------------------
-import threading, traceback
+# -------------------------------------------------------------------------------
Max_Traceback_List_Size = 20
+
def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path):
trcbck_lst = []
- for i,line in enumerate(traceback.extract_tb(e_tb)):
+ for i, line in enumerate(traceback.extract_tb(e_tb)):
trcbck = " " + str(i+1) + ". "
if line[0].find(os.getcwd()) == -1:
trcbck += "file : " + str(line[0]) + ", "
@@ -1091,7 +1131,8 @@
if cap:
cap.ReleaseMouse()
- dlg = wx.SingleChoiceDialog(None,
+ dlg = wx.SingleChoiceDialog(
+ None,
_("""
An unhandled exception (bug) occured. Bug report saved at :
(%s)
@@ -1113,6 +1154,7 @@
return res
+
def get_last_traceback(tb):
while tb.tb_next:
tb = tb.tb_next
@@ -1123,17 +1165,18 @@
return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()])
-ignored_exceptions = [] # a problem with a line in a module is only reported once per session
-
-def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
-
- def save_bug_report(e_type, e_value, e_traceback, bug_report_path,date):
+ignored_exceptions = [] # a problem with a line in a module is only reported once per session
+
+
+def AddExceptHook(path, app_version='[No version]'):
+
+ def save_bug_report(e_type, e_value, e_traceback, bug_report_path, date):
info = {
- 'app-title': wx.GetApp().GetAppName(), # app_title
+ 'app-title': wx.GetApp().GetAppName(),
'app-version': app_version,
'wx-version': wx.VERSION_STRING,
'wx-platform': wx.Platform,
- 'python-version': platform.python_version(), # sys.version.split()[0],
+ 'python-version': platform.python_version(),
'platform': platform.platform(),
'e-type': e_type,
'e-value': e_value,
@@ -1148,7 +1191,7 @@
if 'self' in exception_locals:
try:
info['self'] = format_namespace(exception_locals['self'].__dict__)
- except:
+ except Exception:
pass
if not os.path.exists(path):
os.mkdir(path)
@@ -1160,7 +1203,7 @@
output.close()
def handle_exception(e_type, e_value, e_traceback):
- traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
+ traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
last_tb = get_last_traceback(e_traceback)
ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
if ex not in ignored_exceptions:
@@ -1169,19 +1212,21 @@
bug_report_path = path + os.sep + "bug_report_" + time.strftime("%Y_%m_%d__%H-%M-%S") + ".txt"
save_bug_report(e_type, e_value, e_traceback, bug_report_path, date)
Display_Exception_Dialog(e_type, e_value, e_traceback, bug_report_path)
- #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
+ # sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
sys.excepthook = handle_exception
init_old = threading.Thread.__init__
+
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
+
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
- except:
+ except Exception:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
--- a/Beremiz_service.py Mon Aug 21 20:17:19 2017 +0000
+++ b/Beremiz_service.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,8 +23,18 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys, getopt
+import os
+import sys
+import getopt
+import threading
from threading import Thread
+import traceback
+import __builtin__
+import Pyro.core as pyro
+
+from runtime import PLCObject, PLCprint, ServicePublisher
+import util.paths as paths
+
def usage():
print """
@@ -42,13 +52,14 @@
-e - python extension (absolute path .py)
working_dir - directory where are stored PLC files
-"""%sys.argv[0]
+""" % sys.argv[0]
+
try:
opts, argv = getopt.getopt(sys.argv[1:], "i:p:n:x:t:a:w:c:e:h")
except getopt.GetoptError, err:
# print help information and exit:
- print str(err) # will print something like "option -a not recognized"
+ print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
@@ -64,7 +75,7 @@
enabletwisted = True
havetwisted = False
-extensions=[]
+extensions = []
for o, a in opts:
if o == "-h":
@@ -97,7 +108,7 @@
usage()
sys.exit()
-import util.paths as paths
+
beremiz_dir = paths.AbsDir(__file__)
if len(argv) > 1:
@@ -108,21 +119,22 @@
os.chdir(WorkingDir)
elif len(argv) == 0:
WorkingDir = os.getcwd()
- argv=[WorkingDir]
-
-import __builtin__
+ argv = [WorkingDir]
+
if __name__ == '__main__':
__builtin__.__dict__['_'] = lambda x: x
+
def Bpath(*args):
- return os.path.join(beremiz_dir,*args)
+ return os.path.join(beremiz_dir, *args)
+
def SetupI18n():
# Import module for internationalization
import gettext
# Get folder containing translation files
- localedir = os.path.join(beremiz_dir,"locale")
+ localedir = os.path.join(beremiz_dir, "locale")
# Get the default language
langid = wx.LANGUAGE_DEFAULT
# Define translation domain (name of translation files)
@@ -138,12 +150,10 @@
# Define locale domain
loc.AddCatalog(domain)
-
import locale
global default_locale
default_locale = locale.getdefaultlocale()[1]
-
# sys.stdout.encoding = default_locale
# if Beremiz_service is started from Beremiz IDE
# sys.stdout.encoding is None (that means 'ascii' encoding').
@@ -156,13 +166,14 @@
__builtin__.__dict__['_'] = unicode_translation
# __builtin__.__dict__['_'] = wx.GetTranslation
+
if enablewx:
try:
import wxversion
wxversion.select(['2.8', '3.0'])
import wx
havewx = True
- except:
+ except ImportError:
print "Wx unavailable !"
havewx = False
@@ -186,15 +197,14 @@
class ParamsEntryDialog(wx.TextEntryDialog):
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
event(self, function)
-
- def __init__(self, parent, message, caption = _("Please enter text"), defaultValue = "",
- style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ def __init__(self, parent, message, caption=_("Please enter text"), defaultValue="",
+ style=wx.OK | wx.CANCEL | wx.CENTRE, pos=wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
self.Tests = []
@@ -207,10 +217,10 @@
def OnOK(self, event):
value = self.GetValue()
- texts = {"value" : value}
+ texts = {"value": value}
for function, message in self.Tests:
if not function(value):
- message = wx.MessageDialog(self, message%texts, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, message % texts, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
return
@@ -262,7 +272,7 @@
menu = wx.Menu()
menu.Append(self.TBMENU_START, _("Start PLC"))
menu.Append(self.TBMENU_STOP, _("Stop PLC"))
- if self.level==1:
+ if self.level == 1:
menu.AppendSeparator()
menu.Append(self.TBMENU_CHANGE_NAME, _("Change Name"))
menu.Append(self.TBMENU_CHANGE_INTERFACE, _("Change IP of interface to bind"))
@@ -285,13 +295,13 @@
elif "wxGTK" in wx.PlatformInfo:
img = img.Scale(22, 22)
# wxMac can be any size upto 128x128, so leave the source img alone....
- icon = wx.IconFromBitmap(img.ConvertToBitmap() )
+ icon = wx.IconFromBitmap(img.ConvertToBitmap())
return icon
def OnTaskBarStartPLC(self, evt):
if self.pyroserver.plcobj is not None:
plcstatus = self.pyroserver.plcobj.GetPLCstatus()[0]
- if plcstatus is "Stopped":
+ if plcstatus is "Stopped":
self.pyroserver.plcobj.StartPLC()
else:
print _("PLC is empty or already started.")
@@ -306,17 +316,17 @@
def OnTaskBarChangeInterface(self, evt):
ip_addr = self.pyroserver.ip_addr
ip_addr = '' if ip_addr is None else ip_addr
- dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr)
+ dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr)
dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")),
- ( lambda x :len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4, _("IP is not valid!"))
- ])
+ (lambda x:len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4,
+ _("IP is not valid!"))])
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.ip_addr = dlg.GetValue()
self.pyroserver.Stop()
def OnTaskBarChangePort(self, evt):
dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port))
- dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port : 0 <= int(port) <= 65535 , _("Port number must be 0 <= port <= 65535!"))])
+ dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port: 0 <= int(port) <= 65535, _("Port number must be 0 <= port <= 65535!"))])
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.port = int(dlg.GetValue())
self.pyroserver.Stop()
@@ -331,14 +341,14 @@
servicename = self.pyroserver.servicename
servicename = '' if servicename is None else servicename
dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=servicename)
- dlg.SetTests([(lambda name : len(name) is not 0 , _("Name must not be null!"))])
+ dlg.SetTests([(lambda name: len(name) is not 0, _("Name must not be null!"))])
if dlg.ShowModal() == wx.ID_OK:
self.pyroserver.servicename = dlg.GetValue()
self.pyroserver.Restart()
def _LiveShellLocals(self):
if self.pyroserver.plcobj is not None:
- return {"locals":self.pyroserver.plcobj.python_runtime_vars}
+ return {"locals": self.pyroserver.plcobj.python_runtime_vars}
else:
return {}
@@ -363,7 +373,7 @@
wx.CallAfter(wx.GetApp().ExitMainLoop)
def UpdateIcon(self, plcstatus):
- if plcstatus is "Started" :
+ if plcstatus is "Started":
currenticon = self.MakeIcon(starticon)
elif plcstatus is "Stopped":
currenticon = self.MakeIcon(stopicon)
@@ -371,19 +381,19 @@
currenticon = self.MakeIcon(defaulticon)
self.SetIcon(currenticon, "Beremiz Service")
-from runtime import PLCObject, PLCprint, ServicePublisher
-import Pyro.core as pyro
if not os.path.isdir(WorkingDir):
os.mkdir(WorkingDir)
+
def default_evaluator(tocall, *args, **kwargs):
try:
- res=(tocall(*args,**kwargs), None)
+ res = (tocall(*args, **kwargs), None)
except Exception:
- res=(None, sys.exc_info())
+ res = (None, sys.exc_info())
return res
+
class Server():
def __init__(self, servicename, ip_addr, port,
workdir, argv, autostart=False,
@@ -419,11 +429,11 @@
def Start(self):
pyro.initServer()
- self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port)
+ self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port)
self.plcobj = PLCObject(self.workdir, self.daemon, self.argv,
self.statuschange, self.evaluator,
self.pyruntimevars)
- uri = self.daemon.connect(self.plcobj,"PLCObject")
+ uri = self.daemon.connect(self.plcobj, "PLCObject")
print _("Pyro port :"), self.port
print _("Pyro object's uri :"), uri
@@ -435,17 +445,17 @@
# Configure and publish service
# Not publish service if localhost in address params
- if (self.servicename is not None and
- self.ip_addr is not None and
- self.ip_addr != "localhost" and
- self.ip_addr != "127.0.0.1"):
+ if self.servicename is not None and \
+ self.ip_addr is not None and \
+ self.ip_addr != "localhost" and \
+ self.ip_addr != "127.0.0.1":
print _("Publishing service on local network")
self.servicepublisher = ServicePublisher.ServicePublisher()
self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port)
self.plcobj.AutoLoad()
if self.plcobj.GetPLCstatus()[0] != "Empty":
- if self.autostart :
+ if self.autostart:
self.plcobj.StartPLC()
self.plcobj.StatusChange()
@@ -462,6 +472,7 @@
self.servicepublisher = None
self.daemon.shutdown(True)
+
if enabletwisted:
import warnings
with warnings.catch_warnings():
@@ -474,7 +485,7 @@
from twisted.internet import reactor
havetwisted = True
- except:
+ except ImportError:
print _("Twisted unavailable.")
havetwisted = False
@@ -492,12 +503,12 @@
main_thread = currentThread()
def statuschangeTskBar(status):
- wx.CallAfter(taskbar_instance.UpdateIcon,status)
+ wx.CallAfter(taskbar_instance.UpdateIcon, status)
statuschange.append(statuschangeTskBar)
def wx_evaluator(obj, *args, **kwargs):
- tocall,args,kwargs = obj.call
+ tocall, args, kwargs = obj.call
obj.res = default_evaluator(tocall, *args, **kwargs)
wx_eval_lock.release()
@@ -507,8 +518,8 @@
# avoid dead lock if called from the wx mainloop
return default_evaluator(tocall, *args, **kwargs)
else:
- o=type('',(object,),dict(call=(tocall, args, kwargs), res=None))
- wx.CallAfter(wx_evaluator,o)
+ o = type('', (object,), dict(call=(tocall, args, kwargs), res=None))
+ wx.CallAfter(wx_evaluator, o)
wx_eval_lock.acquire()
return o.res
@@ -524,32 +535,40 @@
# Exception hooks s
-import threading, traceback
+
+
def LogException(*exp):
if pyroserver.plcobj is not None:
- pyroserver.plcobj.LogMessage(0,'\n'.join(traceback.format_exception(*exp)))
+ pyroserver.plcobj.LogMessage(0, '\n'.join(traceback.format_exception(*exp)))
else:
traceback.print_exception(*exp)
+
sys.excepthook = LogException
+
+
def installThreadExcepthook():
init_old = threading.Thread.__init__
+
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
+
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
- except:
+ except Exception:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
+
+
installThreadExcepthook()
if havetwisted:
- if webport is not None :
+ if webport is not None:
try:
import runtime.NevowServer as NS
except Exception, e:
@@ -557,7 +576,7 @@
webport = None
NS.WorkingDir = WorkingDir
- if wampconf is not None :
+ if wampconf is not None:
try:
import runtime.WampClient as WC
except Exception, e:
@@ -571,7 +590,7 @@
execfile(extfilename, locals())
if havetwisted:
- if webport is not None :
+ if webport is not None:
try:
website = NS.RegisterWebsite(webport)
pyruntimevars["website"] = website
@@ -579,7 +598,7 @@
except Exception, e:
print _("Nevow Web service failed. "), e
- if wampconf is not None :
+ if wampconf is not None:
try:
WC.RegisterWampClient(wampconf)
pyruntimevars["wampsession"] = WC.GetSession
@@ -589,7 +608,7 @@
if havetwisted or havewx:
- pyro_thread=Thread(target=pyroserver.Loop)
+ pyro_thread = Thread(target=pyroserver.Loop)
pyro_thread.start()
if havetwisted:
@@ -597,9 +616,9 @@
elif havewx:
app.MainLoop()
else:
- try :
+ try:
pyroserver.Loop()
- except KeyboardInterrupt,e:
+ except KeyboardInterrupt, e:
pass
pyroserver.Quit()
sys.exit(0)
--- a/CodeFileTreeNode.py Mon Aug 21 20:17:19 2017 +0000
+++ b/CodeFileTreeNode.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,7 +23,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, re, traceback
+import os
+import re
+import traceback
from copy import deepcopy
from lxml import etree
@@ -80,11 +82,12 @@
SECTION_TAG_ELEMENT = "<xsd:element name=\"%s\" type=\"CodeText\"/>"
+
class CodeFile:
-
+
CODEFILE_NAME = "CodeFile"
SECTIONS_NAMES = []
-
+
def __init__(self):
sections_str = {"codefile_name": self.CODEFILE_NAME}
if "includes" in self.SECTIONS_NAMES:
@@ -94,34 +97,34 @@
sections_str["sections"] = "\n".join(
[SECTION_TAG_ELEMENT % name
for name in self.SECTIONS_NAMES if name != "includes"])
-
+
self.CodeFileParser = GenerateParserFromXSDstring(
CODEFILE_XSD % sections_str)
self.CodeFileVariables = etree.XPath("variables/variable")
-
+
filepath = self.CodeFileName()
-
+
if os.path.isfile(filepath):
xmlfile = open(filepath, 'r')
codefile_xml = xmlfile.read()
xmlfile.close()
-
+
codefile_xml = codefile_xml.replace(
- '<%s>' % self.CODEFILE_NAME,
+ '<%s>' % self.CODEFILE_NAME,
'<%s xmlns:xhtml="http://www.w3.org/1999/xhtml">' % self.CODEFILE_NAME)
for cre, repl in [
- (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
- (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
+ (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
+ (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
codefile_xml = cre.sub(repl, codefile_xml)
-
+
try:
self.CodeFile, error = self.CodeFileParser.LoadXMLString(codefile_xml)
if error is not None:
(fname, lnum, src) = ((self.CODEFILE_NAME,) + error)
- self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src))
+ self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1=fname, a2=lnum, a3=src))
self.CreateCodeFileBuffer(True)
except Exception, exc:
- msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1 = CTNName, a2 = unicode(exc))
+ msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1=CTNName, a2=unicode(exc))
self.GetCTRoot().logger.write_error(msg)
self.GetCTRoot().logger.write_error(traceback.format_exc())
else:
@@ -132,13 +135,13 @@
def GetBaseTypes(self):
return self.GetCTRoot().GetBaseTypes()
- def GetDataTypes(self, basetypes = False):
+ def GetDataTypes(self, basetypes=False):
return self.GetCTRoot().GetDataTypes(basetypes=basetypes)
def GenerateNewName(self, format, start_idx):
return self.GetCTRoot().GenerateNewName(
None, None, format, start_idx,
- dict([(var.getname().upper(), True)
+ dict([(var.getname().upper(), True)
for var in self.CodeFile.variables.getvariable()]))
def SetVariables(self, variables):
@@ -152,17 +155,18 @@
variable.setonchange(var["OnChange"])
variable.setopts(var["Options"])
self.CodeFile.variables.appendvariable(variable)
-
+
def GetVariables(self):
datas = []
for var in self.CodeFileVariables(self.CodeFile):
- datas.append({"Name" : var.getname(),
- "Type" : var.gettype(),
- "Initial" : var.getinitial(),
- "Description" : var.getdesc(),
- "OnChange" : var.getonchange(),
- "Options" : var.getopts(),
- })
+ datas.append({
+ "Name": var.getname(),
+ "Type": var.gettype(),
+ "Initial": var.getinitial(),
+ "Description": var.getdesc(),
+ "OnChange": var.getonchange(),
+ "Options": var.getopts(),
+ })
return datas
def SetTextParts(self, parts):
@@ -170,42 +174,42 @@
section_code = parts.get(section)
if section_code is not None:
getattr(self.CodeFile, section).setanyText(section_code)
-
+
def GetTextParts(self):
return dict([(section, getattr(self.CodeFile, section).getanyText())
for section in self.SECTIONS_NAMES])
-
+
def CTNTestModified(self):
- return self.ChangesToSave or not self.CodeFileIsSaved()
+ return self.ChangesToSave or not self.CodeFileIsSaved()
def OnCTNSave(self, from_project_path=None):
filepath = self.CodeFileName()
-
- xmlfile = open(filepath,"w")
+
+ xmlfile = open(filepath, "w")
xmlfile.write(etree.tostring(
- self.CodeFile,
- pretty_print=True,
- xml_declaration=True,
+ self.CodeFile,
+ pretty_print=True,
+ xml_declaration=True,
encoding='utf-8'))
xmlfile.close()
-
+
self.MarkCodeFileAsSaved()
return True
def CTNGlobalInstances(self):
variables = self.CodeFileVariables(self.CodeFile)
- ret = [(variable.getname(),
- variable.gettype(),
- variable.getinitial())
- for variable in variables]
+ ret = [(variable.getname(),
+ variable.gettype(),
+ variable.getinitial())
+ for variable in variables]
ret.extend([("On"+variable.getname()+"Change", "python_poll", "")
- for variable in variables
- if variable.getonchange()])
+ for variable in variables
+ if variable.getonchange()])
return ret
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Current Buffering Management Functions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
"""
Return a copy of the codefile model
@@ -219,31 +223,30 @@
def BufferCodeFile(self):
self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile))
-
+
def StartBuffering(self):
self.Buffering = True
-
+
def EndBuffering(self):
if self.Buffering:
self.CodeFileBuffer.Buffering(self.CodeFileParser.Dumps(self.CodeFile))
self.Buffering = False
-
+
def MarkCodeFileAsSaved(self):
self.EndBuffering()
self.CodeFileBuffer.CurrentSaved()
-
+
def CodeFileIsSaved(self):
return self.CodeFileBuffer.IsCurrentSaved() and not self.Buffering
-
+
def LoadPrevious(self):
self.EndBuffering()
self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Previous())
-
+
def LoadNext(self):
self.CodeFile = self.CodeFileParser.Loads(self.CodeFileBuffer.Next())
-
+
def GetBufferState(self):
first = self.CodeFileBuffer.IsFirst() and not self.Buffering
last = self.CodeFileBuffer.IsLast()
return not first, not last
-
--- a/ConfigTreeNode.py Mon Aug 21 20:17:19 2017 +0000
+++ b/ConfigTreeNode.py Mon Aug 21 23:22:58 2017 +0300
@@ -31,7 +31,9 @@
- ... TODO : document
"""
-import os,traceback,types
+import os
+import traceback
+import types
import shutil
from lxml import etree
@@ -55,6 +57,7 @@
NameTypeSeparator = '@'
XSDSchemaErrorMessage = _("{a1} XML file doesn't follow XSD schema at line {a2}:\n{a3}")
+
class ConfigTreeNode:
"""
This class is the one that define confnodes.
@@ -67,7 +70,7 @@
LibraryControler = None
EditorType = ConfTreeNodeEditor
IconPath = None
-
+
def _AddParamsMembers(self):
self.CTNParams = None
if self.XSD:
@@ -78,7 +81,7 @@
setattr(self, name, obj)
def __init__(self):
- # Create BaseParam
+ # Create BaseParam
self.BaseParams = _BaseParamsParser.CreateRoot()
self.MandatoryParams = ("BaseParams", self.BaseParams)
self._AddParamsMembers()
@@ -86,39 +89,39 @@
self._View = None
# copy ConfNodeMethods so that it can be later customized
self.ConfNodeMethods = [dic.copy() for dic in self.ConfNodeMethods]
-
+
def ConfNodeBaseXmlFilePath(self, CTNName=None):
return os.path.join(self.CTNPath(CTNName), "baseconfnode.xml")
-
+
def ConfNodeXmlFilePath(self, CTNName=None):
return os.path.join(self.CTNPath(CTNName), "confnode.xml")
def ConfNodePath(self):
return os.path.join(self.CTNParent.ConfNodePath(), self.CTNType)
- def CTNPath(self,CTNName=None,project_path=None):
+ def CTNPath(self, CTNName=None, project_path=None):
if not CTNName:
CTNName = self.CTNName()
if not project_path:
project_path = self.CTNParent.CTNPath()
return os.path.join(project_path,
CTNName + NameTypeSeparator + self.CTNType)
-
+
def CTNName(self):
return self.BaseParams.getName()
-
+
def CTNEnabled(self):
return self.BaseParams.getEnabled()
-
+
def CTNFullName(self):
parent = self.CTNParent.CTNFullName()
if parent != "":
return parent + "." + self.CTNName()
return self.BaseParams.getName()
-
+
def GetIconName(self):
return None
-
+
def CTNTestModified(self):
return self.ChangesToSave
@@ -134,15 +137,15 @@
return True
return False
-
+
def RemoteExec(self, script, **kwargs):
return self.CTNParent.RemoteExec(script, **kwargs)
-
+
def OnCTNSave(self, from_project_path=None):
- #Default, do nothing and return success
+ """Default, do nothing and return success"""
return True
- def GetParamsAttributes(self, path = None):
+ def GetParamsAttributes(self, path=None):
if path:
parts = path.split(".", 1)
if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
@@ -154,7 +157,7 @@
if self.CTNParams:
params.append(self.CTNParams[1].getElementInfos(self.CTNParams[0]))
return params
-
+
def SetParamsAttribute(self, path, value):
self.ChangesToSave = True
# Filter IEC_Channel and Name, that have specific behavior
@@ -169,7 +172,7 @@
res = self.FindNewName(value)
self.CTNRequestSave()
return res, True
-
+
parts = path.split(".", 1)
if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
self.MandatoryParams[1].setElementValue(parts[1], value)
@@ -189,32 +192,32 @@
if not os.path.isdir(ctnpath):
# Create it
os.mkdir(ctnpath)
-
+
# generate XML for base XML parameters controller of the confnode
if self.MandatoryParams:
- BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(),'w')
+ BaseXMLFile = open(self.ConfNodeBaseXmlFilePath(), 'w')
BaseXMLFile.write(etree.tostring(
- self.MandatoryParams[1],
- pretty_print=True,
- xml_declaration=True,
+ self.MandatoryParams[1],
+ pretty_print=True,
+ xml_declaration=True,
encoding='utf-8'))
BaseXMLFile.close()
-
+
# generate XML for XML parameters controller of the confnode
if self.CTNParams:
- XMLFile = open(self.ConfNodeXmlFilePath(),'w')
+ XMLFile = open(self.ConfNodeXmlFilePath(), 'w')
XMLFile.write(etree.tostring(
- self.CTNParams[1],
- pretty_print=True,
- xml_declaration=True,
+ self.CTNParams[1],
+ pretty_print=True,
+ xml_declaration=True,
encoding='utf-8'))
XMLFile.close()
-
+
# Call the confnode specific OnCTNSave method
result = self.OnCTNSave(from_project_path)
if not result:
- return _("Error while saving \"%s\"\n")%self.CTNPath()
-
+ return _("Error while saving \"%s\"\n") % self.CTNPath()
+
# mark confnode as saved
self.ChangesToSave = False
# go through all children and do the same
@@ -226,7 +229,7 @@
if result:
return result
return None
-
+
def CTNImport(self, src_CTNPath):
shutil.copytree(src_CTNPath, self.CTNPath)
return True
@@ -236,13 +239,13 @@
@return: [(instance_name, instance_type),...]
"""
return []
-
+
def _GlobalInstances(self):
instances = self.CTNGlobalInstances()
for CTNChild in self.IECSortedChildren():
instances.extend(CTNChild._GlobalInstances())
return instances
-
+
def CTNGenerate_C(self, buildpath, locations):
"""
Generate C code
@@ -255,9 +258,9 @@
}, ...]
@return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
"""
- self.GetCTRoot().logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
- return [],"",False
-
+ self.GetCTRoot().logger.write_warning(".".join(map(lambda x: str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
+ return [], "", False
+
def _Generate_C(self, buildpath, locations):
# Generate confnodes [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files
# extra_files = [(fname,fobject), ...]
@@ -273,46 +276,46 @@
# confnode asks for some LDFLAGS
if CTNLDFLAGS:
# LDFLAGS can be either string
- if type(CTNLDFLAGS)==type(str()):
- LDFLAGS=[CTNLDFLAGS]
- #or list of strings
- elif type(CTNLDFLAGS)==type(list()):
- LDFLAGS=CTNLDFLAGS[:]
+ if isinstance(CTNLDFLAGS, str):
+ LDFLAGS = [CTNLDFLAGS]
+ # or list of strings
+ elif isinstance(CTNLDFLAGS, list):
+ LDFLAGS = CTNLDFLAGS[:]
else:
- LDFLAGS=[]
-
+ LDFLAGS = []
+
# recurse through all children, and stack their results
for CTNChild in self.IECSortedChildren():
new_location = CTNChild.GetCurrentLocation()
# How deep are we in the tree ?
- depth=len(new_location)
+ depth = len(new_location)
_LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \
CTNChild._Generate_C(
- #keep the same path
+ # 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 ])
+ [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 IterChildren(self):
for CTNType, Children in self.Children.items():
for CTNInstance in Children:
yield CTNInstance
-
+
def IECSortedChildren(self):
# reorder children by IEC_channels
- ordered = [(chld.BaseParams.getIEC_Channel(),chld) for chld in self.IterChildren()]
+ ordered = [(chld.BaseParams.getIEC_Channel(), chld) for chld in self.IterChildren()]
if ordered:
ordered.sort()
return zip(*ordered)[1]
else:
return []
-
+
def _GetChildBySomething(self, something, toks):
for CTNInstance in self.IterChildren():
# if match component of the name
@@ -320,7 +323,7 @@
# if Name have other components
if len(toks) >= 2:
# Recurse in order to find the latest object
- return CTNInstance._GetChildBySomething( something, toks[1:])
+ return CTNInstance._GetChildBySomething(something, toks[1:])
# No sub name -> found
return CTNInstance
# Not found
@@ -338,7 +341,7 @@
return self._GetChildBySomething("IEC_Channel", Location)
else:
return self
-
+
def GetCurrentLocation(self):
"""
@return: Tupple containing confnode IEC location of current confnode : %I0.0.4.5 => (0,0,4,5)
@@ -349,13 +352,13 @@
"""
@return: String "ParentParentName.ParentName.Name"
"""
- return self.CTNParent._GetCurrentName() + self.BaseParams.getName()
+ return self.CTNParent._GetCurrentName() + self.BaseParams.getName()
def _GetCurrentName(self):
"""
@return: String "ParentParentName.ParentName.Name."
"""
- return self.CTNParent._GetCurrentName() + self.BaseParams.getName() + "."
+ return self.CTNParent._GetCurrentName() + self.BaseParams.getName() + "."
def GetCTRoot(self):
return self.CTNParent.GetCTRoot()
@@ -372,7 +375,7 @@
This function is meant to be overridden by confnodes.
It should returns an list of dictionaries
-
+
- IEC_type is an IEC type like BOOL/BYTE/SINT/...
- location is a string of this variable's location, like "%IX0.0.0"
'''
@@ -392,9 +395,9 @@
# Get Current Name
CurrentName = self.BaseParams.getName()
# Do nothing if no change
- #if CurrentName == DesiredName: return CurrentName
+ # if CurrentName == DesiredName: return CurrentName
# Build a list of used Name out of parent's Children
- AllNames=[]
+ AllNames = []
for CTNInstance in self.CTNParent.IterChildren():
if CTNInstance != self:
AllNames.append(CTNInstance.BaseParams.getName())
@@ -407,9 +410,9 @@
BaseDesiredName = DesiredName
suffix = 1
while res in AllNames:
- res = "%s_%d"%(BaseDesiredName, suffix)
+ res = "%s_%d" % (BaseDesiredName, suffix)
suffix += 1
-
+
# Get old path
oldname = self.CTNPath()
# Check previous confnode existance
@@ -421,12 +424,12 @@
shutil.move(oldname, self.CTNPath())
# warn user he has two left hands
if DesiredName != res:
- msg = _("A child named \"{a1}\" already exists -> \"{a2}\"\n").format(a1 = DesiredName, a2 = res)
+ msg = _("A child named \"{a1}\" already exists -> \"{a2}\"\n").format(a1=DesiredName, a2=res)
self.GetCTRoot().logger.write_warning(msg)
return res
def GetAllChannels(self):
- AllChannels=[]
+ AllChannels = []
for CTNInstance in self.CTNParent.IterChildren():
if CTNInstance != self:
AllChannels.append(CTNInstance.BaseParams.getIEC_Channel())
@@ -441,20 +444,20 @@
# Get Current IEC channel
CurrentChannel = self.BaseParams.getIEC_Channel()
# Do nothing if no change
- #if CurrentChannel == DesiredChannel: return CurrentChannel
+ # if CurrentChannel == DesiredChannel: return CurrentChannel
# Build a list of used Channels out of parent's Children
AllChannels = self.GetAllChannels()
-
+
# Now, try to guess the nearest available channel
res = DesiredChannel
- while res in AllChannels: # While channel not free
- if res < CurrentChannel: # Want to go down ?
- res -= 1 # Test for n-1
- if res < 0 :
- self.GetCTRoot().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
+ 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.GetCTRoot().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
@@ -466,14 +469,14 @@
if self.EditorType is not None:
app_frame = self.GetCTRoot().AppFrame
if self._View is None and not onlyopened:
-
+
self._View = self.EditorType(app_frame.TabsOpened, self, app_frame)
-
+
if self._View is not None:
if name is None:
name = self.CTNFullName()
app_frame.EditProjectElement(self._View, name)
-
+
return self._View
return None
@@ -508,7 +511,7 @@
def CTNRemove(self):
# Fetch the confnode
- #CTNInstance = self.GetChildByName(CTNName)
+ # CTNInstance = self.GetChildByName(CTNName)
# Ask to his parent to remove it
self.CTNParent._doRemoveChild(self)
@@ -521,29 +524,31 @@
# reorganize self.CTNChildrenTypes tuples from (name, CTNClass, Help)
# to ( name, (CTNClass, Help)), an make a dict
transpose = zip(*self.CTNChildrenTypes)
- CTNChildrenTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2])))
+ CTNChildrenTypes = dict(zip(transpose[0], zip(transpose[1], transpose[2])))
# Check that adding this confnode is allowed
try:
CTNClass, CTNHelp = CTNChildrenTypes[CTNType]
except KeyError:
- raise Exception, _("Cannot create child {a1} of type {a2} ").format(a1 = CTNName, a2 = CTNType)
-
+ raise Exception(_("Cannot create child {a1} of type {a2} ").
+ format(a1=CTNName, a2=CTNType))
+
# if CTNClass is a class factory, call it. (prevent unneeded imports)
- if type(CTNClass) == types.FunctionType:
+ if isinstance(CTNClass, types.FunctionType):
CTNClass = CTNClass()
-
+
# Eventualy Initialize child instance list for this class of confnode
ChildrenWithSameClass = self.Children.setdefault(CTNType, list())
# Check count
if getattr(CTNClass, "CTNMaxCount", None) and len(ChildrenWithSameClass) >= CTNClass.CTNMaxCount:
- msg = _("Max count ({a1}) reached for this confnode of type {a2} ").format(a1 = CTNClass.CTNMaxCount, a2 = CTNType)
- raise Exception, msg
-
+ raise Exception(
+ _("Max count ({a1}) reached for this confnode of type {a2} ").
+ format(a1=CTNClass.CTNMaxCount, a2=CTNType))
+
# create the final class, derived of provided confnode and template
class FinalCTNClass(CTNClass, ConfigTreeNode):
"""
ConfNode class is derivated into FinalCTNClass before being instanciated
- This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called
+ This way __init__ is overloaded to ensure ConfigTreeNode.__init__ is called
before CTNClass.__init__, and to do the file related stuff.
"""
def __init__(_self):
@@ -558,25 +563,25 @@
# check name is unique
NewCTNName = _self.FindNewName(CTNName)
# If dir have already be made, and file exist
- if os.path.isdir(_self.CTNPath(NewCTNName)): #and os.path.isfile(_self.ConfNodeXmlFilePath(CTNName)):
- #Load the confnode.xml file into parameters members
+ if os.path.isdir(_self.CTNPath(NewCTNName)): # and os.path.isfile(_self.ConfNodeXmlFilePath(CTNName)):
+ # Load the confnode.xml file into parameters members
_self.LoadXMLParams(NewCTNName)
# Basic check. Better to fail immediately.
if (_self.BaseParams.getName() != NewCTNName):
- msg = _("Project tree layout do not match confnode.xml {a1}!={a2} ").\
- format(a1 = NewCTNName, a2 = _self.BaseParams.getName())
- raise Exception, msg
+ raise Exception(
+ _("Project tree layout do not match confnode.xml {a1}!={a2} ").
+ format(a1=NewCTNName, a2=_self.BaseParams.getName()))
# Now, self.CTNPath() should be OK
-
+
# Check that IEC_Channel is not already in use.
_self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
# Call the confnode real __init__
if getattr(CTNClass, "__init__", None):
CTNClass.__init__(_self)
- #Load and init all the children
+ # Load and init all the children
_self.LoadChildren()
- #just loaded, nothing to saved
+ # just loaded, nothing to saved
_self.ChangesToSave = False
else:
# If confnode do not have corresponding file/dirs - they will be created on Save
@@ -587,31 +592,31 @@
if getattr(CTNClass, "__init__", None):
CTNClass.__init__(_self)
_self.CTNRequestSave()
- #just created, must be saved
+ # just created, must be saved
_self.ChangesToSave = True
-
+
def _getBuildPath(_self):
return self._getBuildPath()
-
+
# Create the object out of the resulting class
newConfNodeOpj = FinalCTNClass()
# Store it in CTNgedChils
ChildrenWithSameClass.append(newConfNodeOpj)
-
+
return newConfNodeOpj
-
+
def ClearChildren(self):
for child in self.IterChildren():
child.ClearChildren()
self.Children = {}
-
- def LoadXMLParams(self, CTNName = None):
+
+ def LoadXMLParams(self, CTNName=None):
methode_name = os.path.join(self.CTNPath(CTNName), "methods.py")
if os.path.isfile(methode_name):
execfile(methode_name)
-
+
ConfNodeName = CTNName if CTNName is not None else self.CTNName()
-
+
# Get the base xml tree
if self.MandatoryParams:
try:
@@ -619,14 +624,14 @@
self.BaseParams, error = _BaseParamsParser.LoadXMLString(basexmlfile.read())
if error is not None:
(fname, lnum, src) = ((ConfNodeName + " BaseParams",) + error)
- self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src))
+ self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1=fname, a2=lnum, a3=src))
self.MandatoryParams = ("BaseParams", self.BaseParams)
basexmlfile.close()
except Exception, exc:
- msg = _("Couldn't load confnode base parameters {a1} :\n {a2}").format(a1 = ConfNodeName, a2 = unicode(exc))
+ msg = _("Couldn't load confnode base parameters {a1} :\n {a2}").format(a1=ConfNodeName, a2=unicode(exc))
self.GetCTRoot().logger.write_error(msg)
self.GetCTRoot().logger.write_error(traceback.format_exc())
-
+
# Get the xml tree
if self.CTNParams:
try:
@@ -634,16 +639,16 @@
obj, error = self.Parser.LoadXMLString(xmlfile.read())
if error is not None:
(fname, lnum, src) = ((ConfNodeName,) + error)
- self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname, a2 = lnum, a3 = src))
+ self.GetCTRoot().logger.write_warning(XSDSchemaErrorMessage.format(a1=fname, a2=lnum, a3=src))
name = obj.getLocalTag()
setattr(self, name, obj)
self.CTNParams = (name, obj)
xmlfile.close()
except Exception, exc:
- msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1 = ConfNodeName, a2 = unicode(exc))
+ msg = _("Couldn't load confnode parameters {a1} :\n {a2}").format(a1=ConfNodeName, a2=unicode(exc))
self.GetCTRoot().logger.write_error(msg)
self.GetCTRoot().logger.write_error(traceback.format_exc())
-
+
def LoadChildren(self):
# Iterate over all CTNName@CTNType in confnode directory, and try to open them
for CTNDir in os.listdir(self.CTNPath()):
@@ -653,7 +658,6 @@
try:
self.CTNAddChild(pname, ptype)
except Exception, exc:
- msg = _("Could not add child \"{a1}\", type {a2} :\n{a3}\n").format(a1 = pname, a2 = ptype, a3 = unicode(exc))
+ msg = _("Could not add child \"{a1}\", type {a2} :\n{a3}\n").format(a1=pname, a2=ptype, a3=unicode(exc))
self.GetCTRoot().logger.write_error(msg)
self.GetCTRoot().logger.write_error(traceback.format_exc())
-
--- a/IDEFrame.py Mon Aug 21 20:17:19 2017 +0000
+++ b/IDEFrame.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,11 +22,14 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys
+import os
+import sys
import cPickle
from types import TupleType
-
-import wx, wx.grid
+import base64
+
+import wx
+import wx.grid
import wx.aui
from editors.EditorPanel import EditorPanel
@@ -43,48 +46,51 @@
from util.BitmapLibrary import GetBitmap
# Define PLCOpenEditor controls id
-[ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK,
- ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK,
- ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORMAINSPLITTER,
- ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER,
- ID_PLCOPENEDITORLIBRARYPANEL, ID_PLCOPENEDITORLIBRARYSEARCHCTRL,
- ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT,
- ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED,
- ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR,
- ID_PLCOPENEDITORPROJECTPANEL,
+[
+ ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK,
+ ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK,
+ ID_PLCOPENEDITORPROJECTTREE, ID_PLCOPENEDITORMAINSPLITTER,
+ ID_PLCOPENEDITORSECONDSPLITTER, ID_PLCOPENEDITORTHIRDSPLITTER,
+ ID_PLCOPENEDITORLIBRARYPANEL, ID_PLCOPENEDITORLIBRARYSEARCHCTRL,
+ ID_PLCOPENEDITORLIBRARYTREE, ID_PLCOPENEDITORLIBRARYCOMMENT,
+ ID_PLCOPENEDITORTABSOPENED, ID_PLCOPENEDITORTABSOPENED,
+ ID_PLCOPENEDITOREDITORMENUTOOLBAR, ID_PLCOPENEDITOREDITORTOOLBAR,
+ ID_PLCOPENEDITORPROJECTPANEL,
] = [wx.NewId() for _init_ctrls in range(17)]
# Define PLCOpenEditor EditMenu extra items id
-[ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE,
- ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
- ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
- ID_PLCOPENEDITOREDITMENUFINDNEXT, ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
- ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, ID_PLCOPENEDITOREDITMENUADDRESOURCE
+[
+ ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, ID_PLCOPENEDITOREDITMENUADDDATATYPE,
+ ID_PLCOPENEDITOREDITMENUADDFUNCTION, ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
+ ID_PLCOPENEDITOREDITMENUADDPROGRAM, ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
+ ID_PLCOPENEDITOREDITMENUFINDNEXT, ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
+ ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, ID_PLCOPENEDITOREDITMENUADDRESOURCE
] = [wx.NewId() for _init_coll_EditMenu_Items in range(10)]
# Define PLCOpenEditor DisplayMenu extra items id
-[ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE,
- ID_PLCOPENEDITORDISPLAYMENUSWITCHPERSPECTIVE,
+[
+ ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE,
+ ID_PLCOPENEDITORDISPLAYMENUSWITCHPERSPECTIVE,
] = [wx.NewId() for _init_coll_DisplayMenu_Items in range(2)]
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# EditorToolBar definitions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Define PLCOpenEditor Toolbar items id
-[ID_PLCOPENEDITOREDITORTOOLBARSELECTION, ID_PLCOPENEDITOREDITORTOOLBARCOMMENT,
- ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, ID_PLCOPENEDITOREDITORTOOLBARBLOCK,
- ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, ID_PLCOPENEDITOREDITORTOOLBARWIRE,
- ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, ID_PLCOPENEDITOREDITORTOOLBARRUNG,
- ID_PLCOPENEDITOREDITORTOOLBARCOIL, ID_PLCOPENEDITOREDITORTOOLBARCONTACT,
- ID_PLCOPENEDITOREDITORTOOLBARBRANCH, ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP,
- ID_PLCOPENEDITOREDITORTOOLBARSTEP, ID_PLCOPENEDITOREDITORTOOLBARTRANSITION,
- ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE,
- ID_PLCOPENEDITOREDITORTOOLBARJUMP, ID_PLCOPENEDITOREDITORTOOLBARMOTION,
+[
+ ID_PLCOPENEDITOREDITORTOOLBARSELECTION, ID_PLCOPENEDITOREDITORTOOLBARCOMMENT,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, ID_PLCOPENEDITOREDITORTOOLBARBLOCK,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, ID_PLCOPENEDITOREDITORTOOLBARWIRE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, ID_PLCOPENEDITOREDITORTOOLBARRUNG,
+ ID_PLCOPENEDITOREDITORTOOLBARCOIL, ID_PLCOPENEDITOREDITORTOOLBARCONTACT,
+ ID_PLCOPENEDITOREDITORTOOLBARBRANCH, ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP,
+ ID_PLCOPENEDITOREDITORTOOLBARSTEP, ID_PLCOPENEDITOREDITORTOOLBARTRANSITION,
+ ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE,
+ ID_PLCOPENEDITOREDITORTOOLBARJUMP, ID_PLCOPENEDITOREDITORTOOLBARMOTION,
] = [wx.NewId() for _init_coll_DefaultEditorToolBar_Items in range(18)]
-
# Define behaviour of each Toolbar item according to current POU body type
# Informations meaning are in this order:
# - Item is toggled
@@ -94,102 +100,101 @@
# - Item icon filename
# - Item tooltip text
EditorToolBarItems = {
- "FBD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
- "move", _("Move the view")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
- "add_comment", _("Create a new comment")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
- "add_variable", _("Create a new variable")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
- "add_block", _("Create a new block")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
- "add_connection", _("Create a new connection"))],
- "LD" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
- "move", _("Move the view")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
- "add_comment", _("Create a new comment")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
- "add_powerrail", _("Create a new power rail")),
- (False, DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARRUNG, "OnRungTool",
- "add_rung", _("Create a new rung")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCOIL, "OnCoilTool",
- "add_coil", _("Create a new coil")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
- "add_contact", _("Create a new contact")),
- (False, DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARBRANCH, "OnBranchTool",
- "add_branch", _("Create a new branch")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
- "add_variable", _("Create a new variable")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
- "add_block", _("Create a new block")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
- "add_connection", _("Create a new connection"))],
- "SFC" : [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
- "move", _("Move the view")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
- "add_comment", _("Create a new comment")),
- (True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, "OnInitialStepTool",
- "add_initial_step", _("Create a new initial step")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARSTEP, "OnStepTool",
- "add_step", _("Create a new step")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, "OnTransitionTool",
- "add_transition", _("Create a new transition")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, "OnActionBlockTool",
- "add_action", _("Create a new action block")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, "OnDivergenceTool",
- "add_divergence", _("Create a new divergence")),
- (False, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARJUMP, "OnJumpTool",
- "add_jump", _("Create a new jump")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
- "add_variable", _("Create a new variable")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
- "add_block", _("Create a new block")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
- "add_connection", _("Create a new connection")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
- "add_powerrail", _("Create a new power rail")),
- (True, FREEDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
- "add_contact", _("Create a new contact"))],
- "ST" : [],
- "IL" : [],
- "debug": [(True, FREEDRAWING_MODE|DRIVENDRAWING_MODE,
- ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
- "move", _("Move the view"))],
+ "FBD": [(True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
+ "add_connection", _("Create a new connection"))],
+ "LD": [(True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
+ "add_powerrail", _("Create a new power rail")),
+ (False, DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARRUNG, "OnRungTool",
+ "add_rung", _("Create a new rung")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOIL, "OnCoilTool",
+ "add_coil", _("Create a new coil")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
+ "add_contact", _("Create a new contact")),
+ (False, DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBRANCH, "OnBranchTool",
+ "add_branch", _("Create a new branch")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
+ "add_connection", _("Create a new connection"))],
+ "SFC": [(True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCOMMENT, "OnCommentTool",
+ "add_comment", _("Create a new comment")),
+ (True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARINITIALSTEP, "OnInitialStepTool",
+ "add_initial_step", _("Create a new initial step")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARSTEP, "OnStepTool",
+ "add_step", _("Create a new step")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARTRANSITION, "OnTransitionTool",
+ "add_transition", _("Create a new transition")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARACTIONBLOCK, "OnActionBlockTool",
+ "add_action", _("Create a new action block")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARDIVERGENCE, "OnDivergenceTool",
+ "add_divergence", _("Create a new divergence")),
+ (False, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARJUMP, "OnJumpTool",
+ "add_jump", _("Create a new jump")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARVARIABLE, "OnVariableTool",
+ "add_variable", _("Create a new variable")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARBLOCK, "OnBlockTool",
+ "add_block", _("Create a new block")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONNECTION, "OnConnectionTool",
+ "add_connection", _("Create a new connection")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARPOWERRAIL, "OnPowerRailTool",
+ "add_powerrail", _("Create a new power rail")),
+ (True, FREEDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARCONTACT, "OnContactTool",
+ "add_contact", _("Create a new contact"))],
+ "ST": [],
+ "IL": [],
+ "debug": [(True, FREEDRAWING_MODE | DRIVENDRAWING_MODE,
+ ID_PLCOPENEDITOREDITORTOOLBARMOTION, "OnMotionTool",
+ "move", _("Move the view"))],
}
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helper Functions
-#-------------------------------------------------------------------------------
-
-import base64
+# -------------------------------------------------------------------------------
+
def EncodeFileSystemPath(path, use_base64=True):
path = path.encode(sys.getfilesystemencoding())
@@ -197,22 +202,29 @@
return base64.encodestring(path)
return path
+
def DecodeFileSystemPath(path, is_base64=True):
if is_base64:
path = base64.decodestring(path)
return unicode(path, sys.getfilesystemencoding())
-# Compatibility function for wx versions < 2.6
+
def AppendMenu(parent, help, id, kind, text):
+ """
+ Compatibility function for wx versions < 2.6
+ """
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)
-[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
- POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
+
+[
+ TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
+ POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
] = range(10)
+
def GetShortcutKeyCallbackFunction(viewer_function):
def ShortcutKeyFunction(self, event):
control = self.FindFocus()
@@ -224,6 +236,7 @@
control.ProcessEvent(event)
return ShortcutKeyFunction
+
def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
def DeleteElementFunction(self, selected):
name = self.ProjectTree.GetItemText(selected)
@@ -236,6 +249,7 @@
remove_function(self.Controler, name)
return DeleteElementFunction
+
if wx.Platform == '__WXMSW__':
TAB_BORDER = 6
NOTEBOOK_BORDER = 6
@@ -243,15 +257,16 @@
TAB_BORDER = 7
NOTEBOOK_BORDER = 2
+
def SimplifyTabLayout(tabs, rect):
for tab in tabs:
if tab["pos"][0] == rect.x:
others = [t for t in tabs if t != tab]
- others.sort(lambda x,y: cmp(x["pos"][0], y["pos"][0]))
+ others.sort(lambda x, y: cmp(x["pos"][0], y["pos"][0]))
for other in others:
- if (other["pos"][1] == tab["pos"][1] and
- other["size"][1] == tab["size"][1] and
- other["pos"][0] == tab["pos"][0] + tab["size"][0] + TAB_BORDER):
+ if other["pos"][1] == tab["pos"][1] and \
+ other["size"][1] == tab["size"][1] and \
+ other["pos"][0] == tab["pos"][0] + tab["size"][0] + TAB_BORDER:
tab["size"] = (tab["size"][0] + other["size"][0] + TAB_BORDER, tab["size"][1])
tab["pages"].extend(other["pages"])
@@ -262,11 +277,11 @@
elif tab["pos"][1] == rect.y:
others = [t for t in tabs if t != tab]
- others.sort(lambda x,y: cmp(x["pos"][1], y["pos"][1]))
+ others.sort(lambda x, y: cmp(x["pos"][1], y["pos"][1]))
for other in others:
- if (other["pos"][0] == tab["pos"][0] and
- other["size"][0] == tab["size"][0] and
- other["pos"][1] == tab["pos"][1] + tab["size"][1] + TAB_BORDER):
+ if other["pos"][0] == tab["pos"][0] and \
+ other["size"][0] == tab["size"][0] and \
+ other["pos"][1] == tab["pos"][1] + tab["size"][1] + TAB_BORDER:
tab["size"] = (tab["size"][0], tab["size"][1] + other["size"][1] + TAB_BORDER)
tab["pages"].extend(other["pages"])
@@ -276,6 +291,7 @@
return True
return False
+
def ComputeTabsLayout(tabs, rect):
if len(tabs) == 0:
return tabs
@@ -284,7 +300,7 @@
split = None
for idx, tab in enumerate(tabs):
if len(tab["pages"]) == 0:
- raise ValueError, "Not possible"
+ raise ValueError("Not possible")
if tab["size"][0] == rect.width:
if tab["pos"][1] == rect.y:
split = (wx.TOP, float(tab["size"][1]) / float(rect.height))
@@ -305,7 +321,7 @@
split_rect = wx.Rect(rect.x, rect.y,
rect.width - tab["size"][0] - TAB_BORDER, rect.height)
break
- if split != None:
+ if split is not None:
split_tab = tabs.pop(idx)
return {"split": split,
"tab": split_tab,
@@ -315,17 +331,15 @@
return ComputeTabsLayout(tabs, rect)
return tabs
-#-------------------------------------------------------------------------------
-# IDEFrame Base Class
-#-------------------------------------------------------------------------------
UNEDITABLE_NAMES_DICT = dict([(_(name), name) for name in UNEDITABLE_NAMES])
+
class IDEFrame(wx.Frame):
-
+ """IDEFrame Base Class"""
# Compatibility function for wx versions < 2.6
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
@@ -342,79 +356,79 @@
def _init_coll_AddMenu_Items(self, parent, add_config=True):
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDDATATYPE,
- kind=wx.ITEM_NORMAL, text=_(u'&Data Type'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Data Type'))
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTION,
- kind=wx.ITEM_NORMAL, text=_(u'&Function'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Function'))
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK,
- kind=wx.ITEM_NORMAL, text=_(u'Function &Block'))
+ kind=wx.ITEM_NORMAL, text=_(u'Function &Block'))
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDPROGRAM,
- kind=wx.ITEM_NORMAL, text=_(u'&Program'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Program'))
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDRESOURCE,
- kind=wx.ITEM_NORMAL, text=_(u'&Resource'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Resource'))
if add_config:
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION,
- kind=wx.ITEM_NORMAL, text=_(u'&Configuration'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Configuration'))
def _init_coll_EditMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_UNDO,
- kind=wx.ITEM_NORMAL, text=_(u'Undo') + '\tCTRL+Z')
+ kind=wx.ITEM_NORMAL, text=_(u'Undo') + '\tCTRL+Z')
AppendMenu(parent, help='', id=wx.ID_REDO,
- kind=wx.ITEM_NORMAL, text=_(u'Redo') + '\tCTRL+Y')
- #AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
+ kind=wx.ITEM_NORMAL, text=_(u'Redo') + '\tCTRL+Y')
+ # AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
# kind=wx.ITEM_CHECK, text=_(u'Enable Undo/Redo'))
- enable_undo_redo = _(u'Enable Undo/Redo') # Keeping text in translations for possible menu reactivation
+ enable_undo_redo = _(u'Enable Undo/Redo') # Keeping text in translations for possible menu reactivation
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_CUT,
- kind=wx.ITEM_NORMAL, text=_(u'Cut') + '\tCTRL+X')
+ kind=wx.ITEM_NORMAL, text=_(u'Cut') + '\tCTRL+X')
AppendMenu(parent, help='', id=wx.ID_COPY,
- kind=wx.ITEM_NORMAL, text=_(u'Copy') + '\tCTRL+C')
+ kind=wx.ITEM_NORMAL, text=_(u'Copy') + '\tCTRL+C')
AppendMenu(parent, help='', id=wx.ID_PASTE,
- kind=wx.ITEM_NORMAL, text=_(u'Paste') + '\tCTRL+V')
+ kind=wx.ITEM_NORMAL, text=_(u'Paste') + '\tCTRL+V')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_FIND,
- kind=wx.ITEM_NORMAL, text=_(u'Find') + '\tCTRL+F')
+ kind=wx.ITEM_NORMAL, text=_(u'Find') + '\tCTRL+F')
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDNEXT,
- kind=wx.ITEM_NORMAL, text=_(u'Find Next') + '\tCTRL+K')
+ kind=wx.ITEM_NORMAL, text=_(u'Find Next') + '\tCTRL+K')
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
- kind=wx.ITEM_NORMAL, text=_(u'Find Previous') + '\tCTRL+SHIFT+K')
+ kind=wx.ITEM_NORMAL, text=_(u'Find Previous') + '\tCTRL+SHIFT+K')
parent.AppendSeparator()
AppendMenu(parent, help='', id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT,
- kind=wx.ITEM_NORMAL, text=_(u'Search in Project') + '\tCTRL+SHIFT+F')
+ kind=wx.ITEM_NORMAL, text=_(u'Search in Project') + '\tCTRL+SHIFT+F')
parent.AppendSeparator()
add_menu = wx.Menu(title='')
self._init_coll_AddMenu_Items(add_menu)
parent.AppendMenu(wx.ID_ADD, _(u"&Add Element"), add_menu)
AppendMenu(parent, help='', id=wx.ID_SELECTALL,
- kind=wx.ITEM_NORMAL, text=_(u'Select All') + '\tCTRL+A')
+ kind=wx.ITEM_NORMAL, text=_(u'Select All') + '\tCTRL+A')
AppendMenu(parent, help='', id=wx.ID_DELETE,
- kind=wx.ITEM_NORMAL, text=_(u'&Delete'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Delete'))
self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO)
self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO)
- #self.Bind(wx.EVT_MENU, self.OnEnableUndoRedoMenu, id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO)
+ # self.Bind(wx.EVT_MENU, self.OnEnableUndoRedoMenu, id=ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO)
self.Bind(wx.EVT_MENU, self.OnCutMenu, id=wx.ID_CUT)
self.Bind(wx.EVT_MENU, self.OnCopyMenu, id=wx.ID_COPY)
self.Bind(wx.EVT_MENU, self.OnPasteMenu, id=wx.ID_PASTE)
self.Bind(wx.EVT_MENU, self.OnFindMenu, id=wx.ID_FIND)
self.Bind(wx.EVT_MENU, self.OnFindNextMenu,
- id=ID_PLCOPENEDITOREDITMENUFINDNEXT)
+ id=ID_PLCOPENEDITOREDITMENUFINDNEXT)
self.Bind(wx.EVT_MENU, self.OnFindPreviousMenu,
- id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS)
+ id=ID_PLCOPENEDITOREDITMENUFINDPREVIOUS)
self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu,
- id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
+ id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
self.Bind(wx.EVT_MENU, self.OnSearchInProjectMenu,
- id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
+ id=ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT)
self.Bind(wx.EVT_MENU, self.OnAddDataTypeMenu,
- id=ID_PLCOPENEDITOREDITMENUADDDATATYPE)
+ id=ID_PLCOPENEDITOREDITMENUADDDATATYPE)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("function"),
- id=ID_PLCOPENEDITOREDITMENUADDFUNCTION)
+ id=ID_PLCOPENEDITOREDITMENUADDFUNCTION)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("functionBlock"),
- id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK)
+ id=ID_PLCOPENEDITOREDITMENUADDFUNCTIONBLOCK)
self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction("program"),
- id=ID_PLCOPENEDITOREDITMENUADDPROGRAM)
+ id=ID_PLCOPENEDITOREDITMENUADDPROGRAM)
self.Bind(wx.EVT_MENU, self.AddResourceMenu,
- id=ID_PLCOPENEDITOREDITMENUADDRESOURCE)
+ id=ID_PLCOPENEDITOREDITMENUADDRESOURCE)
self.Bind(wx.EVT_MENU, self.OnAddConfigurationMenu,
- id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION)
+ id=ID_PLCOPENEDITOREDITMENUADDCONFIGURATION)
self.Bind(wx.EVT_MENU, self.OnSelectAllMenu, id=wx.ID_SELECTALL)
self.Bind(wx.EVT_MENU, self.OnDeleteMenu, id=wx.ID_DELETE)
@@ -429,17 +443,17 @@
def _init_coll_DisplayMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_REFRESH,
- kind=wx.ITEM_NORMAL, text=_(u'Refresh') + '\tCTRL+R')
+ kind=wx.ITEM_NORMAL, text=_(u'Refresh') + '\tCTRL+R')
if self.EnableDebug:
AppendMenu(parent, help='', id=wx.ID_CLEAR,
- kind=wx.ITEM_NORMAL, text=_(u'Clear Errors') + '\tCTRL+K')
+ kind=wx.ITEM_NORMAL, text=_(u'Clear Errors') + '\tCTRL+K')
parent.AppendSeparator()
zoommenu = wx.Menu(title='')
parent.AppendMenu(wx.ID_ZOOM_FIT, _("Zoom"), zoommenu)
for idx, value in enumerate(ZOOM_FACTORS):
new_id = wx.NewId()
AppendMenu(zoommenu, help='', id=new_id,
- kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%")
+ kind=wx.ITEM_RADIO, text=str(int(round(value * 100))) + "%")
self.Bind(wx.EVT_MENU, self.GenerateZoomFunction(idx), id=new_id)
parent.AppendSeparator()
@@ -448,7 +462,7 @@
self.Bind(wx.EVT_MENU, self.SwitchFullScrMode, id=ID_PLCOPENEDITORDISPLAYMENUSWITCHPERSPECTIVE)
AppendMenu(parent, help='', id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE,
- kind=wx.ITEM_NORMAL, text=_(u'Reset Perspective'))
+ kind=wx.ITEM_NORMAL, text=_(u'Reset Perspective'))
self.Bind(wx.EVT_MENU, self.OnResetPerspective, id=ID_PLCOPENEDITORDISPLAYMENURESETPERSPECTIVE)
self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH)
@@ -474,14 +488,14 @@
def _init_icon(self, parent):
if self.icon:
- self.SetIcon(self.icon)
+ self.SetIcon(self.icon)
elif parent and parent.icon:
- self.SetIcon(parent.icon)
-
+ self.SetIcon(parent.icon)
+
def _init_ctrls(self, prnt):
wx.Frame.__init__(self, id=ID_PLCOPENEDITOR, name='IDEFrame',
- parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600),
- style=wx.DEFAULT_FRAME_STYLE)
+ parent=prnt, pos=wx.DefaultPosition, size=wx.Size(1000, 600),
+ style=wx.DEFAULT_FRAME_STYLE)
self._init_icon(prnt)
self.SetClientSize(wx.Size(1000, 600))
self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
@@ -489,95 +503,113 @@
self.TabsImageList = wx.ImageList(31, 16)
self.TabsImageListIndexes = {}
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
# Creating main structure
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
self.AUIManager = wx.aui.AuiManager(self)
self.AUIManager.SetDockSizeConstraint(0.5, 0.5)
self.Panes = {}
- self.LeftNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORLEFTNOTEBOOK,
- style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
- wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
+ self.LeftNoteBook = wx.aui.AuiNotebook(
+ self, ID_PLCOPENEDITORLEFTNOTEBOOK,
+ style=(wx.aui.AUI_NB_TOP |
+ wx.aui.AUI_NB_TAB_SPLIT |
+ wx.aui.AUI_NB_TAB_MOVE |
+ wx.aui.AUI_NB_SCROLL_BUTTONS |
+ wx.aui.AUI_NB_TAB_EXTERNAL_MOVE))
self.LeftNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND,
- self.OnAllowNotebookDnD)
- self.AUIManager.AddPane(self.LeftNoteBook,
- wx.aui.AuiPaneInfo().Name("ProjectPane").
- Left().Layer(1).
- BestSize(wx.Size(300, 500)).CloseButton(False))
-
- self.BottomNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORBOTTOMNOTEBOOK,
- style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
- wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
+ self.OnAllowNotebookDnD)
+ self.AUIManager.AddPane(
+ self.LeftNoteBook,
+ wx.aui.AuiPaneInfo().Name("ProjectPane").Left().Layer(1).
+ BestSize(wx.Size(300, 500)).CloseButton(False))
+
+ self.BottomNoteBook = wx.aui.AuiNotebook(
+ self, ID_PLCOPENEDITORBOTTOMNOTEBOOK,
+ style=(wx.aui.AUI_NB_TOP |
+ wx.aui.AUI_NB_TAB_SPLIT |
+ wx.aui.AUI_NB_TAB_MOVE |
+ wx.aui.AUI_NB_SCROLL_BUTTONS |
+ wx.aui.AUI_NB_TAB_EXTERNAL_MOVE))
self.BottomNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND,
- self.OnAllowNotebookDnD)
- self.AUIManager.AddPane(self.BottomNoteBook,
- wx.aui.AuiPaneInfo().Name("ResultPane").
- Bottom().Layer(0).
- BestSize(wx.Size(800, 300)).CloseButton(False))
-
- self.RightNoteBook = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORRIGHTNOTEBOOK,
- style=wx.aui.AUI_NB_TOP|wx.aui.AUI_NB_TAB_SPLIT|wx.aui.AUI_NB_TAB_MOVE|
- wx.aui.AUI_NB_SCROLL_BUTTONS|wx.aui.AUI_NB_TAB_EXTERNAL_MOVE)
+ self.OnAllowNotebookDnD)
+ self.AUIManager.AddPane(
+ self.BottomNoteBook,
+ wx.aui.AuiPaneInfo().Name("ResultPane").Bottom().Layer(0).
+ BestSize(wx.Size(800, 300)).CloseButton(False))
+
+ self.RightNoteBook = wx.aui.AuiNotebook(
+ self, ID_PLCOPENEDITORRIGHTNOTEBOOK,
+ style=(wx.aui.AUI_NB_TOP |
+ wx.aui.AUI_NB_TAB_SPLIT |
+ wx.aui.AUI_NB_TAB_MOVE |
+ wx.aui.AUI_NB_SCROLL_BUTTONS |
+ wx.aui.AUI_NB_TAB_EXTERNAL_MOVE))
self.RightNoteBook.Bind(wx.aui.EVT_AUINOTEBOOK_ALLOW_DND,
- self.OnAllowNotebookDnD)
- self.AUIManager.AddPane(self.RightNoteBook,
- wx.aui.AuiPaneInfo().Name("LibraryPane").
- Right().Layer(0).
- BestSize(wx.Size(250, 400)).CloseButton(False))
-
- self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED,
- style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON)
+ self.OnAllowNotebookDnD)
+ self.AUIManager.AddPane(
+ self.RightNoteBook,
+ wx.aui.AuiPaneInfo().Name("LibraryPane").Right().Layer(0).
+ BestSize(wx.Size(250, 400)).CloseButton(False))
+
+ self.TabsOpened = wx.aui.AuiNotebook(
+ self, ID_PLCOPENEDITORTABSOPENED,
+ style=(wx.aui.AUI_NB_DEFAULT_STYLE |
+ wx.aui.AUI_NB_WINDOWLIST_BUTTON))
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING,
- self.OnPouSelectedChanging)
+ self.OnPouSelectedChanging)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED,
- self.OnPouSelectedChanged)
+ self.OnPouSelectedChanged)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
- self.OnPageClose)
+ self.OnPageClose)
self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
- self.OnPageDragged)
+ self.OnPageDragged)
self.AUIManager.AddPane(self.TabsOpened,
- wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane"))
-
- #-----------------------------------------------------------------------
+ wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane"))
+
+ # -----------------------------------------------------------------------
# Creating PLCopen Project Types Tree
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
self.MainTabs = {}
- self.ProjectPanel = wx.SplitterWindow(id=ID_PLCOPENEDITORPROJECTPANEL,
- name='ProjectPanel', parent=self.LeftNoteBook, point=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.SP_3D)
+ self.ProjectPanel = wx.SplitterWindow(
+ id=ID_PLCOPENEDITORPROJECTPANEL,
+ name='ProjectPanel', parent=self.LeftNoteBook, point=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.SP_3D)
self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE,
- name='ProjectTree', parent=self.ProjectPanel,
- pos=wx.Point(0, 0), size=wx.Size(0, 0),
- style=wx.SUNKEN_BORDER,
- agwStyle=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.TR_EDIT_LABELS)
+ name='ProjectTree',
+ parent=self.ProjectPanel,
+ pos=wx.Point(0, 0), size=wx.Size(0, 0),
+ style=wx.SUNKEN_BORDER,
+ agwStyle=(wx.TR_HAS_BUTTONS |
+ wx.TR_SINGLE |
+ wx.TR_EDIT_LABELS))
self.ProjectTree.SetBackgroundBitmap(GetBitmap("custom_tree_background"),
- wx.ALIGN_RIGHT|wx.ALIGN_BOTTOM)
+ wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM)
add_menu = wx.Menu()
self._init_coll_AddMenu_Items(add_menu)
self.ProjectTree.SetAddMenu(add_menu)
self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp)
self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnProjectTreeItemEndEdit,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ id=ID_PLCOPENEDITORPROJECTTREE)
self.ProjectTree.Bind(wx.EVT_MOTION, self.OnProjectTreeMotion)
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
# Creating PLCopen Project POU Instance Variables Panel
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
self.PouInstanceVariablesPanel = PouInstanceVariablesPanel(self.ProjectPanel, self, self.Controler, self.EnableDebug)
@@ -586,46 +618,50 @@
self.ProjectPanel.SplitHorizontally(self.ProjectTree, self.PouInstanceVariablesPanel, 300)
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
# Creating Tool Bar
- #-----------------------------------------------------------------------
-
- MenuToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORMENUTOOLBAR, wx.DefaultPosition, wx.DefaultSize,
- wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
+ # -----------------------------------------------------------------------
+
+ MenuToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORMENUTOOLBAR,
+ wx.DefaultPosition, wx.DefaultSize,
+ wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
MenuToolBar.SetToolBitmapSize(wx.Size(25, 25))
MenuToolBar.Realize()
self.Panes["MenuToolBar"] = MenuToolBar
self.AUIManager.AddPane(MenuToolBar, wx.aui.AuiPaneInfo().
- Name("MenuToolBar").Caption(_("Menu ToolBar")).
- ToolbarPane().Top().
- LeftDockable(False).RightDockable(False))
-
- EditorToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORTOOLBAR, wx.DefaultPosition, wx.DefaultSize,
- wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
+ Name("MenuToolBar").Caption(_("Menu ToolBar")).
+ ToolbarPane().Top().
+ LeftDockable(False).RightDockable(False))
+
+ EditorToolBar = wx.ToolBar(self, ID_PLCOPENEDITOREDITORTOOLBAR,
+ wx.DefaultPosition, wx.DefaultSize,
+ wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
EditorToolBar.SetToolBitmapSize(wx.Size(25, 25))
EditorToolBar.AddRadioTool(ID_PLCOPENEDITOREDITORTOOLBARSELECTION,
- GetBitmap("select"), wx.NullBitmap, _("Select an object"))
+ GetBitmap("select"),
+ wx.NullBitmap,
+ _("Select an object"))
EditorToolBar.Realize()
self.Panes["EditorToolBar"] = EditorToolBar
self.AUIManager.AddPane(EditorToolBar, wx.aui.AuiPaneInfo().
- Name("EditorToolBar").Caption(_("Editor ToolBar")).
- ToolbarPane().Top().Position(1).
- LeftDockable(False).RightDockable(False))
+ Name("EditorToolBar").Caption(_("Editor ToolBar")).
+ ToolbarPane().Top().Position(1).
+ LeftDockable(False).RightDockable(False))
self.Bind(wx.EVT_MENU, self.OnSelectionTool,
- id=ID_PLCOPENEDITOREDITORTOOLBARSELECTION)
-
- #-----------------------------------------------------------------------
+ id=ID_PLCOPENEDITOREDITORTOOLBARSELECTION)
+
+ # -----------------------------------------------------------------------
# Creating Search Panel
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
self.SearchResultPanel = SearchResultPanel(self.BottomNoteBook, self)
self.MainTabs["SearchResultPanel"] = (self.SearchResultPanel, _("Search"))
self.BottomNoteBook.AddPage(*self.MainTabs["SearchResultPanel"])
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
# Creating Library Panel
- #-----------------------------------------------------------------------
+ # -----------------------------------------------------------------------
self.LibraryPanel = LibraryPanel(self, True)
self.MainTabs["LibraryPanel"] = (self.LibraryPanel, _("Library"))
@@ -641,13 +677,7 @@
self.AUIManager.Update()
-
- ## Constructor of the PLCOpenEditor class.
- # @param parent The parent window.
- # @param controler The controler been used by PLCOpenEditor (default: None).
- # @param fileOpen The filepath to open if no controler defined (default: None).
- # @param debug The filepath to open if no controler defined (default: False).
- def __init__(self, parent, enable_debug = False):
+ def __init__(self, parent, enable_debug=False):
self.Controler = None
self.Config = wx.ConfigBase.Get()
self.EnableDebug = enable_debug
@@ -664,32 +694,32 @@
# Icons for other items
for imgname, itemtype in [
- #editables
- ("PROJECT", ITEM_PROJECT),
- #("POU", ITEM_POU),
- #("VARIABLE", ITEM_VARIABLE),
- ("TRANSITION", ITEM_TRANSITION),
- ("ACTION", ITEM_ACTION),
- ("CONFIGURATION", ITEM_CONFIGURATION),
- ("RESOURCE", ITEM_RESOURCE),
- ("DATATYPE", ITEM_DATATYPE),
- # uneditables
- ("DATATYPES", ITEM_DATATYPES),
- ("FUNCTION", ITEM_FUNCTION),
- ("FUNCTIONBLOCK", ITEM_FUNCTIONBLOCK),
- ("PROGRAM", ITEM_PROGRAM),
- ("VAR_LOCAL", ITEM_VAR_LOCAL),
- ("VAR_LOCAL", ITEM_VAR_GLOBAL),
- ("VAR_LOCAL", ITEM_VAR_EXTERNAL),
- ("VAR_LOCAL", ITEM_VAR_TEMP),
- ("VAR_INPUT", ITEM_VAR_INPUT),
- ("VAR_OUTPUT", ITEM_VAR_OUTPUT),
- ("VAR_INOUT", ITEM_VAR_INOUT),
- ("TRANSITIONS", ITEM_TRANSITIONS),
- ("ACTIONS", ITEM_ACTIONS),
- ("CONFIGURATIONS", ITEM_CONFIGURATIONS),
- ("RESOURCES", ITEM_RESOURCES),
- ("PROPERTIES", ITEM_PROPERTIES)]:
+ # editables
+ ("PROJECT", ITEM_PROJECT),
+ # ("POU", ITEM_POU),
+ # ("VARIABLE", ITEM_VARIABLE),
+ ("TRANSITION", ITEM_TRANSITION),
+ ("ACTION", ITEM_ACTION),
+ ("CONFIGURATION", ITEM_CONFIGURATION),
+ ("RESOURCE", ITEM_RESOURCE),
+ ("DATATYPE", ITEM_DATATYPE),
+ # uneditables
+ ("DATATYPES", ITEM_DATATYPES),
+ ("FUNCTION", ITEM_FUNCTION),
+ ("FUNCTIONBLOCK", ITEM_FUNCTIONBLOCK),
+ ("PROGRAM", ITEM_PROGRAM),
+ ("VAR_LOCAL", ITEM_VAR_LOCAL),
+ ("VAR_LOCAL", ITEM_VAR_GLOBAL),
+ ("VAR_LOCAL", ITEM_VAR_EXTERNAL),
+ ("VAR_LOCAL", ITEM_VAR_TEMP),
+ ("VAR_INPUT", ITEM_VAR_INPUT),
+ ("VAR_OUTPUT", ITEM_VAR_OUTPUT),
+ ("VAR_INOUT", ITEM_VAR_INOUT),
+ ("TRANSITIONS", ITEM_TRANSITIONS),
+ ("ACTIONS", ITEM_ACTIONS),
+ ("CONFIGURATIONS", ITEM_CONFIGURATIONS),
+ ("RESOURCES", ITEM_RESOURCES),
+ ("PROPERTIES", ITEM_PROPERTIES)]:
self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
# Assign icon list to TreeCtrls
@@ -703,7 +733,7 @@
self.SearchParams = None
self.Highlights = {}
self.DrawingMode = FREEDRAWING_MODE
- #self.DrawingMode = DRIVENDRAWING_MODE
+ # self.DrawingMode = DRIVENDRAWING_MODE
self.AuiTabCtrl = []
# Save default perspective
@@ -717,7 +747,6 @@
"notebooks": notebooks,
}
-
# Initialize Printing configuring elements
self.PrintData = wx.PrintData()
self.PrintData.SetPaperId(wx.PAPER_A4)
@@ -754,9 +783,9 @@
notebook.SetSelection(idx)
return
-#-------------------------------------------------------------------------------
-# Saving and restoring frame organization functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Saving and restoring frame organization functions
+ # -------------------------------------------------------------------------------
def GetTabInfos(self, tab):
for page_name, (page_ref, page_title) in self.MainTabs.iteritems():
@@ -774,7 +803,7 @@
tab_size = child.GetSize()
for page_idx in xrange(child.GetPageCount()):
page = child.GetWindowFromIdx(page_idx)
- if not tab.has_key("size"):
+ if "size" not in tab:
tab["size"] = (tab_size[0], tab_size[1] + page.GetSize()[1])
tab_infos = self.GetTabInfos(page)
if tab_infos is not None:
@@ -808,9 +837,9 @@
if isinstance(tabs, ListType):
if len(tabs) == 0:
return
- raise ValueError, "Not supported"
-
- if tabs.has_key("split"):
+ raise ValueError("Not supported")
+
+ if "split" in tabs:
self.LoadTabLayout(notebook, tabs["others"])
split_dir, split_ratio = tabs["split"]
@@ -867,26 +896,28 @@
self.Config.Flush()
-#-------------------------------------------------------------------------------
-# General Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # General Functions
+ # -------------------------------------------------------------------------------
def SetRefreshFunctions(self):
self.RefreshFunctions = {
- TITLE : self.RefreshTitle,
- EDITORTOOLBAR : self.RefreshEditorToolBar,
- FILEMENU : self.RefreshFileMenu,
- EDITMENU : self.RefreshEditMenu,
- DISPLAYMENU : self.RefreshDisplayMenu,
- PROJECTTREE : self.RefreshProjectTree,
- POUINSTANCEVARIABLESPANEL : self.RefreshPouInstanceVariablesPanel,
- LIBRARYTREE : self.RefreshLibraryPanel,
- SCALING : self.RefreshScaling,
+ TITLE: self.RefreshTitle,
+ EDITORTOOLBAR: self.RefreshEditorToolBar,
+ FILEMENU: self.RefreshFileMenu,
+ EDITMENU: self.RefreshEditMenu,
+ DISPLAYMENU: self.RefreshDisplayMenu,
+ PROJECTTREE: self.RefreshProjectTree,
+ POUINSTANCEVARIABLESPANEL: self.RefreshPouInstanceVariablesPanel,
+ LIBRARYTREE: self.RefreshLibraryPanel,
+ SCALING: self.RefreshScaling,
PAGETITLES: self.RefreshPageTitles}
- ## Call PLCOpenEditor refresh functions.
- # @param elements List of elements to refresh.
def _Refresh(self, *elements):
+ """Call Editor refresh functions.
+
+ :param elements: List of elements to refresh.
+ """
try:
for element in elements:
self.RefreshFunctions[element]()
@@ -894,9 +925,11 @@
# ignore exceptions caused by refresh while quitting
pass
- ## Callback function when AUINotebook Page closed with CloseButton
- # @param event AUINotebook Event.
def OnPageClose(self, event):
+ """Callback function when AUINotebook Page closed with CloseButton
+
+ :param event: AUINotebook Event.
+ """
selected = self.TabsOpened.GetSelection()
if selected > -1:
window = self.TabsOpened.GetPage(selected)
@@ -911,7 +944,6 @@
else:
event.Veto()
-
def GetCopyBuffer(self, primary_selection=False):
data = None
if primary_selection and wx.Platform == '__WXMSW__':
@@ -959,22 +991,20 @@
PROJECTTREE, POUINSTANCEVARIABLESPANEL, SCALING)
dialog.Destroy()
-#-------------------------------------------------------------------------------
-# Notebook Unified Functions
-#-------------------------------------------------------------------------------
-
- ## Function that add a tab in Notebook, calling refresh for tab DClick event
- # for wx.aui.AUINotebook.
- # @param window Panel to display in tab.
- # @param text title for the tab ctrl.
+ # -------------------------------------------------------------------------------
+ # Notebook Unified Functions
+ # -------------------------------------------------------------------------------
+
def AddPage(self, window, text):
+ """Function that add a tab in Notebook, calling refresh for tab DClick event
+ for wx.aui.AUINotebook.
+
+ :param window: Panel to display in tab.
+ :param text: title for the tab ctrl.
+ """
self.TabsOpened.AddPage(window, text)
self.RefreshTabCtrlEvent()
- ## Function that add a tab in Notebook, calling refresh for tab DClick event
- # for wx.aui.AUINotebook.
- # @param window Panel to display in tab.
- # @param text title for the tab ctrl.
def DeletePage(self, window):
for idx in xrange(self.TabsOpened.GetPageCount()):
if self.TabsOpened.GetPage(idx) == window:
@@ -982,37 +1012,44 @@
self.RefreshTabCtrlEvent()
return
- ## Function that fix difference in deleting all tabs between
- # wx.Notebook and wx.aui.AUINotebook.
def DeleteAllPages(self):
+ """Function that fix difference in deleting all tabs between
+ wx.Notebook and wx.aui.AUINotebook.
+ """
for idx in xrange(self.TabsOpened.GetPageCount()):
self.TabsOpened.DeletePage(0)
self.RefreshTabCtrlEvent()
- ## Function that fix difference in setting picture on tab between
- # wx.Notebook and wx.aui.AUINotebook.
- # @param idx Tab index.
- # @param bitmap wx.Bitmap to define on tab.
- # @return True if operation succeeded
def SetPageBitmap(self, idx, bitmap):
+ """Function that fix difference in setting picture on tab between
+ wx.Notebook and wx.aui.AUINotebook.
+
+ :param idx: Tab index.
+ :param bitmap: wx.Bitmap to define on tab.
+ :returns: True if operation succeeded
+ """
return self.TabsOpened.SetPageBitmap(idx, bitmap)
-#-------------------------------------------------------------------------------
-# Dialog Message Functions
-#-------------------------------------------------------------------------------
-
- ## Function displaying an Error dialog in PLCOpenEditor.
- # @param message The message to display.
+ # -------------------------------------------------------------------------------
+ # Dialog Message Functions
+ # -------------------------------------------------------------------------------
+
def ShowErrorMessage(self, message):
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ """Function displaying an Error dialog in editor.
+
+ :param message: The message to display.
+ """
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
- ## Function displaying an Error dialog in PLCOpenEditor.
- # @return False if closing cancelled.
def CheckSaveBeforeClosing(self, title=_("Close Project")):
+ """Function displaying an question dialog if project is not saved"
+
+ :returns: False if closing cancelled.
+ """
if not self.Controler.ProjectIsSaved():
- dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), title, wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+ dialog = wx.MessageDialog(self, _("There are changes, do you want to save?"), title, wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
if answer == wx.ID_YES:
@@ -1027,9 +1064,9 @@
return True
-#-------------------------------------------------------------------------------
-# File Menu Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # File Menu Functions
+ # -------------------------------------------------------------------------------
def RefreshFileMenu(self):
pass
@@ -1076,7 +1113,7 @@
preview = wx.PrintPreview(printout, printout2, data)
if preview.Ok():
- preview_frame = wx.PreviewFrame(preview, self, _("Print preview"), style=wx.DEFAULT_FRAME_STYLE|wx.FRAME_FLOAT_ON_PARENT)
+ preview_frame = wx.PreviewFrame(preview, self, _("Print preview"), style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT)
preview_frame.Initialize()
@@ -1108,9 +1145,9 @@
def OnQuitMenu(self, event):
self.Close()
-#-------------------------------------------------------------------------------
-# Edit Menu Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Edit Menu Functions
+ # -------------------------------------------------------------------------------
def RefreshEditMenu(self):
MenuToolBar = self.Panes["MenuToolBar"]
@@ -1125,14 +1162,14 @@
MenuToolBar.EnableTool(wx.ID_UNDO, undo)
self.EditMenu.Enable(wx.ID_REDO, redo)
MenuToolBar.EnableTool(wx.ID_REDO, redo)
- #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True)
- #self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
+ # self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, True)
+ # self.EditMenu.Check(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO,
# self.Controler.IsProjectBufferEnabled())
self.EditMenu.Enable(wx.ID_FIND, selected > -1)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDNEXT,
- selected > -1 and self.SearchParams is not None)
+ selected > -1 and self.SearchParams is not None)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUFINDPREVIOUS,
- selected > -1 and self.SearchParams is not None)
+ selected > -1 and self.SearchParams is not None)
self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True)
MenuToolBar.EnableTool(ID_PLCOPENEDITOREDITMENUSEARCHINPROJECT, True)
self.EditMenu.Enable(wx.ID_ADD, True)
@@ -1162,7 +1199,7 @@
MenuToolBar.EnableTool(wx.ID_UNDO, False)
self.EditMenu.Enable(wx.ID_REDO, False)
MenuToolBar.EnableTool(wx.ID_REDO, False)
- #self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, False)
+ # self.EditMenu.Enable(ID_PLCOPENEDITOREDITMENUENABLEUNDOREDO, False)
self.EditMenu.Enable(wx.ID_CUT, False)
MenuToolBar.EnableTool(wx.ID_CUT, False)
self.EditMenu.Enable(wx.ID_COPY, False)
@@ -1295,9 +1332,9 @@
self.SearchResultPanel.SetSearchResults(criteria, result)
self.SelectTab(self.SearchResultPanel)
-#-------------------------------------------------------------------------------
-# Display Menu Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Display Menu Functions
+ # -------------------------------------------------------------------------------
def RefreshDisplayMenu(self):
if self.Controler is not None:
@@ -1346,9 +1383,9 @@
def OnResetPerspective(self, event):
self.ResetPerspective()
-#-------------------------------------------------------------------------------
-# Project Editor Panels Management Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Project Editor Panels Management Functions
+ # -------------------------------------------------------------------------------
def OnPageDragged(self, event):
wx.CallAfter(self.RefreshTabCtrlEvent)
@@ -1453,7 +1490,7 @@
event.Skip()
return OnTabsOpenedDClick
- def SwitchFullScrMode(self,evt):
+ def SwitchFullScrMode(self, evt):
pane = self.AUIManager.GetPane(self.TabsOpened)
if pane.IsMaximized():
self.AUIManager.RestorePane(pane)
@@ -1461,9 +1498,9 @@
self.AUIManager.MaximizePane(pane)
self.AUIManager.Update()
-#-------------------------------------------------------------------------------
-# Types Tree Management Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Types Tree Management Functions
+ # -------------------------------------------------------------------------------
def RefreshProjectTree(self):
# Extract current selected item tagname
@@ -1499,16 +1536,16 @@
self.ProjectTree.SetItemTextColour(root, highlight_colours[1])
self.ProjectTree.SetItemExtraImage(root, None)
if infos["type"] == ITEM_POU:
- self.ProjectTree.SetItemImage(root,
- self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
+ self.ProjectTree.SetItemImage(
+ root, self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
if item_alone:
self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"]))
- elif infos.has_key("icon") and infos["icon"] is not None:
+ elif "icon" in infos and infos["icon"] is not None:
icon_name = infos["icon"]
- if not self.TreeImageDict.has_key(icon_name):
+ if icon_name not in self.TreeImageDict:
self.TreeImageDict[icon_name] = self.TreeImageList.Add(GetBitmap(icon_name))
self.ProjectTree.SetItemImage(root, self.TreeImageDict[icon_name])
- elif self.TreeImageDict.has_key(infos["type"]):
+ elif infos["type"] in self.TreeImageDict:
self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
item, root_cookie = self.ProjectTree.GetFirstChild(root)
@@ -1539,8 +1576,8 @@
root = self.ProjectTree.GetRootItem()
if root is not None and root.IsOk():
words = tagname.split("::")
- result = self.RecursiveProjectTreeItemSelection(root,
- zip(words[1:], self.TagNamePartsItemTypes.get(words[0], [])))
+ result = self.RecursiveProjectTreeItemSelection(
+ root, zip(words[1:], self.TagNamePartsItemTypes.get(words[0], [])))
return result
def RecursiveProjectTreeItemSelection(self, root, items):
@@ -1591,18 +1628,18 @@
new_name = event.GetLabel()
if new_name != "":
if not TestIdentifier(new_name):
- message = _("\"%s\" is not a valid identifier!")%new_name
+ message = _("\"%s\" is not a valid identifier!") % new_name
elif new_name.upper() in IEC_KEYWORDS:
- message = _("\"%s\" is a keyword. It can't be used!")%new_name
+ message = _("\"%s\" is a keyword. It can't be used!") % new_name
else:
item = event.GetItem()
old_name = self.ProjectTree.GetItemText(item)
item_infos = self.ProjectTree.GetPyData(item)
if item_infos["type"] == ITEM_PROJECT:
- self.Controler.SetProjectProperties(name = new_name)
+ self.Controler.SetProjectProperties(name=new_name)
elif item_infos["type"] == ITEM_DATATYPE:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectDataTypeNames() if name != old_name]:
- message = _("\"%s\" data type already exists!")%new_name
+ message = _("\"%s\" data type already exists!") % new_name
abort = True
if not abort:
self.Controler.ChangeDataTypeName(old_name, new_name)
@@ -1611,10 +1648,10 @@
self.RefreshPageTitles()
elif item_infos["type"] == ITEM_POU:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
- message = _("\"%s\" pou already exists!")%new_name
+ message = _("\"%s\" pou already exists!") % new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
- messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?") % new_name, _("Error"), wx.YES_NO | wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
@@ -1626,11 +1663,11 @@
self.RefreshPageTitles()
elif item_infos["type"] == ITEM_TRANSITION:
pou_item = self.ProjectTree.GetItemParent(event.GetItem())
- pou_name = self.ProjectTree.GetItemText(pou_item)
+ pou_name = self.ProjectTree.GetItemText(pou_item)
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
- message = _("A POU named \"%s\" already exists!")%new_name
+ message = _("A POU named \"%s\" already exists!") % new_name
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames(pou_name) if name != old_name]:
- message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
+ message = _("A variable with \"%s\" as name already exists in this pou!") % new_name
else:
words = item_infos["tagname"].split("::")
self.Controler.ChangePouTransitionName(words[1], old_name, new_name)
@@ -1641,9 +1678,9 @@
pou_item = self.ProjectTree.GetItemParent(event.GetItem())
pou_name = self.ProjectTree.GetItemText(pou_item)
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
- message = _("A POU named \"%s\" already exists!")%new_name
+ message = _("A POU named \"%s\" already exists!") % new_name
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames(pou_name) if name != old_name]:
- message = _("A variable with \"%s\" as name already exists in this pou!")%new_name
+ message = _("A variable with \"%s\" as name already exists in this pou!") % new_name
else:
words = item_infos["tagname"].split("::")
self.Controler.ChangePouActionName(words[1], old_name, new_name)
@@ -1652,15 +1689,15 @@
self.RefreshPageTitles()
elif item_infos["type"] == ITEM_CONFIGURATION:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames() if name != old_name]:
- message = _("\"%s\" config already exists!")%new_name
+ message = _("\"%s\" config already exists!") % new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
- messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?") % new_name, _("Error"), wx.YES_NO | wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
- messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?") % new_name, _("Error"), wx.YES_NO | wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
@@ -1671,15 +1708,15 @@
self.RefreshPageTitles()
elif item_infos["type"] == ITEM_RESOURCE:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectConfigNames()]:
- message = _("\"%s\" config already exists!")%new_name
+ message = _("\"%s\" config already exists!") % new_name
abort = True
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
- messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ messageDialog = wx.MessageDialog(self, _("There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?") % new_name, _("Error"), wx.YES_NO | wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariableNames()]:
- messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?")%new_name, _("Error"), wx.YES_NO|wx.ICON_QUESTION)
+ messageDialog = wx.MessageDialog(self, _("A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?") % new_name, _("Error"), wx.YES_NO | wx.ICON_QUESTION)
if messageDialog.ShowModal() == wx.ID_NO:
abort = True
messageDialog.Destroy()
@@ -1707,8 +1744,8 @@
self.EditProjectSettings()
else:
if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
- ITEM_CONFIGURATION, ITEM_RESOURCE,
- ITEM_TRANSITION, ITEM_ACTION]:
+ ITEM_CONFIGURATION, ITEM_RESOURCE,
+ ITEM_TRANSITION, ITEM_ACTION]:
self.EditProjectElement(item_infos["type"], item_infos["tagname"])
event.Skip()
@@ -1738,8 +1775,8 @@
if item != self.LastToolTipItem and self.LastToolTipItem is not None:
self.ProjectTree.SetToolTip(None)
self.LastToolTipItem = None
- if (self.LastToolTipItem != item and
- item_infos["type"] in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]):
+ if self.LastToolTipItem != item and \
+ item_infos["type"] in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
bodytype = self.Controler.GetEditedElementBodyType(
item_infos["tagname"])
if item_infos["type"] == ITEM_POU:
@@ -1754,8 +1791,8 @@
block_type = "Action"
self.LastToolTipItem = item
wx.CallAfter(self.ProjectTree.SetToolTipString,
- "%s : %s : %s" % (
- block_type, bodytype, item_infos["name"]))
+ "%s : %s : %s" % (
+ block_type, bodytype, item_infos["name"]))
elif self.LastToolTipItem is not None:
self.ProjectTree.SetToolTip(None)
self.LastToolTipItem = None
@@ -1768,7 +1805,7 @@
else:
event.Skip()
- def EditProjectElement(self, element, tagname, onlyopened = False):
+ def EditProjectElement(self, element, tagname, onlyopened=False):
openedidx = self.IsOpened(tagname)
if openedidx is not None:
old_selected = self.TabsOpened.GetSelection()
@@ -1862,7 +1899,7 @@
if name != "Project":
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add POU"))
- self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions" : "function", "Function Blocks" : "functionBlock", "Programs" : "program"}[name]), id=new_id)
+ self.Bind(wx.EVT_MENU, self.GenerateAddPouFunction({"Functions": "function", "Function Blocks": "functionBlock", "Programs": "program"}[name]), id=new_id)
new_id = wx.NewId()
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Paste POU"))
@@ -1970,10 +2007,9 @@
event.Skip()
-
-#-------------------------------------------------------------------------------
-# Instances Tree Management Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Instances Tree Management Functions
+ # -------------------------------------------------------------------------------
def GetTreeImage(self, var_class):
return self.TreeImageDict[var_class]
@@ -2056,16 +2092,16 @@
self.DebugVariablePanel.InsertValue(iec_path, force=force, graph=graph)
self.EnsureTabVisible(self.DebugVariablePanel)
-#-------------------------------------------------------------------------------
-# Library Panel Management Function
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Library Panel Management Function
+ # -------------------------------------------------------------------------------
def RefreshLibraryPanel(self):
self.LibraryPanel.RefreshTree()
-#-------------------------------------------------------------------------------
-# ToolBars Management Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # ToolBars Management Functions
+ # -------------------------------------------------------------------------------
def AddToMenuToolBar(self, items):
MenuToolBar = self.Panes["MenuToolBar"]
@@ -2133,10 +2169,9 @@
self.CurrentMenu = menu
self.ResetCurrentMode()
-
-#-------------------------------------------------------------------------------
-# EditorToolBar Items Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # EditorToolBar Items Functions
+ # -------------------------------------------------------------------------------
def ResetCurrentMode(self):
selected = self.TabsOpened.GetSelection()
@@ -2272,10 +2307,9 @@
else:
self.TabsOpened.GetPage(selected).AddJump()
-
-#-------------------------------------------------------------------------------
-# Add Project Elements Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Add Project Elements Functions
+ # -------------------------------------------------------------------------------
def OnAddNewProject(self, event):
# Asks user to create main program after creating new project
@@ -2290,7 +2324,7 @@
self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE)
self.EditProjectElement(ITEM_DATATYPE, tagname)
- def GenerateAddPouFunction(self, pou_type, type_readonly = False):
+ def GenerateAddPouFunction(self, pou_type, type_readonly=False):
def OnAddPouMenu(event):
dialog = PouDialog(self, pou_type, type_readonly)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
@@ -2383,7 +2417,7 @@
if self.ProjectTree.GetPyData(selected)["type"] != ITEM_PROJECT:
pou_type = self.ProjectTree.GetItemText(selected)
- pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs'
+ pou_type = UNEDITABLE_NAMES_DICT[pou_type] # one of 'Functions', 'Function Blocks' or 'Programs'
pou_type = {'Functions': 'function', 'Function Blocks': 'functionBlock', 'Programs': 'program'}[pou_type]
else:
pou_type = None
@@ -2398,17 +2432,18 @@
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
self.EditProjectElement(ITEM_POU, result[0])
-#-------------------------------------------------------------------------------
-# Remove Project Elements Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Remove Project Elements Functions
+ # -------------------------------------------------------------------------------
def CheckElementIsUsedBeforeDeletion(self, check_function, title, name):
if not check_function(name):
return True
- dialog = wx.MessageDialog(self,
+ dialog = wx.MessageDialog(
+ self,
_("\"%s\" is used by one or more POUs. Do you wish to continue?") % name,
- title, wx.YES_NO|wx.ICON_QUESTION)
+ title, wx.YES_NO | wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
return answer == wx.ID_YES
@@ -2502,9 +2537,9 @@
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL)
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def ShowHighlight(self, infos, start, end, highlight_type):
self.SelectProjectTreeItem(infos[0])
@@ -2541,14 +2576,17 @@
def ClearSearchResults(self):
self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Viewer Printout
-#-------------------------------------------------------------------------------
-
-UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
+# -------------------------------------------------------------------------------
+
+
+def UPPER_DIV(x, y):
+ return (x / y) + {True: 0, False: 1}[(x % y) == 0]
+
class GraphicPrintout(wx.Printout):
- def __init__(self, viewer, page_size, margins, preview = False):
+ def __init__(self, viewer, page_size, margins, preview=False):
wx.Printout.__init__(self)
self.Viewer = viewer
self.PageSize = page_size
@@ -2625,9 +2663,6 @@
dc.SetClippingRegion(posX, posY, self.PageSize[0] * scale, self.PageSize[1] * scale)
dc.SetUserScale(scale, scale)
- #-------------------------------------------
-
self.Viewer.DoDrawing(dc, True)
return True
-
--- a/NativeLib.py Mon Aug 21 20:17:19 2017 +0000
+++ b/NativeLib.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,7 +27,7 @@
import util.paths as paths
from POULibrary import POULibrary
+
class NativeLibrary(POULibrary):
def GetLibraryPath(self):
- return paths.AbsNeighbourFile(__file__, "NativeLib.xml")
-
+ return paths.AbsNeighbourFile(__file__, "NativeLib.xml")
--- a/PLCControler.py Mon Aug 21 20:17:19 2017 +0000
+++ b/PLCControler.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,47 +27,52 @@
from types import StringType, UnicodeType, TupleType
from lxml import etree
from copy import deepcopy
-import os,sys,re
+import os
+import sys
+import re
import datetime
import util.paths as paths
from time import localtime
from collections import OrderedDict, namedtuple
-
+from util.TranslationCatalogs import NoTranslate
from plcopen import *
from graphics.GraphicCommons import *
from PLCGenerator import *
duration_model = re.compile("(?:([0-9]{1,2})h)?(?:([0-9]{1,2})m(?!s))?(?:([0-9]{1,2})s)?(?:([0-9]{1,3}(?:\.[0-9]*)?)ms)?")
-ITEMS_EDITABLE = [ITEM_PROJECT,
- ITEM_POU,
- ITEM_VARIABLE,
- ITEM_TRANSITION,
- ITEM_ACTION,
- ITEM_CONFIGURATION,
- ITEM_RESOURCE,
- ITEM_DATATYPE
- ] = range(8)
-
-ITEMS_UNEDITABLE = [ITEM_DATATYPES,
- ITEM_FUNCTION,
- ITEM_FUNCTIONBLOCK,
- ITEM_PROGRAM,
- ITEM_TRANSITIONS,
- ITEM_ACTIONS,
- ITEM_CONFIGURATIONS,
- ITEM_RESOURCES,
- ITEM_PROPERTIES
- ] = range(8, 17)
-
-ITEMS_VARIABLE = [ITEM_VAR_LOCAL,
- ITEM_VAR_GLOBAL,
- ITEM_VAR_EXTERNAL,
- ITEM_VAR_TEMP,
- ITEM_VAR_INPUT,
- ITEM_VAR_OUTPUT,
- ITEM_VAR_INOUT
- ] = range(17, 24)
+ITEMS_EDITABLE = [
+ ITEM_PROJECT,
+ ITEM_POU,
+ ITEM_VARIABLE,
+ ITEM_TRANSITION,
+ ITEM_ACTION,
+ ITEM_CONFIGURATION,
+ ITEM_RESOURCE,
+ ITEM_DATATYPE
+] = range(8)
+
+ITEMS_UNEDITABLE = [
+ ITEM_DATATYPES,
+ ITEM_FUNCTION,
+ ITEM_FUNCTIONBLOCK,
+ ITEM_PROGRAM,
+ ITEM_TRANSITIONS,
+ ITEM_ACTIONS,
+ ITEM_CONFIGURATIONS,
+ ITEM_RESOURCES,
+ ITEM_PROPERTIES
+] = range(8, 17)
+
+ITEMS_VARIABLE = [
+ ITEM_VAR_LOCAL,
+ ITEM_VAR_GLOBAL,
+ ITEM_VAR_EXTERNAL,
+ ITEM_VAR_TEMP,
+ ITEM_VAR_INPUT,
+ ITEM_VAR_OUTPUT,
+ ITEM_VAR_INOUT
+] = range(17, 24)
VAR_CLASS_INFOS = {
"Local": ("localVars", ITEM_VAR_LOCAL),
@@ -78,10 +83,11 @@
"Output": ("outputVars", ITEM_VAR_OUTPUT),
"InOut": ("inOutVars", ITEM_VAR_INOUT)}
-POU_TYPES = {"program": ITEM_PROGRAM,
- "functionBlock": ITEM_FUNCTIONBLOCK,
- "function": ITEM_FUNCTION,
- }
+POU_TYPES = {
+ "program": ITEM_PROGRAM,
+ "functionBlock": ITEM_FUNCTIONBLOCK,
+ "function": ITEM_FUNCTION,
+}
LOCATIONS_ITEMS = [LOCATION_CONFNODE,
LOCATION_MODULE,
@@ -92,21 +98,22 @@
ScriptDirectory = paths.AbsDir(__file__)
+
def GetUneditableNames():
- _ = lambda x:x
+ _ = NoTranslate
return [_("User-defined POUs"), _("Functions"), _("Function Blocks"),
_("Programs"), _("Data Types"), _("Transitions"), _("Actions"),
_("Configurations"), _("Resources"), _("Properties")]
+
+
UNEDITABLE_NAMES = GetUneditableNames()
[USER_DEFINED_POUS, FUNCTIONS, FUNCTION_BLOCKS, PROGRAMS,
DATA_TYPES, TRANSITIONS, ACTIONS, CONFIGURATIONS,
RESOURCES, PROPERTIES] = UNEDITABLE_NAMES
-#-------------------------------------------------------------------------------
-# Helper object for loading library in xslt stylesheets
-#-------------------------------------------------------------------------------
class LibraryResolver(etree.Resolver):
+ """Helper object for loading library in xslt stylesheets"""
def __init__(self, controller, debug=False):
self.Controller = controller
@@ -126,32 +133,42 @@
lib_el.append(deepcopy(ctn["types"]))
return self.resolve_string(etree.tostring(lib_el), context)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers functions for translating list of arguments
# from xslt to valid arguments
-#-------------------------------------------------------------------------------
-
-_StringValue = lambda x: x
-_BoolValue = lambda x: x in ["true", "0"]
+# -------------------------------------------------------------------------------
+
+
+def _StringValue(x):
+ return x
+
+
+def _BoolValue(x):
+ return x in ["true", "0"]
+
def _translate_args(translations, args):
return [translate(arg[0]) if len(arg) > 0 else None
for translate, arg in
zip(translations, args)]
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers object for generating pou var list
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class _VariableInfos(object):
__slots__ = ["Name", "Class", "Option", "Location", "InitialValue",
"Edit", "Documentation", "Type", "Tree", "Number"]
+
def __init__(self, *args):
for attr, value in zip(self.__slots__, args):
setattr(self, attr, value if value is not None else "")
+
def copy(self):
return _VariableInfos(*[getattr(self, attr) for attr in self.__slots__])
+
class VariablesInfosFactory:
def __init__(self, variables):
@@ -188,9 +205,10 @@
[_StringValue] * 5 + [_BoolValue] + [_StringValue], args) +
[self.GetType(), self.GetTree()])))
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers object for generating pou variable instance list
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def class_extraction(value):
class_type = {
@@ -212,14 +230,18 @@
return None
+
class _VariablesTreeItemInfos(object):
__slots__ = ["name", "var_class", "type", "edit", "debug", "variables"]
+
def __init__(self, *args):
for attr, value in zip(self.__slots__, args):
setattr(self, attr, value if value is not None else "")
+
def copy(self):
return _VariableTreeItem(*[getattr(self, attr) for attr in self.__slots__])
+
class VariablesTreeInfosFactory:
def __init__(self):
@@ -241,23 +263,18 @@
[_StringValue, class_extraction, _StringValue] +
[_BoolValue] * 2, args) + [[]])))
-#-------------------------------------------------------------------------------
-# Helpers object for generating instances path list
-#-------------------------------------------------------------------------------
class InstancesPathFactory:
-
+ """Helpers object for generating instances path list"""
def __init__(self, instances):
self.Instances = instances
def AddInstance(self, context, *args):
self.Instances.append(args[0][0])
-#-------------------------------------------------------------------------------
-# Helpers object for generating instance tagname
-#-------------------------------------------------------------------------------
class InstanceTagName:
+ """Helpers object for generating instance tagname"""
def __init__(self, controller):
self.Controller = controller
@@ -281,13 +298,16 @@
def TransitionTagName(self, context, *args):
self.TagName = self.Controller.ComputePouTransitionName(args[0][0], args[0][1])
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Helpers object for generating pou block instances list
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
_Point = namedtuple("Point", ["x", "y"])
-_BlockInstanceInfos = namedtuple("BlockInstanceInfos",
+_BlockInstanceInfos = namedtuple(
+ "BlockInstanceInfos",
["type", "id", "x", "y", "width", "height", "specific_values", "inputs", "outputs"])
_BlockSpecificValues = (
@@ -347,20 +367,26 @@
[lambda x: x]),
}
-_InstanceConnectionInfos = namedtuple("InstanceConnectionInfos",
+_InstanceConnectionInfos = namedtuple(
+ "InstanceConnectionInfos",
["name", "negated", "edge", "position", "links"])
-_ConnectionLinkInfos = namedtuple("ConnectionLinkInfos",
+_ConnectionLinkInfos = namedtuple(
+ "ConnectionLinkInfos",
["refLocalId", "formalParameter", "points"])
+
class _ActionInfos(object):
__slots__ = ["qualifier", "type", "value", "duration", "indicator"]
+
def __init__(self, *args):
for attr, value in zip(self.__slots__, args):
setattr(self, attr, value if value is not None else "")
+
def copy(self):
return _ActionInfos(*[getattr(self, attr) for attr in self.__slots__])
+
class BlockInstanceFactory:
def __init__(self, block_instances):
@@ -380,8 +406,8 @@
specific_values_tuple, specific_values_translation = \
_SpecificValuesTuples.get(args[0][0], _BlockSpecificValues)
- if (args[0][0] == "step" and len(self.SpecificValues) < 3 or
- args[0][0] == "transition" and len(self.SpecificValues) < 4):
+ if args[0][0] == "step" and len(self.SpecificValues) < 3 or \
+ args[0][0] == "transition" and len(self.SpecificValues) < 4:
self.SpecificValues.append([None])
elif args[0][0] == "actionBlock" and len(self.SpecificValues) < 1:
self.SpecificValues.append([[]])
@@ -426,23 +452,25 @@
translated_args = _translate_args([_StringValue] * 5, args)
self.SpecificValues[0][0].append(_ActionInfos(*translated_args))
+
pou_block_instances_xslt = etree.parse(
os.path.join(ScriptDirectory, "plcopen", "pou_block_instances.xslt"))
-#-------------------------------------------------------------------------------
-# Undo Buffer for PLCOpenEditor
-#-------------------------------------------------------------------------------
# Length of the buffer
UNDO_BUFFER_LENGTH = 20
-"""
-Class implementing a buffer of changes made on the current editing model
-"""
+
class UndoBuffer:
-
- # Constructor initialising buffer
- def __init__(self, currentstate, issaved = False):
+ """
+ Undo Buffer for PLCOpenEditor
+ Class implementing a buffer of changes made on the current editing model
+ """
+
+ def __init__(self, currentstate, issaved=False):
+ """
+ Constructor initialising buffer
+ """
self.Buffer = []
self.CurrentIndex = -1
self.MinIndex = -1
@@ -464,8 +492,10 @@
else:
self.LastSave = -1
- # Add a new state in buffer
def Buffering(self, currentstate):
+ """
+ Add a new state in buffer
+ """
self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
self.Buffer[self.CurrentIndex] = currentstate
# Actualising buffer limits
@@ -477,8 +507,10 @@
self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
self.MinIndex = max(self.MinIndex, 0)
- # Return current state of buffer
def Current(self):
+ """
+ Return current state of buffer
+ """
return self.Buffer[self.CurrentIndex]
# Change current state to previous in buffer and return new current state
@@ -512,14 +544,11 @@
return self.LastSave == self.CurrentIndex
-#-------------------------------------------------------------------------------
-# Controler for PLCOpenEditor
-#-------------------------------------------------------------------------------
-
-"""
-Class which controls the operations made on the plcopen model and answers to view requests
-"""
class PLCControler:
+ """
+ Controler for PLCOpenEditor
+ Class which controls the operations made on the plcopen model and answers to view requests
+ """
# Create a new PLCControler
def __init__(self):
@@ -547,15 +576,15 @@
def GetQualifierTypes(self):
return QualifierList
- def GetProject(self, debug = False):
+ def GetProject(self, debug=False):
if debug and self.CurrentCompiledProject is not None:
return self.CurrentCompiledProject
else:
return self.Project
-#-------------------------------------------------------------------------------
-# Project management functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Project management functions
+ # -------------------------------------------------------------------------------
# Return if a project is opened
def HasOpenedProject(self):
@@ -579,28 +608,28 @@
self.Buffering = False
# Return project data type names
- def GetProjectDataTypeNames(self, debug = False):
+ def GetProjectDataTypeNames(self, debug=False):
project = self.GetProject(debug)
if project is not None:
return [datatype.getname() for datatype in project.getdataTypes()]
return []
# Return project pou names
- def GetProjectPouNames(self, debug = False):
+ def GetProjectPouNames(self, debug=False):
project = self.GetProject(debug)
if project is not None:
return [pou.getname() for pou in project.getpous()]
return []
# Return project pou names
- def GetProjectConfigNames(self, debug = False):
+ def GetProjectConfigNames(self, debug=False):
project = self.GetProject(debug)
if project is not None:
return [config.getname() for config in project.getconfigurations()]
return []
# Return project pou variable names
- def GetProjectPouVariableNames(self, pou_name = None, debug = False):
+ def GetProjectPouVariableNames(self, pou_name=None, debug=False):
variables = []
project = self.GetProject(debug)
if project is not None:
@@ -627,7 +656,7 @@
if self.ProjectIsSaved():
return self.FileName
else:
- return "~%s~"%self.FileName
+ return "~%s~" % self.FileName
return ""
# Change file path and save file name or create a default one if file path not defined
@@ -635,12 +664,12 @@
self.FilePath = filepath
if filepath == "":
self.LastNewIndex += 1
- self.FileName = _("Unnamed%d")%self.LastNewIndex
+ self.FileName = _("Unnamed%d") % self.LastNewIndex
else:
self.FileName = os.path.splitext(os.path.basename(filepath))[0]
# Change project properties
- def SetProjectProperties(self, name = None, properties = None, buffer = True):
+ def SetProjectProperties(self, name=None, properties=None, buffer=True):
if self.Project is not None:
if name is not None:
self.Project.setname(name)
@@ -658,7 +687,7 @@
return None
# Return project properties
- def GetProjectProperties(self, debug = False):
+ def GetProjectProperties(self, debug=False):
project = self.GetProject(debug)
if project is not None:
properties = project.getfileHeader()
@@ -667,17 +696,34 @@
return None
# Return project informations
- def GetProjectInfos(self, debug = False):
+ def GetProjectInfos(self, debug=False):
project = self.GetProject(debug)
if project is not None:
infos = {"name": project.getname(), "type": ITEM_PROJECT}
- datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values":[]}
+ datatypes = {"name": DATA_TYPES, "type": ITEM_DATATYPES, "values": []}
for datatype in project.getdataTypes():
- datatypes["values"].append({"name": datatype.getname(), "type": ITEM_DATATYPE,
- "tagname": self.ComputeDataTypeName(datatype.getname()), "values": []})
- pou_types = {"function": {"name": FUNCTIONS, "type": ITEM_FUNCTION, "values":[]},
- "functionBlock": {"name": FUNCTION_BLOCKS, "type": ITEM_FUNCTIONBLOCK, "values":[]},
- "program": {"name": PROGRAMS, "type": ITEM_PROGRAM, "values":[]}}
+ datatypes["values"].append({
+ "name": datatype.getname(),
+ "type": ITEM_DATATYPE,
+ "tagname": self.ComputeDataTypeName(datatype.getname()),
+ "values": []})
+ pou_types = {
+ "function": {
+ "name": FUNCTIONS,
+ "type": ITEM_FUNCTION,
+ "values": []
+ },
+ "functionBlock": {
+ "name": FUNCTION_BLOCKS,
+ "type": ITEM_FUNCTIONBLOCK,
+ "values": []
+ },
+ "program": {
+ "name": PROGRAMS,
+ "type": ITEM_PROGRAM,
+ "values": []
+ }
+ }
for pou in project.getpous():
pou_type = pou.getpouType()
pou_infos = {"name": pou.getname(), "type": ITEM_POU,
@@ -686,13 +732,17 @@
if pou.getbodyType() == "SFC":
transitions = []
for transition in pou.gettransitionList():
- transitions.append({"name": transition.getname(), "type": ITEM_TRANSITION,
+ transitions.append({
+ "name": transition.getname(),
+ "type": ITEM_TRANSITION,
"tagname": self.ComputePouTransitionName(pou.getname(), transition.getname()),
"values": []})
pou_values.append({"name": TRANSITIONS, "type": ITEM_TRANSITIONS, "values": transitions})
actions = []
for action in pou.getactionList():
- actions.append({"name": action.getname(), "type": ITEM_ACTION,
+ actions.append({
+ "name": action.getname(),
+ "type": ITEM_ACTION,
"tagname": self.ComputePouActionName(pou.getname(), action.getname()),
"values": []})
pou_values.append({"name": ACTIONS, "type": ITEM_ACTIONS, "values": actions})
@@ -702,13 +752,17 @@
configurations = {"name": CONFIGURATIONS, "type": ITEM_CONFIGURATIONS, "values": []}
for config in project.getconfigurations():
config_name = config.getname()
- config_infos = {"name": config_name, "type": ITEM_CONFIGURATION,
+ config_infos = {
+ "name": config_name,
+ "type": ITEM_CONFIGURATION,
"tagname": self.ComputeConfigurationName(config.getname()),
"values": []}
resources = {"name": RESOURCES, "type": ITEM_RESOURCES, "values": []}
for resource in config.getresource():
resource_name = resource.getname()
- resource_infos = {"name": resource_name, "type": ITEM_RESOURCE,
+ resource_infos = {
+ "name": resource_name,
+ "type": ITEM_RESOURCE,
"tagname": self.ComputeConfigurationResourceName(config.getname(), resource.getname()),
"values": []}
resources["values"].append(resource_infos)
@@ -719,7 +773,7 @@
return infos
return None
- def GetPouVariables(self, tagname, debug = False):
+ def GetPouVariables(self, tagname, debug=False):
pou_type = None
project = self.GetProject(debug)
if project is not None:
@@ -732,8 +786,8 @@
etree.parse(
os.path.join(ScriptDirectory, "plcopen", "pou_variables.xslt"),
parser),
- extensions = {("pou_vars_ns", name): getattr(factory, name)
- for name in ["SetRoot", "AddVariable"]})
+ extensions={("pou_vars_ns", name): getattr(factory, name)
+ for name in ["SetRoot", "AddVariable"]})
obj = None
words = tagname.split("::")
@@ -747,7 +801,7 @@
return None
- def GetInstanceList(self, root, name, debug = False):
+ def GetInstanceList(self, root, name, debug=False):
instances = []
project = self.GetProject(debug)
if project is not None:
@@ -760,15 +814,15 @@
etree.parse(
os.path.join(ScriptDirectory, "plcopen", "instances_path.xslt"),
parser),
- extensions = {
+ extensions={
("instances_ns", "AddInstance"): factory.AddInstance})
- instances_path_xslt_tree(root,
- instance_type=etree.XSLT.strparam(name))
+ instances_path_xslt_tree(
+ root, instance_type=etree.XSLT.strparam(name))
return instances
- def SearchPouInstances(self, tagname, debug = False):
+ def SearchPouInstances(self, tagname, debug=False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
@@ -784,7 +838,7 @@
self.ComputePouName(words[1]), debug)]
return []
- def GetPouInstanceTagName(self, instance_path, debug = False):
+ def GetPouInstanceTagName(self, instance_path, debug=False):
project = self.GetProject(debug)
factory = InstanceTagName(self)
@@ -795,17 +849,19 @@
etree.parse(
os.path.join(ScriptDirectory, "plcopen", "instance_tagname.xslt"),
parser),
- extensions = {("instance_tagname_ns", name): getattr(factory, name)
- for name in ["ConfigTagName", "ResourceTagName",
- "PouTagName", "ActionTagName",
- "TransitionTagName"]})
-
- instance_tagname_xslt_tree(project,
- instance_path=etree.XSLT.strparam(instance_path))
+ extensions={("instance_tagname_ns", name): getattr(factory, name)
+ for name in ["ConfigTagName",
+ "ResourceTagName",
+ "PouTagName",
+ "ActionTagName",
+ "TransitionTagName"]})
+
+ instance_tagname_xslt_tree(
+ project, instance_path=etree.XSLT.strparam(instance_path))
return factory.GetTagName()
- def GetInstanceInfos(self, instance_path, debug = False):
+ def GetInstanceInfos(self, instance_path, debug=False):
tagname = self.GetPouInstanceTagName(instance_path)
if tagname is not None:
infos = self.GetPouVariables(tagname, debug)
@@ -822,21 +878,21 @@
return None
# Return if data type given by name is used by another data type or pou
- def DataTypeIsUsed(self, name, debug = False):
+ def DataTypeIsUsed(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
return len(self.GetInstanceList(project, name, debug)) > 0
return False
# Return if pou given by name is used by another pou
- def PouIsUsed(self, name, debug = False):
+ def PouIsUsed(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
return len(self.GetInstanceList(project, name, debug)) > 0
return False
# Return if pou given by name is directly or undirectly used by the reference pou
- def PouIsUsedBy(self, name, reference, debug = False):
+ def PouIsUsedBy(self, name, reference, debug=False):
pou_infos = self.GetPou(reference, debug)
if pou_infos is not None:
return len(self.GetInstanceList(pou_infos, name, debug)) > 0
@@ -890,9 +946,9 @@
row, col = next_row, next_col
return infos
-#-------------------------------------------------------------------------------
-# Project Pous management functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Project Pous management functions
+ # -------------------------------------------------------------------------------
# Add a Data Type to Project
def ProjectAddDataType(self, datatype_name=None):
@@ -942,7 +998,7 @@
'''
try:
new_pou, error = LoadPou(pou_xml)
- except:
+ except Exception:
error = ""
if error is not None:
return _("Couldn't paste non-POU object.")
@@ -969,7 +1025,7 @@
# programs cannot be pasted as functions or function blocks
if orig_type == 'functionBlock' and pou_type == 'function' or \
orig_type == 'program' and pou_type in ['function', 'functionBlock']:
- msg = _('''{a1} "{a2}" can't be pasted as a {a3}.''').format(a1 = orig_type, a2 = name, a3 = pou_type)
+ msg = _('''{a1} "{a2}" can't be pasted as a {a3}.''').format(a1=orig_type, a2=name, a3=pou_type)
return msg
new_pou.setpouType(pou_type)
@@ -1139,7 +1195,7 @@
self.BufferProject()
# Return the description of the pou given by its name
- def GetPouDescription(self, name, debug = False):
+ def GetPouDescription(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its type
@@ -1149,7 +1205,7 @@
return ""
# Return the description of the pou given by its name
- def SetPouDescription(self, name, description, debug = False):
+ def SetPouDescription(self, name, description, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its type
@@ -1159,7 +1215,7 @@
self.BufferProject()
# Return the type of the pou given by its name
- def GetPouType(self, name, debug = False):
+ def GetPouType(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its type
@@ -1169,7 +1225,7 @@
return None
# Return pous with SFC language
- def GetSFCPous(self, debug = False):
+ def GetSFCPous(self, debug=False):
list = []
project = self.GetProject(debug)
if project is not None:
@@ -1179,7 +1235,7 @@
return list
# Return the body language of the pou given by its name
- def GetPouBodyType(self, name, debug = False):
+ def GetPouBodyType(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its body language
@@ -1189,7 +1245,7 @@
return None
# Return the actions of a pou
- def GetPouTransitions(self, pou_name, debug = False):
+ def GetPouTransitions(self, pou_name, debug=False):
transitions = []
project = self.GetProject(debug)
if project is not None:
@@ -1201,7 +1257,7 @@
return transitions
# Return the body language of the transition given by its name
- def GetTransitionBodyType(self, pou_name, pou_transition, debug = False):
+ def GetTransitionBodyType(self, pou_name, pou_transition, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name
@@ -1214,7 +1270,7 @@
return None
# Return the actions of a pou
- def GetPouActions(self, pou_name, debug = False):
+ def GetPouActions(self, pou_name, debug=False):
actions = []
project = self.GetProject(debug)
if project is not None:
@@ -1226,7 +1282,7 @@
return actions
# Return the body language of the pou given by its name
- def GetActionBodyType(self, pou_name, pou_action, debug = False):
+ def GetActionBodyType(self, pou_name, pou_action, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the pou correponding to name and return its body language
@@ -1332,17 +1388,17 @@
etree.parse(
os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
parser),
- extensions = {("var_infos_ns", name): getattr(factory, name)
- for name in ["SetType", "AddDimension", "AddTree",
- "AddVarToTree", "AddVariable"]})
- variables_infos_xslt_tree(object_with_vars,
- tree=etree.XSLT.strparam(str(tree)))
+ extensions={("var_infos_ns", name): getattr(factory, name)
+ for name in ["SetType", "AddDimension", "AddTree",
+ "AddVarToTree", "AddVariable"]})
+ variables_infos_xslt_tree(
+ object_with_vars, tree=etree.XSLT.strparam(str(tree)))
return variables
# Add a global var to configuration to configuration
def AddConfigurationGlobalVar(self, config_name, var_type, var_name,
- location="", description=""):
+ location="", description=""):
if self.Project is not None:
# Found the configuration corresponding to name
configuration = self.Project.getconfiguration(config_name)
@@ -1364,7 +1420,7 @@
in self.ExtractVarLists(vars)])
# Return the configuration globalvars
- def GetConfigurationGlobalVars(self, name, debug = False):
+ def GetConfigurationGlobalVars(self, name, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the configuration corresponding to name
@@ -1376,7 +1432,7 @@
return []
# Return configuration variable names
- def GetConfigurationVariableNames(self, config_name = None, debug = False):
+ def GetConfigurationVariableNames(self, config_name=None, debug=False):
variables = []
project = self.GetProject(debug)
if project is not None:
@@ -1384,7 +1440,8 @@
if config_name is None or config_name == configuration.getname():
variables.extend(
[var.getname() for var in reduce(
- lambda x, y: x + y, [varlist.getvariable()
+ lambda x, y: x + y, [
+ varlist.getvariable()
for varlist in configuration.globalVars],
[])])
return variables
@@ -1401,7 +1458,7 @@
in self.ExtractVarLists(vars)])
# Return the resource globalvars
- def GetConfigurationResourceGlobalVars(self, config_name, name, debug = False):
+ def GetConfigurationResourceGlobalVars(self, config_name, name, debug=False):
project = self.GetProject(debug)
if project is not None:
# Found the resource corresponding to name
@@ -1413,8 +1470,8 @@
return []
# Return resource variable names
- def GetConfigurationResourceVariableNames(self,
- config_name = None, resource_name = None, debug = False):
+ def GetConfigurationResourceVariableNames(
+ self, config_name=None, resource_name=None, debug=False):
variables = []
project = self.GetProject(debug)
if project is not None:
@@ -1424,13 +1481,14 @@
if resource_name is None or resource.getname() == resource_name:
variables.extend(
[var.getname() for var in reduce(
- lambda x, y: x + y, [varlist.getvariable()
+ lambda x, y: x + y, [
+ varlist.getvariable()
for varlist in resource.globalVars],
[])])
return variables
# Return the interface for the given pou
- def GetPouInterfaceVars(self, pou, tree=False, debug = False):
+ def GetPouInterfaceVars(self, pou, tree=False, debug=False):
interface = pou.interface
# Verify that the pou has an interface
if interface is not None:
@@ -1497,11 +1555,11 @@
etree.parse(
os.path.join(ScriptDirectory, "plcopen", "variables_infos.xslt"),
parser),
- extensions = {("var_infos_ns", name): getattr(factory, name)
- for name in ["SetType", "AddDimension",
- "AddTree", "AddVarToTree"]})
- return_type_infos_xslt_tree(return_type,
- tree=etree.XSLT.strparam(str(tree)))
+ extensions={("var_infos_ns", name): getattr(factory, name)
+ for name in ["SetType", "AddDimension",
+ "AddTree", "AddVarToTree"]})
+ return_type_infos_xslt_tree(
+ return_type, tree=etree.XSLT.strparam(str(tree)))
if tree:
return [factory.GetType(), factory.GetTree()]
return factory.GetType()
@@ -1516,11 +1574,11 @@
addedcat = [{"name": _("%s POUs") % confnodetypes["name"],
"list": [pou.getblockInfos()
for pou in confnodetypes["types"].getpous()]}
- for confnodetypes in typeslist]
+ for confnodetypes in typeslist]
self.TotalTypes.extend(addedcat)
for cat in addedcat:
for desc in cat["list"]:
- BlkLst = self.TotalTypesDict.setdefault(desc["name"],[])
+ BlkLst = self.TotalTypesDict.setdefault(desc["name"], [])
BlkLst.append((section["name"], desc))
# Function that clear the confnode list
@@ -1529,7 +1587,7 @@
self.TotalTypesDict = StdBlckDct.copy()
self.TotalTypes = StdBlckLst[:]
- def GetConfNodeDataTypes(self, exclude = None, only_locatables = False):
+ def GetConfNodeDataTypes(self, exclude=None, only_locatables=False):
return [{"name": _("%s Data Types") % confnodetypes["name"],
"list": [
datatype.getname()
@@ -1570,9 +1628,9 @@
return global_vars
# Function that returns the block definition associated to the block type given
- def GetBlockType(self, typename, inputs = None, debug = False):
+ def GetBlockType(self, typename, inputs=None, debug=False):
result_blocktype = None
- for sectioname, blocktype in self.TotalTypesDict.get(typename,[]):
+ for sectioname, blocktype in self.TotalTypesDict.get(typename, []):
if inputs is not None and inputs != "undefined":
block_inputs = tuple([var_type for name, var_type, modifier in blocktype["inputs"]])
if reduce(lambda x, y: x and y, map(lambda x: x[0] == "ANY" or self.IsOfType(*x), zip(inputs, block_inputs)), True):
@@ -1597,20 +1655,20 @@
return blocktype_infos
if inputs == tuple([var_type
- for name, var_type, modifier in blocktype_infos["inputs"]]):
+ for name, var_type, modifier in blocktype_infos["inputs"]]):
return blocktype_infos
return None
# Return Block types checking for recursion
- def GetBlockTypes(self, tagname = "", debug = False):
+ def GetBlockTypes(self, tagname="", debug=False):
typename = None
words = tagname.split("::")
name = None
project = self.GetProject(debug)
if project is not None:
pou_type = None
- if words[0] in ["P","T","A"]:
+ if words[0] in ["P", "T", "A"]:
name = words[1]
pou_type = self.GetPouType(name, debug)
filter = (["function"]
@@ -1621,35 +1679,38 @@
"list": [block for block in category["list"]
if block["type"] in filter]}
for category in self.TotalTypes]
- blocktypes.append({"name" : USER_DEFINED_POUS,
+ blocktypes.append({
+ "name": USER_DEFINED_POUS,
"list": [pou.getblockInfos()
for pou in project.getpous(name, filter)
if (name is None or
- len(self.GetInstanceList(pou, name, debug)) == 0)]})
+ len(self.GetInstanceList(pou, name, debug)) == 0)]
+ })
return blocktypes
return self.TotalTypes
# Return Function Block types checking for recursion
- def GetFunctionBlockTypes(self, tagname = "", debug = False):
+ def GetFunctionBlockTypes(self, tagname="", debug=False):
project = self.GetProject(debug)
words = tagname.split("::")
name = None
- if project is not None and words[0] in ["P","T","A"]:
+ if project is not None and words[0] in ["P", "T", "A"]:
name = words[1]
blocktypes = []
for blocks in self.TotalTypesDict.itervalues():
- for sectioname,block in blocks:
+ for sectioname, block in blocks:
if block["type"] == "functionBlock":
blocktypes.append(block["name"])
if project is not None:
- blocktypes.extend([pou.getname()
+ blocktypes.extend([
+ pou.getname()
for pou in project.getpous(name, ["functionBlock"])
if (name is None or
len(self.GetInstanceList(pou, name, debug)) == 0)])
return blocktypes
# Return Block types checking for recursion
- def GetBlockResource(self, debug = False):
+ def GetBlockResource(self, debug=False):
blocktypes = []
for category in StdBlckLst[:-1]:
for blocktype in category["list"]:
@@ -1663,7 +1724,7 @@
return blocktypes
# Return Data Types checking for recursion
- def GetDataTypes(self, tagname = "", basetypes = True, confnodetypes = True, only_locatables = False, debug = False):
+ def GetDataTypes(self, tagname="", basetypes=True, confnodetypes=True, only_locatables=False, debug=False):
if basetypes:
datatypes = self.GetBaseTypes()
else:
@@ -1677,16 +1738,16 @@
datatypes.extend([
datatype.getname()
for datatype in project.getdataTypes(name)
- if (not only_locatables or self.IsLocatableDataType(datatype, debug))
+ if ((not only_locatables or self.IsLocatableDataType(datatype, debug))
and (name is None or
- len(self.GetInstanceList(datatype, name, debug)) == 0)])
+ len(self.GetInstanceList(datatype, name, debug)) == 0))])
if confnodetypes:
for category in self.GetConfNodeDataTypes(name, only_locatables):
datatypes.extend(category["list"])
return datatypes
# Return Data Type Object
- def GetPou(self, typename, debug = False):
+ def GetPou(self, typename, debug=False):
project = self.GetProject(debug)
if project is not None:
result = project.getpou(typename)
@@ -1702,9 +1763,8 @@
return result
return None
-
# Return Data Type Object
- def GetDataType(self, typename, debug = False):
+ def GetDataType(self, typename, debug=False):
project = self.GetProject(debug)
if project is not None:
result = project.getdataType(typename)
@@ -1730,8 +1790,8 @@
return None
# Return Base Type of given possible derived type
- def GetBaseType(self, typename, debug = False):
- if TypeHierarchy.has_key(typename):
+ def GetBaseType(self, typename, debug=False):
+ if typename in TypeHierarchy:
return typename
datatype = self.GetDataType(typename, debug)
@@ -1749,9 +1809,9 @@
TypeHierarchy_list has a rough order to it (e.g. SINT, INT, DINT, ...),
which makes it easy for a user to find a type in a menu.
'''
- return [x for x,y in TypeHierarchy_list if not x.startswith("ANY")]
-
- def IsOfType(self, typename, reference, debug = False):
+ return [x for x, y in TypeHierarchy_list if not x.startswith("ANY")]
+
+ def IsOfType(self, typename, reference, debug=False):
if reference is None or typename == reference:
return True
@@ -1772,7 +1832,7 @@
return not typename.startswith("ANY")
return True
- def IsLocatableDataType(self, datatype, debug = False):
+ def IsLocatableDataType(self, datatype, debug=False):
basetype_content = datatype.baseType.getcontent()
basetype_content_type = basetype_content.getLocalTag()
if basetype_content_type in ["enum", "struct"]:
@@ -1785,20 +1845,20 @@
return self.IsLocatableType(array_base_type.getname(), debug)
return True
- def IsLocatableType(self, typename, debug = False):
+ def IsLocatableType(self, typename, debug=False):
if isinstance(typename, TupleType) or self.GetBlockType(typename) is not None:
return False
# the size of these types is implementation dependend
if typename in ["TIME", "DATE", "DT", "TOD"]:
return False
-
+
datatype = self.GetDataType(typename, debug)
if datatype is not None:
return self.IsLocatableDataType(datatype)
return True
- def IsEnumeratedType(self, typename, debug = False):
+ def IsEnumeratedType(self, typename, debug=False):
if isinstance(typename, TupleType):
typename = typename[1]
datatype = self.GetDataType(typename, debug)
@@ -1810,7 +1870,7 @@
return basetype_content_type == "enum"
return False
- def IsSubrangeType(self, typename, exclude=None, debug = False):
+ def IsSubrangeType(self, typename, exclude=None, debug=False):
if typename == exclude:
return False
if isinstance(typename, TupleType):
@@ -1826,11 +1886,11 @@
self.GetDataTypeBaseType(datatype), exclude)
return False
- def IsNumType(self, typename, debug = False):
+ def IsNumType(self, typename, debug=False):
return self.IsOfType(typename, "ANY_NUM", debug) or\
self.IsOfType(typename, "ANY_BIT", debug)
- def GetDataTypeRange(self, typename, debug = False):
+ def GetDataTypeRange(self, typename, debug=False):
range = DataTypeRange.get(typename)
if range is not None:
return range
@@ -1846,7 +1906,7 @@
return None
# Return Subrange types
- def GetSubrangeBaseTypes(self, exclude, debug = False):
+ def GetSubrangeBaseTypes(self, exclude, debug=False):
subrange_basetypes = DataTypeRange.keys()
project = self.GetProject(debug)
if project is not None:
@@ -1860,7 +1920,7 @@
return subrange_basetypes
# Return Enumerated Values
- def GetEnumeratedDataValues(self, typename = None, debug = False):
+ def GetEnumeratedDataValues(self, typename=None, debug=False):
values = []
if typename is not None:
datatype_obj = self.GetDataType(typename, debug)
@@ -1882,9 +1942,9 @@
values.extend(confnodetype["types"].GetEnumeratedDataTypeValues())
return values
-#-------------------------------------------------------------------------------
-# Project Element tag name computation functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Project Element tag name computation functions
+ # -------------------------------------------------------------------------------
# Compute a data type name
def ComputeDataTypeName(self, datatype):
@@ -1912,16 +1972,21 @@
def GetElementType(self, tagname):
words = tagname.split("::")
- return {"D" : ITEM_DATATYPE, "P" : ITEM_POU,
- "T" : ITEM_TRANSITION, "A" : ITEM_ACTION,
- "C" : ITEM_CONFIGURATION, "R" : ITEM_RESOURCE}[words[0]]
-
-#-------------------------------------------------------------------------------
-# Project opened Data types management functions
-#-------------------------------------------------------------------------------
+ return {
+ "D": ITEM_DATATYPE,
+ "P": ITEM_POU,
+ "T": ITEM_TRANSITION,
+ "A": ITEM_ACTION,
+ "C": ITEM_CONFIGURATION,
+ "R": ITEM_RESOURCE
+ }[words[0]]
+
+ # -------------------------------------------------------------------------------
+ # Project opened Data types management functions
+ # -------------------------------------------------------------------------------
# Return the data type informations
- def GetDataTypeInfos(self, tagname, debug = False):
+ def GetDataTypeInfos(self, tagname, debug=False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
@@ -1939,8 +2004,8 @@
base_type = basetype_content.baseType.getcontent()
base_type_type = base_type.getLocalTag()
infos["base_type"] = (base_type.getname()
- if base_type_type == "derived"
- else base_type_type)
+ if base_type_type == "derived"
+ else base_type_type)
elif basetype_content_type == "enum":
infos["type"] = "Enumerated"
infos["values"] = []
@@ -1954,8 +2019,8 @@
base_type = basetype_content.baseType.getcontent()
base_type_type = base_type.getLocalTag()
infos["base_type"] = (base_type.getname()
- if base_type_type == "derived"
- else base_type_type.upper())
+ if base_type_type == "derived"
+ else base_type_type.upper())
elif basetype_content_type == "struct":
infos["type"] = "Structure"
infos["elements"] = []
@@ -1971,9 +2036,10 @@
base_type = element_type.baseType.getcontent()
base_type_type = base_type.getLocalTag()
element_infos["Type"] = ("array",
- base_type.getname()
- if base_type_type == "derived"
- else base_type_type.upper(), dimensions)
+ base_type.getname()
+ if base_type_type == "derived"
+ else base_type_type.upper(),
+ dimensions)
elif element_type_type == "derived":
element_infos["Type"] = element_type.getname()
else:
@@ -1986,8 +2052,8 @@
else:
infos["type"] = "Directly"
infos["base_type"] = (basetype_content.getname()
- if basetype_content_type == "derived"
- else basetype_content_type.upper())
+ if basetype_content_type == "derived"
+ else basetype_content_type.upper())
if datatype.initialValue is not None:
infos["initial"] = datatype.initialValue.getvalue()
@@ -2116,12 +2182,12 @@
datatype.initialValue = None
self.BufferProject()
-#-------------------------------------------------------------------------------
-# Project opened Pous management functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Project opened Pous management functions
+ # -------------------------------------------------------------------------------
# Return edited element
- def GetEditedElement(self, tagname, debug = False):
+ def GetEditedElement(self, tagname, debug=False):
project = self.GetProject(debug)
if project is not None:
words = tagname.split("::")
@@ -2145,21 +2211,21 @@
# Return edited element name
def GetEditedElementName(self, tagname):
words = tagname.split("::")
- if words[0] in ["P","C","D"]:
+ if words[0] in ["P", "C", "D"]:
return words[1]
else:
return words[2]
return None
# Return edited element name and type
- def GetEditedElementType(self, tagname, debug = False):
+ def GetEditedElementType(self, tagname, debug=False):
words = tagname.split("::")
- if words[0] in ["P","T","A"]:
+ if words[0] in ["P", "T", "A"]:
return words[1], self.GetPouType(words[1], debug)
return None, None
# Return language in which edited element is written
- def GetEditedElementBodyType(self, tagname, debug = False):
+ def GetEditedElementBodyType(self, tagname, debug=False):
words = tagname.split("::")
if words[0] == "P":
return self.GetPouBodyType(words[1], debug)
@@ -2170,9 +2236,9 @@
return None
# Return the edited element variables
- def GetEditedElementInterfaceVars(self, tagname, tree=False, debug = False):
+ def GetEditedElementInterfaceVars(self, tagname, tree=False, debug=False):
words = tagname.split("::")
- if words[0] in ["P","T","A"]:
+ if words[0] in ["P", "T", "A"]:
project = self.GetProject(debug)
if project is not None:
pou = project.getpou(words[1])
@@ -2181,7 +2247,7 @@
return []
# Return the edited element return type
- def GetEditedElementInterfaceReturnType(self, tagname, tree=False, debug = False):
+ def GetEditedElementInterfaceReturnType(self, tagname, tree=False, debug=False):
words = tagname.split("::")
if words[0] == "P":
project = self.GetProject(debug)
@@ -2201,14 +2267,14 @@
element.settext(text)
# Return the edited element text
- def GetEditedElementText(self, tagname, debug = False):
+ def GetEditedElementText(self, tagname, debug=False):
element = self.GetEditedElement(tagname, debug)
if element is not None:
return element.gettext()
return ""
# Return the edited element transitions
- def GetEditedElementTransitions(self, tagname, debug = False):
+ def GetEditedElementTransitions(self, tagname, debug=False):
pou = self.GetEditedElement(tagname, debug)
if pou is not None and pou.getbodyType() == "SFC":
transitions = []
@@ -2218,7 +2284,7 @@
return []
# Return edited element transitions
- def GetEditedElementActions(self, tagname, debug = False):
+ def GetEditedElementActions(self, tagname, debug=False):
pou = self.GetEditedElement(tagname, debug)
if pou is not None and pou.getbodyType() == "SFC":
actions = []
@@ -2228,9 +2294,9 @@
return []
# Return the names of the pou elements
- def GetEditedElementVariables(self, tagname, debug = False):
+ def GetEditedElementVariables(self, tagname, debug=False):
words = tagname.split("::")
- if words[0] in ["P","T","A"]:
+ if words[0] in ["P", "T", "A"]:
return self.GetProjectPouVariableNames(words[1], debug)
elif words[0] in ["C", "R"]:
names = self.GetConfigurationVariableNames(words[1], debug)
@@ -2240,13 +2306,13 @@
return names
return []
- def GetEditedElementCopy(self, tagname, debug = False):
+ def GetEditedElementCopy(self, tagname, debug=False):
element = self.GetEditedElement(tagname, debug)
if element is not None:
return element.tostring()
return ""
- def GetEditedElementInstancesCopy(self, tagname, blocks_id = None, wires = None, debug = False):
+ def GetEditedElementInstancesCopy(self, tagname, blocks_id=None, wires=None, debug=False):
element = self.GetEditedElement(tagname, debug)
text = ""
if element is not None:
@@ -2273,14 +2339,15 @@
names.update(dict([(varname.upper(), True)
for varname in self.GetEditedElementVariables(tagname, debug)]))
words = tagname.split("::")
- if words[0] in ["P","T","A"]:
+ if words[0] in ["P", "T", "A"]:
element = self.GetEditedElement(tagname, debug)
if element is not None and element.getbodyType() not in ["ST", "IL"]:
for instance in element.getinstances():
- if isinstance(instance,
- (PLCOpenParser.GetElementClass("step", "sfcObjects"),
- PLCOpenParser.GetElementClass("connector", "commonObjects"),
- PLCOpenParser.GetElementClass("continuation", "commonObjects"))):
+ if isinstance(
+ instance,
+ (PLCOpenParser.GetElementClass("step", "sfcObjects"),
+ PLCOpenParser.GetElementClass("connector", "commonObjects"),
+ PLCOpenParser.GetElementClass("continuation", "commonObjects"))):
names[instance.getname().upper()] = True
else:
project = self.GetProject(debug)
@@ -2302,7 +2369,7 @@
i = start_idx
while name is None or names.get(name.upper(), False):
- name = (format%i)
+ name = (format % i)
i += 1
return name
@@ -2325,7 +2392,7 @@
try:
instances, error = LoadPouInstances(text, bodytype)
- except:
+ except Exception:
instances, error = [], ""
if error is not None or len(instances) == 0:
return _("Invalid plcopen element(s)!!!")
@@ -2340,10 +2407,10 @@
blockname = instance.getinstanceName()
if blocktype_infos["type"] != "function" and blockname is not None:
if element_type == "function":
- return _("FunctionBlock \"%s\" can't be pasted in a Function!!!")%blocktype
+ return _("FunctionBlock \"%s\" can't be pasted in a Function!!!") % blocktype
blockname = self.GenerateNewName(tagname,
blockname,
- "%s%%d"%blocktype,
+ "%s%%d" % blocktype,
debug=debug)
exclude[blockname] = True
instance.setinstanceName(blockname)
@@ -2357,7 +2424,7 @@
exclude[stepname] = True
instance.setname(stepname)
localid = instance.getlocalId()
- if not used_id.has_key(localid):
+ if localid not in used_id:
new_id[localid] = True
idx = 1
@@ -2366,8 +2433,8 @@
for instance in instances:
localId = instance.getlocalId()
bbox.union(instance.getBoundingBox())
- if used_id.has_key(localId):
- while used_id.has_key(idx) or new_id.has_key(idx):
+ if localId in used_id:
+ while (idx in used_id) or (idx in new_id):
idx += 1
new_id[idx] = True
instance.setlocalId(idx)
@@ -2404,7 +2471,7 @@
return new_id, connections
- def GetEditedElementInstancesInfos(self, tagname, debug = False):
+ def GetEditedElementInstancesInfos(self, tagname, debug=False):
element_instances = OrderedDict()
element = self.GetEditedElement(tagname, debug)
if element is not None:
@@ -2412,7 +2479,7 @@
pou_block_instances_xslt_tree = etree.XSLT(
pou_block_instances_xslt,
- extensions = {
+ extensions={
("pou_block_instances_ns", name): getattr(factory, name)
for name in ["AddBlockInstance", "SetSpecificValues",
"AddInstanceConnection", "AddConnectionLink",
@@ -2440,7 +2507,7 @@
result = wire.GetConnectedInfos(-1)
else:
result = wire.GetConnectedInfos(0)
- if result != None:
+ if result is not None:
refLocalId, formalParameter = result
connections = connection.getconnections()
if connections is None or len(connection.getconnections()) <= idx:
@@ -2465,7 +2532,7 @@
var_type_obj.setcontent(derived_type)
return var_type_obj
- def AddEditedElementPouVar(self, tagname, var_type, name,**args):
+ def AddEditedElementPouVar(self, tagname, var_type, name, **args):
if self.Project is not None:
words = tagname.split("::")
if words[0] in ['P', 'T', 'A']:
@@ -2500,7 +2567,7 @@
if pou is not None:
pou.removepouVar(type, name)
- def AddEditedElementBlock(self, tagname, id, blocktype, blockname = None):
+ def AddEditedElementBlock(self, tagname, id, blocktype, blockname=None):
element = self.GetEditedElement(tagname)
if element is not None:
block = PLCOpenParser.CreateElement("block", "fbdObjects")
@@ -3053,7 +3120,7 @@
self.RemoveEditedElementPouVar(tagname, instance.gettypeName(), instance.getinstanceName())
element.removeinstance(id)
- def GetEditedResourceVariables(self, tagname, debug = False):
+ def GetEditedResourceVariables(self, tagname, debug=False):
varlist = []
words = tagname.split("::")
for var in self.GetConfigurationGlobalVars(words[1], debug):
@@ -3076,17 +3143,17 @@
new_task.setname(task["Name"])
if task["Triggering"] == "Interrupt":
new_task.setsingle(task["Single"])
-## result = duration_model.match(task["Interval"]).groups()
-## if reduce(lambda x, y: x or y != None, result):
-## values = []
-## for value in result[:-1]:
-## if value != None:
-## values.append(int(value))
-## else:
-## values.append(0)
-## if result[-1] is not None:
-## values.append(int(float(result[-1]) * 1000))
-## new_task.setinterval(datetime.time(*values))
+# result = duration_model.match(task["Interval"]).groups()
+# if reduce(lambda x, y: x or y != None, result):
+# values = []
+# for value in result[:-1]:
+# if value != None:
+# values.append(int(value))
+# else:
+# values.append(0)
+# if result[-1] is not None:
+# values.append(int(float(result[-1]) * 1000))
+# new_task.setinterval(datetime.time(*values))
if task["Triggering"] == "Cyclic":
new_task.setinterval(task["Interval"])
new_task.setpriority(int(task["Priority"]))
@@ -3103,7 +3170,7 @@
new_instance.setname(instance["Name"])
new_instance.settypeName(instance["Type"])
- def GetEditedResourceInfos(self, tagname, debug = False):
+ def GetEditedResourceInfos(self, tagname, debug=False):
resource = self.GetEditedElement(tagname, debug)
if resource is not None:
tasks = resource.gettask()
@@ -3120,19 +3187,19 @@
new_task["Single"] = ""
interval = task.getinterval()
if interval is not None:
-## text = ""
-## if interval.hour != 0:
-## text += "%dh"%interval.hour
-## if interval.minute != 0:
-## text += "%dm"%interval.minute
-## if interval.second != 0:
-## text += "%ds"%interval.second
-## if interval.microsecond != 0:
-## if interval.microsecond % 1000 != 0:
-## text += "%.3fms"%(float(interval.microsecond) / 1000)
-## else:
-## text += "%dms"%(interval.microsecond / 1000)
-## new_task["Interval"] = text
+ # text = ""
+ # if interval.hour != 0:
+ # text += "%dh"%interval.hour
+ # if interval.minute != 0:
+ # text += "%dm"%interval.minute
+ # if interval.second != 0:
+ # text += "%ds"%interval.second
+ # if interval.microsecond != 0:
+ # if interval.microsecond % 1000 != 0:
+ # text += "%.3fms"%(float(interval.microsecond) / 1000)
+ # else:
+ # text += "%dms"%(interval.microsecond / 1000)
+ # new_task["Interval"] = text
new_task["Interval"] = interval
else:
new_task["Interval"] = ""
@@ -3172,7 +3239,7 @@
self.CurrentElementEditing = None
return error
- def SaveXMLFile(self, filepath = None):
+ def SaveXMLFile(self, filepath=None):
if not filepath and self.FilePath == "":
return False
else:
@@ -3189,9 +3256,9 @@
self.SetFilePath(filepath)
return True
-#-------------------------------------------------------------------------------
-# Search in Current Project Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Search in Current Project Functions
+ # -------------------------------------------------------------------------------
def SearchInProject(self, criteria):
return self.Project.Search(criteria)
@@ -3209,14 +3276,12 @@
return search_results
return []
-#-------------------------------------------------------------------------------
-# Current Buffering Management Functions
-#-------------------------------------------------------------------------------
-
- """
- Return a copy of the project
- """
+ # -------------------------------------------------------------------------------
+ # Current Buffering Management Functions
+ # -------------------------------------------------------------------------------
+
def Copy(self, model):
+ """Return a copy of the project"""
return deepcopy(model)
def CreateProjectBuffer(self, saved):
--- a/PLCGenerator.py Mon Aug 21 20:17:19 2017 +0000
+++ b/PLCGenerator.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,14 +29,14 @@
# Dictionary associating PLCOpen variable categories to the corresponding
# IEC 61131-3 variable categories
-varTypeNames = {"localVars" : "VAR", "tempVars" : "VAR_TEMP", "inputVars" : "VAR_INPUT",
- "outputVars" : "VAR_OUTPUT", "inOutVars" : "VAR_IN_OUT", "externalVars" : "VAR_EXTERNAL",
- "globalVars" : "VAR_GLOBAL", "accessVars" : "VAR_ACCESS"}
+varTypeNames = {"localVars": "VAR", "tempVars": "VAR_TEMP", "inputVars": "VAR_INPUT",
+ "outputVars": "VAR_OUTPUT", "inOutVars": "VAR_IN_OUT", "externalVars": "VAR_EXTERNAL",
+ "globalVars": "VAR_GLOBAL", "accessVars": "VAR_ACCESS"}
# Dictionary associating PLCOpen POU categories to the corresponding
# IEC 61131-3 POU categories
-pouTypeNames = {"function" : "FUNCTION", "functionBlock" : "FUNCTION_BLOCK", "program" : "PROGRAM"}
+pouTypeNames = {"function": "FUNCTION", "functionBlock": "FUNCTION_BLOCK", "program": "PROGRAM"}
errorVarTypes = {
@@ -45,8 +45,9 @@
"VAR_INOUT": "var_inout",
}
-# Helper function for reindenting text
+
def ReIndentText(text, nb_spaces):
+ """ Helper function for reindenting text """
compute = ""
lines = text.splitlines()
if len(lines) > 0:
@@ -62,11 +63,12 @@
indent += " "
for line in lines:
if line != "":
- compute += "%s%s\n"%(indent, line)
+ compute += "%s%s\n" % (indent, line)
else:
compute += "\n"
return compute
+
def SortInstances(a, b):
ax, ay = int(a.getx()), int(a.gety())
bx, by = int(b.getx()), int(b.gety())
@@ -75,25 +77,26 @@
else:
return cmp(ay, by)
-# Helper for emulate join on element list
+
def JoinList(separator, mylist):
- if len(mylist) > 0 :
+ """ Helper for emulate join on element list """
+ if len(mylist) > 0:
return reduce(lambda x, y: x + separator + y, mylist)
- else :
+ else:
return mylist
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Specific exception for PLC generating errors
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class PLCGenException(Exception):
pass
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Generator of PLC program
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class ProgramGenerator:
@@ -114,9 +117,9 @@
def ComputeValue(self, value, var_type):
base_type = self.Controler.GetBaseType(var_type)
if base_type == "STRING" and not value.startswith("'") and not value.endswith("'"):
- return "'%s'"%value
+ return "'%s'" % value
elif base_type == "WSTRING" and not value.startswith('"') and not value.endswith('"'):
- return "\"%s\""%value
+ return "\"%s\"" % value
return value
# Generate a data type from its name
@@ -154,16 +157,16 @@
max_value = basetype_content.range.getupper()
datatype_def += [(basetype_name, (tagname, "base")),
(" (", ()),
- ("%s"%min_value, (tagname, "lower")),
+ ("%s" % min_value, (tagname, "lower")),
("..", ()),
- ("%s"%max_value, (tagname, "upper")),
- (")",())]
+ ("%s" % max_value, (tagname, "upper")),
+ (")", ())]
# Data type is an enumerated type
elif basetype_content_type == "enum":
values = [[(value.getname(), (tagname, "value", i))]
for i, value in enumerate(
basetype_content.xpath("ppx:values/ppx:value",
- namespaces=PLCOpenParser.NSMAP))]
+ namespaces=PLCOpenParser.NSMAP))]
datatype_def += [("(", ())]
datatype_def += JoinList([(", ", ())], values)
datatype_def += [(")", ())]
@@ -178,13 +181,13 @@
# Array derived directly from an elementary type
else:
basetype_name = base_type_type.upper()
- dimensions = [[("%s"%dimension.getlower(), (tagname, "range", i, "lower")),
+ dimensions = [[("%s" % dimension.getlower(), (tagname, "range", i, "lower")),
("..", ()),
- ("%s"%dimension.getupper(), (tagname, "range", i, "upper"))]
+ ("%s" % dimension.getupper(), (tagname, "range", i, "upper"))]
for i, dimension in enumerate(basetype_content.getdimension())]
datatype_def += [("ARRAY [", ())]
datatype_def += JoinList([(",", ())], dimensions)
- datatype_def += [("] OF " , ()),
+ datatype_def += [("] OF ", ()),
(basetype_name, (tagname, "base"))]
# Data type is a structure
elif basetype_content_type == "struct":
@@ -245,18 +248,18 @@
pou = self.Project.getpou(pou_name)
pou_type = pou.getpouType()
# Verify that POU type exists
- if pouTypeNames.has_key(pou_type):
+ if pou_type in pouTypeNames:
# Create a POU program generator
pou_program = PouProgramGenerator(self, pou.getname(), pouTypeNames[pou_type], self.Errors, self.Warnings)
program = pou_program.GenerateProgram(pou)
self.Program += program
else:
- raise PLCGenException, _("Undefined pou type \"%s\"")%pou_type
+ raise PLCGenException(_("Undefined pou type \"%s\"") % pou_type)
# Generate a POU defined and used in text
def GeneratePouProgramInText(self, text):
for pou_name in self.PouComputed.keys():
- model = re.compile("(?:^|[^0-9^A-Z])%s(?:$|[^0-9^A-Z])"%pou_name.upper())
+ model = re.compile("(?:^|[^0-9^A-Z])%s(?:$|[^0-9^A-Z])" % pou_name.upper())
if model.search(text) is not None:
self.GeneratePouProgram(pou_name)
@@ -394,11 +397,11 @@
# Single argument if exists
if single is not None:
if len(single) == 0:
- msg = _("Source signal has to be defined for single task '{a1}' in resource '{a2}.{a3}'.").\
- format(a1 = task.getname(), a2 = config_name, a3 = resource.getname())
- raise PLCGenException, msg
-
- if single[0]=='[' and single[-1]==']' :
+ raise PLCGenException(
+ _("Source signal has to be defined for single task '{a1}' in resource '{a2}.{a3}'.").
+ format(a1=task.getname(), a2=config_name, a3=resource.getname()))
+
+ if single[0] == '[' and single[-1] == ']':
SNGLKW = "MULTI"
else:
SNGLKW = "SINGLE"
@@ -411,19 +414,19 @@
resrce += [("INTERVAL := ", ()),
(interval, (tagname, "task", task_number, "interval")),
(",", ())]
-## resrce += [("INTERVAL := t#", ())]
-## if interval.hour != 0:
-## resrce += [("%dh"%interval.hour, (tagname, "task", task_number, "interval", "hour"))]
-## if interval.minute != 0:
-## resrce += [("%dm"%interval.minute, (tagname, "task", task_number, "interval", "minute"))]
-## if interval.second != 0:
-## resrce += [("%ds"%interval.second, (tagname, "task", task_number, "interval", "second"))]
-## if interval.microsecond != 0:
-## resrce += [("%dms"%(interval.microsecond / 1000), (tagname, "task", task_number, "interval", "millisecond"))]
-## resrce += [(",", ())]
+# resrce += [("INTERVAL := t#", ())]
+# if interval.hour != 0:
+# resrce += [("%dh"%interval.hour, (tagname, "task", task_number, "interval", "hour"))]
+# if interval.minute != 0:
+# resrce += [("%dm"%interval.minute, (tagname, "task", task_number, "interval", "minute"))]
+# if interval.second != 0:
+# resrce += [("%ds"%interval.second, (tagname, "task", task_number, "interval", "second"))]
+# if interval.microsecond != 0:
+# resrce += [("%dms"%(interval.microsecond / 1000), (tagname, "task", task_number, "interval", "millisecond"))]
+# resrce += [(",", ())]
# Priority argument
resrce += [("PRIORITY := ", ()),
- ("%d"%task.getpriority(), (tagname, "task", task_number, "priority")),
+ ("%d" % task.getpriority(), (tagname, "task", task_number, "priority")),
(");\n", ())]
task_number += 1
instance_number = 0
@@ -441,10 +444,10 @@
# Generate any program assign to no task
for instance in resource.getpouInstance():
resrce += [(" PROGRAM ", ()),
- (instance.getname(), (tagname, "instance", instance_number, "name")),
- (" : ", ()),
- (instance.gettypeName(), (tagname, "instance", instance_number, "type")),
- (";\n", ())]
+ (instance.getname(), (tagname, "instance", instance_number, "name")),
+ (" : ", ()),
+ (instance.gettypeName(), (tagname, "instance", instance_number, "type")),
+ (";\n", ())]
instance_number += 1
resrce += [(" END_RESOURCE\n", ())]
return resrce
@@ -477,9 +480,9 @@
return self.Program
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Generator of POU programs
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
[ConnectorClass, ContinuationClass, ActionBlockClass] = [
PLCOpenParser.GetElementClass(instance_name, "commonObjects")
@@ -494,12 +497,14 @@
SelectionConvergenceClass, SelectionDivergenceClass,
SimultaneousConvergenceClass, SimultaneousDivergenceClass] = [
PLCOpenParser.GetElementClass(instance_name, "sfcObjects")
- for instance_name in ["step", "transition", "jumpStep",
- "selectionConvergence", "selectionDivergence",
- "simultaneousConvergence", "simultaneousDivergence"]]
+ for instance_name in [
+ "step", "transition", "jumpStep",
+ "selectionConvergence", "selectionDivergence",
+ "simultaneousConvergence", "simultaneousDivergence"]]
TransitionObjClass = PLCOpenParser.GetElementClass("transition", "transitions")
ActionObjClass = PLCOpenParser.GetElementClass("action", "actions")
+
class PouProgramGenerator:
# Create a new POU program generator
@@ -517,7 +522,7 @@
self.ComputedConnectors = {}
self.ConnectionTypes = {}
self.RelatedConnections = []
- self.SFCNetworks = {"Steps":{}, "Transitions":{}, "Actions":{}}
+ self.SFCNetworks = {"Steps": {}, "Transitions": {}, "Actions": {}}
self.SFCComputedBlocks = []
self.ActionNumber = 0
self.Program = []
@@ -590,7 +595,7 @@
parameter = link.getformalParameter()
instance = body.getcontentInstance(link.getrefLocalId())
if isinstance(instance, (InVariableClass, InOutVariableClass,
- ContinuationClass, ContactClass, CoilClass)):
+ ContinuationClass, ContactClass, CoilClass)):
return instance.connectionPointOut
elif isinstance(instance, BlockClass):
outputvariables = instance.outputVariables.getvariable()
@@ -691,14 +696,15 @@
self.Interface.append((varTypeNames[varlist_type], option, True, located))
LITERAL_TYPES = {
- "T": "TIME",
- "D": "DATE",
+ "T": "TIME",
+ "D": "DATE",
"TOD": "TIME_OF_DAY",
- "DT": "DATE_AND_TIME",
- "2": None,
- "8": None,
- "16": None,
+ "DT": "DATE_AND_TIME",
+ "2": None,
+ "8": None,
+ "16": None,
}
+
def ComputeConnectionTypes(self, pou):
body = pou.getbody()
if isinstance(body, ListType):
@@ -712,8 +718,7 @@
InOutVariableClass)):
expression = instance.getexpression()
var_type = self.GetVariableType(expression)
- if (isinstance(pou, TransitionObjClass)
- and expression == pou.getname()):
+ if isinstance(pou, TransitionObjClass) and expression == pou.getname():
var_type = "BOOL"
elif (not isinstance(pou, (TransitionObjClass, ActionObjClass)) and
pou.getpouType() == "function" and expression == pou.getname()):
@@ -740,7 +745,7 @@
if isinstance(instance, (OutVariableClass, InOutVariableClass)):
self.ConnectionTypes[instance.connectionPointIn] = var_type
connected = self.GetConnectedConnector(instance.connectionPointIn, body)
- if connected is not None and not self.ConnectionTypes.has_key(connected):
+ if connected is not None and connected not in self.ConnectionTypes:
for related in self.ExtractRelatedConnections(connected):
self.ConnectionTypes[related] = var_type
elif isinstance(instance, (ContactClass, CoilClass)):
@@ -749,7 +754,7 @@
self.ConnectionTypes[instance.connectionPointIn] = "BOOL"
for link in instance.connectionPointIn.getconnections():
connected = self.GetLinkedConnector(link, body)
- if connected is not None and not self.ConnectionTypes.has_key(connected):
+ if connected is not None and connected not in self.ConnectionTypes:
for related in self.ExtractRelatedConnections(connected):
self.ConnectionTypes[related] = "BOOL"
elif isinstance(instance, LeftPowerRailClass):
@@ -761,7 +766,7 @@
self.ConnectionTypes[connection] = "BOOL"
for link in connection.getconnections():
connected = self.GetLinkedConnector(link, body)
- if connected is not None and not self.ConnectionTypes.has_key(connected):
+ if connected is not None and connected not in self.ConnectionTypes:
for related in self.ExtractRelatedConnections(connected):
self.ConnectionTypes[related] = "BOOL"
elif isinstance(instance, TransitionClass):
@@ -770,10 +775,12 @@
self.ConnectionTypes[content["value"]] = "BOOL"
connections = content["value"].getconnections()
if not connections:
- raise PLCGenException, _("SFC transition in POU \"%s\" must be connected.") % self.Name
- for link in connections:
+ raise PLCGenException(
+ _("SFC transition in POU \"%s\" must be connected.") % self.Name)
+
+ for link in connections:
connected = self.GetLinkedConnector(link, body)
- if connected is not None and not self.ConnectionTypes.has_key(connected):
+ if connected is not None and connected not in self.ConnectionTypes:
for related in self.ExtractRelatedConnections(connected):
self.ConnectionTypes[related] = "BOOL"
elif isinstance(instance, ContinuationClass):
@@ -783,8 +790,9 @@
for element in body.getcontentInstances():
if isinstance(element, ConnectorClass) and element.getname() == name:
if connector is not None:
- msg = _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").
+ format(a1=name, a2=self.Name))
connector = element
if connector is not None:
undefined = [instance.connectionPointOut, connector.connectionPointIn]
@@ -793,7 +801,7 @@
undefined.append(connected)
related = []
for connection in undefined:
- if self.ConnectionTypes.has_key(connection):
+ if connection in self.ConnectionTypes:
var_type = self.ConnectionTypes[connection]
else:
related.extend(self.ExtractRelatedConnections(connection))
@@ -803,8 +811,10 @@
for connection in related:
self.ConnectionTypes[connection] = var_type
else:
- msg = _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").
+ format(a1=name, a2=self.Name))
+
elif isinstance(instance, BlockClass):
block_infos = self.GetBlockType(instance.gettypeName(), "undefined")
if block_infos is not None:
@@ -826,7 +836,8 @@
if block_infos is not None:
self.ComputeBlockInputTypes(instance, block_infos, body)
else:
- raise PLCGenException, _("No informations found for \"%s\" block")%(instance.gettypeName())
+ raise PLCGenException(
+ _("No informations found for \"%s\" block") % (instance.gettypeName()))
if body_type == "SFC":
previous_tagname = self.TagName
for action in pou.getactionList():
@@ -848,10 +859,10 @@
for oname, otype, oqualifier in block_infos["outputs"]:
if output_name == oname:
if otype.startswith("ANY"):
- if not undefined.has_key(otype):
+ if otype not in undefined:
undefined[otype] = []
undefined[otype].append(variable.connectionPointOut)
- elif not self.ConnectionTypes.has_key(variable.connectionPointOut):
+ elif variable.connectionPointOut not in self.ConnectionTypes:
for connection in self.ExtractRelatedConnections(variable.connectionPointOut):
self.ConnectionTypes[connection] = otype
for variable in instance.inputVariables.getvariable():
@@ -864,14 +875,14 @@
if input_name == iname:
connected = self.GetConnectedConnector(variable.connectionPointIn, body)
if itype.startswith("ANY"):
- if not undefined.has_key(itype):
+ if itype not in undefined:
undefined[itype] = []
undefined[itype].append(variable.connectionPointIn)
if connected is not None:
undefined[itype].append(connected)
else:
self.ConnectionTypes[variable.connectionPointIn] = itype
- if connected is not None and not self.ConnectionTypes.has_key(connected):
+ if connected is not None and connected not in self.ConnectionTypes:
for connection in self.ExtractRelatedConnections(connected):
self.ConnectionTypes[connection] = itype
for var_type, connections in undefined.items():
@@ -894,7 +905,7 @@
body = body[0]
body_content = body.getcontent()
body_type = body_content.getLocalTag()
- if body_type in ["IL","ST"]:
+ if body_type in ["IL", "ST"]:
text = body_content.getanyText()
self.ParentGenerator.GeneratePouProgramInText(text.upper())
self.Program = [(ReIndentText(text, len(self.CurrentIndent)),
@@ -912,7 +923,7 @@
self.GenerateSFCJump(instance, pou)
if len(self.InitialSteps) > 0 and len(self.SFCComputedBlocks) > 0:
action_name = "COMPUTE_FUNCTION_BLOCKS"
- action_infos = {"qualifier" : "S", "content" : action_name}
+ action_infos = {"qualifier": "S", "content": action_name}
self.SFCNetworks["Steps"][self.InitialSteps[0]]["actions"].append(action_infos)
self.SFCNetworks["Actions"][action_name] = (self.SFCComputedBlocks, ())
self.Program = []
@@ -920,7 +931,7 @@
for initialstep in self.InitialSteps:
self.ComputeSFCStep(initialstep)
else:
- otherInstances = {"outVariables&coils" : [], "blocks" : [], "connectors" : []}
+ otherInstances = {"outVariables&coils": [], "blocks": [], "connectors": []}
orderedInstances = []
for instance in body.getcontentInstances():
if isinstance(instance, (OutVariableClass, InOutVariableClass, BlockClass)):
@@ -958,11 +969,13 @@
if block_infos is None:
block_infos = self.GetBlockType(block_type)
if block_infos is None:
- raise PLCGenException, _("Undefined block type \"{a1}\" in \"{a2}\" POU").format(a1 = block_type, a2 = self.Name)
+ raise PLCGenException(
+ _("Undefined block type \"{a1}\" in \"{a2}\" POU").
+ format(a1=block_type, a2=self.Name))
try:
self.GenerateBlock(instance, block_infos, body, None)
except ValueError, e:
- raise PLCGenException, e.message
+ raise PLCGenException(e.message)
elif isinstance(instance, ConnectorClass):
connector = instance.getname()
if self.ComputedConnectors.get(connector, None):
@@ -1031,7 +1044,7 @@
[(input_name, None) for input_name in input_names])
for variable in input_variables:
parameter = variable.getformalParameter()
- if input_connected.has_key(parameter):
+ if parameter in input_connected:
input_connected[parameter] = variable
if input_connected["EN"] is None:
input_connected.pop("EN")
@@ -1053,7 +1066,7 @@
if connections is not None:
if parameter != "EN":
one_input_connected = True
- if inout_variables.has_key(parameter):
+ if parameter in inout_variables:
expression = self.ComputeExpression(body, connections, executionOrderId > 0, True)
if expression is not None:
inout_variables[parameter] = value
@@ -1073,11 +1086,11 @@
if one_input_connected:
for i, variable in enumerate(output_variables):
parameter = variable.getformalParameter()
- if not inout_variables.has_key(parameter) and parameter in output_names + ["", "ENO"]:
+ if parameter not in inout_variables and parameter in output_names + ["", "ENO"]:
if variable.getformalParameter() == "":
- variable_name = "%s%d"%(type, block.getlocalId())
+ variable_name = "%s%d" % (type, block.getlocalId())
else:
- variable_name = "%s%d_%s"%(type, block.getlocalId(), parameter)
+ variable_name = "%s%d_%s" % (type, block.getlocalId(), parameter)
if self.Interface[-1][0] != "VAR" or self.Interface[-1][1] is not None or self.Interface[-1][2]:
self.Interface.append(("VAR", None, False, []))
if variable.connectionPointOut in self.ConnectionTypes:
@@ -1086,7 +1099,7 @@
self.Interface[-1][3].append(("ANY", variable_name, None, None))
if len(output_variables) > 1 and parameter not in ["", "OUT"]:
vars.append([(parameter, (self.TagName, "block", block.getlocalId(), "output", i)),
- (" => %s"%variable_name, ())])
+ (" => %s" % variable_name, ())])
else:
output_info = (self.TagName, "block", block.getlocalId(), "output", i)
output_name = variable_name
@@ -1098,7 +1111,7 @@
self.Program += JoinList([(", ", ())], vars)
self.Program += [(");\n", ())]
else:
- msg = _("\"{a1}\" function cancelled in \"{a2}\" POU: No input connected").format(a1 = type, a2 = self.TagName.split("::")[-1])
+ msg = _("\"{a1}\" function cancelled in \"{a2}\" POU: No input connected").format(a1=type, a2=self.TagName.split("::")[-1])
self.Warnings.append(msg)
elif block_infos["type"] == "functionBlock":
if not self.ComputedBlocks.get(block, False) and not order:
@@ -1116,7 +1129,7 @@
input_info = (self.TagName, "block", block.getlocalId(), "input", input_idx)
connections = variable.connectionPointIn.getconnections()
if connections is not None:
- expression = self.ComputeExpression(body, connections, executionOrderId > 0, inout_variables.has_key(parameter))
+ expression = self.ComputeExpression(body, connections, executionOrderId > 0, parameter in inout_variables)
if expression is not None:
vars.append([(parameter, input_info),
(" := ", ())] + self.ExtractModifier(variable, expression, input_info))
@@ -1145,9 +1158,9 @@
else:
for i, variable in enumerate(output_variables):
blockPointx, blockPointy = variable.connectionPointOut.getrelPositionXY()
- if (connectionPoint is None or
- block.getx() + blockPointx == connectionPoint.getx() and
- block.gety() + blockPointy == connectionPoint.gety()):
+ if connectionPoint is None or \
+ block.getx() + blockPointx == connectionPoint.getx() and \
+ block.gety() + blockPointy == connectionPoint.gety():
output_variable = variable
output_parameter = variable.getformalParameter()
output_idx = i
@@ -1155,21 +1168,21 @@
if output_variable is not None:
if block_infos["type"] == "function":
output_info = (self.TagName, "block", block.getlocalId(), "output", output_idx)
- if inout_variables.has_key(output_parameter):
+ if output_parameter in inout_variables:
output_value = inout_variables[output_parameter]
else:
if output_parameter == "":
- output_name = "%s%d"%(type, block.getlocalId())
+ output_name = "%s%d" % (type, block.getlocalId())
else:
- output_name = "%s%d_%s"%(type, block.getlocalId(), output_parameter)
+ output_name = "%s%d_%s" % (type, block.getlocalId(), output_parameter)
output_value = [(output_name, output_info)]
return self.ExtractModifier(output_variable, output_value, output_info)
if block_infos["type"] == "functionBlock":
output_info = (self.TagName, "block", block.getlocalId(), "output", output_idx)
- output_name = self.ExtractModifier(output_variable, [("%s.%s"%(name, output_parameter), output_info)], output_info)
+ output_name = self.ExtractModifier(output_variable, [("%s.%s" % (name, output_parameter), output_info)], output_info)
if to_inout:
- variable_name = "%s_%s"%(name, output_parameter)
+ variable_name = "%s_%s" % (name, output_parameter)
if not self.IsAlreadyDefined(variable_name):
if self.Interface[-1][0] != "VAR" or self.Interface[-1][1] is not None or self.Interface[-1][2]:
self.Interface.append(("VAR", None, False, []))
@@ -1179,7 +1192,7 @@
else:
self.Interface[-1][3].append(("ANY", variable_name, None, None))
self.Program += [(self.CurrentIndent, ()),
- ("%s := "%variable_name, ())]
+ ("%s := " % variable_name, ())]
self.Program += output_name
self.Program += [(";\n", ())]
return [(variable_name, ())]
@@ -1188,14 +1201,14 @@
if output_parameter is None:
output_parameter = ""
if name:
- blockname = "{a1}({a2})".format(a1 = name, a2 = type)
+ blockname = "{a1}({a2})".format(a1=name, a2=type)
else:
blockname = type
- msg = _("No output {a1} variable found in block {a2} in POU {a3}. Connection must be broken").\
- format(a1 = output_parameter, a2 = blockname, a3 = self.Name)
- raise ValueError, msg
-
- def GeneratePaths(self, connections, body, order = False, to_inout = False):
+ raise ValueError(
+ _("No output {a1} variable found in block {a2} in POU {a3}. Connection must be broken").
+ format(a1=output_parameter, a2=blockname, a3=self.Name))
+
+ def GeneratePaths(self, connections, body, order=False, to_inout=False):
paths = []
for connection in connections:
localId = connection.getrefLocalId()
@@ -1211,24 +1224,26 @@
if block_infos is None:
block_infos = self.GetBlockType(block_type)
if block_infos is None:
- msg = _("Undefined block type \"{a1}\" in \"{a2}\" POU").format(a1 = block_type, a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("Undefined block type \"{a1}\" in \"{a2}\" POU").
+ format(a1=block_type, a2=self.Name))
try:
paths.append(str(self.GenerateBlock(next, block_infos, body, connection, order, to_inout)))
except ValueError, e:
- raise PLCGenException, e.message
+ raise PLCGenException(e.message)
elif isinstance(next, ContinuationClass):
name = next.getname()
computed_value = self.ComputedConnectors.get(name, None)
- if computed_value != None:
+ if computed_value is not None:
paths.append(str(computed_value))
else:
connector = None
for instance in body.getcontentInstances():
if isinstance(instance, ConnectorClass) and instance.getname() == name:
if connector is not None:
- msg = _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("More than one connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").
+ format(a1=name, a2=self.Name))
connector = instance
if connector is not None:
connections = connector.connectionPointIn.getconnections()
@@ -1238,8 +1253,9 @@
self.ComputedConnectors[name] = expression
paths.append(str(expression))
else:
- msg = _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").format(a1 = name, a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("No connector found corresponding to \"{a1}\" continuation in \"{a2}\" POU").
+ format(a1=name, a2=self.Name))
elif isinstance(next, ContactClass):
contact_info = (self.TagName, "contact", next.getlocalId())
variable = str(self.ExtractModifier(next, [(next.getvariable(), contact_info + ("reference",))], contact_info))
@@ -1260,7 +1276,7 @@
paths.append(str(self.GeneratePaths(next.connectionPointIn.getconnections(), body, order)))
return paths
- def ComputePaths(self, paths, first = False):
+ def ComputePaths(self, paths, first=False):
if type(paths) == TupleType:
if None in paths:
return [("TRUE", ())]
@@ -1278,7 +1294,7 @@
else:
return eval(paths)
- def ComputeExpression(self, body, connections, order = False, to_inout = False):
+ def ComputeExpression(self, body, connections, order=False, to_inout=False):
paths = self.GeneratePaths(connections, body, order, to_inout)
if len(paths) == 0:
return None
@@ -1315,15 +1331,15 @@
if self.Interface[-1][0] != "VAR" or self.Interface[-1][1] is not None or self.Interface[-1][2]:
self.Interface.append(("VAR", None, False, []))
i = 1
- name = "%s%d"%(edge, i)
+ name = "%s%d" % (edge, i)
while self.IsAlreadyDefined(name):
i += 1
- name = "%s%d"%(edge, i)
+ name = "%s%d" % (edge, i)
self.Interface[-1][3].append((edge, name, None, None))
self.Program += [(self.CurrentIndent, ()), (name, var_info), ("(CLK := ", ())]
self.Program += expression
self.Program += [(");\n", ())]
- return [("%s.Q"%name, var_info)]
+ return [("%s.Q" % name, var_info)]
def ExtractDivergenceInput(self, divergence, pou):
connectionPointIn = divergence.getconnectionPointIn()
@@ -1354,10 +1370,10 @@
if step_name not in self.SFCNetworks["Steps"].keys():
if step.getinitialStep():
self.InitialSteps.append(step_name)
- step_infos = {"id" : step.getlocalId(),
- "initial" : step.getinitialStep(),
- "transitions" : [],
- "actions" : []}
+ step_infos = {"id": step.getlocalId(),
+ "initial": step.getinitialStep(),
+ "transitions": [],
+ "actions": []}
self.SFCNetworks["Steps"][step_name] = step_infos
if step.connectionPointIn is not None:
instances = []
@@ -1389,8 +1405,10 @@
jump_target = jump.gettargetName()
if not pou.hasstep(jump_target):
pname = pou.getname()
- msg = _("SFC jump in pou \"{a1}\" refers to non-existent SFC step \"{a2}\"").format( a1 = pname, a2 = jump_target)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("SFC jump in pou \"{a1}\" refers to non-existent SFC step \"{a2}\"").
+ format(a1=pname, a2=jump_target))
+
if jump.connectionPointIn is not None:
instances = []
connections = jump.connectionPointIn.getconnections()
@@ -1430,10 +1448,10 @@
if step_name in self.SFCNetworks["Steps"].keys():
actions = actionBlock.getactions()
for i, action in enumerate(actions):
- action_infos = {"id" : actionBlock.getlocalId(),
- "qualifier" : action["qualifier"],
- "content" : action["value"],
- "num" : i}
+ action_infos = {"id": actionBlock.getlocalId(),
+ "qualifier": action["qualifier"],
+ "content": action["value"],
+ "num": i}
if "duration" in action:
action_infos["duration"] = action["duration"]
if "indicator" in action:
@@ -1441,9 +1459,12 @@
if action["type"] == "reference":
self.GenerateSFCAction(action["value"], pou)
else:
- action_name = "%s_INLINE%d"%(step_name.upper(), self.GetActionNumber())
- self.SFCNetworks["Actions"][action_name] = ([(self.CurrentIndent, ()),
- (action["value"], (self.TagName, "action_block", action_infos["id"], "action", i, "inline")),
+ action_name = "%s_INLINE%d" % (step_name.upper(), self.GetActionNumber())
+ self.SFCNetworks["Actions"][action_name] = ([
+ (self.CurrentIndent, ()),
+ (action["value"], (
+ self.TagName, "action_block", action_infos["id"],
+ "action", i, "inline")),
("\n", ())], ())
action_infos["content"] = action_name
self.SFCNetworks["Steps"][step_name]["actions"].append(action_infos)
@@ -1480,15 +1501,15 @@
steps.extend(self.ExtractConvergenceInputs(step, pou))
elif isinstance(instance, SimultaneousConvergenceClass):
steps.extend(self.ExtractConvergenceInputs(instance, pou))
- transition_infos = {"id" : transition.getlocalId(),
+ transition_infos = {"id": transition.getlocalId(),
"priority": transition.getpriority(),
- "from": [],
- "to" : [],
- "content": []}
+ "from": [],
+ "to": [],
+ "content": []}
self.SFCNetworks["Transitions"][transition] = transition_infos
transitionValues = transition.getconditionContent()
if transitionValues["type"] == "inline":
- transition_infos["content"] = [("\n%s:= "%self.CurrentIndent, ()),
+ transition_infos["content"] = [("\n%s:= " % self.CurrentIndent, ()),
(transitionValues["value"], (self.TagName, "transition", transition.getlocalId(), "inline")),
(";\n", ())]
elif transitionValues["type"] == "reference":
@@ -1505,17 +1526,19 @@
(ReIndentText(transitionBody.getcontent().getanyText(), len(self.CurrentIndent)), (self.TagName, "body", len(self.CurrentIndent)))]
else:
for instance in transitionBody.getcontentInstances():
- if isinstance(instance, OutVariableClass) and instance.getexpression() == transitionValues["value"]\
- or isinstance(instance, CoilClass) and instance.getvariable() == transitionValues["value"]:
+ if isinstance(instance, OutVariableClass) and instance.getexpression() == transitionValues["value"] or \
+ isinstance(instance, CoilClass) and instance.getvariable() == transitionValues["value"]:
connections = instance.connectionPointIn.getconnections()
if connections is not None:
expression = self.ComputeExpression(transitionBody, connections)
if expression is not None:
- transition_infos["content"] = [("\n%s:= "%self.CurrentIndent, ())] + expression + [(";\n", ())]
+ transition_infos["content"] = [("\n%s:= " % self.CurrentIndent, ())] + expression + [(";\n", ())]
self.SFCComputedBlocks += self.Program
self.Program = []
- if not transition_infos.has_key("content"):
- raise PLCGenException, _("Transition \"%s\" body must contain an output variable or coil referring to its name") % transitionValues["value"]
+ if "content" not in transition_infos:
+ raise PLCGenException(
+ _("Transition \"%s\" body must contain an output variable or coil referring to its name")
+ % transitionValues["value"])
self.TagName = previous_tagname
elif transitionValues["type"] == "connection":
body = pou.getbody()
@@ -1525,7 +1548,7 @@
if connections is not None:
expression = self.ComputeExpression(body, connections)
if expression is not None:
- transition_infos["content"] = [("\n%s:= "%self.CurrentIndent, ())] + expression + [(";\n", ())]
+ transition_infos["content"] = [("\n%s:= " % self.CurrentIndent, ())] + expression + [(";\n", ())]
self.SFCComputedBlocks += self.Program
self.Program = []
for step in steps:
@@ -1564,7 +1587,7 @@
(action_infos["indicator"], action_info + ("indicator",))]
self.Program += [(");\n", ())]
self.IndentLeft()
- self.Program += [("%sEND_STEP\n\n"%self.CurrentIndent, ())]
+ self.Program += [("%sEND_STEP\n\n" % self.CurrentIndent, ())]
for action in actions:
self.ComputeSFCAction(action)
for transition in step_infos["transitions"]:
@@ -1573,19 +1596,19 @@
def ComputeSFCAction(self, action_name):
if action_name in self.SFCNetworks["Actions"].keys():
action_content, action_info = self.SFCNetworks["Actions"].pop(action_name)
- self.Program += [("%sACTION "%self.CurrentIndent, ()),
+ self.Program += [("%sACTION " % self.CurrentIndent, ()),
(action_name, action_info),
(":\n", ())]
self.Program += action_content
- self.Program += [("%sEND_ACTION\n\n"%self.CurrentIndent, ())]
+ self.Program += [("%sEND_ACTION\n\n" % self.CurrentIndent, ())]
def ComputeSFCTransition(self, transition):
if transition in self.SFCNetworks["Transitions"].keys():
transition_infos = self.SFCNetworks["Transitions"].pop(transition)
- self.Program += [("%sTRANSITION"%self.CurrentIndent, ())]
- if transition_infos["priority"] != None:
+ self.Program += [("%sTRANSITION" % self.CurrentIndent, ())]
+ if transition_infos["priority"] is not None:
self.Program += [(" (PRIORITY := ", ()),
- ("%d"%transition_infos["priority"], (self.TagName, "transition", transition_infos["id"], "priority")),
+ ("%d" % transition_infos["priority"], (self.TagName, "transition", transition_infos["id"], "priority")),
(")", ())]
self.Program += [(" FROM ", ())]
if len(transition_infos["from"]) > 1:
@@ -1595,9 +1618,9 @@
elif len(transition_infos["from"]) == 1:
self.Program += transition_infos["from"][0]
else:
- msg = _("Transition with content \"{a1}\" not connected to a previous step in \"{a2}\" POU").\
- format(a1 = transition_infos["content"], a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("Transition with content \"{a1}\" not connected to a previous step in \"{a2}\" POU").
+ format(a1=transition_infos["content"], a2=self.Name))
self.Program += [(" TO ", ())]
if len(transition_infos["to"]) > 1:
self.Program += [("(", ())]
@@ -1606,11 +1629,11 @@
elif len(transition_infos["to"]) == 1:
self.Program += transition_infos["to"][0]
else:
- msg = _("Transition with content \"{a1}\" not connected to a next step in \"{a2}\" POU").\
- format(a1 = transition_infos["content"], a2 = self.Name)
- raise PLCGenException, msg
+ raise PLCGenException(
+ _("Transition with content \"{a1}\" not connected to a next step in \"{a2}\" POU").
+ format(a1=transition_infos["content"], a2=self.Name))
self.Program += transition_infos["content"]
- self.Program += [("%sEND_TRANSITION\n\n"%self.CurrentIndent, ())]
+ self.Program += [("%sEND_TRANSITION\n\n" % self.CurrentIndent, ())]
for [(step_name, step_infos)] in transition_infos["to"]:
self.ComputeSFCStep(step_name)
@@ -1619,35 +1642,35 @@
self.ComputeConnectionTypes(pou)
self.ComputeProgram(pou)
- program = [("%s "%self.Type, ()),
+ program = [("%s " % self.Type, ()),
(self.Name, (self.TagName, "name"))]
if self.ReturnType is not None:
program += [(" : ", ()),
(self.ReturnType, (self.TagName, "return"))]
program += [("\n", ())]
if len(self.Interface) == 0:
- raise PLCGenException, _("No variable defined in \"%s\" POU")%self.Name
- if len(self.Program) == 0 :
- raise PLCGenException, _("No body defined in \"%s\" POU")%self.Name
+ raise PLCGenException(_("No variable defined in \"%s\" POU") % self.Name)
+ if len(self.Program) == 0:
+ raise PLCGenException(_("No body defined in \"%s\" POU") % self.Name)
var_number = 0
for list_type, option, located, variables in self.Interface:
variable_type = errorVarTypes.get(list_type, "var_local")
- program += [(" %s"%list_type, ())]
+ program += [(" %s" % list_type, ())]
if option is not None:
- program += [(" %s"%option, (self.TagName, variable_type, (var_number, var_number + len(variables)), option.lower()))]
+ program += [(" %s" % option, (self.TagName, variable_type, (var_number, var_number + len(variables)), option.lower()))]
program += [("\n", ())]
for var_type, var_name, var_address, var_initial in variables:
program += [(" ", ())]
if var_name:
program += [(var_name, (self.TagName, variable_type, var_number, "name")),
(" ", ())]
- if var_address != None:
+ if var_address is not None:
program += [("AT ", ()),
(var_address, (self.TagName, variable_type, var_number, "location")),
(" ", ())]
program += [(": ", ()),
(var_type, (self.TagName, variable_type, var_number, "type"))]
- if var_initial != None:
+ if var_initial is not None:
program += [(" := ", ()),
(self.ParentGenerator.ComputeValue(var_initial, var_type), (self.TagName, variable_type, var_number, "initial value"))]
program += [(";\n", ())]
@@ -1655,11 +1678,11 @@
program += [(" END_VAR\n", ())]
program += [("\n", ())]
program += self.Program
- program += [("END_%s\n\n"%self.Type, ())]
+ program += [("END_%s\n\n" % self.Type, ())]
return program
+
def GenerateCurrentProgram(controler, project, errors, warnings):
generator = ProgramGenerator(controler, project, errors, warnings)
generator.GenerateProgram()
return generator.GetGeneratedProgram()
-
--- a/PLCOpenEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/PLCOpenEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,10 +24,35 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import wx
-import os, sys, platform, time, traceback, getopt
+import os
+import sys
+import platform
+import time
+import traceback
+import getopt
import version
import util.paths as paths
+from docutil import *
+from IDEFrame import IDEFrame, AppendMenu
+from IDEFrame import \
+ TITLE, \
+ EDITORTOOLBAR, \
+ FILEMENU, \
+ EDITMENU, \
+ DISPLAYMENU, \
+ PROJECTTREE, \
+ POUINSTANCEVARIABLESPANEL, \
+ LIBRARYTREE, \
+ PAGETITLES
+
+from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath
+from editors.Viewer import Viewer
+from PLCControler import PLCControler
+from dialogs import ProjectDialog
+from dialogs.AboutDialog import ShowAboutDialog
+
+
beremiz_dir = paths.AbsDir(__file__)
__version__ = "$Revision: 1.130 $"
@@ -37,7 +62,7 @@
# command line
def usage():
print "\nUsage of PLCOpenEditor.py :"
- print "\n %s [Filepath]\n"%sys.argv[0]
+ print "\n %s [Filepath]\n" % sys.argv[0]
# Parse options given to PLCOpenEditor in command line
try:
@@ -68,32 +93,25 @@
else:
app = wx.PySimpleApp()
-
from util.misc import InstallLocalRessources
InstallLocalRessources(beremiz_dir)
-from docutil import *
-from IDEFrame import IDEFrame, AppendMenu
-from IDEFrame import TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE, PAGETITLES
-from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath
-from editors.Viewer import Viewer
-from PLCControler import PLCControler
-from dialogs import ProjectDialog
-from dialogs.AboutDialog import ShowAboutDialog
-
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# PLCOpenEditor Main Class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Define PLCOpenEditor FileMenu extra items id
-[ID_PLCOPENEDITORFILEMENUGENERATE,
+[
+ ID_PLCOPENEDITORFILEMENUGENERATE,
] = [wx.NewId() for _init_coll_FileMenu_Items in range(1)]
+
class PLCOpenEditor(IDEFrame):
# Compatibility function for wx versions < 2.6
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
@@ -101,33 +119,33 @@
def _init_coll_FileMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_NEW,
- kind=wx.ITEM_NORMAL, text=_(u'New') +'\tCTRL+N')
+ kind=wx.ITEM_NORMAL, text=_(u'New') + '\tCTRL+N')
AppendMenu(parent, help='', id=wx.ID_OPEN,
- kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O')
+ kind=wx.ITEM_NORMAL, text=_(u'Open') + '\tCTRL+O')
AppendMenu(parent, help='', id=wx.ID_CLOSE,
- kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W')
+ kind=wx.ITEM_NORMAL, text=_(u'Close Tab') + '\tCTRL+W')
AppendMenu(parent, help='', id=wx.ID_CLOSE_ALL,
- kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W')
+ kind=wx.ITEM_NORMAL, text=_(u'Close Project') + '\tCTRL+SHIFT+W')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_SAVE,
- kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S')
+ kind=wx.ITEM_NORMAL, text=_(u'Save') + '\tCTRL+S')
AppendMenu(parent, help='', id=wx.ID_SAVEAS,
- kind=wx.ITEM_NORMAL, text=_(u'Save As...') + '\tCTRL+SHIFT+S')
+ kind=wx.ITEM_NORMAL, text=_(u'Save As...') + '\tCTRL+SHIFT+S')
AppendMenu(parent, help='', id=ID_PLCOPENEDITORFILEMENUGENERATE,
- kind=wx.ITEM_NORMAL, text=_(u'Generate Program') + '\tCTRL+G')
+ kind=wx.ITEM_NORMAL, text=_(u'Generate Program') + '\tCTRL+G')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_PAGE_SETUP,
- kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Page Setup') + '\tCTRL+ALT+P')
AppendMenu(parent, help='', id=wx.ID_PREVIEW,
- kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Preview') + '\tCTRL+SHIFT+P')
AppendMenu(parent, help='', id=wx.ID_PRINT,
- kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P')
+ kind=wx.ITEM_NORMAL, text=_(u'Print') + '\tCTRL+P')
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
- kind=wx.ITEM_NORMAL, text=_(u'&Properties'))
+ kind=wx.ITEM_NORMAL, text=_(u'&Properties'))
parent.AppendSeparator()
AppendMenu(parent, help='', id=wx.ID_EXIT,
- kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q')
+ kind=wx.ITEM_NORMAL, text=_(u'Quit') + '\tCTRL+Q')
self.Bind(wx.EVT_MENU, self.OnNewProjectMenu, id=wx.ID_NEW)
self.Bind(wx.EVT_MENU, self.OnOpenProjectMenu, id=wx.ID_OPEN)
@@ -136,7 +154,7 @@
self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
self.Bind(wx.EVT_MENU, self.OnSaveProjectAsMenu, id=wx.ID_SAVEAS)
self.Bind(wx.EVT_MENU, self.OnGenerateProgramMenu,
- id=ID_PLCOPENEDITORFILEMENUGENERATE)
+ id=ID_PLCOPENEDITORFILEMENUGENERATE)
self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
@@ -151,31 +169,34 @@
def _init_coll_HelpMenu_Items(self, parent):
AppendMenu(parent, help='', id=wx.ID_HELP,
- kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor') + '\tF1')
- #AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS,
+ kind=wx.ITEM_NORMAL, text=_(u'PLCOpenEditor') + '\tF1')
+ # AppendMenu(parent, help='', id=wx.ID_HELP_CONTENTS,
# kind=wx.ITEM_NORMAL, text=u'PLCOpen\tF2')
- #AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT,
+ # AppendMenu(parent, help='', id=wx.ID_HELP_CONTEXT,
# kind=wx.ITEM_NORMAL, text=u'IEC 61131-3\tF3')
-
- handler=lambda event: {
- wx.MessageBox(version.GetCommunityHelpMsg(), _(u'Community support'), wx.OK | wx.ICON_INFORMATION)
- }
+
+ def handler(event):
+ return wx.MessageBox(
+ version.GetCommunityHelpMsg(),
+ _(u'Community support'),
+ wx.OK | wx.ICON_INFORMATION)
+
id = wx.NewId()
- parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support'))
+ parent.Append(help='', id=id, kind=wx.ITEM_NORMAL, text=_(u'Community support'))
self.Bind(wx.EVT_MENU, handler, id=id)
-
+
AppendMenu(parent, help='', id=wx.ID_ABOUT,
- kind=wx.ITEM_NORMAL, text=_(u'About'))
+ kind=wx.ITEM_NORMAL, text=_(u'About'))
self.Bind(wx.EVT_MENU, self.OnPLCOpenEditorMenu, id=wx.ID_HELP)
- #self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS)
+ # self.Bind(wx.EVT_MENU, self.OnPLCOpenMenu, id=wx.ID_HELP_CONTENTS)
self.Bind(wx.EVT_MENU, self.OnAboutMenu, id=wx.ID_ABOUT)
- ## Constructor of the PLCOpenEditor class.
- # @param parent The parent window.
- # @param controler The controler been used by PLCOpenEditor (default: None).
- # @param fileOpen The filepath to open if no controler defined (default: None).
- # @param debug The filepath to open if no controler defined (default: False).
- def __init__(self, parent, fileOpen = None):
+ def __init__(self, parent, fileOpen=None):
+ """ Constructor of the PLCOpenEditor class.
+
+ :param parent: The parent window.
+ :param fileOpen: The filepath to open if no controler defined (default: None).
+ """
self.icon = wx.Icon(os.path.join(beremiz_dir, "images", "poe.ico"), wx.BITMAP_TYPE_ICO)
IDEFrame.__init__(self, parent)
@@ -203,7 +224,7 @@
if result is not None:
(num, line) = result
- self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1 = num, a2 = line))
+ self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1=num, a2=line))
def OnCloseFrame(self, event):
if self.Controler is None or self.CheckSaveBeforeClosing(_("Close Application")):
@@ -218,13 +239,13 @@
def RefreshTitle(self):
name = _("PLCOpenEditor")
if self.Controler is not None:
- self.SetTitle("%s - %s"%(name, self.Controler.GetFilename()))
+ self.SetTitle("%s - %s" % (name, self.Controler.GetFilename()))
else:
self.SetTitle(name)
-#-------------------------------------------------------------------------------
-# File Menu Functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # File Menu Functions
+ # -------------------------------------------------------------------------------
def RefreshFileMenu(self):
MenuToolBar = self.Panes["MenuToolBar"]
@@ -316,7 +337,7 @@
if result is not None:
(num, line) = result
- self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1 = num, a2 = line))
+ self.ShowErrorMessage(_("PLC syntax error at line {a1}:\n{a2}").format(a1=num, a2=line))
def OnCloseProjectMenu(self, event):
if not self.CheckSaveBeforeClosing():
@@ -331,7 +352,7 @@
self.SaveProjectAs()
def OnGenerateProgramMenu(self, event):
- dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE|wx.CHANGE_DIR)
+ dialog = wx.FileDialog(self, _("Choose a file"), os.getcwd(), self.Controler.GetProgramFilePath(), _("ST files (*.st)|*.st|All files|*.*"), wx.SAVE | wx.CHANGE_DIR)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
message_text = ""
@@ -341,14 +362,14 @@
message_text += "".join([_("warning: %s\n") % warning for warning in warnings])
if len(errors) > 0:
message_text += "".join([_("error: %s\n") % error for error in errors])
- message_text += _("Can't generate program to file %s!")%filepath
+ message_text += _("Can't generate program to file %s!") % filepath
header, icon = _("Error"), wx.ICON_ERROR
else:
message_text += _("Program was successfully generated!")
else:
- message_text += _("\"%s\" is not a valid folder!")%os.path.dirname(filepath)
+ message_text += _("\"%s\" is not a valid folder!") % os.path.dirname(filepath)
header, icon = _("Error"), wx.ICON_ERROR
- message = wx.MessageDialog(self, message_text, header, wx.OK|icon)
+ message = wx.MessageDialog(self, message_text, header, wx.OK | icon)
message.ShowModal()
message.Destroy()
dialog.Destroy()
@@ -379,28 +400,30 @@
if filepath != "":
directory, filename = os.path.split(filepath)
else:
- directory, filename = os.getcwd(), "%(projectName)s.xml"%self.Controler.GetProjectProperties()
- dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE|wx.OVERWRITE_PROMPT)
+ directory, filename = os.getcwd(), "%(projectName)s.xml" % self.Controler.GetProjectProperties()
+ dialog = wx.FileDialog(self, _("Choose a file"), directory, filename, _("PLCOpen files (*.xml)|*.xml|All files|*.*"), wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
filepath = dialog.GetPath()
if os.path.isdir(os.path.dirname(filepath)):
result = self.Controler.SaveXMLFile(filepath)
if not result:
- self.ShowErrorMessage(_("Can't save project to file %s!")%filepath)
+ self.ShowErrorMessage(_("Can't save project to file %s!") % filepath)
else:
- self.ShowErrorMessage(_("\"%s\" is not a valid folder!")%os.path.dirname(filepath))
+ self.ShowErrorMessage(_("\"%s\" is not a valid folder!") % os.path.dirname(filepath))
self._Refresh(TITLE, FILEMENU, PAGETITLES)
dialog.Destroy()
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Exception Handler
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
Max_Traceback_List_Size = 20
-def Display_Exception_Dialog(e_type,e_value,e_tb):
+
+def Display_Exception_Dialog(e_type, e_value, e_tb):
trcbck_lst = []
- for i,line in enumerate(traceback.extract_tb(e_tb)):
+ for i, line in enumerate(traceback.extract_tb(e_tb)):
trcbck = " " + str(i+1) + _(". ")
if line[0].find(os.getcwd()) == -1:
trcbck += _("file : ") + str(line[0]) + _(", ")
@@ -414,7 +437,8 @@
if cap:
cap.ReleaseMouse()
- dlg = wx.SingleChoiceDialog(None,
+ dlg = wx.SingleChoiceDialog(
+ None,
_("""
An unhandled exception (bug) occured. Bug report saved at :
(%s)
@@ -436,11 +460,13 @@
return res
+
def Display_Error_Dialog(e_value):
- message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(None, str(e_value), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
+
def get_last_traceback(tb):
while tb.tb_next:
tb = tb.tb_next
@@ -451,49 +477,51 @@
return '\n'.join(['%s%s: %s' % (indent, k, repr(v)[:10000]) for k, v in d.iteritems()])
-ignored_exceptions = [] # a problem with a line in a module is only reported once per session
-
-def AddExceptHook(path, app_version='[No version]'):#, ignored_exceptions=[]):
+ignored_exceptions = [] # a problem with a line in a module is only reported once per session
+
+
+def AddExceptHook(path, app_version='[No version]'):
def handle_exception(e_type, e_value, e_traceback):
- traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
+ traceback.print_exception(e_type, e_value, e_traceback) # this is very helpful when there's an exception in the rest of this func
last_tb = get_last_traceback(e_traceback)
ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
if str(e_value).startswith("!!!"):
Display_Error_Dialog(e_value)
elif ex not in ignored_exceptions:
- result = Display_Exception_Dialog(e_type,e_value,e_traceback)
+ result = Display_Exception_Dialog(e_type, e_value, e_traceback)
if result:
ignored_exceptions.append(ex)
info = {
- 'app-title' : wx.GetApp().GetAppName(), # app_title
- 'app-version' : app_version,
- 'wx-version' : wx.VERSION_STRING,
- 'wx-platform' : wx.Platform,
- 'python-version' : platform.python_version(), #sys.version.split()[0],
- 'platform' : platform.platform(),
- 'e-type' : e_type,
- 'e-value' : e_value,
- 'date' : time.ctime(),
- 'cwd' : os.getcwd(),
+ 'app-title': wx.GetApp().GetAppName(),
+ 'app-version': app_version,
+ 'wx-version': wx.VERSION_STRING,
+ 'wx-platform': wx.Platform,
+ 'python-version': platform.python_version(),
+ 'platform': platform.platform(),
+ 'e-type': e_type,
+ 'e-value': e_value,
+ 'date': time.ctime(),
+ 'cwd': os.getcwd(),
}
if e_traceback:
info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
last_tb = get_last_traceback(e_traceback)
- exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
+ exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
info['locals'] = format_namespace(exception_locals)
if 'self' in exception_locals:
info['self'] = format_namespace(exception_locals['self'].__dict__)
- output = open(path+os.sep+"bug_report_"+time.strftime("%Y_%m_%d__%H-%M-%S")+".txt",'w')
+ output = open(path+os.sep+"bug_report_"+time.strftime("%Y_%m_%d__%H-%M-%S")+".txt", 'w')
lst = info.keys()
lst.sort()
for a in lst:
output.write(a+":\n"+str(info[a])+"\n\n")
- #sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
+ # sys.excepthook = lambda *args: wx.CallAfter(handle_exception, *args)
sys.excepthook = handle_exception
+
if __name__ == '__main__':
if wx.VERSION < (3, 0, 0):
wx.InitAllImageHandlers()
@@ -505,4 +533,3 @@
frame.Show()
app.MainLoop()
-
--- a/POULibrary.py Mon Aug 21 20:17:19 2017 +0000
+++ b/POULibrary.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,6 +24,7 @@
from weakref import ref
+
class POULibrary:
def __init__(self, CTR, LibName, TypeStack):
from PLCControler import PLCControler
@@ -33,21 +34,21 @@
self.LibraryControler.OpenXMLFile(self.GetLibraryPath())
self.LibraryControler.ClearConfNodeTypes()
self.LibraryControler.AddConfNodeTypesList(TypeStack)
- self.program = None;
+ self.program = None
def GetSTCode(self):
if not self.program:
self.program = self.LibraryControler.GenerateProgram()[0]+"\n"
- return self.program
+ return self.program
def GetName(self):
return self.LibName
def GetCTR(self):
return self.CTR()
-
+
def GetTypes(self):
- return {"name" : self.GetName(), "types": self.LibraryControler.Project}
+ return {"name": self.GetName(), "types": self.LibraryControler.Project}
def GetLibraryPath(self):
raise Exception("Not implemented")
--- a/ProjectController.py Mon Aug 21 20:17:19 2017 +0000
+++ b/ProjectController.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,12 +26,15 @@
"""
Beremiz Project Controller
"""
-import os,sys,traceback
+import os
+import sys
+import traceback
import time
import features
import shutil
import wx
-import re, tempfile
+import re
+import tempfile
from math import ceil
from types import ListType
from threading import Timer, Lock, Thread
@@ -64,18 +67,20 @@
ITEM_CONFNODE = 25
+
def ExtractChildrenTypesFromCatalog(catalog):
children_types = []
- for n,d,h,c in catalog:
+ for n, d, h, c in catalog:
if isinstance(c, ListType):
children_types.extend(ExtractChildrenTypesFromCatalog(c))
else:
children_types.append((n, GetClassImporter(c), d))
return children_types
+
def ExtractMenuItemsFromCatalog(catalog):
menu_items = []
- for n,d,h,c in catalog:
+ for n, d, h, c in catalog:
if isinstance(c, ListType):
children = ExtractMenuItemsFromCatalog(c)
else:
@@ -83,63 +88,66 @@
menu_items.append((n, d, h, children))
return menu_items
+
def GetAddMenuItems():
return ExtractMenuItemsFromCatalog(features.catalog)
+
class Iec2CSettings():
def __init__(self):
self.iec2c = None
self.iec2c_buildopts = None
- self.ieclib_path = self.findLibPath()
+ self.ieclib_path = self.findLibPath()
self.ieclib_c_path = self.findLibCPath()
def findObject(self, paths, test):
- path=None
+ path = None
for p in paths:
if test(p):
path = p
- break
+ break
return path
-
+
def findCmd(self):
- cmd="iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")
- paths=[
+ cmd = "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")
+ paths = [
os.path.join(base_folder, "matiec")
]
- path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, cmd)))
+ path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, cmd)))
# otherwise use iec2c from PATH
if path is not None:
- cmd=os.path.join(path, cmd)
+ cmd = os.path.join(path, cmd)
return cmd
-
+
def findLibPath(self):
- paths=[
+ paths = [
os.path.join(base_folder, "matiec", "lib"),
"/usr/lib/matiec"
]
- path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, "ieclib.txt")))
+ path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, "ieclib.txt")))
return path
-
+
def findLibCPath(self):
- path=None
- paths=[
+ path = None
+ paths = [
os.path.join(self.ieclib_path, "C"),
self.ieclib_path]
- path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, "iec_types.h")))
+ path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, "iec_types.h")))
return path
def findSupportedOptions(self):
- buildcmd = "\"%s\" -h"%(self.getCmd())
- options =["-f", "-l", "-p"]
+ buildcmd = "\"%s\" -h" % (self.getCmd())
+ options = ["-f", "-l", "-p"]
buildopt = ""
try:
# Invoke compiler. Output files are listed to stdout, errors to stderr
status, result, err_result = ProcessLogger(None, buildcmd,
- no_stdout=True, no_stderr=True).spin()
- except Exception,e:
+ no_stdout=True,
+ no_stderr=True).spin()
+ except Exception, e:
return buildopt
for opt in options:
@@ -165,8 +173,10 @@
self.ieclib_c_path = self.findLibCPath()
return self.ieclib_c_path
+
iec2c_cfg = Iec2CSettings()
+
class ProjectController(ConfigTreeNode, PLCControler):
"""
This class define Root object of the confnode tree.
@@ -196,12 +206,12 @@
</xsd:element>"""+(("""
<xsd:element name="Libraries" minOccurs="0">
<xsd:complexType>
- """+"\n".join(['<xsd:attribute name='+
- '"Enable_'+ libname + '_Library" '+
+ """+"\n".join(['<xsd:attribute name=' +
+ '"Enable_' + libname + '_Library" ' +
'type="xsd:boolean" use="optional" default="true"/>'
- for libname,lib in features.libraries])+"""
+ for libname, lib in features.libraries])+"""
</xsd:complexType>
- </xsd:element>""") if len(features.libraries)>0 else '') + """
+ </xsd:element>""") if len(features.libraries) > 0 else '') + """
</xsd:sequence>
<xsd:attribute name="URI_location" type="xsd:string" use="optional" default=""/>
<xsd:attribute name="Disable_Extensions" type="xsd:boolean" use="optional" default="false"/>
@@ -226,7 +236,7 @@
self.IECdebug_datas = {}
self.IECdebug_lock = Lock()
- self.DebugTimer=None
+ self.DebugTimer = None
self.ResetIECProgramsAndVariables()
# In both new or load scenario, no need to save
@@ -253,8 +263,8 @@
def LoadLibraries(self):
self.Libraries = []
- TypeStack=[]
- for libname,clsname in features.libraries:
+ TypeStack = []
+ for libname, clsname in features.libraries:
if self.BeremizRoot.Libraries is None or getattr(self.BeremizRoot.Libraries, "Enable_"+libname+"_Library"):
Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
TypeStack.append(Lib.GetTypes())
@@ -273,7 +283,8 @@
# Timer to pull PLC status
self.StatusTimer = wx.Timer(self.AppFrame, -1)
self.AppFrame.Bind(wx.EVT_TIMER,
- self.PullPLCStatusProc, self.StatusTimer)
+ self.PullPLCStatusProc,
+ self.StatusTimer)
if self._connector is not None:
frame.LogViewer.SetLogSource(self._connector)
@@ -282,7 +293,8 @@
# Timer to dispatch debug values to consumers
self.DispatchDebugValuesTimer = wx.Timer(self.AppFrame, -1)
self.AppFrame.Bind(wx.EVT_TIMER,
- self.DispatchDebugValuesProc, self.DispatchDebugValuesTimer)
+ self.DispatchDebugValuesProc,
+ self.DispatchDebugValuesTimer)
self.RefreshConfNodesBlockLists()
@@ -298,7 +310,7 @@
return "Project"
def CTNTestModified(self):
- return self.ChangesToSave or not self.ProjectIsSaved()
+ return self.ChangesToSave or not self.ProjectIsSaved()
def CTNFullName(self):
return ""
@@ -346,7 +358,7 @@
target.setcontent(self.Parser.CreateElement(target_name, "TargetType"))
return target
- def GetParamsAttributes(self, path = None):
+ def GetParamsAttributes(self, path=None):
params = ConfigTreeNode.GetParamsAttributes(self, path)
if params[0]["name"] == "BeremizRoot":
for child in params[0]["children"]:
@@ -367,10 +379,11 @@
if CheckPathPerm(self.ProjectPath):
return True
if self.AppFrame is not None:
- 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)
+ 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:
@@ -452,7 +465,7 @@
if error is not None:
if self.Project is not None:
(fname_err, lnum, src) = (("PLC",) + error)
- self.logger.write_warning(XSDSchemaErrorMessage.format(a1 = fname_err, a2 = lnum, a3 = src))
+ self.logger.write_warning(XSDSchemaErrorMessage.format(a1=fname_err, a2=lnum, a3=src))
else:
return error, False
if len(self.GetProjectConfigNames()) == 0:
@@ -465,11 +478,11 @@
self._setBuildPath(BuildPath)
# If dir have already be made, and file exist
if os.path.isdir(self.CTNPath()) and os.path.isfile(self.ConfNodeXmlFilePath()):
- #Load the confnode.xml file into parameters members
+ # Load the confnode.xml file into parameters members
result = self.LoadXMLParams()
if result:
return result, False
- #Load and init all the children
+ # Load and init all the children
self.LoadChildren()
self.RefreshConfNodesBlockLists()
self.UpdateButtons()
@@ -539,7 +552,7 @@
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)
+ 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:
@@ -554,24 +567,24 @@
def GetLibrariesTypes(self):
self.LoadLibraries()
- return [ lib.GetTypes() for lib in self.Libraries ]
+ return [lib.GetTypes() for lib in self.Libraries]
def GetLibrariesSTCode(self):
- return "\n".join([ lib.GetSTCode() for lib in self.Libraries ])
+ return "\n".join([lib.GetSTCode() for lib in self.Libraries])
def GetLibrariesCCode(self, buildpath):
- if len(self.Libraries)==0:
- return [],[],()
+ if len(self.Libraries) == 0:
+ return [], [], ()
self.GetIECProgramsAndVariables()
- LibIECCflags = '"-I%s" -Wno-unused-function'%os.path.abspath(self.GetIECLibPath())
- LocatedCCodeAndFlags=[]
- Extras=[]
+ LibIECCflags = '"-I%s" -Wno-unused-function' % os.path.abspath(self.GetIECLibPath())
+ LocatedCCodeAndFlags = []
+ Extras = []
for lib in self.Libraries:
- res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)
+ res = lib.Generate_C(buildpath, self._VariablesList, LibIECCflags)
LocatedCCodeAndFlags.append(res[:2])
- if len(res)>2:
+ if len(res) > 2:
Extras.extend(res[2:])
- return map(list,zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
+ return map(list, zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
# Update PLCOpenEditor ConfNode Block types from loaded confnodes
def RefreshConfNodesBlockLists(self):
@@ -660,10 +673,10 @@
def GetLocations(self):
locations = []
- filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
+ 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"))
+ 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
@@ -675,7 +688,7 @@
# 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(',')))
+ resdict['LOC'] = tuple(map(int, resdict['LOC'].split(',')))
# set located size to 'X' if not given
if not resdict['SIZE']:
resdict['SIZE'] = 'X'
@@ -706,10 +719,10 @@
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)
+ 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])
+ 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
@@ -728,12 +741,10 @@
plc_file.close()
return True
-
-
def _Compile_ST_to_SoftPLC(self):
self.logger.write(_("Compiling IEC Program into C code...\n"))
buildpath = self._getBuildPath()
- buildcmd = "\"%s\" %s -I \"%s\" -T \"%s\" \"%s\""%(
+ buildcmd = "\"%s\" %s -I \"%s\" -T \"%s\" \"%s\"" % (
iec2c_cfg.getCmd(),
iec2c_cfg.getOptions(),
iec2c_cfg.getLibPath(),
@@ -743,8 +754,8 @@
try:
# Invoke compiler. Output files are listed to stdout, errors to stderr
status, result, err_result = ProcessLogger(self.logger, buildcmd,
- no_stdout=True, no_stderr=True).spin()
- except Exception,e:
+ no_stdout=True, no_stderr=True).spin()
+ except Exception, e:
self.logger.write_error(buildcmd + "\n")
self.logger.write_error(repr(e) + "\n")
return False
@@ -773,31 +784,33 @@
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
+ 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)
+ 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" ]
+ 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)
+ C_files = map(lambda filename: os.path.join(buildpath, filename), C_files)
# prepend beremiz include to configuration header
- H_files = [ fname for fname in result.splitlines() if fname[-2:]==".h" or fname[-2:]==".H" ]
+ H_files = [fname for fname in result.splitlines() if fname[-2:] == ".h" or fname[-2:] == ".H"]
H_files.remove("LOCATED_VARIABLES.h")
- H_files = map(lambda filename:os.path.join(buildpath, filename), H_files)
+ H_files = map(lambda filename: os.path.join(buildpath, filename), H_files)
for H_file in H_files:
- with file(H_file, 'r') as original: data = original.read()
- with file(H_file, 'w') as modified: modified.write('#include "beremiz.h"\n' + data)
+ with file(H_file, 'r') as original:
+ data = original.read()
+ with file(H_file, 'w') as modified:
+ modified.write('#include "beremiz.h"\n' + data)
self.logger.write(_("Extracting Located Variables...\n"))
# Keep track of generated located variables for later use by self._Generate_C
@@ -805,7 +818,7 @@
# Keep track of generated C files for later use by self.CTNGenerate_C
self.PLCGeneratedCFiles = C_files
# compute CFLAGS for plc
- self.plcCFLAGS = '"-I%s" -Wno-unused-function'%iec2c_cfg.getLibCPath()
+ self.plcCFLAGS = '"-I%s" -Wno-unused-function' % iec2c_cfg.getLibCPath()
return True
def GetBuilder(self):
@@ -817,19 +830,19 @@
targetclass = targets.GetBuilder(targetname)
# if target already
- if self._builder is None or not isinstance(self._builder,targetclass):
+ 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()
+ builder = self.GetBuilder()
if builder is not None:
builder.ResetBinaryCodeMD5()
self.EnableMethod("_Transfer", False)
def GetLastBuildMD5(self):
- builder=self.GetBuilder()
+ builder = self.GetBuilder()
if builder is not None:
return builder.GetBinaryCodeMD5()
else:
@@ -850,9 +863,9 @@
"""
return ([(C_file_name, self.plcCFLAGS)
- for C_file_name in self.PLCGeneratedCFiles ],
- "", # no ldflags
- False) # do not expose retreive/publish calls
+ for C_file_name in self.PLCGeneratedCFiles],
+ "", # no ldflags
+ False) # do not expose retreive/publish calls
def ResetIECProgramsAndVariables(self):
"""
@@ -875,7 +888,7 @@
"""
if self._ProgramList is None or self._VariablesList is None:
try:
- csvfile = os.path.join(self._getBuildPath(),"VARIABLES.csv")
+ csvfile = os.path.join(self._getBuildPath(), "VARIABLES.csv")
# describes CSV columns
ProgramsListAttributeName = ["num", "C_path", "type"]
VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
@@ -886,7 +899,7 @@
# Separate sections
ListGroup = []
- for line in open(csvfile,'r').xreadlines():
+ for line in open(csvfile, 'r').xreadlines():
strippedline = line.strip()
if strippedline.startswith("//"):
# Start new section
@@ -898,9 +911,9 @@
# first section contains programs
for line in ListGroup[0]:
# Split and Maps each field to dictionnary entries
- attrs = dict(zip(ProgramsListAttributeName,line.strip().split(';')))
+ attrs = dict(zip(ProgramsListAttributeName, line.strip().split(';')))
# Truncate "C_path" to remove conf an resources names
- attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
+ attrs["C_path"] = '__'.join(attrs["C_path"].split(".", 2)[1:])
# Push this dictionnary into result.
self._ProgramList.append(attrs)
@@ -909,9 +922,9 @@
Idx = 0
for line in ListGroup[1]:
# Split and Maps each field to dictionnary entries
- attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
+ attrs = dict(zip(VariablesListAttributeName, line.strip().split(';')))
# Truncate "C_path" to remove conf an resources names
- parts = attrs["C_path"].split(".",2)
+ parts = attrs["C_path"].split(".", 2)
if len(parts) > 2:
config_FB = config_FBs.get(tuple(parts[:2]))
if config_FB:
@@ -927,19 +940,19 @@
# Push this dictionnary into result.
self._DbgVariablesList.append(attrs)
# Fill in IEC<->C translation dicts
- IEC_path=attrs["IEC_path"]
- self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
+ IEC_path = attrs["IEC_path"]
+ self._IECPathToIdx[IEC_path] = (Idx, attrs["type"])
# Ignores numbers given in CSV file
# Idx=int(attrs["num"])
# Count variables only, ignore FBs
- Idx+=1
+ Idx += 1
self._VariablesList.append(attrs)
# third section contains ticktime
if len(ListGroup) > 2:
self._Ticktime = int(ListGroup[2][0])
- except Exception,e:
+ except Exception, e:
self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
self.logger.write_error(traceback.format_exc())
self.ResetIECProgramsAndVariables()
@@ -956,31 +969,35 @@
# prepare debug code
variable_decl_array = []
bofs = 0
- for v in self._DbgVariablesList :
+ for v in self._DbgVariablesList:
sz = DebugTypesSize.get(v["type"], 0)
variable_decl_array += [
- "{&(%(C_path)s), "%v+
- {"EXT":"%(type)s_P_ENUM",
- "IN":"%(type)s_P_ENUM",
- "MEM":"%(type)s_O_ENUM",
- "OUT":"%(type)s_O_ENUM",
- "VAR":"%(type)s_ENUM"}[v["vartype"]]%v +
- "}"]
+ "{&(%(C_path)s), " % v +
+ {
+ "EXT": "%(type)s_P_ENUM",
+ "IN": "%(type)s_P_ENUM",
+ "MEM": "%(type)s_O_ENUM",
+ "OUT": "%(type)s_O_ENUM",
+ "VAR": "%(type)s_ENUM"
+ }[v["vartype"]] % v +
+ "}"]
bofs += sz
debug_code = targets.GetCode("plc_debug.c") % {
- "buffer_size":bofs,
- "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;",
- "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
- for v in self._VariablesList if v["C_path"].find('.')<0]),
- "variable_decl_array": ",\n".join(variable_decl_array)
- }
+ "buffer_size": bofs,
+ "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;",
+ "FB": "extern %(type)s %(C_path)s;"
+ }[v["vartype"]] % v
+ for v in self._VariablesList if v["C_path"].find('.') < 0]),
+ "variable_decl_array": ",\n".join(variable_decl_array)
+ }
return debug_code
@@ -991,43 +1008,43 @@
"""
# 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])
+ 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 not self.BeremizRoot.getDisable_Extensions():
plc_main_code = targets.GetCode("plc_main_head.c") % {
- "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();"%locstr for locstr in locstrs]),
- "publish_calls":"\n ".join([ #Call publish in reverse order
- "__publish_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
- "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)])
+ "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();" % locstr for locstr in locstrs]),
+ "publish_calls": "\n ".join([ # Call publish in reverse order
+ "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
+ "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.GetCode("plc_main_head.c") % {
- "calls_prototypes":"\n",
- "retrieve_calls":"\n",
- "publish_calls":"\n",
- "init_calls":"\n",
- "cleanup_calls":"\n"
- }
+ "calls_prototypes": "\n",
+ "retrieve_calls": "\n",
+ "publish_calls": "\n",
+ "init_calls": "\n",
+ "cleanup_calls": "\n"
+ }
plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
plc_main_code += targets.GetCode("plc_main_tail.c")
return plc_main_code
-
def _Build(self):
"""
Method called by user to (re)build SoftPLC and confnode tree
@@ -1073,7 +1090,7 @@
# Build
try:
- if not builder.build() :
+ if not builder.build():
self.logger.write_error(_("C Build failed.\n"))
return False
except Exception, exc:
@@ -1110,7 +1127,7 @@
self.ResetBuildMD5()
return False
- self.LocationCFilesAndCFLAGS = LibCFilesAndCFLAGS + CTNLocationCFilesAndCFLAGS
+ self.LocationCFilesAndCFLAGS = LibCFilesAndCFLAGS + CTNLocationCFilesAndCFLAGS
self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
ExtraFiles = CTNExtraFiles + LibExtraFiles
@@ -1122,14 +1139,14 @@
# Recreate directory
os.mkdir(extrafilespath)
# Then write the files
- for fname,fobject in ExtraFiles:
- fpath = os.path.join(extrafilespath,fname)
+ 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
# Header file for extensions
- open(os.path.join(buildpath,"beremiz.h"), "w").write(targets.GetHeader())
+ open(os.path.join(buildpath, "beremiz.h"), "w").write(targets.GetHeader())
# Template based part of C code generation
# files are stacked at the beginning, as files of confnode tree root
@@ -1137,16 +1154,16 @@
# debugger code
(self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
# init/cleanup/retrieve/publish, run and align code
- (self.Generate_plc_main,"plc_main.c","Common runtime")]:
+ (self.Generate_plc_main, "plc_main.c", "Common runtime")]:
try:
# Do generate
code = generator()
if code is None:
- raise
- code_path = os.path.join(buildpath,filename)
+ 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))
+ 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())
@@ -1158,30 +1175,34 @@
def ShowError(self, logger, from_location, to_location):
chunk_infos = self.GetChunkInfos(from_location, to_location)
for infos, (start_row, start_col) in chunk_infos:
- row = 1 if from_location[0] < start_row else (from_location[0] - start_row)
+ row = 1 if from_location[0] < start_row else (from_location[0] - start_row)
col = 1 if (start_row != from_location[0]) else (from_location[1] - start_col)
start = (row, col)
- row = 1 if to_location[0] < start_row else (to_location[0] - start_row)
+ row = 1 if to_location[0] < start_row else (to_location[0] - start_row)
col = 1 if (start_row != to_location[0]) else (to_location[1] - start_col)
end = (row, col)
-
+
if self.AppFrame is not None:
self.AppFrame.ShowError(infos, start, end)
_IECCodeView = None
+
def _showIECcode(self):
self._OpenView("IEC code")
_IECRawCodeView = None
+
def _editIECrawcode(self):
self._OpenView("IEC raw code")
_ProjectFilesView = None
+
def _OpenProjectFiles(self):
self._OpenView("Project Files")
_FileEditors = {}
+
def _OpenFileEditor(self, filepath):
self._OpenView(filepath)
@@ -1195,10 +1216,10 @@
self._IECCodeView.SetKeywords(IEC_KEYWORDS)
try:
text = file(plc_file).read()
- except:
+ except Exception:
text = '(* No IEC code have been generated at that time ! *)'
- self._IECCodeView.SetText(text = text)
- self._IECCodeView.Editor.SetReadOnly(True)
+ self._IECCodeView.SetText(text=text)
+ self._IECCodeView.Editor.SetReadOnly(True)
self._IECCodeView.SetIcon(GetBitmap("ST"))
setattr(self._IECCodeView, "_OnClose", self.OnCloseEditor)
@@ -1240,7 +1261,7 @@
elif name is not None and name.find("::") != -1:
filepath, editor_name = name.split("::")
- if not self._FileEditors.has_key(filepath):
+ if filepath not in self._FileEditors:
if os.path.isfile(filepath):
file_extension = os.path.splitext(filepath)[1]
@@ -1253,9 +1274,12 @@
editor_name = editors.keys()[0]
elif len(editors) > 0:
names = editors.keys()
- dialog = wx.SingleChoiceDialog(self.AppFrame,
- _("Select an editor:"), _("Editor selection"),
- names, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(
+ self.AppFrame,
+ _("Select an editor:"),
+ _("Editor selection"),
+ names,
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
editor_name = names[dialog.GetSelection()]
dialog.Destroy()
@@ -1269,7 +1293,7 @@
if isinstance(self._FileEditors[filepath], DebugViewer):
self._FileEditors[filepath].SetDataProducer(self)
- if self._FileEditors.has_key(filepath):
+ if filepath in self._FileEditors:
editor = self._FileEditors[filepath]
self.AppFrame.EditProjectElement(editor, editor.GetTagName())
@@ -1305,11 +1329,10 @@
self.ShowMethod("_showIECcode", os.path.isfile(self._getIECcodepath()))
if self.AppFrame is not None and not self.UpdateMethodsFromPLCStatus():
self.AppFrame.RefreshStatusToolBar()
-
+
def UpdateButtons(self):
wx.CallAfter(self._UpdateButtons)
-
def UpdatePLCLog(self, log_count):
if log_count:
if self.AppFrame is not None:
@@ -1328,19 +1351,19 @@
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,[]):
+ "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
if self.AppFrame is not None:
@@ -1364,8 +1387,8 @@
"Disconnected": _("Disconnected")
}
return msgs.get(status, status)
-
- def ShowPLCProgress(self, status = "", progress = 0):
+
+ def ShowPLCProgress(self, status="", progress=0):
self.AppFrame.ProgressStatusBar.Show()
self.AppFrame.ConnectionStatusBar.SetStatusText(self.GetTextStatus(status), 1)
self.AppFrame.ProgressStatusBar.SetValue(progress)
@@ -1376,25 +1399,25 @@
self.previous_plcstate = ""
self.AppFrame.ProgressStatusBar.Hide()
self.UpdateMethodsFromPLCStatus()
-
+
def PullPLCStatusProc(self, event):
self.UpdateMethodsFromPLCStatus()
def SnapshotAndResetDebugValuesBuffers(self):
buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
- [list() for n in xrange(len(self.TracedIECPath))])
+ [list() for n in xrange(len(self.TracedIECPath))])
ticks, self.DebugTicks = self.DebugTicks, []
return ticks, buffers
def RegisterDebugVarToConnector(self):
- self.DebugTimer=None
+ self.DebugTimer = None
Idxs = []
self.TracedIECPath = []
self.TracedIECTypes = []
if self._connector is not None:
self.IECdebug_lock.acquire()
IECPathsToPop = []
- for IECPath,data_tuple in self.IECdebug_datas.iteritems():
+ for IECPath, data_tuple in self.IECdebug_datas.iteritems():
WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
if len(WeakCallableDict) == 0:
# Callable Dict is empty.
@@ -1402,14 +1425,14 @@
IECPathsToPop.append(IECPath)
elif IECPath != "__tick__":
# Convert
- Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
+ 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: Unsupported type to debug '%s'\n")%IEC_Type)
+ self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n") % IEC_Type)
else:
- self.logger.write_warning(_("Debug: Unknown variable '%s'\n")%IECPath)
+ self.logger.write_warning(_("Debug: Unknown variable '%s'\n") % IECPath)
for IECPathToPop in IECPathsToPop:
self.IECdebug_datas.pop(IECPathToPop)
@@ -1438,12 +1461,12 @@
if self.IsPLCStarted():
# 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])
+ 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))
+ Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
return IEC_Type
def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False):
@@ -1452,24 +1475,24 @@
to a WeakKeyDictionary linking
weakly referenced callables
"""
- if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
+ if IECPath != "__tick__" and IECPath not in self._IECPathToIdx:
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
+ IECdebug_data = [
+ WeakKeyDictionary(), # Callables
+ [], # Data storage [(tick, data),...]
+ "Registered", # Variable status
None,
buffer_list] # Forced value
self.IECdebug_datas[IECPath] = IECdebug_data
else:
IECdebug_data[4] |= buffer_list
- IECdebug_data[0][callableobj]=buffer_list
+ IECdebug_data[0][callableobj] = buffer_list
self.IECdebug_lock.release()
@@ -1481,12 +1504,12 @@
self.IECdebug_lock.acquire()
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
if IECdebug_data is not None:
- IECdebug_data[0].pop(callableobj,None)
+ IECdebug_data[0].pop(callableobj, None)
if len(IECdebug_data[0]) == 0:
self.IECdebug_datas.pop(IECPath)
else:
IECdebug_data[4] = reduce(
- lambda x, y: x|y,
+ lambda x, y: x | y,
IECdebug_data[0].itervalues(),
False)
self.IECdebug_lock.release()
@@ -1501,7 +1524,7 @@
self.ReArmDebugRegisterTimer()
def ForceDebugIECVariable(self, IECPath, fvalue):
- if not self.IECdebug_datas.has_key(IECPath):
+ if IECPath not in self.IECdebug_datas:
return
self.IECdebug_lock.acquire()
@@ -1516,7 +1539,7 @@
self.ReArmDebugRegisterTimer()
def ReleaseDebugIECVariable(self, IECPath):
- if not self.IECdebug_datas.has_key(IECPath):
+ if IECPath not in self.IECdebug_datas:
return
self.IECdebug_lock.acquire()
@@ -1534,8 +1557,8 @@
data_tuple = self.IECdebug_datas.get(IECPath, None)
if data_tuple is not None:
WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
- #data_log.append((debug_tick, value))
- for weakcallable,buffer_list in WeakCallableDict.iteritems():
+ # data_log.append((debug_tick, value))
+ for weakcallable, buffer_list in WeakCallableDict.iteritems():
function = getattr(weakcallable, function_name, None)
if function is not None:
if buffer_list:
@@ -1560,20 +1583,19 @@
while (not self.debug_break) and (self._connector is not None):
plc_status, Traces = self._connector.GetTraceVariables()
debug_getvar_retry += 1
- #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
- if plc_status == "Started" :
+ # print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
+ if plc_status == "Started":
if len(Traces) > 0:
Failed = False
self.IECdebug_lock.acquire()
- for debug_tick, debug_buff in Traces :
+ for debug_tick, debug_buff in Traces:
debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
- if (debug_vars is not None and
- len(debug_vars) == len(self.TracedIECPath)):
+ if debug_vars is not None and len(debug_vars) == len(self.TracedIECPath):
for IECPath, values_buffer, value in izip(
self.TracedIECPath,
self.DebugValuesBuffers,
debug_vars):
- IECdebug_data = self.IECdebug_datas.get(IECPath, None) #FIXME get
+ IECdebug_data = self.IECdebug_datas.get(IECPath, None) # FIXME get
if IECdebug_data is not None and value is not None:
forced = IECdebug_data[2:4] == ["Forced", value]
if not IECdebug_data[4] and len(values_buffer) > 0:
@@ -1659,7 +1681,7 @@
self.logger.write_error(_("Couldn't stop PLC !\n"))
# debugthread should die on his own
- #self.KillDebugThread()
+ # self.KillDebugThread()
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
@@ -1686,10 +1708,7 @@
return
# Get connector uri
- uri = self.\
- BeremizRoot.\
- getURI_location().\
- strip()
+ uri = self.BeremizRoot.getURI_location().strip()
# if uri is empty launch discovery dialog
if uri == "":
@@ -1699,7 +1718,7 @@
answer = dialog.ShowModal()
uri = dialog.GetURI()
dialog.Destroy()
- except:
+ except Exception:
self.logger.write_error(_("Local service discovery failed!\n"))
self.logger.write_error(traceback.format_exc())
uri = None
@@ -1709,9 +1728,7 @@
self.logger.write_error(_("Connection canceled!\n"))
return
else:
- self.\
- BeremizRoot.\
- setURI_location(uri)
+ self.BeremizRoot.setURI_location(uri)
self.ChangesToSave = True
if self._View is not None:
self._View.RefreshView()
@@ -1725,13 +1742,13 @@
try:
self._SetConnector(connectors.ConnectorFactory(uri, self))
except Exception, msg:
- self.logger.write_error(_("Exception while connecting %s!\n")%uri)
+ 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)
+ self.logger.write_error(_("Connection failed to %s!\n") % uri)
else:
self.ShowMethod("_Connect", False)
self.ShowMethod("_Disconnect", True)
@@ -1746,9 +1763,9 @@
else:
status = ""
- #self.logger.write(_("PLC is %s\n")%status)
-
- if self.previous_plcstate in ["Started","Stopped"]:
+ # self.logger.write(_("PLC is %s\n")%status)
+
+ if self.previous_plcstate in ["Started", "Stopped"]:
if self.DebugAvailable() and self.GetIECProgramsAndVariables():
self.logger.write(_("Debugger ready\n"))
self._connect_debug()
@@ -1763,22 +1780,21 @@
# 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.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.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)
+ # self.EnableMethod("_Transfer", False)
else:
-# self.logger.write_warning(
-# _("Cannot compare latest build to target. Please build.\n"))
+ # self.logger.write_warning(
+ # _("Cannot compare latest build to target. Please build.\n"))
self.EnableMethod("_Transfer", False)
-
def _Disconnect(self):
self._SetConnector(None)
@@ -1787,7 +1803,7 @@
MD5 = self.GetLastBuildMD5()
# Check if md5 file is empty : ask user to build PLC
- if MD5 is None :
+ if MD5 is None:
self.logger.write_error(_("Failed : Must build before transfer.\n"))
return False
@@ -1803,14 +1819,14 @@
extrafiles.extend(
[(name, open(os.path.join(extrafilespath, name),
- 'rb').read()) \
+ 'rb').read())
for name in os.listdir(extrafilespath)])
# Send PLC on target
builder = self.GetBuilder()
if builder is not None:
data = builder.GetBinaryCode()
- if data is not None :
+ if data is not None:
if self._connector.NewPLC(MD5, data, extrafiles) and self.GetIECProgramsAndVariables():
self.UnsubscribeAllDebugIECVariable()
self.ProgramTransferred()
@@ -1818,83 +1834,102 @@
self.AppFrame.CloseObsoleteDebugTabs()
self.AppFrame.RefreshPouInstanceVariablesPanel()
self.logger.write(_("Transfer completed successfully.\n"))
- self.AppFrame.LogViewer.ResetLogCounters();
+ self.AppFrame.LogViewer.ResetLogCounters()
else:
self.logger.write_error(_("Transfer failed\n"))
- self.HidePLCProgress()
+ self.HidePLCProgress()
else:
self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n"))
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
StatusMethods = [
- {"bitmap" : "Build",
- "name" : _("Build"),
- "tooltip" : _("Build project into build folder"),
- "method" : "_Build"},
- {"bitmap" : "Clean",
- "name" : _("Clean"),
- "enabled" : False,
- "tooltip" : _("Clean project build folder"),
- "method" : "_Clean"},
- {"bitmap" : "Run",
- "name" : _("Run"),
- "shown" : False,
- "tooltip" : _("Start PLC"),
- "method" : "_Run"},
- {"bitmap" : "Stop",
- "name" : _("Stop"),
- "shown" : False,
- "tooltip" : _("Stop Running PLC"),
- "method" : "_Stop"},
- {"bitmap" : "Connect",
- "name" : _("Connect"),
- "tooltip" : _("Connect to the target PLC"),
- "method" : "_Connect"},
- {"bitmap" : "Transfer",
- "name" : _("Transfer"),
- "shown" : False,
- "tooltip" : _("Transfer PLC"),
- "method" : "_Transfer"},
- {"bitmap" : "Disconnect",
- "name" : _("Disconnect"),
- "shown" : False,
- "tooltip" : _("Disconnect from PLC"),
- "method" : "_Disconnect"},
- {"bitmap" : "ShowIECcode",
- "name" : _("Show code"),
- "shown" : False,
- "tooltip" : _("Show IEC code generated by PLCGenerator"),
- "method" : "_showIECcode"},
+ {
+ "bitmap": "Build",
+ "name": _("Build"),
+ "tooltip": _("Build project into build folder"),
+ "method": "_Build"
+ },
+ {
+ "bitmap": "Clean",
+ "name": _("Clean"),
+ "tooltip": _("Clean project build folder"),
+ "method": "_Clean",
+ "enabled": False,
+ },
+ {
+ "bitmap": "Run",
+ "name": _("Run"),
+ "tooltip": _("Start PLC"),
+ "method": "_Run",
+ "shown": False,
+ },
+ {
+ "bitmap": "Stop",
+ "name": _("Stop"),
+ "tooltip": _("Stop Running PLC"),
+ "method": "_Stop",
+ "shown": False,
+ },
+ {
+ "bitmap": "Connect",
+ "name": _("Connect"),
+ "tooltip": _("Connect to the target PLC"),
+ "method": "_Connect"
+ },
+ {
+ "bitmap": "Transfer",
+ "name": _("Transfer"),
+ "tooltip": _("Transfer PLC"),
+ "method": "_Transfer",
+ "shown": False,
+ },
+ {
+ "bitmap": "Disconnect",
+ "name": _("Disconnect"),
+ "tooltip": _("Disconnect from PLC"),
+ "method": "_Disconnect",
+ "shown": False,
+ },
+ {
+ "bitmap": "ShowIECcode",
+ "name": _("Show code"),
+ "tooltip": _("Show IEC code generated by PLCGenerator"),
+ "method": "_showIECcode",
+ "shown": False,
+ },
]
ConfNodeMethods = [
- {"bitmap" : "editIECrawcode",
- "name" : _("Raw IEC code"),
- "tooltip" : _("Edit raw IEC code added to code generated by PLCGenerator"),
- "method" : "_editIECrawcode"},
- {"bitmap" : "ManageFolder",
- "name" : _("Project Files"),
- "tooltip" : _("Open a file explorer to manage project files"),
- "method" : "_OpenProjectFiles"},
+ {
+ "bitmap": "editIECrawcode",
+ "name": _("Raw IEC code"),
+ "tooltip": _("Edit raw IEC code added to code generated by PLCGenerator"),
+ "method": "_editIECrawcode"
+ },
+ {
+ "bitmap": "ManageFolder",
+ "name": _("Project Files"),
+ "tooltip": _("Open a file explorer to manage project files"),
+ "method": "_OpenProjectFiles"
+ },
]
-
def EnableMethod(self, method, value):
for d in self.StatusMethods:
- if d["method"]==method:
- d["enabled"]=value
+ if d["method"] == method:
+ d["enabled"] = value
return True
return False
def ShowMethod(self, method, value):
for d in self.StatusMethods:
- if d["method"]==method:
- d["shown"]=value
+ if d["method"] == method:
+ d["shown"] = value
return True
return False
def CallMethod(self, method):
for d in self.StatusMethods:
- if d["method"]==method and d.get("enabled", True) and d.get("shown", True):
+ if d["method"] == method and d.get("enabled", True) and d.get("shown", True):
getattr(self, method)()
--- a/c_ext/CFileEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/c_ext/CFileEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,22 +27,23 @@
from controls.CustomStyledTextCtrl import faces
from editors.CodeFileEditor import CodeFileEditor, CodeEditor
+
class CppEditor(CodeEditor):
- KEYWORDS = ["asm", "auto", "bool", "break", "case", "catch", "char", "class",
- "const", "const_cast", "continue", "default", "delete", "do", "double",
- "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false",
- "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
- "namespace", "new", "operator", "private", "protected", "public", "register",
- "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
- "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
- "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
- "void", "volatile", "wchar_t", "while"]
+ 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"]
COMMENT_HEADER = "/"
-
+
def SetCodeLexer(self):
self.SetLexer(stc.STC_LEX_CPP)
-
+
self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060,size:%(size)d' % faces)
self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060,size:%(size)d' % faces)
self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060,size:%(size)d' % faces)
@@ -53,15 +54,12 @@
self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold,size:%(size)d' % faces)
self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF,size:%(size)d' % faces)
-#-------------------------------------------------------------------------------
-# CFileEditor Main Frame Class
-#-------------------------------------------------------------------------------
class CFileEditor(CodeFileEditor):
-
+ """
+ CFileEditor Main Frame Class
+ """
+
CONFNODEEDITOR_TABS = [
(_("C code"), "_create_CodePanel")]
CODE_EDITOR = CppEditor
-
-
-
--- a/c_ext/c_ext.py Mon Aug 21 20:17:19 2017 +0000
+++ b/c_ext/c_ext.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,6 +27,7 @@
from CFileEditor import CFileEditor
from CodeFileTreeNode import CodeFile
+
class CFile(CodeFile):
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -47,13 +48,13 @@
"retrieveFunction",
"publishFunction"]
EditorType = CFileEditor
-
+
def GetIconName(self):
return "Cfile"
def CodeFileName(self):
return os.path.join(self.CTNPath(), "cfile.xml")
-
+
def CTNGenerate_C(self, buildpath, locations):
"""
Generate C code
@@ -70,17 +71,17 @@
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"
text += "#include <stdio.h>\n\n"
-
+
# Adding includes
text += "/* User includes */\n"
text += self.CodeFile.includes.getanyText().strip()
text += "\n"
-
+
text += '#include "iec_types_all.h"\n\n'
-
+
# Adding variables
config = self.GetCTRoot().GetProjectConfigNames()[0]
text += "/* User variables reference */\n"
@@ -93,36 +94,35 @@
text += "extern %(type)s %(global)s;\n" % var_infos
text += "#define %(name)s %(global)s.value\n" % var_infos
text += "\n"
-
+
# Adding user global variables and routines
text += "/* User internal user variables and routines */\n"
text += self.CodeFile.globals.getanyText().strip()
text += "\n"
-
+
# Adding Beremiz confnode functions
text += "/* Beremiz confnode functions */\n"
- text += "int __init_%s(int argc,char **argv)\n{\n"%location_str
+ text += "int __init_%s(int argc,char **argv)\n{\n" % location_str
text += self.CodeFile.initFunction.getanyText().strip()
text += " return 0;\n}\n\n"
-
- text += "void __cleanup_%s(void)\n{\n"%location_str
+
+ text += "void __cleanup_%s(void)\n{\n" % location_str
text += self.CodeFile.cleanUpFunction.getanyText().strip()
text += "\n}\n\n"
-
- text += "void __retrieve_%s(void)\n{\n"%location_str
+
+ text += "void __retrieve_%s(void)\n{\n" % location_str
text += self.CodeFile.retrieveFunction.getanyText().strip()
text += "\n}\n\n"
-
- text += "void __publish_%s(void)\n{\n"%location_str
+
+ text += "void __publish_%s(void)\n{\n" % location_str
text += self.CodeFile.publishFunction.getanyText().strip()
text += "\n}\n\n"
-
- Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c"%location_str)
- cfile = open(Gen_Cfile_path,'w')
+
+ Gen_Cfile_path = os.path.join(buildpath, "CFile_%s.c" % location_str)
+ cfile = open(Gen_Cfile_path, 'w')
cfile.write(text)
cfile.close()
-
- matiec_CFLAGS = '"-I%s"'%os.path.abspath(self.GetCTRoot().GetIECLibPath())
-
- return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_CFLAGS))],str(self.CExtension.getLDFLAGS()),True
+ matiec_CFLAGS = '"-I%s"' % os.path.abspath(self.GetCTRoot().GetIECLibPath())
+
+ return [(Gen_Cfile_path, str(self.CExtension.getCFLAGS() + matiec_CFLAGS))], str(self.CExtension.getLDFLAGS()), True
--- a/canfestival/NetworkEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/canfestival/NetworkEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,55 +28,62 @@
from networkeditortemplate import NetworkEditorTemplate
from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
-[ID_NETWORKEDITOR,
+[
+ ID_NETWORKEDITOR,
] = [wx.NewId() for _init_ctrls in range(1)]
-[ID_NETWORKEDITORCONFNODEMENUADDSLAVE, ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE,
- ID_NETWORKEDITORCONFNODEMENUMASTER,
+[
+ ID_NETWORKEDITORCONFNODEMENUADDSLAVE,
+ ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE,
+ ID_NETWORKEDITORCONFNODEMENUMASTER,
] = [wx.NewId() for _init_coll_ConfNodeMenu_Items in range(3)]
-[ID_NETWORKEDITORMASTERMENUNODEINFOS, ID_NETWORKEDITORMASTERMENUDS301PROFILE,
- ID_NETWORKEDITORMASTERMENUDS302PROFILE, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE,
- ID_NETWORKEDITORMASTERMENUADD,
+[
+ ID_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,
+[
+ ID_NETWORKEDITORADDMENUSDOSERVER, ID_NETWORKEDITORADDMENUSDOCLIENT,
+ ID_NETWORKEDITORADDMENUPDOTRANSMIT, ID_NETWORKEDITORADDMENUPDORECEIVE,
+ ID_NETWORKEDITORADDMENUMAPVARIABLE, ID_NETWORKEDITORADDMENUUSERTYPE,
] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
+
class NetworkEditor(ConfTreeNodeEditor, NetworkEditorTemplate):
-
+
ID = ID_NETWORKEDITOR
CONFNODEEDITOR_TABS = [
(_("CANOpen network"), "_create_NetworkEditor")]
-
+
def _create_NetworkEditor(self, prnt):
- self.NetworkEditor = wx.Panel(id=-1, parent=prnt, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
-
+ self.NetworkEditor = wx.Panel(
+ id=-1, parent=prnt, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
NetworkEditorTemplate._init_ctrls(self, self.NetworkEditor)
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
- main_sizer.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW|wx.ALL)
-
+
+ main_sizer.AddWindow(self.NetworkNodes, 0, border=5, flag=wx.GROW | wx.ALL)
+
self.NetworkEditor.SetSizer(main_sizer)
-
+
return self.NetworkEditor
-
+
def __init__(self, parent, controler, window):
ConfTreeNodeEditor.__init__(self, parent, controler, window)
NetworkEditorTemplate.__init__(self, controler, window, False)
-
+
self.RefreshNetworkNodes()
self.RefreshBufferState()
-
+
def __del__(self):
self.Controler.OnCloseEditor(self)
-
+
def GetConfNodeMenuItems(self):
add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_NETWORKEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
(wx.ITEM_NORMAL, (_('SDO Client'), ID_NETWORKEDITORADDMENUSDOCLIENT, '', self.OnAddSDOClientMenu)),
@@ -84,7 +91,7 @@
(wx.ITEM_NORMAL, (_('PDO Receive'), ID_NETWORKEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
(wx.ITEM_NORMAL, (_('Map Variable'), ID_NETWORKEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
(wx.ITEM_NORMAL, (_('User Type'), ID_NETWORKEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
-
+
profile = self.Manager.GetCurrentProfileName()
if profile not in ("None", "DS-301"):
other_profile_text = _("%s Profile") % profile
@@ -93,35 +100,35 @@
add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
else:
other_profile_text = _('Other Profile')
-
+
master_menu = [(wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_NETWORKEDITORMASTERMENUDS301PROFILE, '', self.OnCommunicationMenu)),
(wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_NETWORKEDITORMASTERMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
(wx.ITEM_NORMAL, (other_profile_text, ID_NETWORKEDITORMASTERMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
(wx.ITEM_SEPARATOR, None),
(add_menu, (_('Add'), ID_NETWORKEDITORMASTERMENUADD))]
-
+
return [(wx.ITEM_NORMAL, (_('Add slave'), ID_NETWORKEDITORCONFNODEMENUADDSLAVE, '', self.OnAddSlaveMenu)),
(wx.ITEM_NORMAL, (_('Remove slave'), ID_NETWORKEDITORCONFNODEMENUREMOVESLAVE, '', self.OnRemoveSlaveMenu)),
(wx.ITEM_SEPARATOR, None),
(master_menu, (_('Master'), ID_NETWORKEDITORCONFNODEMENUMASTER))]
-
+
def RefreshMainMenu(self):
pass
-
+
def RefreshConfNodeMenu(self, confnode_menu):
confnode_menu.Enable(ID_NETWORKEDITORCONFNODEMENUMASTER, self.NetworkNodes.GetSelection() == 0)
-
+
def RefreshView(self):
ConfTreeNodeEditor.RefreshView(self)
self.RefreshCurrentIndexList()
-
+
def RefreshBufferState(self):
NetworkEditorTemplate.RefreshBufferState(self)
self.ParentWindow.RefreshTitle()
self.ParentWindow.RefreshFileMenu()
self.ParentWindow.RefreshEditMenu()
self.ParentWindow.RefreshPageTitles()
-
+
def OnNodeSelectedChanged(self, event):
NetworkEditorTemplate.OnNodeSelectedChanged(self, event)
wx.CallAfter(self.ParentWindow.RefreshEditMenu)
--- a/canfestival/SlaveEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/canfestival/SlaveEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,33 +28,36 @@
from nodeeditortemplate import NodeEditorTemplate
from editors.ConfTreeNodeEditor import ConfTreeNodeEditor
-[ID_SLAVEEDITORCONFNODEMENUNODEINFOS, ID_SLAVEEDITORCONFNODEMENUDS301PROFILE,
- ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE,
- ID_SLAVEEDITORCONFNODEMENUADD,
+[
+ 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,
+[
+ ID_SLAVEEDITORADDMENUSDOSERVER, ID_SLAVEEDITORADDMENUSDOCLIENT,
+ ID_SLAVEEDITORADDMENUPDOTRANSMIT, ID_SLAVEEDITORADDMENUPDORECEIVE,
+ ID_SLAVEEDITORADDMENUMAPVARIABLE, ID_SLAVEEDITORADDMENUUSERTYPE,
] = [wx.NewId() for _init_coll_AddMenu_Items in range(6)]
+
class SlaveEditor(ConfTreeNodeEditor, NodeEditorTemplate):
-
+
CONFNODEEDITOR_TABS = [
(_("CANOpen slave"), "_create_SlaveNodeEditor")]
-
+
def _create_SlaveNodeEditor(self, prnt):
self.SlaveNodeEditor = EditingPanel(prnt, self, self.Controler, self.Editable)
return self.SlaveNodeEditor
-
+
def __init__(self, parent, controler, window, editable=True):
self.Editable = editable
ConfTreeNodeEditor.__init__(self, parent, controler, window)
NodeEditorTemplate.__init__(self, controler, window, False)
-
+
def __del__(self):
self.Controler.OnCloseEditor(self)
-
+
def GetConfNodeMenuItems(self):
if self.Editable:
add_menu = [(wx.ITEM_NORMAL, (_('SDO Server'), ID_SLAVEEDITORADDMENUSDOSERVER, '', self.OnAddSDOServerMenu)),
@@ -63,7 +66,7 @@
(wx.ITEM_NORMAL, (_('PDO Receive'), ID_SLAVEEDITORADDMENUPDORECEIVE, '', self.OnAddPDOReceiveMenu)),
(wx.ITEM_NORMAL, (_('Map Variable'), ID_SLAVEEDITORADDMENUMAPVARIABLE, '', self.OnAddMapVariableMenu)),
(wx.ITEM_NORMAL, (_('User Type'), ID_SLAVEEDITORADDMENUUSERTYPE, '', self.OnAddUserTypeMenu))]
-
+
profile = self.Controler.GetCurrentProfileName()
if profile not in ("None", "DS-301"):
other_profile_text = _("%s Profile") % profile
@@ -72,14 +75,14 @@
add_menu.append((wx.ITEM_NORMAL, (text, wx.NewId(), '', self.GetProfileCallBack(text))))
else:
other_profile_text = _('Other Profile')
-
+
return [(wx.ITEM_NORMAL, (_('DS-301 Profile'), ID_SLAVEEDITORCONFNODEMENUDS301PROFILE, '', self.OnCommunicationMenu)),
(wx.ITEM_NORMAL, (_('DS-302 Profile'), ID_SLAVEEDITORCONFNODEMENUDS302PROFILE, '', self.OnOtherCommunicationMenu)),
(wx.ITEM_NORMAL, (other_profile_text, ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, '', self.OnEditProfileMenu)),
(wx.ITEM_SEPARATOR, None),
(add_menu, (_('Add'), ID_SLAVEEDITORCONFNODEMENUADD))]
return []
-
+
def RefreshConfNodeMenu(self, confnode_menu):
if self.Editable:
confnode_menu.Enable(ID_SLAVEEDITORCONFNODEMENUDSOTHERPROFILE, False)
@@ -90,37 +93,37 @@
def RefreshCurrentIndexList(self):
self.RefreshView()
-
+
def RefreshBufferState(self):
self.ParentWindow.RefreshTitle()
self.ParentWindow.RefreshFileMenu()
self.ParentWindow.RefreshEditMenu()
self.ParentWindow.RefreshPageTitles()
+
class MasterViewer(SlaveEditor):
SHOW_BASE_PARAMS = False
SHOW_PARAMS = False
-
+
def __init__(self, parent, controler, window, tagname):
SlaveEditor.__init__(self, parent, controler, window, False)
-
+
self.TagName = tagname
-
+
def GetTagName(self):
return self.TagName
-
+
def GetCurrentNodeId(self):
return None
-
+
def GetInstancePath(self):
return self.Controler.CTNFullName() + ".generated_master"
-
+
def GetTitle(self):
return self.GetInstancePath()
-
+
def IsViewing(self, tagname):
return self.GetInstancePath() == tagname
def RefreshView(self):
self.SlaveNodeEditor.RefreshIndexList()
-
--- a/canfestival/canfestival.py Mon Aug 21 20:17:19 2017 +0000
+++ b/canfestival/canfestival.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,37 +23,54 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys, shutil
+import os
+import sys
+import shutil
+import wx
+from gnosis.xml.pickle import *
+from gnosis.xml.pickle.util import setParanoia
+
import util.paths as paths
-
-base_folder = paths.AbsParentDir(__file__, 2)
-CanFestivalPath = os.path.join(base_folder, "CanFestival-3")
-sys.path.append(os.path.join(CanFestivalPath, "objdictgen"))
-
-import wx
-
-from nodelist import NodeList
+from util.TranslationCatalogs import AddCatalog
+from ConfigTreeNode import ConfigTreeNode
+from PLCControler import \
+ LOCATION_CONFNODE, \
+ LOCATION_MODULE, \
+ LOCATION_GROUP, \
+ LOCATION_VAR_INPUT, \
+ LOCATION_VAR_OUTPUT, \
+ LOCATION_VAR_MEMORY
+
+try:
+ from nodelist import NodeList
+except ImportError:
+ base_folder = paths.AbsParentDir(__file__, 2)
+ 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
+import config_utils
+import gen_cfile
+import eds_utils
import canfestival_config as local_canfestival_config
-from ConfigTreeNode import ConfigTreeNode
+
from commondialogs import CreateNodeDialog
from subindextable import IECTypeConversion, SizeConversion
-
-from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
from SlaveEditor import SlaveEditor, MasterViewer
from NetworkEditor import NetworkEditor
-from gnosis.xml.pickle import *
-from gnosis.xml.pickle.util import setParanoia
+
+AddCatalog(os.path.join(CanFestivalPath, "objdictgen", "locale"))
setParanoia(0)
-from util.TranslationCatalogs import AddCatalog
-AddCatalog(os.path.join(CanFestivalPath, "objdictgen", "locale"))
-
-#--------------------------------------------------
+
+# --------------------------------------------------
# Location Tree Helper
-#--------------------------------------------------
+# --------------------------------------------------
+
def GetSlaveLocationTree(slave_node, current_location, name):
entries = []
@@ -67,19 +84,19 @@
"size": size,
"IEC_type": IECTypeConversion.get(typeinfos["name"]),
"var_name": "%s_%4.4x_%2.2x" % ("_".join(name.split()), index, subindex),
- "location": "%s%s"%(SizeConversion[size], ".".join(map(str, current_location +
- (index, subindex)))),
+ "location": "%s%s" % (SizeConversion[size], ".".join(map(str, current_location +
+ (index, subindex)))),
"description": "",
"children": []})
- return {"name": name,
- "type": LOCATION_CONFNODE,
- "location": ".".join([str(i) for i in current_location]) + ".x",
- "children": entries
- }
-
-#--------------------------------------------------
+ return {"name": name,
+ "type": LOCATION_CONFNODE,
+ "location": ".".join([str(i) for i in current_location]) + ".x",
+ "children": entries}
+
+# --------------------------------------------------
# SLAVE
-#--------------------------------------------------
+# --------------------------------------------------
+
class _SlaveCTN(NodeManager):
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
@@ -102,7 +119,7 @@
</xsd:element>
</xsd:schema>
"""
-
+
EditorType = SlaveEditor
IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png")
@@ -122,21 +139,21 @@
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
+ 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
+ "", # description
"None", # profile
- "", # prfile filepath
+ "", # prfile filepath
"heartbeat", # NMT
[]) # options
dialog.Destroy()
@@ -156,48 +173,50 @@
if self._View is not None:
self._View.SetBusId(self.GetCurrentLocation())
return self._View
-
+
def _ExportSlave(self):
- dialog = wx.FileDialog(self.GetCTRoot().AppFrame,
- _("Choose a file"),
- os.path.expanduser("~"),
- "%s.eds" % self.CTNName(),
+ dialog = wx.FileDialog(self.GetCTRoot().AppFrame,
+ _("Choose a file"),
+ os.path.expanduser("~"),
+ "%s.eds" % self.CTNName(),
_("EDS files (*.eds)|*.eds|All files|*.*"),
- wx.SAVE|wx.OVERWRITE_PROMPT)
+ wx.SAVE | wx.OVERWRITE_PROMPT)
if dialog.ShowModal() == wx.ID_OK:
result = eds_utils.GenerateEDSFile(dialog.GetPath(), self.GetCurrentNodeCopy())
if result:
self.GetCTRoot().logger.write_error(_("Error: Export slave failed\n"))
- dialog.Destroy()
-
+ dialog.Destroy()
+
ConfNodeMethods = [
- {"bitmap" : "ExportSlave",
- "name" : _("Export slave"),
- "tooltip" : _("Export CanOpen slave to EDS file"),
- "method" : "_ExportSlave"},
+ {
+ "bitmap": "ExportSlave",
+ "name": _("Export slave"),
+ "tooltip": _("Export CanOpen slave to EDS file"),
+ "method": "_ExportSlave"
+ },
]
-
+
def CTNTestModified(self):
return self.ChangesToSave or self.OneFileHasChanged()
-
+
def OnCTNSave(self, from_project_path=None):
return self.SaveCurrentInFile(self.GetSlaveODPath())
def SetParamsAttribute(self, path, value):
result = ConfigTreeNode.SetParamsAttribute(self, path, value)
-
+
# Filter IEC_Channel and Name, that have specific behavior
if path == "BaseParams.IEC_Channel" and self._View is not None:
self._View.SetBusId(self.GetCurrentLocation())
-
+
return result
-
+
def GetVariableLocationTree(self):
current_location = self.GetCurrentLocation()
- return GetSlaveLocationTree(self.CurrentNode,
- self.GetCurrentLocation(),
+ return GetSlaveLocationTree(self.CurrentNode,
+ self.GetCurrentLocation(),
self.BaseParams.getName())
-
+
def CTNGenerate_C(self, buildpath, locations):
"""
Generate C code
@@ -214,75 +233,78 @@
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 )
+ 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)
+ 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
+ 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 GetIconName(self):
return None
-
+
def OnCloseEditor(self, view):
self.Parent.OnCloseEditor(view)
-
+
def CTNFullName(self):
return self.Fullname
-
+
def CTNTestModified(self):
return False
-
+
def GetBufferState(self):
return self.GetCurrentBufferState()
-
+
ConfNodeMethods = []
+
class _NodeManager(NodeManager):
def __init__(self, parent, *args, **kwargs):
NodeManager.__init__(self, *args, **kwargs)
self.Parent = parent
-
+
def __del__(self):
self.Parent = None
-
+
def GetCurrentNodeName(self):
return self.Parent.CTNName()
-
+
def GetCurrentNodeID(self):
return self.Parent.CanFestivalNode.getNodeId()
-
+
+
class _NodeListCTN(NodeList):
XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -295,20 +317,20 @@
</xsd:complexType>
</xsd:element>
</xsd:schema>
- """
-
+ """
+
EditorType = NetworkEditor
IconPath = os.path.join(CanFestivalPath, "objdictgen", "networkedit.png")
-
+
def __init__(self):
manager = _NodeManager(self)
NodeList.__init__(self, manager)
self.LoadProject(self.CTNPath())
self.SetNetworkName(self.BaseParams.getName())
-
+
def GetCanDevice(self):
return self.CanFestivalNode.getCAN_Device()
-
+
def SetParamsAttribute(self, path, value):
if path == "CanFestivalNode.NodeId":
nodeid = self.CanFestivalNode.getNodeId()
@@ -319,10 +341,10 @@
value += dir
if value < 0:
value = nodeid
-
+
value, refresh = ConfigTreeNode.SetParamsAttribute(self, path, value)
refresh_network = False
-
+
# Filter IEC_Channel and Name, that have specific behavior
if path == "BaseParams.IEC_Channel" and self._View is not None:
self._View.SetBusId(self.GetCurrentLocation())
@@ -331,31 +353,35 @@
refresh_network = True
elif path == "CanFestivalNode.NodeId":
refresh_network = True
-
+
if refresh_network and self._View is not None:
wx.CallAfter(self._View.RefreshBufferState)
return value, refresh
-
+
def GetVariableLocationTree(self):
current_location = self.GetCurrentLocation()
nodeindexes = self.SlaveNodes.keys()
nodeindexes.sort()
- return {"name": self.BaseParams.getName(),
- "type": LOCATION_CONFNODE,
- "location": self.GetFullIEC_Channel(),
- "children": [GetSlaveLocationTree(self.Manager.GetCurrentNodeCopy(),
- current_location,
- _("Local entries"))] +
- [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"],
- current_location + (nodeid,),
- self.SlaveNodes[nodeid]["Name"])
- for nodeid in nodeindexes]
+ children = []
+ children += [GetSlaveLocationTree(self.Manager.GetCurrentNodeCopy(),
+ current_location,
+ _("Local entries"))]
+ children += [GetSlaveLocationTree(self.SlaveNodes[nodeid]["Node"],
+ current_location + (nodeid,),
+ self.SlaveNodes[nodeid]["Name"]) for nodeid in nodeindexes]
+
+ return {
+ "name": self.BaseParams.getName(),
+ "type": LOCATION_CONFNODE,
+ "location": self.GetFullIEC_Channel(),
+ "children": children
}
-
+
_GeneratedMasterView = None
+
def _ShowGeneratedMaster(self):
self._OpenView("Generated master")
-
+
def _OpenView(self, name=None, onlyopened=False):
if name == "Generated master":
app_frame = self.GetCTRoot().AppFrame
@@ -365,37 +391,39 @@
if not os.path.exists(buildpath):
self.GetCTRoot().logger.write_error(_("Error: No PLC built\n"))
return
-
+
masterpath = os.path.join(buildpath, "MasterGenerated.od")
if not os.path.exists(masterpath):
self.GetCTRoot().logger.write_error(_("Error: No Master generated\n"))
return
-
+
manager = MiniNodeManager(self, masterpath, self.CTNFullName())
self._GeneratedMasterView = MasterViewer(app_frame.TabsOpened, manager, app_frame, name)
-
+
if self._GeneratedMasterView is not None:
app_frame.EditProjectElement(self._GeneratedMasterView, self._GeneratedMasterView.GetInstancePath())
-
+
return self._GeneratedMasterView
else:
ConfigTreeNode._OpenView(self, name, onlyopened)
if self._View is not None:
self._View.SetBusId(self.GetCurrentLocation())
return self._View
-
+
ConfNodeMethods = [
- {"bitmap" : "ShowMaster",
- "name" : _("Show Master"),
- "tooltip" : _("Show Master generated by config_utils"),
- "method" : "_ShowGeneratedMaster"}
+ {
+ "bitmap": "ShowMaster",
+ "name": _("Show Master"),
+ "tooltip": _("Show Master generated by config_utils"),
+ "method": "_ShowGeneratedMaster"
+ }
]
-
+
def OnCloseEditor(self, view):
ConfigTreeNode.OnCloseEditor(self, view)
if self._GeneratedMasterView == view:
self._GeneratedMasterView = None
-
+
def OnCTNClose(self):
ConfigTreeNode.OnCTNClose(self)
self._CloseView(self._GeneratedMasterView)
@@ -403,11 +431,11 @@
def CTNTestModified(self):
return self.ChangesToSave or self.HasChanged()
-
+
def OnCTNSave(self, from_project_path=None):
self.SetRoot(self.CTNPath())
if from_project_path is not None:
- shutil.copytree(self.GetEDSFolder(from_project_path),
+ shutil.copytree(self.GetEDSFolder(from_project_path),
self.GetEDSFolder())
return self.SaveProject() is None
@@ -428,32 +456,33 @@
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 )
+ 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)
+ 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
+ raise Exception(e.message)
# Do generate C file.
res = gen_cfile.GenerateFile(Gen_OD_path, master, pointers)
- if res :
- raise Exception, res
-
+ 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
-
+
+ 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 = """<?xml version="1.0" encoding="ISO-8859-1" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
@@ -464,29 +493,30 @@
</xsd:element>
</xsd:schema>
"""
-
- CTNChildrenTypes = [("CanOpenNode",_NodeListCTN, "CanOpen Master"),
- ("CanOpenSlave",_SlaveCTN, "CanOpen Slave")]
- def GetParamsAttributes(self, path = None):
- infos = ConfigTreeNode.GetParamsAttributes(self, path = path)
+
+ CTNChildrenTypes = [("CanOpenNode", _NodeListCTN, "CanOpen Master"),
+ ("CanOpenSlave", _SlaveCTN, "CanOpen Slave")]
+
+ def GetParamsAttributes(self, path=None):
+ infos = ConfigTreeNode.GetParamsAttributes(self, path=path)
for element in infos:
if element["name"] == "CanFestivalInstance":
for child in element["children"]:
if child["name"] == "CAN_Driver":
child["type"] = local_canfestival_config.DLL_LIST
return infos
-
+
def GetCanDriver(self):
res = self.CanFestivalInstance.getCAN_Driver()
- if not res :
+ if not res:
return ""
return res
-
+
def CTNGenerate_C(self, buildpath, locations):
can_driver = self.GetCanDriver()
if can_driver is not None:
can_drivers = local_canfestival_config.DLL_LIST
- if can_driver not in can_drivers :
+ if can_driver not in can_drivers:
can_driver = can_drivers[0]
can_drv_ext = self.GetCTRoot().GetBuilder().extension
can_drv_prefix = self.GetCTRoot().GetBuilder().dlopen_prefix
@@ -494,106 +524,104 @@
else:
can_driver_name = ""
-
- format_dict = {"locstr" : "_".join(map(str,self.GetCurrentLocation())),
- "candriver" : can_driver_name,
- "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" : "",
- "pre_op" : "",
- "pre_op_register" : "",
+ format_dict = {"locstr": "_".join(map(str, self.GetCurrentLocation())),
+ "candriver": can_driver_name,
+ "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": "",
+ "pre_op": "",
+ "pre_op_register": "",
}
for child in self.IECSortedChildren():
- childlocstr = "_".join(map(str,child.GetCurrentLocation()))
+ 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 '%(
+ 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)
+ 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))
+ "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){}\n" % (nodename))
else:
format_dict["slavebootups"] += (
- "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n"%(nodename)+
- " check_and_start_node(d, nodeId);\n"+
+ "static void %s_post_SlaveBootup(CO_Data* d, UNS8 nodeId){\n" % (nodename) +
+ " check_and_start_node(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))
+ "%s_Data.post_SlaveBootup = %s_post_SlaveBootup;\n" % (nodename, nodename))
format_dict["pre_op"] += (
- "static void %s_preOperational(CO_Data* d){\n "%(nodename)+
- "".join([" masterSendNMTstateChange(d, %d, NMT_Reset_Comunication);\n"%NdId for NdId in SlaveIDs])+
+ "static void %s_preOperational(CO_Data* d){\n " % (nodename) +
+ "".join([" masterSendNMTstateChange(d, %d, NMT_Reset_Comunication);\n" % NdId for NdId in SlaveIDs]) +
"}\n")
format_dict["pre_op_register"] += (
- "%s_Data.preOperational = %s_preOperational;\n"%(nodename,nodename))
+ "%s_Data.preOperational = %s_preOperational;\n" % (nodename, nodename))
else:
# Slave node
align = child_data.getSync_Align()
- align_ratio=child_data.getSync_Align_Ratio()
+ 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"+
+ "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 '%(
+ "%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)
+ 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'%(
+ 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 = paths.AbsNeighbourFile(__file__,"cf_runtime.c")
+ format_dict["nodes_open"] += 'NODE_OPEN(%s)\n ' % (nodename)
+ format_dict["nodes_close"] += 'NODE_CLOSE(%s)\n ' % (nodename)
+ format_dict["nodes_stop"] += 'NODE_STOP(%s)\n ' % (nodename)
+
+ filename = paths.AbsNeighbourFile(__file__, "cf_runtime.c")
cf_main = open(filename).read() % format_dict
- cf_main_path = os.path.join(buildpath, "CF_%(locstr)s.c"%format_dict)
- f = open(cf_main_path,'w')
+ 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()
- res = [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))],local_canfestival_config.getLDFLAGS(CanFestivalPath), True
-
+ res = [(cf_main_path, local_canfestival_config.getCFLAGS(CanFestivalPath))], local_canfestival_config.getLDFLAGS(CanFestivalPath), True
+
if can_driver is not None:
- can_driver_path = os.path.join(CanFestivalPath,"drivers",can_driver,can_driver_name)
+ can_driver_path = os.path.join(CanFestivalPath, "drivers", can_driver, can_driver_name)
if os.path.exists(can_driver_path):
- res += ((can_driver_name, file(can_driver_path,"rb")),)
+ res += ((can_driver_name, file(can_driver_path, "rb")),)
return res
-
--- a/canfestival/config_utils.py Mon Aug 21 20:17:19 2017 +0000
+++ b/canfestival/config_utils.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,30 +25,46 @@
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
+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}
+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)))
+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
@@ -61,22 +77,22 @@
@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):
+def GetNodePDOIndexes(node, type, parameters=False):
"""
Find the PDO indexes of a node
- @param node: node
+ @param node: node
@param type: type of PDO searched (RPDO or TPDO or both)
@param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
@return: a list of indexes found
"""
-
+
indexes = []
if type & RPDO:
indexes.extend([idx for idx in node.GetIndexes() if 0x1400 <= idx <= 0x15FF])
@@ -91,17 +107,17 @@
def SearchNodePDOMapping(loc_infos, node):
"""
Find the PDO indexes of a node
- @param node: node
+ @param node: node
@param type: type of PDO searched (RPDO or TPDO or both)
@param parameters: indicate which indexes are expected (PDO paramaters : True or PDO mappings : False)
@return: a list of indexes found
"""
-
+
model = (loc_infos["index"] << 16) + (loc_infos["subindex"] << 8)
-
+
for PDOidx in GetNodePDOIndexes(node, loc_infos["pdotype"]):
values = node.GetEntry(PDOidx)
- if values != None:
+ if values is not None:
for subindex, mapping in enumerate(values):
if subindex != 0 and mapping & 0xFFFFFF00 == model:
return PDOidx, subindex
@@ -115,10 +131,10 @@
@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
- """
-
- dcfdata=[]
+ @return: a tuple of value and number of parameters to add to DCF
+ """
+
+ dcfdata = []
# Create entry for RPDO or TPDO parameters and Disable PDO
# ---- INDEX ----- --- SUBINDEX ---- ----- SIZE ------ ------ DATA ------
dcfdata += [LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(0x80000000 + cobid, 4)]
@@ -137,6 +153,7 @@
dcfdata += [LE_to_BE(idx, 2) + LE_to_BE(0x01, 1) + LE_to_BE(0x04, 4) + LE_to_BE(cobid, 4)]
return "".join(dcfdata), len(dcfdata)
+
class ConciseDCFGenerator:
def __init__(self, nodelist, nodename):
@@ -152,7 +169,7 @@
self.TrashVariables = {}
# Dictionary of pointed variables
self.PointedVariables = {}
-
+
self.NodeList = nodelist
self.Manager = self.NodeList.Manager
self.MasterNode = self.Manager.GetCurrentNodeCopy()
@@ -161,41 +178,40 @@
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 :
+ 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
@@ -206,40 +222,39 @@
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}
+ 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)
+ RSDO_cobid = node.GetEntry(0x1200, 0x01)
if not RSDO_cobid:
RSDO_cobid = 0x600 + nodeid
- TSDO_cobid = node.GetEntry(0x1200,0x02)
+ TSDO_cobid = node.GetEntry(0x1200, 0x02)
if not TSDO_cobid:
TSDO_cobid = 0x580 + nodeid
-
+
# Configure Master's SDO parameters entries
self.Manager.ManageEntriesOfCurrent([0x1280 + idx], [], self.MasterNode)
self.MasterNode.SetEntry(0x1280 + idx, 0x01, RSDO_cobid)
self.MasterNode.SetEntry(0x1280 + idx, 0x02, TSDO_cobid)
- self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)
-
-
+ self.MasterNode.SetEntry(0x1280 + idx, 0x03, nodeid)
+
def GetMasterNode(self):
"""
Return MasterNode.
"""
return self.MasterNode
-
+
def AddParamsToDCF(self, nodeid, data, nbparams):
"""
Add entry to DCF, for the requested nodeID
@@ -249,19 +264,19 @@
"""
# Get current DCF for slave
nodeDCF = self.MasterNode.GetEntry(0x1F22, nodeid)
-
+
# Extract data and number of params in current DCF
- if nodeDCF != None and nodeDCF != '':
+ if nodeDCF is not None and nodeDCF != '':
tmpnbparams = [i for i in nodeDCF[:4]]
tmpnbparams.reverse()
- nbparams += int(''.join(["%2.2x"%ord(i) for i in tmpnbparams]), 16)
+ nbparams += int(''.join(["%2.2x" % ord(i) for i in tmpnbparams]), 16)
data = nodeDCF[4:] + data
-
+
# Build new DCF
dcf = LE_to_BE(nbparams, 0x04) + data
# Set new DCF for slave
self.MasterNode.SetEntry(0x1F22, nodeid, dcf)
-
+
def GetEmptyPDO(self, nodeid, pdotype, start_index=None):
"""
Search a not configured PDO for a slave
@@ -275,12 +290,12 @@
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:
+ if values is not 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)
@@ -296,7 +311,7 @@
return index, cobid, values[0]
index += 1
return None
-
+
def AddPDOMapping(self, nodeid, pdotype, pdoindex, pdocobid, pdomapping, sync_TPDOs):
"""
Record a new mapping request for a slave, and add related slave config to the DCF
@@ -305,16 +320,18 @@
@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]}
-
+ self.MasterMapping[pdocobid] = {
+ "type": InvertPDOType[pdotype],
+ "mapping": [None] + [(loc_infos["type"], name) for name, loc_infos in pdomapping]
+ }
+
# Return the data to add to DCF
if sync_TPDOs:
return GeneratePDOMappingDCF(pdoindex, pdocobid, 0x01, pdomapping)
else:
return GeneratePDOMappingDCF(pdoindex, pdocobid, 0xFF, pdomapping)
return 0, ""
-
+
def GenerateDCF(self, locations, current_location, sync_TPDOs):
"""
Generate Concise DCF of MasterNode for the locations list given
@@ -322,87 +339,101 @@
@param current_location: tuple of the located prefixes not to be considered
@param sync_TPDOs: indicate if TPDO must be synchronous
"""
-
- #-------------------------------------------------------------------------------
+
+ # -------------------------------------------------------------------------------
# Verify that locations correspond to real slave variables
- #-------------------------------------------------------------------------------
-
+ # -------------------------------------------------------------------------------
+
# Get list of locations check if exists and mappables -> put them in IECLocations
for location in locations:
COlocationtype = IECToCOType[location["IEC_TYPE"]]
name = location["NAME"]
if name in self.IECLocations:
if self.IECLocations[name]["type"] != COlocationtype:
- raise PDOmappingException, _("Type conflict for location \"%s\"") % name
+ raise PDOmappingException(_("Type conflict for location \"%s\"") % name)
else:
# Get only the part of the location that concern this node
loc = location["LOC"][len(current_location):]
# loc correspond to (ID, INDEX, SUBINDEX [,BIT])
if len(loc) not in (2, 3, 4):
- raise PDOmappingException, _("Bad location size : %s") % str(loc)
+ raise PDOmappingException(_("Bad location size : %s") % str(loc))
elif len(loc) == 2:
continue
-
+
direction = location["DIR"]
-
+
sizelocation = location["SIZE"]
-
+
# Extract and check nodeid
nodeid, index, subindex = loc[:3]
-
+
# Check Id is in slave node list
if nodeid not in self.NodeList.SlaveNodes.keys():
- raise PDOmappingException, _("Non existing node ID : {a1} (variable {a2})").format(a1 = nodeid, a2 = name)
-
+ raise PDOmappingException(
+ _("Non existing node ID : {a1} (variable {a2})").
+ format(a1=nodeid, a2=name))
+
# Get the model for this node (made from EDS)
node = self.NodeList.SlaveNodes[nodeid]["Node"]
-
+
# Extract and check index and subindex
if not node.IsEntry(index, subindex):
msg = _("No such index/subindex ({a1},{a2}) in ID : {a3} (variable {a4})").\
- format(a1 = "%x" % index, a2 ="%x" % subindex, a3 = nodeid, a4 = name)
- raise PDOmappingException, msg
-
+ format(a1="%x" % index, a2="%x" % subindex, a3=nodeid, a4=name)
+ raise PDOmappingException(msg)
+
# Get the entry info
subentry_infos = node.GetSubentryInfos(index, subindex)
-
+
# If a PDO mappable
if subentry_infos and subentry_infos["pdo"]:
if sizelocation == "X" and len(loc) > 3:
numbit = loc[3]
elif sizelocation != "X" and len(loc) > 3:
- msg = _("Cannot set bit offset for non bool '{a1}' variable (ID:{a2},Idx:{a3},sIdx:{a4}))").\
- format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
- raise PDOmappingException, msg
+ raise PDOmappingException(
+ _("Cannot set bit offset for non bool '{a1}' variable (ID:{a2},Idx:{a3},sIdx:{a4}))").
+ format(a1=name, a2=nodeid, a3="%x" % index, a4="%x" % subindex))
else:
numbit = None
-
+
if location["IEC_TYPE"] != "BOOL" and subentry_infos["type"] != COlocationtype:
- raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\
- format(a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
-
+ raise PDOmappingException(
+ _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").
+ format(a1=location["IEC_TYPE"],
+ a2=COlocationtype,
+ a3=subentry_infos["type"],
+ a4=name))
+
typeinfos = node.GetEntryInfos(COlocationtype)
- self.IECLocations[name] = {"type":COlocationtype, "pdotype":SlavePDOType[direction],
- "nodeid": nodeid, "index": index,"subindex": subindex,
- "bit": numbit, "size": typeinfos["size"], "sizelocation": sizelocation}
+ 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 : '{a1}' (ID:{a2},Idx:{a3},sIdx:{a4}))").\
- format(a1 = name, a2 = nodeid, a3 = "%x" % index, a4 = "%x" % subindex)
-
- #-------------------------------------------------------------------------------
+ raise PDOmappingException(
+ _("Not PDO mappable variable : '{a1}' (ID:{a2},Idx:{a3},sIdx:{a4}))").
+ format(a1=name, a2=nodeid, a3="%x" % index, a4="%x" % subindex))
+
+ # -------------------------------------------------------------------------------
# Search for locations already mapped
- #-------------------------------------------------------------------------------
-
+ # -------------------------------------------------------------------------------
+
for name, locationinfos in self.IECLocations.items():
node = self.NodeList.SlaveNodes[locationinfos["nodeid"]]["Node"]
-
+
# Search if slave has a PDO mapping this locations
result = SearchNodePDOMapping(locationinfos, node)
- if result != None:
+ if result is not None:
index, subindex = result
# Get COB ID of the PDO
cobid = self.NodeList.GetSlaveNodeEntry(locationinfos["nodeid"], index - 0x200, 1)
-
+
# Add PDO to MasterMapping
if cobid not in self.MasterMapping.keys():
# Verify that PDO transmit type is conform to sync_TPDOs
@@ -414,18 +445,18 @@
else:
# Change TransmitType to ASYCHRONE
data, nbparams = GeneratePDOMappingDCF(index - 0x200, cobid, 0xFF, [])
-
- # Add entry to slave dcf to change transmit type of
+
+ # Add entry to slave dcf to change transmit type of
self.AddParamsToDCF(locationinfos["nodeid"], data, nbparams)
-
+
mapping = [None]
values = node.GetEntry(index)
# Store the size of each entry mapped in PDO
for value in values[1:]:
if value != 0:
mapping.append(value % 0x100)
- self.MasterMapping[cobid] = {"type" : InvertPDOType[locationinfos["pdotype"]], "mapping" : mapping}
-
+ self.MasterMapping[cobid] = {"type": InvertPDOType[locationinfos["pdotype"]], "mapping": mapping}
+
# Indicate that this PDO entry must be saved
if locationinfos["bit"] is not None:
if not isinstance(self.MasterMapping[cobid]["mapping"][subindex], ListType):
@@ -434,24 +465,24 @@
self.MasterMapping[cobid]["mapping"][subindex][locationinfos["bit"]] = (locationinfos["type"], name)
else:
self.MasterMapping[cobid]["mapping"][subindex] = (locationinfos["type"], name)
-
+
else:
# Add location to those that haven't been mapped yet
if locationinfos["nodeid"] not in self.LocationsNotMapped.keys():
- self.LocationsNotMapped[locationinfos["nodeid"]] = {TPDO : [], RPDO : []}
+ self.LocationsNotMapped[locationinfos["nodeid"]] = {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:
@@ -459,7 +490,8 @@
pdomapping = []
result = self.GetEmptyPDO(nodeid, pdotype)
if result is None:
- raise PDOmappingException, _("Unable to define PDO mapping for node %02x") % nodeid
+ 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"]
@@ -473,7 +505,8 @@
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
+ raise PDOmappingException(
+ _("Unable to define PDO mapping for node %02x") % nodeid)
pdoindex, pdocobid, pdonbparams = result
else:
pdomapping.append((name, loc_infos))
@@ -483,78 +516,79 @@
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"]
-
+ 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
+ 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):
+ if not self.MasterNode.IsEntry(mapvariableidx):
# Add entry to MasterNode
self.Manager.AddMapVariableToCurrent(mapvariableidx, "beremiz"+indexname, 3, 1, self.MasterNode)
new_index = True
@@ -567,30 +601,31 @@
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
+ if variable_infos["bit"] is not None:
+ subindexname = "%(index)d_%(subindex)d_%(bit)d" % variable_infos
else:
- subindexname = "%(index)d_%(subindex)d"%variable_infos
+ 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})
-
+ 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:
+ if typeinfos is not 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)
+ self.PointedVariables[(mapvariableidx, nbsubentries)] = "%s_%s" % (indexname, subindexname)
+
def GenerateConciseDCF(locations, current_location, nodelist, sync_TPDOs, nodename):
"""
@@ -605,13 +640,14 @@
@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()
+ masternode, pointers = dcfgenerator.GetMasterNode(), dcfgenerator.GetPointedVariables()
# allow access to local OD from Master PLC
pointers.update(LocalODPointers(locations, current_location, masternode))
- return masternode,pointers
+ return masternode, pointers
+
def LocalODPointers(locations, current_location, slave):
IECLocations = {}
@@ -621,36 +657,44 @@
name = location["NAME"]
if name in IECLocations:
if IECLocations[name] != COlocationtype:
- raise PDOmappingException, _("Type conflict for location \"%s\"") % name
+ raise PDOmappingException(_("Type conflict for location \"%s\"") % name)
else:
# Get only the part of the location that concern this node
loc = location["LOC"][len(current_location):]
# loc correspond to (ID, INDEX, SUBINDEX [,BIT])
if len(loc) not in (2, 3, 4):
- raise PDOmappingException, _("Bad location size : %s") % str(loc)
+ raise PDOmappingException(_("Bad location size : %s") % str(loc))
elif len(loc) != 2:
continue
-
+
# Extract and check nodeid
index, subindex = loc[:2]
-
+
# Extract and check index and subindex
if not slave.IsEntry(index, subindex):
- raise PDOmappingException, _("No such index/subindex ({a1},{a2}) (variable {a3})").\
- format(a1 = "%x" % index, a2 = "%x" % subindex, a3 = name)
-
+ raise PDOmappingException(
+ _("No such index/subindex ({a1},{a2}) (variable {a3})").
+ format(a1="%x" % index, a2="%x" % subindex, a3=name))
+
# Get the entry info
- subentry_infos = slave.GetSubentryInfos(index, subindex)
+ subentry_infos = slave.GetSubentryInfos(index, subindex)
if subentry_infos["type"] != COlocationtype:
- raise PDOmappingException, _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").\
- format( a1 = location["IEC_TYPE"], a2 = COlocationtype, a3 = subentry_infos["type"] , a4 = name)
-
+ raise PDOmappingException(
+ _("Invalid type \"{a1}\"-> {a2} != {a3} for location \"{a4}\"").
+ format(a1=location["IEC_TYPE"],
+ a2=COlocationtype,
+ a3=subentry_infos["type"],
+ a4=name))
+
IECLocations[name] = COlocationtype
pointers[(index, subindex)] = name
return pointers
-
+
+
if __name__ == "__main__":
- import os, sys, getopt
+ import os
+ import sys
+ import getopt
def usage():
print """
@@ -666,14 +710,14 @@
Reset the reference result of config_utils test.
Use with caution. Be sure that config_utils
is currently working properly.
-"""%sys.argv[0]
-
+""" % 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"])
+ opts, args = getopt.getopt(sys.argv[1:], "hr", ["help", "reset"])
except getopt.GetoptError:
# print help information and exit:
usage()
@@ -693,54 +737,56 @@
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)}]
-
+ 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
+ print "%s\nTest Failed!" % message
sys.exit()
-
+
import pprint
- # Get Text corresponding to MasterNode
+ # Get Text corresponding to MasterNode
result_node = masternode.PrintString()
result_vars = pprint.pformat(pointedvariables)
result = result_node + "\n********POINTERS*********\n" + result_vars + "\n"
-
+
# If reset has been choosen
if reset:
# Write Text into reference result file
testfile = open("test_config/result.txt", "w")
testfile.write(result)
testfile.close()
-
+
print "Reset Successful!"
else:
import os
-
+
testfile = open("test_config/result_tmp.txt", "w")
testfile.write(result)
testfile.close()
-
+
os.system("diff test_config/result.txt test_config/result_tmp.txt")
os.remove("test_config/result_tmp.txt")
--- a/connectors/PYRO/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/connectors/PYRO/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,199 +1,202 @@
-#!/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 program 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
-# of the License, or (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import Pyro
-import Pyro.core
-import Pyro.util
-from Pyro.errors import PyroError
-import traceback
-from time import sleep
-import copy
-import socket
-service_type = '_PYRO._tcp.local.'
-import os.path
-# this module attribute contains a list of DNS-SD (Zeroconf) service types
-# supported by this connector confnode.
-#
-# for connectors that do not support DNS-SD, this attribute can be omitted
-# or set to an empty list.
-
-def PYRO_connector_factory(uri, confnodesroot):
- """
- This returns the connector to Pyro style PLCobject
- """
- confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)
-
- servicetype, location = uri.split("://")
- if servicetype == "PYROS":
- schemename = "PYROLOCSSL"
- # Protect against name->IP substitution in Pyro3
- Pyro.config.PYRO_DNS_URI = True
- # Beware Pyro lib need str path, not unicode
- # don't rely on PYRO_STORAGE ! see documentation
- Pyro.config.PYROSSL_CERTDIR = os.path.abspath(str(confnodesroot.ProjectPath) + '/certs')
- if not os.path.exists(Pyro.config.PYROSSL_CERTDIR):
- confnodesroot.logger.write_error(
- 'Error : the directory %s is missing for SSL certificates (certs_dir).'
- 'Please fix it in your project.\n' % Pyro.config.PYROSSL_CERTDIR)
- return None
- else:
- confnodesroot.logger.write(_("PYRO using certificates in '%s' \n")
- % (Pyro.config.PYROSSL_CERTDIR))
- Pyro.config.PYROSSL_CERT = "client.crt"
- Pyro.config.PYROSSL_KEY = "client.key"
- # Ugly Monkey Patching
- def _gettimeout(self):
- return self.timeout
-
- def _settimeout(self, timeout):
- self.timeout = timeout
- from M2Crypto.SSL import Connection
- Connection.timeout = None
- Connection.gettimeout = _gettimeout
- Connection.settimeout = _settimeout
- # M2Crypto.SSL.Checker.WrongHost: Peer certificate commonName does not
- # match host, expected 127.0.0.1, got server
- Connection.clientPostConnectionCheck = None
- else:
- schemename = "PYROLOC"
- if location.find(service_type) != -1:
- try:
- from util.Zeroconf import Zeroconf
- r = Zeroconf()
- i = r.getServiceInfo(service_type, location)
- if i is None:
- raise Exception("'%s' not found" % location)
- ip = str(socket.inet_ntoa(i.getAddress()))
- port = str(i.getPort())
- newlocation = ip + ':' + port
- confnodesroot.logger.write(_("'{a1}' is located at {a2}\n").format(a1 = location, a2 = newlocation))
- location = newlocation
- r.close()
- except Exception, msg:
- confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n") % location)
- confnodesroot.logger.write_error(traceback.format_exc())
- return None
-
- # Try to get the proxy object
- try:
- RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
- except Exception, msg:
- confnodesroot.logger.write_error(_("Connection to '%s' failed.\n") % location)
- confnodesroot.logger.write_error(traceback.format_exc())
- return None
-
- def PyroCatcher(func, default=None):
- """
- A function that catch a Pyro exceptions, write error to logger
- and return default value when it happen
- """
- def catcher_func(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except Pyro.errors.ConnectionClosedError, e:
- confnodesroot.logger.write_error(_("Connection lost!\n"))
- confnodesroot._SetConnector(None)
- except Pyro.errors.ProtocolError, e:
- confnodesroot.logger.write_error(_("Pyro exception: %s\n") % e)
- except Exception, e:
- # confnodesroot.logger.write_error(traceback.format_exc())
- errmess = ''.join(Pyro.util.getPyroTraceback(e))
- confnodesroot.logger.write_error(errmess + "\n")
- print errmess
- confnodesroot._SetConnector(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())() is None:
- confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
- return None
-
- class PyroProxyProxy(object):
- """
- A proxy proxy class to handle Beremiz Pyro interface specific behavior.
- And to put Pyro exception catcher in between caller and Pyro proxy
- """
- def __init__(self):
- # for safe use in from debug thread, must create a copy
- self.RemotePLCObjectProxyCopy = None
-
- def GetPyroProxy(self):
- """
- This func returns the real Pyro Proxy.
- Use this if you musn't keep reference to it.
- """
- return RemotePLCObjectProxy
-
- def _PyroStartPLC(self, *args, **kwargs):
- """
- confnodesroot._connector.GetPyroProxy() is used
- rather than RemotePLCObjectProxy because
- object is recreated meanwhile,
- so we must not keep ref to it here
- """
- current_status, log_count = 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
- """
- confnodesroot.logger.write(_("Force runtime reload\n"))
- confnodesroot._connector.GetPyroProxy().ForceReload()
- confnodesroot._Disconnect()
- # let remote PLC time to resurect.(freeze app)
- sleep(0.5)
- confnodesroot._Connect()
- self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
- return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs)
- StartPLC = PyroCatcher(_PyroStartPLC, False)
-
- def _PyroGetTraceVariables(self):
- """
- for safe use in from debug thread, must use the copy
- """
- if self.RemotePLCObjectProxyCopy is None:
- self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
- return self.RemotePLCObjectProxyCopy.GetTraceVariables()
- GetTraceVariables = PyroCatcher(_PyroGetTraceVariables, ("Broken", None))
-
- def _PyroGetPLCstatus(self):
- return RemotePLCObjectProxy.GetPLCstatus()
- GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken", None))
-
- def _PyroRemoteExec(self, script, **kwargs):
- return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
- RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
-
- def __getattr__(self, attrName):
- member = self.__dict__.get(attrName, None)
- if member is None:
- def my_local_func(*args, **kwargs):
- return RemotePLCObjectProxy.__getattr__(attrName)(*args, **kwargs)
- member = PyroCatcher(my_local_func, None)
- self.__dict__[attrName] = member
- return member
-
- return PyroProxyProxy()
+#!/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 program 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import Pyro
+import Pyro.core
+import Pyro.util
+from Pyro.errors import PyroError
+import traceback
+from time import sleep
+import copy
+import socket
+import os.path
+
+service_type = '_PYRO._tcp.local.'
+# this module attribute contains a list of DNS-SD (Zeroconf) service types
+# supported by this connector confnode.
+#
+# for connectors that do not support DNS-SD, this attribute can be omitted
+# or set to an empty list.
+
+
+def PYRO_connector_factory(uri, confnodesroot):
+ """
+ This returns the connector to Pyro style PLCobject
+ """
+ confnodesroot.logger.write(_("PYRO connecting to URI : %s\n") % uri)
+
+ servicetype, location = uri.split("://")
+ if servicetype == "PYROS":
+ schemename = "PYROLOCSSL"
+ # Protect against name->IP substitution in Pyro3
+ Pyro.config.PYRO_DNS_URI = True
+ # Beware Pyro lib need str path, not unicode
+ # don't rely on PYRO_STORAGE ! see documentation
+ Pyro.config.PYROSSL_CERTDIR = os.path.abspath(str(confnodesroot.ProjectPath) + '/certs')
+ if not os.path.exists(Pyro.config.PYROSSL_CERTDIR):
+ confnodesroot.logger.write_error(
+ 'Error : the directory %s is missing for SSL certificates (certs_dir).'
+ 'Please fix it in your project.\n' % Pyro.config.PYROSSL_CERTDIR)
+ return None
+ else:
+ confnodesroot.logger.write(_("PYRO using certificates in '%s' \n")
+ % (Pyro.config.PYROSSL_CERTDIR))
+ Pyro.config.PYROSSL_CERT = "client.crt"
+ Pyro.config.PYROSSL_KEY = "client.key"
+
+ # Ugly Monkey Patching
+ def _gettimeout(self):
+ return self.timeout
+
+ def _settimeout(self, timeout):
+ self.timeout = timeout
+ from M2Crypto.SSL import Connection
+ Connection.timeout = None
+ Connection.gettimeout = _gettimeout
+ Connection.settimeout = _settimeout
+ # M2Crypto.SSL.Checker.WrongHost: Peer certificate commonName does not
+ # match host, expected 127.0.0.1, got server
+ Connection.clientPostConnectionCheck = None
+ else:
+ schemename = "PYROLOC"
+ if location.find(service_type) != -1:
+ try:
+ from util.Zeroconf import Zeroconf
+ r = Zeroconf()
+ i = r.getServiceInfo(service_type, location)
+ if i is None:
+ raise Exception("'%s' not found" % location)
+ ip = str(socket.inet_ntoa(i.getAddress()))
+ port = str(i.getPort())
+ newlocation = ip + ':' + port
+ confnodesroot.logger.write(_("'{a1}' is located at {a2}\n").format(a1=location, a2=newlocation))
+ location = newlocation
+ r.close()
+ except Exception, msg:
+ confnodesroot.logger.write_error(_("MDNS resolution failure for '%s'\n") % location)
+ confnodesroot.logger.write_error(traceback.format_exc())
+ return None
+
+ # Try to get the proxy object
+ try:
+ RemotePLCObjectProxy = Pyro.core.getAttrProxyForURI(schemename + "://" + location + "/PLCObject")
+ except Exception, msg:
+ confnodesroot.logger.write_error(_("Connection to '%s' failed.\n") % location)
+ confnodesroot.logger.write_error(traceback.format_exc())
+ return None
+
+ def PyroCatcher(func, default=None):
+ """
+ A function that catch a Pyro exceptions, write error to logger
+ and return default value when it happen
+ """
+ def catcher_func(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Pyro.errors.ConnectionClosedError, e:
+ confnodesroot.logger.write_error(_("Connection lost!\n"))
+ confnodesroot._SetConnector(None)
+ except Pyro.errors.ProtocolError, e:
+ confnodesroot.logger.write_error(_("Pyro exception: %s\n") % e)
+ except Exception, e:
+ # confnodesroot.logger.write_error(traceback.format_exc())
+ errmess = ''.join(Pyro.util.getPyroTraceback(e))
+ confnodesroot.logger.write_error(errmess + "\n")
+ print errmess
+ confnodesroot._SetConnector(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())() is None:
+ confnodesroot.logger.write_error(_("Cannot get PLC status - connection failed.\n"))
+ return None
+
+ class PyroProxyProxy(object):
+ """
+ A proxy proxy class to handle Beremiz Pyro interface specific behavior.
+ And to put Pyro exception catcher in between caller and Pyro proxy
+ """
+ def __init__(self):
+ # for safe use in from debug thread, must create a copy
+ self.RemotePLCObjectProxyCopy = None
+
+ def GetPyroProxy(self):
+ """
+ This func returns the real Pyro Proxy.
+ Use this if you musn't keep reference to it.
+ """
+ return RemotePLCObjectProxy
+
+ def _PyroStartPLC(self, *args, **kwargs):
+ """
+ confnodesroot._connector.GetPyroProxy() is used
+ rather than RemotePLCObjectProxy because
+ object is recreated meanwhile,
+ so we must not keep ref to it here
+ """
+ current_status, log_count = 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
+ """
+ confnodesroot.logger.write(_("Force runtime reload\n"))
+ confnodesroot._connector.GetPyroProxy().ForceReload()
+ confnodesroot._Disconnect()
+ # let remote PLC time to resurect.(freeze app)
+ sleep(0.5)
+ confnodesroot._Connect()
+ self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
+ return confnodesroot._connector.GetPyroProxy().StartPLC(*args, **kwargs)
+ StartPLC = PyroCatcher(_PyroStartPLC, False)
+
+ def _PyroGetTraceVariables(self):
+ """
+ for safe use in from debug thread, must use the copy
+ """
+ if self.RemotePLCObjectProxyCopy is None:
+ self.RemotePLCObjectProxyCopy = copy.copy(confnodesroot._connector.GetPyroProxy())
+ return self.RemotePLCObjectProxyCopy.GetTraceVariables()
+ GetTraceVariables = PyroCatcher(_PyroGetTraceVariables, ("Broken", None))
+
+ def _PyroGetPLCstatus(self):
+ return RemotePLCObjectProxy.GetPLCstatus()
+ GetPLCstatus = PyroCatcher(_PyroGetPLCstatus, ("Broken", None))
+
+ def _PyroRemoteExec(self, script, **kwargs):
+ return RemotePLCObjectProxy.RemoteExec(script, **kwargs)
+ RemoteExec = PyroCatcher(_PyroRemoteExec, (-1, "RemoteExec script failed!"))
+
+ def __getattr__(self, attrName):
+ member = self.__dict__.get(attrName, None)
+ if member is None:
+ def my_local_func(*args, **kwargs):
+ return RemotePLCObjectProxy.__getattr__(attrName)(*args, **kwargs)
+ member = PyroCatcher(my_local_func, None)
+ self.__dict__[attrName] = member
+ return member
+
+ return PyroProxyProxy()
--- a/connectors/WAMP/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/connectors/WAMP/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,8 +22,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import sys, traceback, atexit
-#from twisted.python import log
+import sys
+import traceback
+import atexit
from twisted.internet import reactor, threads
from autobahn.twisted import wamp
from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
@@ -36,6 +37,7 @@
_WampConnection = None
_WampSessionEvent = Event()
+
class WampSession(wamp.ApplicationSession):
def onJoin(self, details):
global _WampSession, _WampSessionEvent
@@ -49,10 +51,14 @@
_WampSession = None
print 'WAMP session left'
-PLCObjDefaults = { "StartPLC": False,
- "GetTraceVariables" : ("Broken",None),
- "GetPLCstatus" : ("Broken",None),
- "RemoteExec" : (-1, "RemoteExec script failed!")}
+
+PLCObjDefaults = {
+ "StartPLC": False,
+ "GetTraceVariables": ("Broken", None),
+ "GetPLCstatus": ("Broken", None),
+ "RemoteExec": (-1, "RemoteExec script failed!")
+}
+
def WAMP_connector_factory(uri, confnodesroot):
"""
@@ -61,37 +67,38 @@
"""
servicetype, location = uri.split("://")
urlpath, realm, ID = location.split('#')
- urlprefix = {"WAMP":"ws",
- "WAMPS":"wss"}[servicetype]
+ urlprefix = {"WAMP": "ws",
+ "WAMPS": "wss"}[servicetype]
url = urlprefix+"://"+urlpath
def RegisterWampClient():
- ## start logging to console
+ # start logging to console
# log.startLogging(sys.stdout)
# create a WAMP application session factory
component_config = types.ComponentConfig(
- realm = realm,
- extra = {"ID":ID})
+ realm=realm,
+ extra={"ID": ID})
session_factory = wamp.ApplicationSessionFactory(
- config = component_config)
+ config=component_config)
session_factory.session = WampSession
# create a WAMP-over-WebSocket transport client factory
transport_factory = WampWebSocketClientFactory(
session_factory,
- url = url,
- serializers = [MsgPackSerializer()],
- debug = False,
- debug_wamp = False)
+ url=url,
+ serializers=[MsgPackSerializer()],
+ debug=False,
+ debug_wamp=False)
# start the client from a Twisted endpoint
conn = connectWS(transport_factory)
- confnodesroot.logger.write(_("WAMP connecting to URL : %s\n")%url)
+ confnodesroot.logger.write(_("WAMP connecting to URL : %s\n") % url)
return conn
AddToDoBeforeQuit = confnodesroot.AppFrame.AddToDoBeforeQuit
+
def ThreadProc():
global _WampConnection
_WampConnection = RegisterWampClient()
@@ -99,22 +106,23 @@
reactor.run(installSignalHandlers=False)
def WampSessionProcMapper(funcname):
- wampfuncname = '.'.join((ID,funcname))
- def catcher_func(*args,**kwargs):
+ wampfuncname = '.'.join((ID, funcname))
+
+ def catcher_func(*args, **kwargs):
global _WampSession
- if _WampSession is not None :
+ if _WampSession is not None:
try:
return threads.blockingCallFromThread(
reactor, _WampSession.call, wampfuncname,
- *args,**kwargs)
+ *args, **kwargs)
except TransportLost, e:
confnodesroot.logger.write_error(_("Connection lost!\n"))
confnodesroot._SetConnector(None)
- except Exception,e:
+ except Exception, e:
errmess = traceback.format_exc()
confnodesroot.logger.write_error(errmess+"\n")
print errmess
- #confnodesroot._SetConnector(None)
+ # confnodesroot._SetConnector(None)
return PLCObjDefaults.get(funcname)
return catcher_func
@@ -128,7 +136,7 @@
reactor, RegisterWampClient)
if not _WampSessionEvent.wait(5):
_WampConnection = stopConnecting()
- raise Exception, _("WAMP connection timeout")
+ raise Exception(_("WAMP connection timeout"))
def __del__(self):
global _WampConnection
@@ -144,13 +152,9 @@
return member
# Try to get the proxy object
- try :
+ try:
return WampPLCObjectProxy()
except Exception, msg:
- confnodesroot.logger.write_error(_("WAMP connection to '%s' failed.\n")%location)
+ confnodesroot.logger.write_error(_("WAMP connection to '%s' failed.\n") % location)
confnodesroot.logger.write_error(traceback.format_exc())
return None
-
-
-
-
--- a/connectors/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/connectors/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,66 +1,68 @@
-#!/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
-# Copyright (C) 2017: Andrey Skvortsov
-#
-# See COPYING file for copyrights details.
-#
-# This program 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
-# of the License, or (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# Package initialisation
-
-from os import listdir, path
-import util.paths as paths
-
-_base_path = paths.AbsDir(__file__)
-
-
-def _GetLocalConnectorClassFactory(name):
- return lambda: getattr(__import__(name, globals(), locals()), name + "_connector_factory")
-
-connectors = {name:_GetLocalConnectorClassFactory(name)
- for name in listdir(_base_path)
- if path.isdir(path.join(_base_path, name))
- and not name.startswith("__")}
-
-
-def ConnectorFactory(uri, confnodesroot):
- """
- Return a connector corresponding to the URI
- or None if cannot connect to URI
- """
- servicetype = uri.split("://")[0].upper()
- if servicetype == "LOCAL":
- # Local is special case
- # pyro connection to local runtime
- # started on demand, listening on random port
- servicetype = "PYRO"
- runtime_port = confnodesroot.AppFrame.StartLocalRuntime(
- taskbaricon=True)
- uri = "PYROLOC://127.0.0.1:" + str(runtime_port)
- elif servicetype in connectors:
- pass
- elif servicetype[-1] == 'S' and servicetype[:-1] in connectors:
- servicetype = servicetype[:-1]
- else:
- return None
-
- # import module according to uri type
- connectorclass = connectors[servicetype]()
- return connectorclass(uri, confnodesroot)
+#!/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
+# Copyright (C) 2017: Andrey Skvortsov
+#
+# See COPYING file for copyrights details.
+#
+# This program 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Package initialisation
+
+from os import listdir, path
+import util.paths as paths
+
+_base_path = paths.AbsDir(__file__)
+
+
+def _GetLocalConnectorClassFactory(name):
+ return lambda: getattr(__import__(name, globals(), locals()), name + "_connector_factory")
+
+
+connectors = {name:
+ _GetLocalConnectorClassFactory(name)
+ for name in listdir(_base_path)
+ if (path.isdir(path.join(_base_path, name))
+ and not name.startswith("__"))}
+
+
+def ConnectorFactory(uri, confnodesroot):
+ """
+ Return a connector corresponding to the URI
+ or None if cannot connect to URI
+ """
+ servicetype = uri.split("://")[0].upper()
+ if servicetype == "LOCAL":
+ # Local is special case
+ # pyro connection to local runtime
+ # started on demand, listening on random port
+ servicetype = "PYRO"
+ runtime_port = confnodesroot.AppFrame.StartLocalRuntime(
+ taskbaricon=True)
+ uri = "PYROLOC://127.0.0.1:" + str(runtime_port)
+ elif servicetype in connectors:
+ pass
+ elif servicetype[-1] == 'S' and servicetype[:-1] in connectors:
+ servicetype = servicetype[:-1]
+ else:
+ return None
+
+ # import module according to uri type
+ connectorclass = connectors[servicetype]()
+ return connectorclass(uri, confnodesroot)
--- a/controls/CustomEditableListBox.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomEditableListBox.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,16 +25,17 @@
import wx
import wx.gizmos
+
class CustomEditableListBox(wx.gizmos.EditableListBox):
-
+
def __init__(self, *args, **kwargs):
wx.gizmos.EditableListBox.__init__(self, *args, **kwargs)
-
+
listbox = self.GetListCtrl()
listbox.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
listbox.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnLabelBeginEdit)
listbox.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnLabelEndEdit)
-
+
for button, tooltip, call_function in [
(self.GetEditButton(), _("Edit item"), "_OnEditButton"),
(self.GetNewButton(), _("New item"), "_OnNewButton"),
@@ -43,13 +44,13 @@
(self.GetDownButton(), _("Move down"), "_OnDownButton")]:
button.SetToolTipString(tooltip)
button.Bind(wx.EVT_BUTTON, self.GetButtonPressedFunction(call_function))
-
+
self.Editing = False
-
+
def EnsureCurrentItemVisible(self):
listctrl = self.GetListCtrl()
listctrl.EnsureVisible(listctrl.GetFocusedItem())
-
+
def OnLabelBeginEdit(self, event):
self.Editing = True
func = getattr(self, "_OnLabelBeginEdit", None)
@@ -57,7 +58,7 @@
func(event)
else:
event.Skip()
-
+
def OnLabelEndEdit(self, event):
self.Editing = False
func = getattr(self, "_OnLabelEndEdit", None)
@@ -65,7 +66,7 @@
func(event)
else:
event.Skip()
-
+
def GetButtonPressedFunction(self, call_function):
def OnButtonPressed(event):
if wx.Platform != '__WXMSW__' or not self.Editing:
@@ -77,7 +78,7 @@
wx.CallAfter(self.EnsureCurrentItemVisible)
event.Skip()
return OnButtonPressed
-
+
def OnKeyDown(self, event):
button = None
keycode = event.GetKeyCode()
--- a/controls/CustomGrid.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomGrid.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,46 +25,47 @@
import wx
import wx.grid
+
class CustomGrid(wx.grid.Grid):
-
+
def __init__(self, *args, **kwargs):
wx.grid.Grid.__init__(self, *args, **kwargs)
-
+
self.Editable = True
-
+
self.AddButton = None
self.DeleteButton = None
self.UpButton = None
self.DownButton = None
-
+
self.SetFont(wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, 'Sans'))
self.SetLabelFont(wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, 'Sans'))
self.SetSelectionBackground(wx.WHITE)
self.SetSelectionForeground(wx.BLACK)
self.DisableDragRowSize()
-
+
self.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnSelectCell)
self.Bind(wx.grid.EVT_GRID_EDITOR_HIDDEN, self.OnEditorHidden)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
-
+
def SetFocus(self):
if self:
wx.grid.Grid.SetFocus(self)
-
+
def SetDefaultValue(self, default_value):
self.DefaultValue = default_value
-
+
def SetEditable(self, editable=True):
self.Editable = editable
self.RefreshButtons()
-
+
def SetButtons(self, buttons):
for name in ["Add", "Delete", "Up", "Down"]:
button = buttons.get(name, None)
setattr(self, "%sButton" % name, button)
if button is not None:
button.Bind(wx.EVT_BUTTON, getattr(self, "On%sButton" % name))
-
+
def RefreshButtons(self):
if self:
rows = self.Table.GetNumberRows()
@@ -77,7 +78,7 @@
self.UpButton.Enable(self.Editable and row > 0)
if self.DownButton is not None:
self.DownButton.Enable(self.Editable and 0 <= row < rows - 1)
-
+
def CloseEditControl(self):
row, col = self.GetGridCursorRow(), self.GetGridCursorCol()
if row != -1 and col != -1:
@@ -119,27 +120,27 @@
self.Table.ResetView(self)
if new_row != row:
self.SetSelectedCell(new_row, col)
-
+
def SetSelectedCell(self, row, col):
self.SetGridCursor(row, col)
self.MakeCellVisible(row, col)
self.RefreshButtons()
-
+
def OnAddButton(self, event):
self.AddRow()
self.SetFocus()
event.Skip()
-
+
def OnDeleteButton(self, event):
self.DeleteRow()
self.SetFocus()
event.Skip()
-
+
def OnUpButton(self, event):
self.MoveRow(self.GetGridCursorRow(), -1)
self.SetFocus()
event.Skip()
-
+
def OnDownButton(self, event):
self.MoveRow(self.GetGridCursorRow(), 1)
self.SetFocus()
--- a/controls/CustomStyledTextCtrl.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomStyledTextCtrl.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,19 +26,21 @@
import wx.stc
if wx.Platform == '__WXMSW__':
- faces = { 'times': 'Times New Roman',
- 'mono' : 'Courier New',
- 'helv' : 'Arial',
- 'other': 'Comic Sans MS',
- 'size' : 10,
- }
+ faces = {
+ 'times': 'Times New Roman',
+ 'mono': 'Courier New',
+ 'helv': 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size': 10,
+ }
else:
- faces = { 'times': 'Times',
- 'mono' : 'Courier',
- 'helv' : 'Helvetica',
- 'other': 'new century schoolbook',
- 'size' : 12,
- }
+ faces = {
+ 'times': 'Times',
+ 'mono': 'Courier',
+ 'helv': 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size': 12,
+ }
NAVIGATION_KEYS = [
wx.WXK_END,
@@ -58,6 +60,7 @@
wx.WXK_NUMPAD_PAGEDOWN,
wx.WXK_NUMPAD_END]
+
def GetCursorPos(old, new):
if old == "":
return 0
@@ -81,13 +84,14 @@
else:
return None
+
class CustomStyledTextCtrl(wx.stc.StyledTextCtrl):
-
+
def __init__(self, *args, **kwargs):
wx.stc.StyledTextCtrl.__init__(self, *args, **kwargs)
-
+
self.Bind(wx.EVT_MOTION, self.OnMotion)
-
+
def OnMotion(self, event):
if wx.Platform == '__WXMSW__':
if not event.Dragging():
--- a/controls/CustomTable.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomTable.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,8 +30,9 @@
else:
ROW_HEIGHT = 28
+
class CustomTable(wx.grid.PyGridTableBase):
-
+
"""
A custom wx.grid.Grid Table using user supplied data
"""
@@ -47,10 +48,10 @@
# see if the table has changed size
self._rows = self.GetNumberRows()
self._cols = self.GetNumberCols()
-
+
def GetNumberCols(self):
return len(self.colnames)
-
+
def GetNumberRows(self):
return len(self.data)
@@ -66,11 +67,11 @@
def GetValue(self, row, col):
if row < self.GetNumberRows():
return self.data[row].get(self.GetColLabelValue(col, False), "")
-
+
def SetValue(self, row, col, value):
if col < len(self.colnames):
self.data[row][self.GetColLabelValue(col, False)] = value
-
+
def GetValueByName(self, row, colname):
if row < self.GetNumberRows():
return self.data[row].get(colname)
@@ -91,10 +92,10 @@
(self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
]:
if new < current:
- msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
+ msg = wx.grid.GridTableMessage(self, delmsg, new, current-new)
grid.ProcessTableMessage(msg)
elif new > current:
- msg = wx.grid.GridTableMessage(self,addmsg,new-current)
+ msg = wx.grid.GridTableMessage(self, addmsg, new-current)
grid.ProcessTableMessage(msg)
self.UpdateValues(grid)
grid.EndBatch()
@@ -125,33 +126,33 @@
row_highlights = self.Highlights.get(row, {})
for col in range(self.GetNumberCols()):
colname = self.GetColLabelValue(col, False)
-
+
grid.SetReadOnly(row, col, True)
grid.SetCellEditor(row, col, None)
grid.SetCellRenderer(row, col, None)
-
+
highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
grid.SetCellBackgroundColour(row, col, highlight_colours[0])
grid.SetCellTextColour(row, col, highlight_colours[1])
self.ResizeRow(grid, row)
-
+
def ResizeRow(self, grid, row):
if grid.GetRowSize(row) < ROW_HEIGHT:
grid.SetRowMinimalHeight(row, ROW_HEIGHT)
grid.AutoSizeRow(row, False)
-
+
def SetData(self, data):
self.data = data
-
+
def GetData(self):
return self.data
-
+
def GetCurrentIndex(self):
return self.CurrentIndex
-
+
def SetCurrentIndex(self, index):
self.CurrentIndex = index
-
+
def AppendRow(self, row_content):
self.data.append(row_content)
--- a/controls/CustomToolTip.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomToolTip.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,45 +26,45 @@
from controls.CustomStyledTextCtrl import faces
-TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip
-TOOLTIP_MAX_LINE = 5 # Maximum number of line in ToolTip
-TOOLTIP_WAIT_PERIOD = 0.5 # Wait period before displaying tooltip in second
+TOOLTIP_MAX_CHARACTERS = 30 # Maximum number of characters by line in ToolTip
+TOOLTIP_MAX_LINE = 5 # Maximum number of line in ToolTip
+TOOLTIP_WAIT_PERIOD = 0.5 # Wait period before displaying tooltip in second
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Custom ToolTip
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a custom tool tip
-"""
class CustomToolTip(wx.PopupWindow):
-
+ """
+ Class that implements a custom tool tip
+ """
+
def __init__(self, parent, tip, restricted=True):
"""
Constructor
@param parent: Parent window
@param tip: Tip text (may be multiline)
- @param restricted: Tool tip must follow size restriction in line and
+ @param restricted: Tool tip must follow size restriction in line and
characters number defined (default True)
"""
wx.PopupWindow.__init__(self, parent)
-
+
self.Restricted = restricted
-
+
self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.SetTip(tip)
-
+
# Initialize text font style
self.Font = wx.Font(
- faces["size"],
- wx.SWISS,
- wx.NORMAL,
- wx.NORMAL,
- faceName = faces["mono"])
-
+ faces["size"],
+ wx.SWISS,
+ wx.NORMAL,
+ wx.NORMAL,
+ faceName=faces["mono"])
+
self.Bind(wx.EVT_PAINT, self.OnPaint)
-
+
def SetFont(self, font):
"""
Set tool tip text font style
@@ -72,7 +72,7 @@
"""
self.Font = font
self.RefreshTip()
-
+
def SetTip(self, tip):
"""
Set tool tip text
@@ -87,8 +87,7 @@
new_line = words[0]
for word in words[1:]:
# Add word to line
- if len(new_line + " " + word) <= \
- TOOLTIP_MAX_CHARACTERS:
+ if len(new_line + " " + word) <= TOOLTIP_MAX_CHARACTERS:
new_line += " " + word
# Create new line
else:
@@ -97,24 +96,24 @@
self.Tip.append(new_line)
else:
self.Tip.append(line)
-
+
# Restrict number of lines
if len(self.Tip) > TOOLTIP_MAX_LINE:
self.Tip = self.Tip[:TOOLTIP_MAX_LINE]
-
+
# Add ... to the end of last line to indicate that tool tip
# text is too long
if len(self.Tip[-1]) < TOOLTIP_MAX_CHARACTERS - 3:
self.Tip[-1] += "..."
else:
- self.Tip[-1] = self.Tip[-1]\
- [:TOOLTIP_MAX_CHARACTERS - 3] + "..."
+ self.Tip[-1] = self.Tip[-1][:TOOLTIP_MAX_CHARACTERS - 3] + \
+ "..."
else:
self.Tip = tip.splitlines()
-
+
# Prevent to call wx method in non-wx threads
wx.CallAfter(self.RefreshTip)
-
+
def SetToolTipPosition(self, pos):
"""
Set tool tip position
@@ -122,32 +121,32 @@
"""
# Get screen size to prevent tool tip to go out of the screen
screen_width, screen_height = wx.GetDisplaySize()
-
+
# Calculate position of tool tip to stay in screen limits
tip_width, tip_height = self.GetToolTipSize()
self.SetPosition(wx.Point(
max(0, min(pos.x, screen_width - tip_width)),
max(0, min(pos.y, screen_height - tip_height))))
-
+
def GetToolTipSize(self):
"""
Get tool tip size according to tip text and restriction
@return: wx.Size(tool_tip_width, tool_tip_height)
"""
max_width = max_height = 0
-
+
# Create a memory DC for calculating text extent
dc = wx.MemoryDC()
dc.SetFont(self.Font)
-
+
# Compute max tip text size
for line in self.Tip:
w, h = dc.GetTextExtent(line)
max_width = max(max_width, w)
max_height += h
-
+
return wx.Size(max_width + 4, max_height + 4)
-
+
def RefreshTip(self):
"""
Refresh tip on screen
@@ -156,10 +155,10 @@
if self:
# Refresh tool tip size and position
self.SetClientSize(self.GetToolTipSize())
-
+
# Redraw tool tip
self.Refresh()
-
+
def OnPaint(self, event):
"""
Callback for Paint Event
@@ -168,26 +167,26 @@
# Get buffered paint DC for tool tip
dc = wx.AutoBufferedPaintDC(self)
dc.Clear()
-
+
# Set DC drawing style
dc.SetPen(wx.BLACK_PEN)
dc.SetBrush(wx.Brush(wx.Colour(255, 238, 170)))
dc.SetFont(self.Font)
-
+
# Draw Tool tip
dc.BeginDrawing()
tip_width, tip_height = self.GetToolTipSize()
-
+
# Draw background rectangle
dc.DrawRectangle(0, 0, tip_width, tip_height)
-
+
# Draw tool tip text
line_offset = 0
for line in self.Tip:
dc.DrawText(line, 2, line_offset + 2)
line_width, line_height = dc.GetTextExtent(line)
line_offset += line_height
-
+
dc.EndDrawing()
-
+
event.Skip()
--- a/controls/CustomTree.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/CustomTree.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,44 +30,51 @@
# Customize CustomTreeItem for adding icon on item left
CT.GenericTreeItem._ExtraImage = None
+
def SetExtraImage(self, image):
self._type = (1 if image is not None else 0)
self._ExtraImage = image
+
CT.GenericTreeItem.SetExtraImage = SetExtraImage
_DefaultGetCurrentCheckedImage = CT.GenericTreeItem.GetCurrentCheckedImage
+
+
def GetCurrentCheckedImage(self):
if self._ExtraImage is not None:
return self._ExtraImage
return _DefaultGetCurrentCheckedImage(self)
+
+
CT.GenericTreeItem.GetCurrentCheckedImage = GetCurrentCheckedImage
+
class CustomTree(CT.CustomTreeCtrl):
-
+
def __init__(self, *args, **kwargs):
CT.CustomTreeCtrl.__init__(self, *args, **kwargs)
-
+
self.BackgroundBitmap = None
- self.BackgroundAlign = wx.ALIGN_LEFT|wx.ALIGN_TOP
-
+ self.BackgroundAlign = wx.ALIGN_LEFT | wx.ALIGN_TOP
+
self.AddMenu = None
self.Enabled = False
-
+
self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
-
+
def SetBackgroundBitmap(self, bitmap, align):
self.BackgroundBitmap = bitmap
self.BackgroundAlign = align
-
+
def SetImageListCheck(self, sizex, sizey, imglist=None):
CT.CustomTreeCtrl.SetImageListCheck(self, sizex, sizey, imglist=None)
-
+
self.ExtraImages = {}
for image in ["function", "functionBlock", "program"]:
self.ExtraImages[image] = self._imageListCheck.Add(GetBitmap(image.upper()))
-
+
def SetItemExtraImage(self, item, bitmap):
dc = wx.ClientDC(self)
image = self.ExtraImages.get(bitmap)
@@ -76,45 +83,45 @@
else:
item.SetExtraImage(None)
self.CalculateSize(item, dc)
- self.RefreshLine(item)
-
+ self.RefreshLine(item)
+
def SetAddMenu(self, add_menu):
self.AddMenu = add_menu
-
+
def Enable(self, enabled):
self.Enabled = enabled
-
+
def GetBitmapRect(self):
client_size = self.GetClientSize()
bitmap_size = self.BackgroundBitmap.GetSize()
-
+
if self.BackgroundAlign & wx.ALIGN_RIGHT:
x = client_size[0] - bitmap_size[0]
elif self.BackgroundAlign & wx.ALIGN_CENTER_HORIZONTAL:
x = (client_size[0] - bitmap_size[0]) / 2
else:
x = 0
-
+
if self.BackgroundAlign & wx.ALIGN_BOTTOM:
y = client_size[1] - bitmap_size[1]
elif self.BackgroundAlign & wx.ALIGN_CENTER_VERTICAL:
y = (client_size[1] - bitmap_size[1]) / 2
else:
y = 0
-
+
return wx.Rect(x, y, bitmap_size[0], bitmap_size[1])
-
+
def OnLeftUp(self, event):
if self.Enabled:
pos = event.GetPosition()
item, flags = self.HitTest(pos)
-
+
bitmap_rect = self.GetBitmapRect()
- if (bitmap_rect.InsideXY(pos.x, pos.y) or
- flags & wx.TREE_HITTEST_NOWHERE) and self.AddMenu is not None:
+ if ((bitmap_rect.InsideXY(pos.x, pos.y) or
+ flags & wx.TREE_HITTEST_NOWHERE) and self.AddMenu is not None):
wx.CallAfter(self.PopupMenuXY, self.AddMenu, pos.x, pos.y)
event.Skip()
-
+
def OnEraseBackground(self, event):
dc = event.GetDC()
@@ -122,12 +129,12 @@
dc = wx.ClientDC(self)
rect = self.GetUpdateRegion().GetBox()
dc.SetClippingRect(rect)
-
+
dc.Clear()
-
+
bitmap_rect = self.GetBitmapRect()
dc.DrawBitmap(self.BackgroundBitmap, bitmap_rect.x, bitmap_rect.y)
-
+
def OnScroll(self, event):
wx.CallAfter(self.Refresh)
event.Skip()
--- a/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/DebugVariableGraphicViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -53,19 +53,20 @@
# Canvas height
[SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI] = [0, 100, 200]
-CANVAS_BORDER = (20., 10.) # Border height on at bottom and top of graph
-CANVAS_PADDING = 8.5 # Border inside graph where no label is drawn
-VALUE_LABEL_HEIGHT = 17. # Height of variable label in graph
-AXES_LABEL_HEIGHT = 12.75 # Height of variable value in graph
+CANVAS_BORDER = (20., 10.) # Border height on at bottom and top of graph
+CANVAS_PADDING = 8.5 # Border inside graph where no label is drawn
+VALUE_LABEL_HEIGHT = 17. # Height of variable label in graph
+AXES_LABEL_HEIGHT = 12.75 # Height of variable value in graph
# Colors used cyclically for graph curves
COLOR_CYCLE = ['r', 'b', 'g', 'm', 'y', 'k']
# Color for graph cursor
CURSOR_COLOR = '#800080'
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Graphic Viewer Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def merge_ranges(ranges):
"""
@@ -83,37 +84,37 @@
min_value = range_min
elif range_min is not None:
min_value = min(min_value, range_min)
-
+
# Update maximal range value
if max_value is None:
max_value = range_max
elif range_min is not None:
max_value = max(max_value, range_max)
-
+
# Calculate range center and width if at least one valid range is defined
if min_value is not None and max_value is not None:
center = (min_value + max_value) / 2.
range_size = max(1.0, max_value - min_value)
-
+
# Set default center and with if no valid range is defined
else:
center = 0.5
range_size = 1.0
-
+
# Return range expended from 10 %
return center - range_size * 0.55, center + range_size * 0.55
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Graphic Viewer Drop Target
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a custom drop target class for Debug Variable Graphic
-Viewer
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableGraphicDropTarget(wx.TextDropTarget):
-
+ """
+ Class that implements a custom drop target class for Debug Variable Graphic
+ Viewer
+ """
+
def __init__(self, parent, window):
"""
Constructor
@@ -123,7 +124,7 @@
wx.TextDropTarget.__init__(self)
self.ParentControl = parent
self.ParentWindow = window
-
+
def __del__(self):
"""
Destructor
@@ -132,7 +133,7 @@
# Panel
self.ParentControl = None
self.ParentWindow = None
-
+
def OnDragOver(self, x, y, d):
"""
Function called when mouse is dragged over Drop Target
@@ -142,9 +143,9 @@
"""
# Signal parent that mouse is dragged over
self.ParentControl.OnMouseDragging(x, y)
-
+
return wx.TextDropTarget.OnDragOver(self, x, y, d)
-
+
def OnDropText(self, x, y, data):
"""
Function called when mouse is released in Drop Target
@@ -154,65 +155,65 @@
"""
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
-
+
message = None
-
+
# Check that data is valid regarding DebugVariablePanel
try:
values = eval(data)
if not isinstance(values, TupleType):
raise ValueError
- except:
- message = _("Invalid value \"%s\" for debug variable")%data
+ except Exception:
+ message = _("Invalid value \"%s\" for debug variable") % data
values = None
-
+
# Display message if data is invalid
if message is not None:
wx.CallAfter(self.ShowMessage, message)
-
+
# Data contain a reference to a variable to debug
elif values[1] == "debug":
target_idx = self.ParentControl.GetIndex()
-
+
# If mouse is dropped in graph canvas bounding box and graph is
# not 3D canvas, graphs will be merged
rect = self.ParentControl.GetAxesBoundingBox()
if not self.ParentControl.Is3DCanvas() and rect.InsideXY(x, y):
# Default merge type is parallel
merge_type = GRAPH_PARALLEL
-
+
# If mouse is dropped in left part of graph canvas, graph
# wall be merged orthogonally
- merge_rect = wx.Rect(rect.x, rect.y,
+ merge_rect = wx.Rect(rect.x, rect.y,
rect.width / 2., rect.height)
if merge_rect.InsideXY(x, y):
merge_type = GRAPH_ORTHOGONAL
-
+
# Merge graphs
- wx.CallAfter(self.ParentWindow.MergeGraphs,
- values[0], target_idx,
+ wx.CallAfter(self.ParentWindow.MergeGraphs,
+ values[0], target_idx,
merge_type, force=True)
-
+
else:
width, height = self.ParentControl.GetSize()
-
+
# Get Before which Viewer the variable has to be moved or added
# according to the position of mouse in Viewer.
if y > height / 2:
target_idx += 1
-
+
# Drag'n Drop is an internal is an internal move inside Debug
- # Variable Panel
+ # Variable Panel
if len(values) > 2 and values[2] == "move":
- self.ParentWindow.MoveValue(values[0],
+ self.ParentWindow.MoveValue(values[0],
target_idx)
-
+
# Drag'n Drop was initiated by another control of Beremiz
else:
- self.ParentWindow.InsertValue(values[0],
- target_idx,
+ self.ParentWindow.InsertValue(values[0],
+ target_idx,
force=True)
-
+
def OnLeave(self):
"""
Function called when mouse is leave Drop Target
@@ -220,30 +221,30 @@
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
return wx.TextDropTarget.OnLeave(self)
-
+
def ShowMessage(self, message):
"""
Show error message in Error Dialog
@param message: Error message to display
"""
- dialog = wx.MessageDialog(self.ParentWindow,
- message,
- _("Error"),
- wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self.ParentWindow,
+ message,
+ _("Error"),
+ wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Graphic Viewer Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a Viewer that display variable values as a graphs
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableGraphicViewer(DebugVariableViewer, FigureCanvas):
-
+ """
+ Class that implements a Viewer that display variable values as a graphs
+ """
+
def __init__(self, parent, window, items, graph_type):
"""
Constructor
@@ -253,36 +254,36 @@
@param graph_type: Graph display type (Parallel or orthogonal)
"""
DebugVariableViewer.__init__(self, window, items)
-
+
self.GraphType = graph_type # Graph type display
self.CursorTick = None # Tick of the graph cursor
-
+
# Mouse position when start dragging
self.MouseStartPos = None
# Tick when moving tick start
self.StartCursorTick = None
# Canvas size when starting to resize canvas
- self.CanvasStartSize = None
-
+ self.CanvasStartSize = None
+
# List of current displayed contextual buttons
self.ContextualButtons = []
# Reference to item for which contextual buttons was displayed
self.ContextualButtonsItem = None
-
+
# Flag indicating that zoom fit current displayed data range or whole
# data range if False
self.ZoomFit = False
-
+
# Create figure for drawing graphs
self.Figure = matplotlib.figure.Figure(facecolor='w')
# Defined border around figure in canvas
- self.Figure.subplotpars.update(top=0.95, left=0.1,
+ self.Figure.subplotpars.update(top=0.95, left=0.1,
bottom=0.1, right=0.95)
-
+
FigureCanvas.__init__(self, parent, -1, self.Figure)
self.SetWindowStyle(wx.WANTS_CHARS)
self.SetBackgroundColour(wx.WHITE)
-
+
# Bind wx events
self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
@@ -290,42 +291,42 @@
self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_SIZE, self.OnResize)
-
+
# Set canvas min size
canvas_size = self.GetCanvasMinSize()
self.SetMinSize(canvas_size)
-
+
# Define Viewer drop target
self.SetDropTarget(DebugVariableGraphicDropTarget(self, window))
-
+
# Connect matplotlib events
self.mpl_connect('button_press_event', self.OnCanvasButtonPressed)
self.mpl_connect('motion_notify_event', self.OnCanvasMotion)
self.mpl_connect('button_release_event', self.OnCanvasButtonReleased)
self.mpl_connect('scroll_event', self.OnCanvasScroll)
-
+
# Add buttons for zooming on current displayed data range
self.Buttons.append(
GraphButton(0, 0, "fit_graph", self.OnZoomFitButton))
-
+
# Add buttons for changing canvas size with predefined height
for size, bitmap in zip(
[SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI],
["minimize_graph", "middle_graph", "maximize_graph"]):
self.Buttons.append(
- GraphButton(0, 0, bitmap,
+ GraphButton(0, 0, bitmap,
self.GetOnChangeSizeButton(size)))
-
+
# Add buttons for exporting graph values to clipboard and close graph
for bitmap, callback in [
("export_graph_mini", self.OnExportGraphButton),
("delete_graph", self.OnCloseButton)]:
self.Buttons.append(GraphButton(0, 0, bitmap, callback))
-
+
# Update graphs elements
self.ResetGraphics()
self.RefreshLabelsPosition(canvas_size.height)
-
+
def AddItem(self, item):
"""
Add an item to the list of items displayed by Viewer
@@ -333,14 +334,14 @@
"""
DebugVariableViewer.AddItem(self, item)
self.ResetGraphics()
-
+
def RemoveItem(self, item):
"""
Remove an item from the list of items displayed by Viewer
@param item: Item to remove from the list
"""
DebugVariableViewer.RemoveItem(self, item)
-
+
# If list of items is not empty
if not self.ItemsIsEmpty():
# Return to parallel graph if there is only one item
@@ -348,51 +349,51 @@
if len(self.Items) == 1:
self.GraphType = GRAPH_PARALLEL
self.ResetGraphics()
-
+
def SetCursorTick(self, cursor_tick):
"""
Set cursor tick
@param cursor_tick: Cursor tick
"""
self.CursorTick = cursor_tick
-
+
def SetZoomFit(self, zoom_fit):
"""
Set flag indicating that zoom fit current displayed data range
@param zoom_fit: Flag for zoom fit (False: zoom fit whole data range)
"""
- # Flag is different from the actual one
+ # Flag is different from the actual one
if zoom_fit != self.ZoomFit:
# Save new flag value
self.ZoomFit = zoom_fit
-
+
# Update button for zoom fit bitmap
self.Buttons[0].SetBitmap("full_graph" if zoom_fit else "fit_graph")
-
+
# Refresh canvas
self.RefreshViewer()
-
+
def SubscribeAllDataConsumers(self):
"""
Function that unsubscribe and remove every item that store values of
a variable that doesn't exist in PLC anymore
"""
DebugVariableViewer.SubscribeAllDataConsumers(self)
-
+
# Graph still have data to display
if not self.ItemsIsEmpty():
# Reset flag indicating that zoom fit current displayed data range
self.SetZoomFit(False)
-
+
self.ResetGraphics()
-
+
def Is3DCanvas(self):
"""
Return if Viewer is a 3D canvas
@return: True if Viewer is a 3D canvas
"""
return self.GraphType == GRAPH_ORTHOGONAL and len(self.Items) == 3
-
+
def GetButtons(self):
"""
Return list of buttons defined in Viewer
@@ -400,7 +401,7 @@
"""
# Add contextual buttons to default buttons
return self.Buttons + self.ContextualButtons
-
+
def PopupContextualButtons(self, item, rect, direction=wx.RIGHT):
"""
Show contextual menu for item aside a label of this item defined
@@ -412,19 +413,19 @@
# Return immediately if contextual menu for item is already shown
if self.ContextualButtonsItem == item:
return
-
+
# Close already shown contextual menu
self.DismissContextualButtons()
-
+
# Save item for which contextual menu is shown
self.ContextualButtonsItem = item
-
+
# If item variable is forced, add button for release variable to
# contextual menu
if self.ContextualButtonsItem.IsForced():
self.ContextualButtons.append(
GraphButton(0, 0, "release", self.OnReleaseItemButton))
-
+
# Add other buttons to contextual menu
for bitmap, callback in [
("force", self.OnForceItemButton),
@@ -432,13 +433,13 @@
("delete_graph", self.OnRemoveItemButton)]:
self.ContextualButtons.append(
GraphButton(0, 0, bitmap, callback))
-
+
# If buttons are shown at left side or upper side of rect, positions
# will be set in reverse order
buttons = self.ContextualButtons[:]
if direction in [wx.TOP, wx.LEFT]:
- buttons.reverse()
-
+ buttons.reverse()
+
# Set contextual menu buttons position aside rect depending on
# direction given
offset = 0
@@ -446,22 +447,22 @@
w, h = button.GetSize()
if direction in [wx.LEFT, wx.RIGHT]:
x = rect.x + (- w - offset
- if direction == wx.LEFT
- else rect.width + offset)
+ if direction == wx.LEFT
+ else rect.width + offset)
y = rect.y + (rect.height - h) / 2
offset += w
else:
- x = rect.x + (rect.width - w ) / 2
+ x = rect.x + (rect.width - w) / 2
y = rect.y + (- h - offset
if direction == wx.TOP
else rect.height + offset)
offset += h
button.SetPosition(x, y)
button.Show()
-
+
# Refresh canvas
self.ParentWindow.ForceRefresh()
-
+
def DismissContextualButtons(self):
"""
Close current shown contextual menu
@@ -469,14 +470,14 @@
# Return immediately if no contextual menu is shown
if self.ContextualButtonsItem is None:
return
-
+
# Reset variables corresponding to contextual menu
self.ContextualButtonsItem = None
self.ContextualButtons = []
-
+
# Refresh canvas
self.ParentWindow.ForceRefresh()
-
+
def IsOverContextualButton(self, x, y):
"""
Return if point is over one contextual button of Viewer
@@ -488,7 +489,7 @@
if button.HitTest(x, y):
return button
return None
-
+
def ExportGraph(self, item=None):
"""
Export item(s) data to clipboard in CSV format
@@ -497,17 +498,17 @@
"""
self.ParentWindow.CopyDataToClipboard(
[(item, [entry for entry in item.GetData()])
- for item in (self.Items
- if item is None
+ for item in (self.Items
+ if item is None
else [item])])
-
+
def OnZoomFitButton(self):
"""
Function called when Viewer Zoom Fit button is pressed
"""
# Toggle zoom fit flag value
self.SetZoomFit(not self.ZoomFit)
-
+
def GetOnChangeSizeButton(self, height):
"""
Function that generate callback function for change Viewer height to
@@ -518,32 +519,32 @@
def OnChangeSizeButton():
self.SetCanvasHeight(height)
return OnChangeSizeButton
-
+
def OnExportGraphButton(self):
"""
Function called when Viewer Export button is pressed
"""
# Export data of every item in Viewer
self.ExportGraph()
-
+
def OnForceItemButton(self):
"""
Function called when contextual menu Force button is pressed
"""
- # Open dialog for forcing item variable value
+ # Open dialog for forcing item variable value
self.ForceValue(self.ContextualButtonsItem)
# Close contextual menu
self.DismissContextualButtons()
-
+
def OnReleaseItemButton(self):
"""
Function called when contextual menu Release button is pressed
"""
- # Release item variable value
+ # Release item variable value
self.ReleaseValue(self.ContextualButtonsItem)
# Close contextual menu
self.DismissContextualButtons()
-
+
def OnExportItemGraphButton(self):
"""
Function called when contextual menu Export button is pressed
@@ -552,17 +553,17 @@
self.ExportGraph(self.ContextualButtonsItem)
# Close contextual menu
self.DismissContextualButtons()
-
- def OnRemoveItemButton(self):
+
+ def OnRemoveItemButton(self):
"""
Function called when contextual menu Remove button is pressed
"""
# Remove item from Viewer
- wx.CallAfter(self.ParentWindow.DeleteValue, self,
+ wx.CallAfter(self.ParentWindow.DeleteValue, self,
self.ContextualButtonsItem)
# Close contextual menu
self.DismissContextualButtons()
-
+
def HandleCursorMove(self, event):
"""
Update Cursor position according to mouse position and graph type
@@ -571,7 +572,7 @@
start_tick, end_tick = self.ParentWindow.GetRange()
cursor_tick = None
items = self.ItemsDict.values()
-
+
# Graph is orthogonal
if self.GraphType == GRAPH_ORTHOGONAL:
# Extract items data displayed in canvas figure
@@ -579,31 +580,31 @@
end_tick = max(end_tick, start_tick)
x_data = items[0].GetData(start_tick, end_tick)
y_data = items[1].GetData(start_tick, end_tick)
-
+
# Search for the nearest point from mouse position
if len(x_data) > 0 and len(y_data) > 0:
- length = min(len(x_data), len(y_data))
- d = numpy.sqrt((x_data[:length,1]-event.xdata) ** 2 + \
- (y_data[:length,1]-event.ydata) ** 2)
-
+ length = min(len(x_data), len(y_data))
+ d = numpy.sqrt((x_data[:length, 1]-event.xdata) ** 2 +
+ (y_data[:length, 1]-event.ydata) ** 2)
+
# Set cursor tick to the tick of this point
cursor_tick = x_data[numpy.argmin(d), 0]
-
+
# Graph is parallel
else:
# Extract items tick
data = items[0].GetData(start_tick, end_tick)
-
+
# Search for point that tick is the nearest from mouse X position
# and set cursor tick to the tick of this point
if len(data) > 0:
cursor_tick = data[numpy.argmin(
- numpy.abs(data[:,0] - event.xdata)), 0]
-
+ numpy.abs(data[:, 0] - event.xdata)), 0]
+
# Update cursor tick
if cursor_tick is not None:
self.ParentWindow.SetCursorTick(cursor_tick)
-
+
def OnCanvasButtonPressed(self, event):
"""
Function called when a button of mouse is pressed
@@ -613,18 +614,18 @@
# comparing to wx
width, height = self.GetSize()
x, y = event.x, height - event.y
-
+
# Return immediately if mouse is over a button
if self.IsOverButton(x, y):
- return
-
+ return
+
# Mouse was clicked inside graph figure
if event.inaxes == self.Axes:
-
+
# Find if it was on an item label
item_idx = None
# Check every label paired with corresponding item
- for i, t in ([pair for pair in enumerate(self.AxesLabels)] +
+ for i, t in ([pair for pair in enumerate(self.AxesLabels)] +
[pair for pair in enumerate(self.Labels)]):
# Get label bounding box
(x0, y0), (x1, y1) = t.get_window_extent().get_points()
@@ -633,46 +634,46 @@
if rect.InsideXY(x, y):
item_idx = i
break
-
+
# If an item label have been clicked
if item_idx is not None:
# Hide buttons and contextual buttons
self.ShowButtons(False)
self.DismissContextualButtons()
-
+
# Start a drag'n drop from mouse position in wx coordinate of
# parent
xw, yw = self.GetPosition()
- self.ParentWindow.StartDragNDrop(self,
- self.ItemsDict.values()[item_idx],
- x + xw, y + yw, # Current mouse position
- x + xw, y + yw) # Mouse position when button was clicked
-
+ self.ParentWindow.StartDragNDrop(
+ self, self.ItemsDict.values()[item_idx],
+ x + xw, y + yw, # Current mouse position
+ x + xw, y + yw) # Mouse position when button was clicked
+
# Don't handle mouse button if canvas is 3D and let matplotlib do
# the default behavior (rotate 3D axes)
elif not self.Is3DCanvas():
# Save mouse position when clicked
self.MouseStartPos = wx.Point(x, y)
-
+
# Mouse button was left button, start moving cursor
if event.button == 1:
# Save current tick in case a drag'n drop is initiate to
# restore it
self.StartCursorTick = self.CursorTick
-
+
self.HandleCursorMove(event)
-
+
# Mouse button is middle button and graph is parallel, start
# moving graph along X coordinate (tick)
elif event.button == 2 and self.GraphType == GRAPH_PARALLEL:
self.StartCursorTick = self.ParentWindow.GetRange()[0]
-
+
# Mouse was clicked outside graph figure and over resize highlight with
# left button, start resizing Viewer
elif event.button == 1 and event.y <= 5:
self.MouseStartPos = wx.Point(x, y)
self.CanvasStartSize = height
-
+
def OnCanvasButtonReleased(self, event):
"""
Function called when a button of mouse is released
@@ -685,57 +686,57 @@
item = self.ParentWindow.DraggingAxesPanel.ItemsDict.values()[0]
# Give mouse position in wx coordinate of parent
self.ParentWindow.StopDragNDrop(item.GetVariable(),
- xw + event.x, yw + height - event.y)
-
+ xw + event.x, yw + height - event.y)
+
else:
# Reset any move in progress
self.MouseStartPos = None
self.CanvasStartSize = None
-
+
# Handle button under mouse if it exist
width, height = self.GetSize()
self.HandleButton(event.x, height - event.y)
-
+
def OnCanvasMotion(self, event):
"""
Function called when a button of mouse is moved over Viewer
@param event: Mouse event
"""
width, height = self.GetSize()
-
+
# If a drag'n drop is in progress, move canvas dragged
if self.ParentWindow.IsDragging():
xw, yw = self.GetPosition()
# Give mouse position in wx coordinate of parent
self.ParentWindow.MoveDragNDrop(
- xw + event.x,
+ xw + event.x,
yw + height - event.y)
-
- # If a Viewer resize is in progress, change Viewer size
+
+ # If a Viewer resize is in progress, change Viewer size
elif event.button == 1 and self.CanvasStartSize is not None:
width, height = self.GetSize()
self.SetCanvasHeight(
self.CanvasStartSize + height - event.y - self.MouseStartPos.y)
-
+
# If no button is pressed, show or hide contextual buttons or resize
# highlight
elif event.button is None:
# Compute direction for items label according graph type
- if self.GraphType == GRAPH_PARALLEL: # Graph is parallel
+ if self.GraphType == GRAPH_PARALLEL: # Graph is parallel
directions = [wx.RIGHT] * len(self.AxesLabels) + \
[wx.LEFT] * len(self.Labels)
- elif len(self.AxesLabels) > 0: # Graph is orthogonal in 2D
- directions = [wx.RIGHT, wx.TOP, # Directions for AxesLabels
- wx.LEFT, wx.BOTTOM] # Directions for Labels
- else: # Graph is orthogonal in 3D
+ elif len(self.AxesLabels) > 0: # Graph is orthogonal in 2D
+ directions = [wx.RIGHT, wx.TOP, # Directions for AxesLabels
+ wx.LEFT, wx.BOTTOM] # Directions for Labels
+ else: # Graph is orthogonal in 3D
directions = [wx.LEFT] * len(self.Labels)
-
+
# Find if mouse is over an item label
item_idx = None
menu_direction = None
for (i, t), dir in zip(
- [pair for pair in enumerate(self.AxesLabels)] +
- [pair for pair in enumerate(self.Labels)],
+ [pair for pair in enumerate(self.AxesLabels)] +
+ [pair for pair in enumerate(self.Labels)],
directions):
# Check every label paired with corresponding item
(x0, y0), (x1, y1) = t.get_window_extent().get_points()
@@ -745,19 +746,19 @@
item_idx = i
menu_direction = dir
break
-
- # If mouse is over an item label,
+
+ # If mouse is over an item label,
if item_idx is not None:
self.PopupContextualButtons(
- self.ItemsDict.values()[item_idx],
+ self.ItemsDict.values()[item_idx],
rect, menu_direction)
return
-
+
# If mouse isn't over a contextual menu, hide the current shown one
- # if it exists
+ # if it exists
if self.IsOverContextualButton(event.x, height - event.y) is None:
self.DismissContextualButtons()
-
+
# Update resize highlight
if event.y <= 5:
if self.SetHighlight(HIGHLIGHT_RESIZE):
@@ -767,46 +768,47 @@
if self.SetHighlight(HIGHLIGHT_NONE):
self.SetCursor(wx.NullCursor)
self.ParentWindow.ForceRefresh()
-
- # Handle buttons if canvas is not 3D
+
+ # Handle buttons if canvas is not 3D
elif not self.Is3DCanvas():
-
+
# If left button is pressed
if event.button == 1:
-
+
# Mouse is inside graph figure
if event.inaxes == self.Axes:
-
+
# If a cursor move is in progress, update cursor position
if self.MouseStartPos is not None:
self.HandleCursorMove(event)
-
+
# Mouse is outside graph figure, cursor move is in progress and
# there is only one item in Viewer, start a drag'n drop
elif self.MouseStartPos is not None and len(self.Items) == 1:
xw, yw = self.GetPosition()
self.ParentWindow.SetCursorTick(self.StartCursorTick)
- self.ParentWindow.StartDragNDrop(self,
- self.ItemsDict.values()[0],
+ self.ParentWindow.StartDragNDrop(
+ self, self.ItemsDict.values()[0],
# Current mouse position
event.x + xw, height - event.y + yw,
# Mouse position when button was clicked
self.MouseStartPos.x + xw,
self.MouseStartPos.y + yw)
-
+
# If middle button is pressed and moving graph along X coordinate
# is in progress
- elif event.button == 2 and self.GraphType == GRAPH_PARALLEL and \
- self.MouseStartPos is not None:
+ elif (event.button == 2 and
+ self.GraphType == GRAPH_PARALLEL and
+ self.MouseStartPos is not None):
start_tick, end_tick = self.ParentWindow.GetRange()
rect = self.GetAxesBoundingBox()
-
+
# Move graph along X coordinate
self.ParentWindow.SetCanvasPosition(
- self.StartCursorTick +
+ self.StartCursorTick +
(self.MouseStartPos.x - event.x) *
(end_tick - start_tick) / rect.width)
-
+
def OnCanvasScroll(self, event):
"""
Function called when a wheel mouse is use in Viewer
@@ -815,7 +817,7 @@
# Change X range of graphs if mouse is in canvas figure and ctrl is
# pressed
if event.inaxes is not None and event.guiEvent.ControlDown():
-
+
# Calculate position of fixed tick point according to graph type
# and mouse position
if self.GraphType == GRAPH_ORTHOGONAL:
@@ -824,10 +826,10 @@
else:
tick = event.xdata
self.ParentWindow.ChangeRange(int(-event.step) / 3, tick)
-
+
# Vetoing event to prevent parent panel to be scrolled
self.ParentWindow.VetoScrollEvent = True
-
+
def OnLeftDClick(self, event):
"""
Function called when a left mouse button is double clicked
@@ -841,17 +843,17 @@
self.ParentWindow.SetCursorTick(self.StartCursorTick)
# Toggle to text Viewer(s)
self.ParentWindow.ToggleViewerType(self)
-
+
else:
event.Skip()
-
+
# Cursor tick move for each arrow key
KEY_CURSOR_INCREMENT = {
wx.WXK_LEFT: -1,
wx.WXK_RIGHT: 1,
wx.WXK_UP: 10,
wx.WXK_DOWN: -10}
-
+
def OnKeyDown(self, event):
"""
Function called when key is pressed
@@ -863,7 +865,7 @@
if move is not None:
self.ParentWindow.MoveCursorTick(move)
event.Skip()
-
+
def OnLeave(self, event):
"""
Function called when mouse leave Viewer
@@ -876,7 +878,7 @@
DebugVariableViewer.OnLeave(self, event)
else:
event.Skip()
-
+
def GetCanvasMinSize(self):
"""
Return the minimum size of Viewer so that all items label can be
@@ -885,10 +887,10 @@
"""
# The minimum height take in account the height of all items, padding
# inside figure and border around figure
- return wx.Size(200,
- CANVAS_BORDER[0] + CANVAS_BORDER[1] +
- 2 * CANVAS_PADDING + VALUE_LABEL_HEIGHT * len(self.Items))
-
+ return wx.Size(200,
+ CANVAS_BORDER[0] + CANVAS_BORDER[1] +
+ 2 * CANVAS_PADDING + VALUE_LABEL_HEIGHT * len(self.Items))
+
def SetCanvasHeight(self, height):
"""
Set Viewer size checking that it respects Viewer minimum size
@@ -899,7 +901,7 @@
self.SetMinSize(wx.Size(min_width, height))
self.RefreshLabelsPosition(height)
self.ParentWindow.RefreshGraphicsSizer()
-
+
def GetAxesBoundingBox(self, parent_coordinate=False):
"""
Return figure bounding box in wx coordinate
@@ -911,15 +913,15 @@
ax, ay, aw, ah = self.figure.gca().get_position().bounds
bbox = wx.Rect(ax * width, height - (ay + ah) * height - 1,
aw * width + 2, ah * height + 1)
-
+
# If parent_coordinate, add Viewer position in parent
if parent_coordinate:
xw, yw = self.GetPosition()
bbox.x += xw
bbox.y += yw
-
+
return bbox
-
+
def RefreshHighlight(self, x, y):
"""
Refresh Viewer highlight according to mouse position
@@ -927,7 +929,7 @@
@param y: Y coordinate of mouse pointer
"""
width, height = self.GetSize()
-
+
# Mouse is over Viewer figure and graph is not 3D
bbox = self.GetAxesBoundingBox()
if bbox.InsideXY(x, y) and not self.Is3DCanvas():
@@ -935,28 +937,28 @@
# Mouse is over Viewer left part of figure
if rect.InsideXY(x, y):
self.SetHighlight(HIGHLIGHT_LEFT)
-
+
# Mouse is over Viewer right part of figure
else:
self.SetHighlight(HIGHLIGHT_RIGHT)
-
+
# Mouse is over upper part of Viewer
elif y < height / 2:
# Viewer is upper one in Debug Variable Panel, show highlight
if self.ParentWindow.IsViewerFirst(self):
self.SetHighlight(HIGHLIGHT_BEFORE)
-
+
# Viewer is not the upper one, show highlight in previous one
# It prevents highlight to move when mouse leave one Viewer to
# another
else:
self.SetHighlight(HIGHLIGHT_NONE)
self.ParentWindow.HighlightPreviousViewer(self)
-
+
# Mouse is over lower part of Viewer
else:
self.SetHighlight(HIGHLIGHT_AFTER)
-
+
def OnAxesMotion(self, event):
"""
Function overriding default function called when mouse is dragged for
@@ -969,13 +971,14 @@
if current_time - self.LastMotionTime > REFRESH_PERIOD:
self.LastMotionTime = current_time
Axes3D._on_move(self.Axes, event)
-
+
def GetAddTextFunction(self):
"""
Return function for adding text in figure according to graph type
@return: Function adding text to figure
"""
text_func = (self.Axes.text2D if self.Is3DCanvas() else self.Axes.text)
+
def AddText(*args, **kwargs):
args = [0, 0, ""]
kwargs["transform"] = self.Axes.transAxes
@@ -984,61 +987,61 @@
def SetAxesColor(self, color):
if LooseVersion(matplotlib.__version__) >= LooseVersion("1.5.0"):
- self.Axes.set_prop_cycle(cycler('color',color))
+ self.Axes.set_prop_cycle(cycler('color', color))
else:
self.Axes.set_color_cycle(color)
-
+
def ResetGraphics(self):
"""
Reset figure and graphical elements displayed in it
- Called any time list of items or graph type change
+ Called any time list of items or graph type change
"""
# Clear figure from any axes defined
self.Figure.clear()
-
+
# Add 3D projection if graph is in 3D
if self.Is3DCanvas():
self.Axes = self.Figure.gca(projection='3d')
self.SetAxesColor(['b'])
-
- # Override function to prevent too much refresh when graph is
+
+ # Override function to prevent too much refresh when graph is
# rotated
self.LastMotionTime = gettime()
setattr(self.Axes, "_on_move", self.OnAxesMotion)
-
+
# Init graph mouse event so that graph can be rotated
self.Axes.mouse_init()
-
+
# Set size of Z axis labels
self.Axes.tick_params(axis='z', labelsize='small')
-
+
else:
self.Axes = self.Figure.gca()
self.SetAxesColor(COLOR_CYCLE)
-
+
# Set size of X and Y axis labels
self.Axes.tick_params(axis='x', labelsize='small')
self.Axes.tick_params(axis='y', labelsize='small')
-
+
# Init variables storing graphical elements added to figure
- self.Plots = [] # List of curves
- self.VLine = None # Vertical line for cursor
- self.HLine = None # Horizontal line for cursor (only orthogonal 2D)
- self.AxesLabels = [] # List of items variable path text label
- self.Labels = [] # List of items text label
-
- # Get function to add a text in figure according to graph type
+ self.Plots = [] # List of curves
+ self.VLine = None # Vertical line for cursor
+ self.HLine = None # Horizontal line for cursor (only orthogonal 2D)
+ self.AxesLabels = [] # List of items variable path text label
+ self.Labels = [] # List of items text label
+
+ # Get function to add a text in figure according to graph type
add_text_func = self.GetAddTextFunction()
-
+
# Graph type is parallel or orthogonal in 3D
if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas():
num_item = len(self.Items)
for idx in xrange(num_item):
-
+
# Get color from color cycle (black if only one item)
- color = ('k' if num_item == 1
- else COLOR_CYCLE[idx % len(COLOR_CYCLE)])
-
+ color = ('k' if num_item == 1 else
+ COLOR_CYCLE[idx % len(COLOR_CYCLE)])
+
# In 3D graph items variable label are not displayed as text
# in figure, but as axis title
if not self.Is3DCanvas():
@@ -1046,12 +1049,12 @@
self.AxesLabels.append(
add_text_func(size='small', color=color,
verticalalignment='top'))
-
+
# Items variable labels are in figure lower right corner
self.Labels.append(
- add_text_func(size='large', color=color,
+ add_text_func(size='large', color=color,
horizontalalignment='right'))
-
+
# Graph type is orthogonal in 2D
else:
# X coordinate labels are in figure lower side
@@ -1059,7 +1062,7 @@
self.Labels.append(
add_text_func(size='large',
horizontalalignment='right'))
-
+
# Y coordinate labels are vertical and in figure left side
self.AxesLabels.append(
add_text_func(size='small', rotation='vertical',
@@ -1067,11 +1070,11 @@
self.Labels.append(
add_text_func(size='large', rotation='vertical',
verticalalignment='top'))
-
+
# Refresh position of labels according to Viewer size
width, height = self.GetSize()
self.RefreshLabelsPosition(height)
-
+
def RefreshLabelsPosition(self, height):
"""
Function called when mouse leave Viewer
@@ -1083,34 +1086,34 @@
# expressed border and text position in pixel on screen and apply the
# ratio calculated hereafter to get border and text position in
# matplotlib coordinate
- canvas_ratio = 1. / height # Divide by canvas height in pixel
+ canvas_ratio = 1. / height # Divide by canvas height in pixel
graph_ratio = 1. / (
(1.0 - (CANVAS_BORDER[0] + CANVAS_BORDER[1]) * canvas_ratio)
- * height) # Divide by figure height in pixel
-
+ * height) # Divide by figure height in pixel
+
# Update position of figure (keeping up and bottom border the same
# size)
self.Figure.subplotpars.update(
- top= 1.0 - CANVAS_BORDER[1] * canvas_ratio,
- bottom= CANVAS_BORDER[0] * canvas_ratio)
-
+ top=1.0 - CANVAS_BORDER[1] * canvas_ratio,
+ bottom=CANVAS_BORDER[0] * canvas_ratio)
+
# Update position of items labels
if self.GraphType == GRAPH_PARALLEL or self.Is3DCanvas():
num_item = len(self.Items)
for idx in xrange(num_item):
-
+
# In 3D graph items variable label are not displayed
if not self.Is3DCanvas():
# Items variable labels are in figure upper left corner
self.AxesLabels[idx].set_position(
- (0.05,
- 1.0 - (CANVAS_PADDING +
+ (0.05,
+ 1.0 - (CANVAS_PADDING +
AXES_LABEL_HEIGHT * idx) * graph_ratio))
-
+
# Items variable labels are in figure lower right corner
self.Labels[idx].set_position(
- (0.95,
- CANVAS_PADDING * graph_ratio +
+ (0.95,
+ CANVAS_PADDING * graph_ratio +
(num_item - idx - 1) * VALUE_LABEL_HEIGHT * graph_ratio))
else:
# X coordinate labels are in figure lower side
@@ -1118,16 +1121,16 @@
(0.1, CANVAS_PADDING * graph_ratio))
self.Labels[0].set_position(
(0.95, CANVAS_PADDING * graph_ratio))
-
+
# Y coordinate labels are vertical and in figure left side
self.AxesLabels[1].set_position(
(0.05, 2 * CANVAS_PADDING * graph_ratio))
self.Labels[1].set_position(
(0.05, 1.0 - CANVAS_PADDING * graph_ratio))
-
+
# Update subplots
self.Figure.subplots_adjust()
-
+
def RefreshViewer(self, refresh_graphics=True):
"""
Function called to refresh displayed by matplotlib canvas
@@ -1138,55 +1141,55 @@
if refresh_graphics:
# Get tick range of values to display
start_tick, end_tick = self.ParentWindow.GetRange()
-
+
# Graph is parallel
- if self.GraphType == GRAPH_PARALLEL:
+ if self.GraphType == GRAPH_PARALLEL:
# Init list of data range for each variable displayed
ranges = []
-
+
# Get data and range for each variable displayed
for idx, item in enumerate(self.Items):
data, min_value, max_value = item.GetDataAndValueRange(
start_tick, end_tick, not self.ZoomFit)
-
+
# Check that data is not empty
if data is not None:
# Add variable range to list of variable data range
ranges.append((min_value, max_value))
-
+
# Add plot to canvas if not yet created
if len(self.Plots) <= idx:
self.Plots.append(
self.Axes.plot(data[:, 0], data[:, 1])[0])
-
+
# Set data to already created plot in canvas
else:
self.Plots[idx].set_data(data[:, 0], data[:, 1])
-
+
# Get X and Y axis ranges
x_min, x_max = start_tick, end_tick
y_min, y_max = merge_ranges(ranges)
-
+
# Display cursor in canvas if a cursor tick is defined and it is
# include in values tick range
- if (self.CursorTick is not None and
- start_tick <= self.CursorTick <= end_tick):
-
+ if self.CursorTick is not None and \
+ start_tick <= self.CursorTick <= end_tick:
+
# Define a vertical line to display cursor position if no
# line is already defined
if self.VLine is None:
- self.VLine = self.Axes.axvline(self.CursorTick,
+ self.VLine = self.Axes.axvline(self.CursorTick,
color=CURSOR_COLOR)
-
+
# Set value of vertical line if already defined
else:
self.VLine.set_xdata((self.CursorTick, self.CursorTick))
self.VLine.set_visible(True)
-
+
# Hide vertical line if cursor tick is not defined or reset
elif self.VLine is not None:
self.VLine.set_visible(False)
-
+
# Graph is orthogonal
else:
# Update tick range, removing ticks that don't have a value for
@@ -1194,76 +1197,75 @@
start_tick = max(start_tick, self.GetItemsMinCommonTick())
end_tick = max(end_tick, start_tick)
items = self.ItemsDict.values()
-
+
# Get data and range for first variable (X coordinate)
x_data, x_min, x_max = items[0].GetDataAndValueRange(
start_tick, end_tick, not self.ZoomFit)
# Get data and range for second variable (Y coordinate)
y_data, y_min, y_max = items[1].GetDataAndValueRange(
start_tick, end_tick, not self.ZoomFit)
-
+
# Normalize X and Y coordinates value range
x_min, x_max = merge_ranges([(x_min, x_max)])
y_min, y_max = merge_ranges([(y_min, y_max)])
-
- # Get X and Y coordinates for cursor if cursor tick is defined
+
+ # Get X and Y coordinates for cursor if cursor tick is defined
if self.CursorTick is not None:
x_cursor, x_forced = items[0].GetValue(
self.CursorTick, raw=True)
y_cursor, y_forced = items[1].GetValue(
self.CursorTick, raw=True)
-
+
# Get common data length so that each value has an x and y
# coordinate
length = (min(len(x_data), len(y_data))
if x_data is not None and y_data is not None
else 0)
-
- # Graph is orthogonal 2D
+
+ # Graph is orthogonal 2D
if len(self.Items) < 3:
-
+
# Check that x and y data are not empty
if x_data is not None and y_data is not None:
-
+
# Add plot to canvas if not yet created
if len(self.Plots) == 0:
self.Plots.append(
- self.Axes.plot(x_data[:, 1][:length],
+ self.Axes.plot(x_data[:, 1][:length],
y_data[:, 1][:length])[0])
-
+
# Set data to already created plot in canvas
else:
self.Plots[0].set_data(
- x_data[:, 1][:length],
+ x_data[:, 1][:length],
y_data[:, 1][:length])
-
+
# Display cursor in canvas if a cursor tick is defined and it is
# include in values tick range
- if (self.CursorTick is not None and
- start_tick <= self.CursorTick <= end_tick):
-
+ if self.CursorTick is not None and \
+ start_tick <= self.CursorTick <= end_tick:
+
# Define a vertical line to display cursor x coordinate
# if no line is already defined
if self.VLine is None:
- self.VLine = self.Axes.axvline(x_cursor,
+ self.VLine = self.Axes.axvline(x_cursor,
color=CURSOR_COLOR)
# Set value of vertical line if already defined
else:
self.VLine.set_xdata((x_cursor, x_cursor))
-
-
+
# Define a horizontal line to display cursor y
# coordinate if no line is already defined
if self.HLine is None:
- self.HLine = self.Axes.axhline(y_cursor,
+ self.HLine = self.Axes.axhline(y_cursor,
color=CURSOR_COLOR)
# Set value of horizontal line if already defined
else:
self.HLine.set_ydata((y_cursor, y_cursor))
-
+
self.VLine.set_visible(True)
self.HLine.set_visible(True)
-
+
# Hide vertical and horizontal line if cursor tick is not
# defined or reset
else:
@@ -1271,42 +1273,43 @@
self.VLine.set_visible(False)
if self.HLine is not None:
self.HLine.set_visible(False)
-
+
# Graph is orthogonal 3D
else:
# Remove all plots already defined in 3D canvas
while len(self.Axes.lines) > 0:
self.Axes.lines.pop()
-
+
# Get data and range for third variable (Z coordinate)
z_data, z_min, z_max = items[2].GetDataAndValueRange(
start_tick, end_tick, not self.ZoomFit)
-
+
# Normalize Z coordinate value range
z_min, z_max = merge_ranges([(z_min, z_max)])
-
+
# Check that x, y and z data are not empty
- if (x_data is not None and y_data is not None and
- z_data is not None):
-
+ if x_data is not None and \
+ y_data is not None and \
+ z_data is not None:
+
# Get common data length so that each value has an x, y
# and z coordinate
length = min(length, len(z_data))
-
+
# Add plot to canvas
self.Axes.plot(x_data[:, 1][:length],
y_data[:, 1][:length],
- zs = z_data[:, 1][:length])
-
+ zs=z_data[:, 1][:length])
+
# Display cursor in canvas if a cursor tick is defined and
# it is include in values tick range
- if (self.CursorTick is not None and
- start_tick <= self.CursorTick <= end_tick):
-
+ if self.CursorTick is not None and \
+ start_tick <= self.CursorTick <= end_tick:
+
# Get Z coordinate for cursor
z_cursor, z_forced = items[2].GetValue(
self.CursorTick, raw=True)
-
+
# Add 3 lines parallel to x, y and z axis to display
# cursor position in 3D
for kwargs in [{"xs": numpy.array([x_min, x_max])},
@@ -1319,14 +1322,14 @@
kwargs.setdefault(param, value)
kwargs["color"] = CURSOR_COLOR
self.Axes.plot(**kwargs)
-
+
# Set Z axis limits
self.Axes.set_zlim(z_min, z_max)
-
+
# Set X and Y axis limits
self.Axes.set_xlim(x_min, x_max)
self.Axes.set_ylim(y_min, y_max)
-
+
# Get value and forced flag for each variable displayed in graph
# If cursor tick is not defined get value and flag of last received
# or get value and flag of variable at cursor tick
@@ -1335,34 +1338,34 @@
if self.CursorTick is not None
else (item.GetValue(), item.IsForced()))
for item in self.Items])
-
+
# Get path of each variable displayed simplified using panel variable
# name mask
- labels = [item.GetVariable(self.ParentWindow.GetVariableNameMask())
+ labels = [item.GetVariable(self.ParentWindow.GetVariableNameMask())
for item in self.Items]
-
- # Get style for each variable according to
+
+ # Get style for each variable according to
styles = map(lambda x: {True: 'italic', False: 'normal'}[x], forced)
-
+
# Graph is orthogonal 3D, set variables path as 3D axis label
if self.Is3DCanvas():
- for idx, label_func in enumerate([self.Axes.set_xlabel,
+ for idx, label_func in enumerate([self.Axes.set_xlabel,
self.Axes.set_ylabel,
self.Axes.set_zlabel]):
label_func(labels[idx], fontdict={'size': 'small',
'color': COLOR_CYCLE[idx]})
-
+
# Graph is not orthogonal 3D, set variables path in axes labels
else:
for label, text in zip(self.AxesLabels, labels):
label.set_text(text)
-
+
# Set value label text and style according to value and forced flag for
# each variable displayed
for label, value, style in zip(self.Labels, values, styles):
label.set_text(value)
label.set_style(style)
-
+
# Refresh figure
self.draw()
@@ -1372,51 +1375,49 @@
"""
# Render figure using agg
FigureCanvasAgg.draw(self)
-
+
# Get bitmap of figure rendered
self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
- if wx.VERSION < (3, 0, 0):
+ if wx.VERSION < (3, 0, 0):
self.bitmap.UseAlpha()
-
+
# Create DC for rendering graphics in bitmap
destDC = wx.MemoryDC()
destDC.SelectObject(self.bitmap)
-
+
# Get Graphics Context for DC, for anti-aliased and transparent
# rendering
destGC = wx.GCDC(destDC)
-
+
destGC.BeginDrawing()
-
+
# Get canvas size and figure bounding box in canvas
width, height = self.GetSize()
bbox = self.GetAxesBoundingBox()
-
+
# If highlight to display is resize, draw thick grey line at bottom
- # side of canvas
+ # side of canvas
if self.Highlight == HIGHLIGHT_RESIZE:
destGC.SetPen(HIGHLIGHT_RESIZE_PEN)
destGC.SetBrush(HIGHLIGHT_RESIZE_BRUSH)
destGC.DrawRectangle(0, height - 5, width, 5)
-
+
# If highlight to display is merging graph, draw 50% transparent blue
# rectangle on left or right part of figure depending on highlight type
elif self.Highlight in [HIGHLIGHT_LEFT, HIGHLIGHT_RIGHT]:
destGC.SetPen(HIGHLIGHT_DROP_PEN)
destGC.SetBrush(HIGHLIGHT_DROP_BRUSH)
-
- x_offset = (bbox.width / 2
+
+ x_offset = (bbox.width / 2
if self.Highlight == HIGHLIGHT_RIGHT
else 0)
- destGC.DrawRectangle(bbox.x + x_offset, bbox.y,
+ destGC.DrawRectangle(bbox.x + x_offset, bbox.y,
bbox.width / 2, bbox.height)
-
+
# Draw other Viewer common elements
self.DrawCommonElements(destGC, self.GetButtons())
-
+
destGC.EndDrawing()
-
+
self._isDrawn = True
self.gui_repaint(drawDC=drawDC)
-
-
--- a/controls/DebugVariablePanel/DebugVariableItem.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/DebugVariableItem.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,24 +27,24 @@
from graphics.DebugDataConsumer import DebugDataConsumer, TYPE_TRANSLATOR
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Constant for calculate CRC for string variables
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
STRING_CRC_SIZE = 8
STRING_CRC_MASK = 2 ** STRING_CRC_SIZE - 1
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Item Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements an element that consumes debug values for PLC variable and
-stores received values for displaying them in graphic panel or table
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableItem(DebugDataConsumer):
-
+ """
+ Class that implements an element that consumes debug values for PLC variable and
+ stores received values for displaying them in graphic panel or table
+ """
+
def __init__(self, parent, variable, store_data=False):
"""
Constructor
@@ -52,24 +52,24 @@
@param variable: Path of variable to debug
"""
DebugDataConsumer.__init__(self)
-
+
self.Parent = parent
self.Variable = variable
self.StoreData = store_data
-
+
# Get Variable data type
self.RefreshVariableType()
-
+
def __del__(self):
"""
Destructor
"""
# Reset reference to debug variable panel
self.Parent = None
-
+
def SetVariable(self, variable):
"""
- Set path of variable
+ Set path of variable
@param variable: Path of variable to debug
"""
if self.Parent is not None and self.Variable != variable:
@@ -77,46 +77,46 @@
self.Variable = variable
# Get Variable data type
self.RefreshVariableType()
-
+
# Refresh debug variable panel
self.Parent.RefreshView()
-
+
def GetVariable(self, mask=None):
"""
- Return path of variable
+ Return path of variable
@param mask: Mask to apply to variable path [var_name, '*',...]
@return: String containing masked variable path
"""
# Apply mask to variable name
if mask is not None:
# '#' correspond to parts that are different between all items
-
+
# Extract variable path parts
parts = self.Variable.split('.')
# Adjust mask size to size of variable path
mask = mask + ['*'] * max(0, len(parts) - len(mask))
-
+
# Store previous mask
last = None
# Init masked variable path
variable = ""
-
+
for m, p in zip(mask, parts):
# Part is not masked, add part prefixed with '.' is previous
# wasn't masked
if m == '*':
variable += ('.' if last == '*' else '') + p
-
+
# Part is mask, add '..' if first or previous wasn't masked
elif last is None or last == '*':
variable += '..'
-
+
last = m
-
+
return variable
-
+
return self.Variable
-
+
def RefreshVariableType(self):
"""
Get and store variable data type
@@ -124,14 +124,14 @@
self.VariableType = self.Parent.GetDataType(self.Variable)
# Reset data stored
self.ResetData()
-
+
def GetVariableType(self):
"""
Return variable data type
@return: Variable data type
"""
return self.VariableType
-
+
def GetData(self, start_tick=None, end_tick=None):
"""
Return data stored contained in given range
@@ -142,7 +142,7 @@
# Return immediately if data empty or none
if self.Data is None or len(self.Data) == 0:
return self.Data
-
+
# Find nearest data outside given range indexes
start_idx = (self.GetNearestData(start_tick, -1)
if start_tick is not None
@@ -150,28 +150,27 @@
end_idx = (self.GetNearestData(end_tick, 1)
if end_tick is not None
else len(self.Data))
-
+
# Return data between indexes
return self.Data[start_idx:end_idx]
-
+
def GetRawValue(self, index):
"""
Return raw value at given index for string variables
@param index: Variable value index
@return: Variable data type
"""
- if (self.VariableType in ["STRING", "WSTRING"] and
- index < len(self.RawData)):
+ if self.VariableType in ["STRING", "WSTRING"] and index < len(self.RawData):
return self.RawData[index][0]
return ""
-
+
def GetValueRange(self):
"""
Return variable value range
@return: (minimum_value, maximum_value)
"""
return self.MinValue, self.MaxValue
-
+
def GetDataAndValueRange(self, start_tick, end_tick, full_range=True):
"""
Return variable data and value range for a given tick range
@@ -179,16 +178,16 @@
@param end_tick: end tick of given range (default None, last data)
@param full_range: Value range is calculated on whole data (False: only
calculated on data in given range)
- @return: (numpy.array([(tick, value, forced),...]),
+ @return: (numpy.array([(tick, value, forced),...]),
min_value, max_value)
"""
# Get data in given tick range
data = self.GetData(start_tick, end_tick)
-
+
# Value range is calculated on whole data
if full_range:
return data, self.MinValue, self.MaxValue
-
+
# Check that data in given range is not empty
values = data[:, 1]
if len(values) > 0:
@@ -196,10 +195,10 @@
return (data,
data[numpy.argmin(values), 1],
data[numpy.argmax(values), 1])
-
+
# Return default values
return data, None, None
-
+
def ResetData(self):
"""
Reset data stored when store data option enabled
@@ -207,31 +206,31 @@
if self.StoreData and self.IsNumVariable():
# Init table storing data
self.Data = numpy.array([]).reshape(0, 3)
-
+
# Init table storing raw data if variable is strin
self.RawData = ([]
if self.VariableType in ["STRING", "WSTRING"]
else None)
-
+
# Init Value range variables
self.MinValue = None
self.MaxValue = None
-
+
else:
self.Data = None
-
+
# Init variable value
self.Value = ""
-
+
def IsNumVariable(self):
"""
Return if variable data type is numeric. String variables are
considered as numeric (string CRC)
@return: True if data type is numeric
"""
- return (self.Parent.IsNumType(self.VariableType) or
+ return (self.Parent.IsNumType(self.VariableType) or
self.VariableType in ["STRING", "WSTRING"])
-
+
def NewValues(self, ticks, values):
"""
Function called by debug thread when a new debug value is available
@@ -240,24 +239,24 @@
@param forced: Forced flag, True if value is forced (default: False)
"""
DebugDataConsumer.NewValues(self, ticks[-1], values[-1], raw=None)
-
+
if self.Data is not None:
-
+
if self.VariableType in ["STRING", "WSTRING"]:
last_raw_data = (self.RawData[-1]
if len(self.RawData) > 0 else None)
last_raw_data_idx = len(self.RawData) - 1
-
+
data_values = []
for tick, (value, forced) in zip(ticks, values):
# Translate forced flag to float for storing in Data table
forced_value = float(forced)
-
+
# String data value is CRC
num_value = (binascii.crc32(value) & STRING_CRC_MASK
if self.VariableType in ["STRING", "WSTRING"]
else float(value))
-
+
# Update variable range values
self.MinValue = (min(self.MinValue, num_value)
if self.MinValue is not None
@@ -265,10 +264,10 @@
self.MaxValue = (max(self.MaxValue, num_value)
if self.MaxValue is not None
else num_value)
-
+
# In the case of string variables, we store raw string value and
# forced flag in raw data table. Only changes in this two values
- # are stored. Index to the corresponding raw value is stored in
+ # are stored. Index to the corresponding raw value is stored in
# data third column
if self.VariableType in ["STRING", "WSTRING"]:
raw_data = (value, forced_value)
@@ -277,20 +276,20 @@
last_raw_data = raw_data
self.RawData.append(raw_data)
extra_value = last_raw_data_idx
-
+
# In other case, data third column is forced flag
else:
extra_value = forced_value
-
+
data_values.append(
[float(tick), num_value, extra_value])
-
+
# Add New data to stored data table
self.Data = numpy.append(self.Data, data_values, axis=0)
-
+
# Signal to debug variable panel to refresh
self.Parent.HasNewData = True
-
+
def SetForced(self, forced):
"""
Update Forced flag
@@ -299,29 +298,27 @@
# Store forced flag
if self.Forced != forced:
self.Forced = forced
-
+
# Signal to debug variable panel to refresh
self.Parent.HasNewData = True
-
+
def SetValue(self, value):
"""
Update value.
@param value: New value
"""
# Remove quote and double quote surrounding string value to get raw value
- if (self.VariableType == "STRING" and
- value.startswith("'") and value.endswith("'") or
- self.VariableType == "WSTRING" and
- value.startswith('"') and value.endswith('"')):
+ if self.VariableType == "STRING" and value.startswith("'") and value.endswith("'") or \
+ self.VariableType == "WSTRING" and value.startswith('"') and value.endswith('"'):
value = value[1:-1]
-
+
# Store variable value
if self.Value != value:
self.Value = value
-
+
# Signal to debug variable panel to refresh
self.Parent.HasNewData = True
-
+
def GetValue(self, tick=None, raw=False):
"""
Return current value or value and forced flag for tick given
@@ -329,26 +326,27 @@
"""
# If tick given and stored data option enabled
if tick is not None and self.Data is not None:
-
+
# Return current value and forced flag if data empty
if len(self.Data) == 0:
return self.Value, self.IsForced()
-
+
# Get index of nearest data from tick given
idx = self.GetNearestData(tick, 0)
-
+
# Get value and forced flag at given index
- value, forced = self.RawData[int(self.Data[idx, 2])] \
- if self.VariableType in ["STRING", "WSTRING"] \
- else self.Data[idx, 1:3]
-
+ value, forced = \
+ self.RawData[int(self.Data[idx, 2])] \
+ if self.VariableType in ["STRING", "WSTRING"] \
+ else self.Data[idx, 1:3]
+
# Get raw value if asked
if not raw:
value = TYPE_TRANSLATOR.get(
self.VariableType, str)(value)
-
+
return value, forced
-
+
# Return raw value if asked
if not raw and self.VariableType in ["STRING", "WSTRING"]:
return TYPE_TRANSLATOR.get(
@@ -368,16 +366,16 @@
# Return immediately if data is empty
if self.Data is None:
return None
-
+
# Extract data ticks
ticks = self.Data[:, 0]
-
+
# Get nearest data from tick
idx = numpy.argmin(abs(ticks - tick))
-
+
# Adjust data index according to constraint
- if (adjust < 0 and ticks[idx] > tick and idx > 0 or
- adjust > 0 and ticks[idx] < tick and idx < len(ticks)):
+ if adjust < 0 and ticks[idx] > tick and idx > 0 or \
+ adjust > 0 and ticks[idx] < tick and idx < len(ticks):
idx += adjust
-
+
return idx
--- a/controls/DebugVariablePanel/DebugVariablePanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/DebugVariablePanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,10 +30,11 @@
import wx.lib.buttons
import matplotlib
-matplotlib.use('WX')
+matplotlib.use('WX') # noqa
import matplotlib.pyplot
from matplotlib.backends.backend_wxagg import _convert_agg_to_wx_bitmap
+
from editors.DebugViewer import DebugViewer
from util.BitmapLibrary import GetBitmap
@@ -41,11 +42,12 @@
from DebugVariableTextViewer import DebugVariableTextViewer
from DebugVariableGraphicViewer import *
-MILLISECOND = 1000000 # Number of nanosecond in a millisecond
-SECOND = 1000 * MILLISECOND # Number of nanosecond in a second
-MINUTE = 60 * SECOND # Number of nanosecond in a minute
-HOUR = 60 * MINUTE # Number of nanosecond in a hour
-DAY = 24 * HOUR # Number of nanosecond in a day
+
+MILLISECOND = 1000000 # Number of nanosecond in a millisecond
+SECOND = 1000 * MILLISECOND # Number of nanosecond in a second
+MINUTE = 60 * SECOND # Number of nanosecond in a minute
+HOUR = 60 * MINUTE # Number of nanosecond in a hour
+DAY = 24 * HOUR # Number of nanosecond in a day
# List of values possible for graph range
# Format is [(time_in_plain_text, value_in_nanosecond),...]
@@ -58,33 +60,35 @@
# Scrollbar increment in pixel
SCROLLBAR_UNIT = 10
+
def compute_mask(x, y):
return [(xp if xp == yp else "*")
for xp, yp in zip(x, y)]
+
def NextTick(variables):
next_tick = None
for item, data in variables:
if len(data) == 0:
continue
-
+
next_tick = (data[0][0]
if next_tick is None
else min(next_tick, data[0][0]))
-
+
return next_tick
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Graphic Panel Drop Target
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a custom drop target class for Debug Variable Graphic
-Panel
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableDropTarget(wx.TextDropTarget):
-
+ """
+ Class that implements a custom drop target class for Debug Variable Graphic
+ Panel
+ """
+
def __init__(self, window):
"""
Constructor
@@ -92,14 +96,14 @@
"""
wx.TextDropTarget.__init__(self)
self.ParentWindow = window
-
+
def __del__(self):
"""
Destructor
"""
# Remove reference to Debug Variable Panel
self.ParentWindow = None
-
+
def OnDragOver(self, x, y, d):
"""
Function called when mouse is dragged over Drop Target
@@ -107,10 +111,10 @@
@param y: Y coordinate of mouse pointer
@param d: Suggested default for return value
"""
- # Signal Debug Variable Panel to refresh highlight giving mouse position
+ # Signal Debug Variable Panel to refresh highlight giving mouse position
self.ParentWindow.RefreshHighlight(x, y)
return wx.TextDropTarget.OnDragOver(self, x, y, d)
-
+
def OnDropText(self, x, y, data):
"""
Function called when mouse is released in Drop Target
@@ -120,34 +124,34 @@
"""
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
-
+
message = None
-
+
# Check that data is valid regarding DebugVariablePanel
try:
values = eval(data)
if not isinstance(values, TupleType):
raise ValueError
- except:
- message = _("Invalid value \"%s\" for debug variable")%data
+ except Exception:
+ message = _("Invalid value \"%s\" for debug variable") % data
values = None
-
+
# Display message if data is invalid
if message is not None:
wx.CallAfter(self.ShowMessage, message)
-
+
# Data contain a reference to a variable to debug
elif values[1] == "debug":
-
+
# Drag'n Drop is an internal is an internal move inside Debug
- # Variable Panel
+ # Variable Panel
if len(values) > 2 and values[2] == "move":
self.ParentWindow.MoveValue(values[0])
-
+
# Drag'n Drop was initiated by another control of Beremiz
else:
self.ParentWindow.InsertValue(values[0], force=True)
-
+
def OnLeave(self):
"""
Function called when mouse is leave Drop Target
@@ -155,30 +159,25 @@
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
return wx.TextDropTarget.OnLeave(self)
-
+
def ShowMessage(self, message):
"""
Show error message in Error Dialog
@param message: Error message to display
"""
- dialog = wx.MessageDialog(self.ParentWindow,
- message,
- _("Error"),
- wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self.ParentWindow,
+ message,
+ _("Error"),
+ wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
-#-------------------------------------------------------------------------------
-# Debug Variable Graphic Panel Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a Viewer that display variable values as a graphs
-"""
-
class DebugVariablePanel(wx.Panel, DebugViewer):
-
+ """
+ Class that implements a Viewer that display variable values as a graphs
+ """
+
def __init__(self, parent, producer, window):
"""
Constructor
@@ -187,49 +186,50 @@
consumers
@param window: Reference to Beremiz frame
"""
- wx.Panel.__init__(self, parent, style=wx.SP_3D|wx.TAB_TRAVERSAL)
-
+ wx.Panel.__init__(self, parent, style=wx.SP_3D | wx.TAB_TRAVERSAL)
+
# Save Reference to Beremiz frame
self.ParentWindow = window
-
+
# Variable storing flag indicating that variable displayed in table
# received new value and then table need to be refreshed
self.HasNewData = False
-
+
# Variable storing flag indicating that refresh has been forced, and
# that next time refresh is possible, it will be done even if no new
# data is available
self.Force = False
-
+
self.SetBackgroundColour(wx.WHITE)
-
+
main_sizer = wx.BoxSizer(wx.VERTICAL)
-
- self.Ticks = numpy.array([]) # List of tick received
- self.StartTick = 0 # Tick starting range of data displayed
- self.Fixed = False # Flag that range of data is fixed
- self.CursorTick = None # Tick of cursor for displaying values
-
+
+ self.Ticks = numpy.array([]) # List of tick received
+ self.StartTick = 0 # Tick starting range of data displayed
+ self.Fixed = False # Flag that range of data is fixed
+ self.CursorTick = None # Tick of cursor for displaying values
+
self.DraggingAxesPanel = None
self.DraggingAxesBoundingBox = None
self.DraggingAxesMousePos = None
self.VetoScrollEvent = False
-
+
self.VariableNameMask = []
-
+
self.GraphicPanels = []
-
+
graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
- main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL)
-
+ main_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW | wx.ALL)
+
range_label = wx.StaticText(self, label=_('Range:'))
graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL)
-
+
self.CanvasRange = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnRangeChanged, self.CanvasRange)
- graphics_button_sizer.AddWindow(self.CanvasRange, 1,
- border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
-
+ graphics_button_sizer.AddWindow(self.CanvasRange, 1,
+ border=5,
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL)
+
self.CanvasRange.Clear()
default_range_idx = 0
for idx, (text, value) in enumerate(RANGE_VALUES):
@@ -237,62 +237,62 @@
if text == "1s":
default_range_idx = idx
self.CanvasRange.SetSelection(default_range_idx)
-
+
for name, bitmap, help in [
- ("CurrentButton", "current", _("Go to current value")),
- ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]:
- button = wx.lib.buttons.GenBitmapButton(self,
- bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
+ ("CurrentButton", "current", _("Go to current value")),
+ ("ExportGraphButton", "export_graph", _("Export graph values to clipboard"))]:
+ button = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button)
graphics_button_sizer.AddWindow(button, border=5, flag=wx.LEFT)
-
- self.CanvasPosition = wx.ScrollBar(self,
- size=wx.Size(0, 16), style=wx.SB_HORIZONTAL)
- self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK,
- self.OnPositionChanging, self.CanvasPosition)
- self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP,
- self.OnPositionChanging, self.CanvasPosition)
- self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN,
- self.OnPositionChanging, self.CanvasPosition)
- self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP,
- self.OnPositionChanging, self.CanvasPosition)
- self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN,
- self.OnPositionChanging, self.CanvasPosition)
- main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM)
-
+
+ self.CanvasPosition = wx.ScrollBar(
+ self, size=wx.Size(0, 16), style=wx.SB_HORIZONTAL)
+ self.CanvasPosition.Bind(wx.EVT_SCROLL_THUMBTRACK,
+ self.OnPositionChanging, self.CanvasPosition)
+ self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEUP,
+ self.OnPositionChanging, self.CanvasPosition)
+ self.CanvasPosition.Bind(wx.EVT_SCROLL_LINEDOWN,
+ self.OnPositionChanging, self.CanvasPosition)
+ self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP,
+ self.OnPositionChanging, self.CanvasPosition)
+ self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN,
+ self.OnPositionChanging, self.CanvasPosition)
+ main_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW | wx.LEFT | wx.RIGHT | wx.BOTTOM)
+
self.TickSizer = wx.BoxSizer(wx.HORIZONTAL)
- main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL|wx.GROW)
-
+ main_sizer.AddSizer(self.TickSizer, border=5, flag=wx.ALL | wx.GROW)
+
self.TickLabel = wx.StaticText(self)
self.TickSizer.AddWindow(self.TickLabel, border=5, flag=wx.RIGHT)
-
- self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY|wx.TE_CENTER|wx.NO_BORDER)
- self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT|wx.GROW)
-
+
+ self.MaskLabel = wx.TextCtrl(self, style=wx.TE_READONLY | wx.TE_CENTER | wx.NO_BORDER)
+ self.TickSizer.AddWindow(self.MaskLabel, 1, border=5, flag=wx.RIGHT | wx.GROW)
+
self.TickTimeLabel = wx.StaticText(self)
self.TickSizer.AddWindow(self.TickTimeLabel)
-
- self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL|wx.VSCROLL)
+
+ self.GraphicsWindow = wx.ScrolledWindow(self, style=wx.HSCROLL | wx.VSCROLL)
self.GraphicsWindow.SetBackgroundColour(wx.WHITE)
self.GraphicsWindow.SetDropTarget(DebugVariableDropTarget(self))
self.GraphicsWindow.Bind(wx.EVT_ERASE_BACKGROUND, self.OnGraphicsWindowEraseBackground)
self.GraphicsWindow.Bind(wx.EVT_PAINT, self.OnGraphicsWindowPaint)
self.GraphicsWindow.Bind(wx.EVT_SIZE, self.OnGraphicsWindowResize)
self.GraphicsWindow.Bind(wx.EVT_MOUSEWHEEL, self.OnGraphicsWindowMouseWheel)
-
+
main_sizer.AddWindow(self.GraphicsWindow, 1, flag=wx.GROW)
-
+
self.GraphicsSizer = wx.BoxSizer(wx.VERTICAL)
self.GraphicsWindow.SetSizer(self.GraphicsSizer)
-
+
DebugViewer.__init__(self, producer, True)
-
+
self.SetSizer(main_sizer)
self.SetTickTime()
-
+
def SetTickTime(self, ticktime=0):
"""
Set Ticktime for calculate data range according to time range selected
@@ -300,26 +300,26 @@
"""
# Save ticktime
self.Ticktime = ticktime
-
+
# Set ticktime to millisecond if undefined
if self.Ticktime == 0:
self.Ticktime = MILLISECOND
-
+
# Calculate range to apply to data
self.CurrentRange = RANGE_VALUES[
self.CanvasRange.GetSelection()][1] / self.Ticktime
-
+
def SetDataProducer(self, producer):
"""
Set Data Producer
@param producer: Data Producer
"""
DebugViewer.SetDataProducer(self, producer)
-
+
# Set ticktime if data producer is available
if self.DataProducer is not None:
self.SetTickTime(self.DataProducer.GetTicktime())
-
+
def RefreshNewData(self):
"""
Called to refresh Panel according to values received by variables
@@ -329,50 +329,50 @@
if self.HasNewData or self.Force:
self.HasNewData = False
self.RefreshView()
-
+
DebugViewer.RefreshNewData(self)
-
+
def NewDataAvailable(self, ticks):
"""
Called by DataProducer for each tick captured or by panel to refresh
graphs
@param tick: PLC tick captured
- All other parameters are passed to refresh function
+ All other parameters are passed to refresh function
"""
# If tick given
if ticks is not None:
tick = ticks[-1]
-
+
# Save tick as start tick for range if data is still empty
if len(self.Ticks) == 0:
self.StartTick = ticks[0]
-
+
# Add tick to list of ticks received
self.Ticks = numpy.append(self.Ticks, ticks)
-
+
# Update start tick for range if range follow ticks received
if not self.Fixed or tick < self.StartTick + self.CurrentRange:
self.StartTick = max(self.StartTick, tick - self.CurrentRange)
-
+
# Force refresh if graph is fixed because range of data received
# is too small to fill data range selected
if self.Fixed and \
self.Ticks[-1] - self.Ticks[0] < self.CurrentRange:
self.Force = True
-
+
self.HasNewData = False
self.RefreshView()
-
+
else:
DebugViewer.NewDataAvailable(self, ticks)
-
+
def ForceRefresh(self):
"""
Called to force refresh of graphs
"""
self.Force = True
wx.CallAfter(self.NewDataAvailable, None)
-
+
def SetCursorTick(self, cursor_tick):
"""
Set Cursor for displaying values of items at a tick given
@@ -381,37 +381,36 @@
# Save cursor tick
self.CursorTick = cursor_tick
self.Fixed = cursor_tick is not None
- self.UpdateCursorTick()
-
+ self.UpdateCursorTick()
+
def MoveCursorTick(self, move):
if self.CursorTick is not None:
- cursor_tick = max(self.Ticks[0],
- min(self.CursorTick + move,
- self.Ticks[-1]))
+ cursor_tick = max(self.Ticks[0],
+ min(self.CursorTick + move, self.Ticks[-1]))
cursor_tick_idx = numpy.argmin(numpy.abs(self.Ticks - cursor_tick))
if self.Ticks[cursor_tick_idx] == self.CursorTick:
- cursor_tick_idx = max(0,
- min(cursor_tick_idx + abs(move) / move,
- len(self.Ticks) - 1))
+ cursor_tick_idx = max(0,
+ min(cursor_tick_idx + abs(move) / move,
+ len(self.Ticks) - 1))
self.CursorTick = self.Ticks[cursor_tick_idx]
- self.StartTick = max(self.Ticks[
- numpy.argmin(numpy.abs(self.Ticks -
- self.CursorTick + self.CurrentRange))],
- min(self.StartTick, self.CursorTick))
+ self.StartTick = max(
+ self.Ticks[numpy.argmin(
+ numpy.abs(self.Ticks - self.CursorTick + self.CurrentRange))],
+ min(self.StartTick, self.CursorTick))
self.RefreshCanvasPosition()
- self.UpdateCursorTick()
-
+ self.UpdateCursorTick()
+
def ResetCursorTick(self):
self.CursorTick = None
self.Fixed = False
self.UpdateCursorTick()
-
+
def UpdateCursorTick(self):
for panel in self.GraphicPanels:
if isinstance(panel, DebugVariableGraphicViewer):
panel.SetCursorTick(self.CursorTick)
self.ForceRefresh()
-
+
def StartDragNDrop(self, panel, item, x_mouse, y_mouse, x_mouse_start, y_mouse_start):
if len(panel.GetItems()) > 1:
self.DraggingAxesPanel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL)
@@ -424,23 +423,23 @@
self.DraggingAxesPanel = panel
self.DraggingAxesBoundingBox = panel.GetAxesBoundingBox(parent_coordinate=True)
self.DraggingAxesMousePos = wx.Point(
- x_mouse_start - self.DraggingAxesBoundingBox.x,
+ x_mouse_start - self.DraggingAxesBoundingBox.x,
y_mouse_start - self.DraggingAxesBoundingBox.y)
self.MoveDragNDrop(x_mouse, y_mouse)
-
+
def MoveDragNDrop(self, x_mouse, y_mouse):
self.DraggingAxesBoundingBox.x = x_mouse - self.DraggingAxesMousePos.x
self.DraggingAxesBoundingBox.y = y_mouse - self.DraggingAxesMousePos.y
self.RefreshHighlight(x_mouse, y_mouse)
-
+
def RefreshHighlight(self, x_mouse, y_mouse):
for idx, panel in enumerate(self.GraphicPanels):
x, y = panel.GetPosition()
width, height = panel.GetSize()
rect = wx.Rect(x, y, width, height)
- if (rect.InsideXY(x_mouse, y_mouse) or
- idx == 0 and y_mouse < 0 or
- idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]):
+ if rect.InsideXY(x_mouse, y_mouse) or \
+ idx == 0 and y_mouse < 0 or \
+ idx == len(self.GraphicPanels) - 1 and y_mouse > panel.GetPosition()[1]:
panel.RefreshHighlight(x_mouse - x, y_mouse - y)
else:
panel.SetHighlight(HIGHLIGHT_NONE)
@@ -448,7 +447,7 @@
self.RefreshView()
else:
self.ForceRefresh()
-
+
def ResetHighlight(self):
for panel in self.GraphicPanels:
panel.SetHighlight(HIGHLIGHT_NONE)
@@ -456,10 +455,10 @@
self.RefreshView()
else:
self.ForceRefresh()
-
+
def IsDragging(self):
return self.DraggingAxesPanel is not None
-
+
def GetDraggingAxesClippingRegion(self, panel):
x, y = panel.GetPosition()
width, height = panel.GetSize()
@@ -468,12 +467,12 @@
bbox.x -= x
bbox.y -= y
return bbox
-
+
def GetDraggingAxesPosition(self, panel):
x, y = panel.GetPosition()
return wx.Point(self.DraggingAxesBoundingBox.x - x,
self.DraggingAxesBoundingBox.y - y)
-
+
def StopDragNDrop(self, variable, x_mouse, y_mouse):
if self.DraggingAxesPanel not in self.GraphicPanels:
self.DraggingAxesPanel.Destroy()
@@ -504,25 +503,25 @@
idx += 1
wx.CallAfter(self.MoveValue, variable, idx, True)
self.ForceRefresh()
- return
+ return
width, height = self.GraphicsWindow.GetVirtualSize()
rect = wx.Rect(0, 0, width, height)
if rect.InsideXY(x_mouse, y_mouse):
wx.CallAfter(self.MoveValue, variable, len(self.GraphicPanels), True)
self.ForceRefresh()
-
+
def RefreshGraphicsSizer(self):
self.GraphicsSizer.Clear()
-
+
for panel in self.GraphicPanels:
self.GraphicsSizer.AddWindow(panel, flag=wx.GROW)
-
+
self.GraphicsSizer.Layout()
self.RefreshGraphicsWindowScrollbars()
-
+
def RefreshView(self):
self.RefreshCanvasPosition()
-
+
width, height = self.GraphicsWindow.GetVirtualSize()
bitmap = wx.EmptyBitmap(width, height)
dc = wx.BufferedDC(wx.ClientDC(self.GraphicsWindow), bitmap)
@@ -531,22 +530,22 @@
if self.DraggingAxesPanel is not None:
destBBox = self.DraggingAxesBoundingBox
srcBBox = self.DraggingAxesPanel.GetAxesBoundingBox()
-
+
srcBmp = _convert_agg_to_wx_bitmap(self.DraggingAxesPanel.get_renderer(), None)
srcDC = wx.MemoryDC()
srcDC.SelectObject(srcBmp)
-
- dc.Blit(destBBox.x, destBBox.y,
- int(destBBox.width), int(destBBox.height),
+
+ dc.Blit(destBBox.x, destBBox.y,
+ int(destBBox.width), int(destBBox.height),
srcDC, srcBBox.x, srcBBox.y)
dc.EndDrawing()
-
+
if not self.Fixed or self.Force:
self.Force = False
refresh_graphics = True
else:
refresh_graphics = False
-
+
if self.DraggingAxesPanel is not None and self.DraggingAxesPanel not in self.GraphicPanels:
self.DraggingAxesPanel.RefreshViewer(refresh_graphics)
for panel in self.GraphicPanels:
@@ -554,7 +553,7 @@
panel.RefreshViewer(refresh_graphics)
else:
panel.RefreshViewer()
-
+
if self.CursorTick is not None:
tick = self.CursorTick
elif len(self.Ticks) > 0:
@@ -570,27 +569,27 @@
((tick_duration % DAY) / HOUR, _("%dh")),
((tick_duration % HOUR) / MINUTE, _("%dm")),
((tick_duration % MINUTE) / SECOND, _("%ds"))]:
-
+
if value > 0 or not_null:
duration += format % value
not_null = True
-
- duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND)
+
+ duration += _("%03gms") % (float(tick_duration % SECOND) / MILLISECOND)
self.TickTimeLabel.SetLabel("t: %s" % duration)
else:
self.TickLabel.SetLabel("")
self.TickTimeLabel.SetLabel("")
self.TickSizer.Layout()
-
+
def SubscribeAllDataConsumers(self):
DebugViewer.SubscribeAllDataConsumers(self)
-
+
if self.DataProducer is not None:
if self.DataProducer is not None:
self.SetTickTime(self.DataProducer.GetTicktime())
-
+
self.ResetCursorTick()
-
+
for panel in self.GraphicPanels[:]:
panel.SubscribeAllDataConsumers()
if panel.ItemsIsEmpty():
@@ -598,28 +597,28 @@
panel.ReleaseMouse()
self.GraphicPanels.remove(panel)
panel.Destroy()
-
+
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
self.ForceRefresh()
-
+
def ResetView(self):
self.UnsubscribeAllDataConsumers()
-
+
self.Fixed = False
for panel in self.GraphicPanels:
panel.Destroy()
self.GraphicPanels = []
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
-
+
def SetCanvasPosition(self, tick):
tick = max(self.Ticks[0], min(tick, self.Ticks[-1] - self.CurrentRange))
self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - tick))]
self.Fixed = True
self.RefreshCanvasPosition()
self.ForceRefresh()
-
+
def RefreshCanvasPosition(self):
if len(self.Ticks) > 0:
pos = int(self.StartTick - self.Ticks[0])
@@ -628,7 +627,7 @@
pos = 0
range = 0
self.CanvasPosition.SetScrollbar(pos, self.CurrentRange, range, self.CurrentRange)
-
+
def ChangeRange(self, dir, tick=None):
current_range = self.CurrentRange
current_range_idx = self.CanvasRange.GetSelection()
@@ -644,7 +643,7 @@
self.StartTick = self.Ticks[numpy.argmin(numpy.abs(self.Ticks - new_start_tick))]
self.Fixed = new_start_tick < self.Ticks[-1] - self.CurrentRange
self.ForceRefresh()
-
+
def RefreshRange(self):
if len(self.Ticks) > 0:
if self.Fixed and self.Ticks[-1] - self.Ticks[0] < self.CurrentRange:
@@ -654,7 +653,7 @@
else:
self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
self.ForceRefresh()
-
+
def OnRangeChanged(self, event):
try:
self.CurrentRange = RANGE_VALUES[self.CanvasRange.GetSelection()][1] / self.Ticktime
@@ -662,13 +661,13 @@
self.CanvasRange.SetValue(str(self.CurrentRange))
wx.CallAfter(self.RefreshRange)
event.Skip()
-
+
def OnCurrentButton(self, event):
if len(self.Ticks) > 0:
self.StartTick = max(self.Ticks[0], self.Ticks[-1] - self.CurrentRange)
self.ResetCursorTick()
event.Skip()
-
+
def CopyDataToClipboard(self, variables):
text = "tick;%s;\n" % ";".join([item.GetVariable() for item, data in variables])
next_tick = NextTick(variables)
@@ -693,7 +692,7 @@
text += "%d;%s;\n" % (next_tick, ";".join(values))
next_tick = NextTick(variables)
self.ParentWindow.SetCopyBuffer(text)
-
+
def OnExportGraphButton(self, event):
items = reduce(lambda x, y: x + y,
[panel.GetItems() for panel in self.GraphicPanels],
@@ -703,25 +702,25 @@
if item.IsNumVariable()]
wx.CallAfter(self.CopyDataToClipboard, variables)
event.Skip()
-
+
def OnPositionChanging(self, event):
if len(self.Ticks) > 0:
self.StartTick = self.Ticks[0] + event.GetPosition()
self.Fixed = True
self.ForceRefresh()
event.Skip()
-
+
def GetRange(self):
return self.StartTick, self.StartTick + self.CurrentRange
-
+
def GetViewerIndex(self, viewer):
if viewer in self.GraphicPanels:
return self.GraphicPanels.index(viewer)
return None
-
+
def IsViewerFirst(self, viewer):
return viewer == self.GraphicPanels[0]
-
+
def HighlightPreviousViewer(self, viewer):
if self.IsViewerFirst(viewer):
return
@@ -729,25 +728,25 @@
if idx is None:
return
self.GraphicPanels[idx-1].SetHighlight(HIGHLIGHT_AFTER)
-
+
def ResetVariableNameMask(self):
items = []
for panel in self.GraphicPanels:
items.extend(panel.GetItems())
if len(items) > 1:
- self.VariableNameMask = reduce(compute_mask,
- [item.GetVariable().split('.') for item in items])
+ self.VariableNameMask = reduce(
+ compute_mask, [item.GetVariable().split('.') for item in items])
elif len(items) > 0:
self.VariableNameMask = items[0].GetVariable().split('.')[:-1] + ['*']
else:
self.VariableNameMask = []
self.MaskLabel.ChangeValue(".".join(self.VariableNameMask))
self.MaskLabel.SetInsertionPoint(self.MaskLabel.GetLastPosition())
-
+
def GetVariableNameMask(self):
return self.VariableNameMask
-
- def InsertValue(self, iec_path, idx = None, force=False, graph=False):
+
+ def InsertValue(self, iec_path, idx=None, force=False, graph=False):
for panel in self.GraphicPanels:
if panel.GetItem(iec_path) is not None:
if graph and isinstance(panel, DebugVariableTextViewer):
@@ -758,7 +757,7 @@
item = DebugVariableItem(self, iec_path, True)
result = self.AddDataConsumer(iec_path.upper(), item, True)
if result is not None or force:
-
+
self.Freeze()
if item.IsNumVariable() and graph:
panel = DebugVariableGraphicViewer(self.GraphicsWindow, self, [item], GRAPH_PARALLEL)
@@ -774,8 +773,8 @@
self.RefreshGraphicsSizer()
self.Thaw()
self.ForceRefresh()
-
- def MoveValue(self, iec_path, idx = None, graph=False):
+
+ def MoveValue(self, iec_path, idx=None, graph=False):
if idx is None:
idx = len(self.GraphicPanels)
source_panel = None
@@ -787,9 +786,9 @@
break
if source_panel is not None:
source_panel_idx = self.GraphicPanels.index(source_panel)
-
+
if (len(source_panel.GetItems()) == 1):
-
+
if source_panel_idx < idx:
self.GraphicPanels.insert(idx, source_panel)
self.GraphicPanels.pop(source_panel_idx)
@@ -798,7 +797,7 @@
self.GraphicPanels.insert(idx, source_panel)
else:
return
-
+
else:
source_panel.RemoveItem(item)
source_size = source_panel.GetSize()
@@ -807,22 +806,22 @@
panel.SetCanvasHeight(source_size.height)
if self.CursorTick is not None:
panel.SetCursorTick(self.CursorTick)
-
+
else:
panel = DebugVariableTextViewer(self.GraphicsWindow, self, [item])
-
+
self.GraphicPanels.insert(idx, panel)
-
+
if source_panel.ItemsIsEmpty():
if source_panel.HasCapture():
source_panel.ReleaseMouse()
source_panel.Destroy()
self.GraphicPanels.remove(source_panel)
-
+
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
self.ForceRefresh()
-
+
def MergeGraphs(self, source, target_idx, merge_type, force=False):
source_item = None
source_panel = None
@@ -846,11 +845,11 @@
graph_type = target_panel.GraphType
if target_panel != source_panel:
if (merge_type == GRAPH_PARALLEL and graph_type != merge_type or
- merge_type == GRAPH_ORTHOGONAL and
+ merge_type == GRAPH_ORTHOGONAL and
(graph_type == GRAPH_PARALLEL and len(target_panel.Items) > 1 or
graph_type == GRAPH_ORTHOGONAL and len(target_panel.Items) >= 3)):
return
-
+
if source_panel is not None:
source_panel.RemoveItem(source_item)
if source_panel.ItemsIsEmpty():
@@ -862,7 +861,7 @@
target_panel.RemoveItem(source_item)
else:
target_panel = None
-
+
if target_panel is not None:
target_panel.AddItem(source_item)
target_panel.GraphType = merge_type
@@ -874,15 +873,15 @@
else:
target_panel.SetCanvasHeight(size.height)
target_panel.ResetGraphics()
-
+
self.ResetVariableNameMask()
self.RefreshGraphicsSizer()
self.ForceRefresh()
-
+
def DeleteValue(self, source_panel, item=None):
source_idx = self.GetViewerIndex(source_panel)
if source_idx is not None:
-
+
if item is None:
source_panel.ClearItems()
source_panel.Destroy()
@@ -900,7 +899,7 @@
self.Fixed = False
self.ResetCursorTick()
self.ForceRefresh()
-
+
def ToggleViewerType(self, panel):
panel_idx = self.GetViewerIndex(panel)
if panel_idx is not None:
@@ -916,7 +915,7 @@
panel.Destroy()
self.RefreshGraphicsSizer()
self.ForceRefresh()
-
+
def ResetGraphicsValues(self):
self.Ticks = numpy.array([])
self.StartTick = 0
@@ -931,23 +930,24 @@
posx = max(0, min(xstart, (vwidth - window_size[0]) / SCROLLBAR_UNIT))
posy = max(0, min(ystart, (vheight - window_size[1]) / SCROLLBAR_UNIT))
self.GraphicsWindow.Scroll(posx, posy)
- self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
- vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT, posx, posy)
-
+ self.GraphicsWindow.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ vwidth / SCROLLBAR_UNIT, vheight / SCROLLBAR_UNIT,
+ posx, posy)
+
def OnGraphicsWindowEraseBackground(self, event):
pass
-
+
def OnGraphicsWindowPaint(self, event):
self.RefreshView()
event.Skip()
-
+
def OnGraphicsWindowResize(self, event):
size = self.GetSize()
for panel in self.GraphicPanels:
panel_size = panel.GetSize()
- if (isinstance(panel, DebugVariableGraphicViewer) and
- panel.GraphType == GRAPH_ORTHOGONAL and
- panel_size.width == panel_size.height):
+ if isinstance(panel, DebugVariableGraphicViewer) and \
+ panel.GraphType == GRAPH_ORTHOGONAL and \
+ panel_size.width == panel_size.height:
panel.SetCanvasHeight(size.width)
self.RefreshGraphicsWindowScrollbars()
self.GraphicsSizer.Layout()
--- a/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/DebugVariableTextViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,16 +30,16 @@
from DebugVariableViewer import DebugVariableViewer
from GraphButton import GraphButton
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Text Viewer Drop Target
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a custom drop target class for Debug Variable Text Viewer
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableTextDropTarget(wx.TextDropTarget):
-
+ """
+ Class that implements a custom drop target class for Debug Variable Text Viewer
+ """
+
def __init__(self, parent, window):
"""
Constructor
@@ -49,7 +49,7 @@
wx.TextDropTarget.__init__(self)
self.ParentControl = parent
self.ParentWindow = window
-
+
def __del__(self):
"""
Destructor
@@ -58,7 +58,7 @@
# Panel
self.ParentControl = None
self.ParentWindow = None
-
+
def OnDragOver(self, x, y, d):
"""
Function called when mouse is dragged over Drop Target
@@ -68,9 +68,9 @@
"""
# Signal parent that mouse is dragged over
self.ParentControl.OnMouseDragging(x, y)
-
+
return wx.TextDropTarget.OnDragOver(self, x, y, d)
-
+
def OnDropText(self, x, y, data):
"""
Function called when mouse is released in Drop Target
@@ -80,76 +80,75 @@
"""
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
-
+
message = None
-
+
# Check that data is valid regarding DebugVariablePanel
try:
values = eval(data)
if not isinstance(values, TupleType):
raise ValueError
- except:
+ except Exception:
message = _("Invalid value \"%s\" for debug variable") % data
values = None
-
+
# Display message if data is invalid
if message is not None:
wx.CallAfter(self.ShowMessage, message)
-
+
# Data contain a reference to a variable to debug
elif values[1] == "debug":
-
+
# Get Before which Viewer the variable has to be moved or added
# according to the position of mouse in Viewer.
width, height = self.ParentControl.GetSize()
target_idx = self.ParentControl.GetIndex()
if y > height / 2:
target_idx += 1
-
+
# Drag'n Drop is an internal is an internal move inside Debug
- # Variable Panel
+ # Variable Panel
if len(values) > 2 and values[2] == "move":
- self.ParentWindow.MoveValue(values[0],
+ self.ParentWindow.MoveValue(values[0],
target_idx)
-
+
# Drag'n Drop was initiated by another control of Beremiz
else:
- self.ParentWindow.InsertValue(values[0],
- target_idx,
+ self.ParentWindow.InsertValue(values[0],
+ target_idx,
force=True)
-
+
def OnLeave(self):
"""
Function called when mouse is leave Drop Target
"""
# Signal Debug Variable Panel to reset highlight
self.ParentWindow.ResetHighlight()
-
+
return wx.TextDropTarget.OnLeave(self)
-
+
def ShowMessage(self, message):
"""
Show error message in Error Dialog
@param message: Error message to display
"""
- dialog = wx.MessageDialog(self.ParentWindow,
- message,
- _("Error"),
- wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self.ParentWindow,
+ message,
+ _("Error"),
+ wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Debug Variable Text Viewer Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a Viewer that display variable values as a text
-"""
+# -------------------------------------------------------------------------------
class DebugVariableTextViewer(DebugVariableViewer, wx.Panel):
-
+ """
+ Class that implements a Viewer that display variable values as a text
+ """
+
def __init__(self, parent, window, items=[]):
"""
Constructor
@@ -158,13 +157,13 @@
@param items: List of DebugVariableItem displayed by Viewer
"""
DebugVariableViewer.__init__(self, window, items)
-
+
wx.Panel.__init__(self, parent)
# Set panel background colour
self.SetBackgroundColour(wx.WHITE)
# Define panel drop target
self.SetDropTarget(DebugVariableTextDropTarget(self, window))
-
+
# Bind events
self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
@@ -174,16 +173,16 @@
self.Bind(wx.EVT_SIZE, self.OnResize)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
self.Bind(wx.EVT_PAINT, self.OnPaint)
-
+
# Define panel min size for parent sizer layout
self.SetMinSize(wx.Size(0, 25))
-
+
# Add buttons to Viewer
for bitmap, callback in [("force", self.OnForceButton),
("release", self.OnReleaseButton),
("delete_graph", self.OnCloseButton)]:
self.Buttons.append(GraphButton(0, 0, bitmap, callback))
-
+
def RefreshViewer(self):
"""
Method that refresh the content displayed by Viewer
@@ -193,24 +192,24 @@
bitmap = wx.EmptyBitmap(width, height)
dc = wx.BufferedDC(wx.ClientDC(self), bitmap)
dc.Clear()
-
+
# Get Graphics Context for DC, for anti-aliased and transparent
# rendering
gc = wx.GCDC(dc)
-
+
gc.BeginDrawing()
-
+
# Get first item
item = self.ItemsDict.values()[0]
-
+
# Get item variable path masked according Debug Variable Panel mask
item_path = item.GetVariable(
self.ParentWindow.GetVariableNameMask())
-
+
# Draw item variable path at Viewer left side
w, h = gc.GetTextExtent(item_path)
gc.DrawText(item_path, 20, (height - h) / 2)
-
+
# Update 'Release' button state and text color according to item forced
# flag value
item_forced = item.IsForced()
@@ -218,17 +217,17 @@
self.RefreshButtonsPosition()
if item_forced:
gc.SetTextForeground(wx.BLUE)
-
+
# Draw item current value at right side of Viewer
item_value = item.GetValue()
w, h = gc.GetTextExtent(item_value)
gc.DrawText(item_value, width - 40 - w, (height - h) / 2)
-
+
# Draw other Viewer common elements
self.DrawCommonElements(gc)
-
+
gc.EndDrawing()
-
+
def OnLeftDown(self, event):
"""
Function called when mouse left button is pressed
@@ -236,15 +235,15 @@
"""
# Get first item
item = self.ItemsDict.values()[0]
-
+
# Calculate item path bounding box
width, height = self.GetSize()
item_path = item.GetVariable(
self.ParentWindow.GetVariableNameMask())
w, h = self.GetTextExtent(item_path)
-
+
# Test if mouse has been pressed in this bounding box. In that case
- # start a move drag'n drop of item variable
+ # start a move drag'n drop of item variable
x, y = event.GetPosition()
item_path_bbox = wx.Rect(20, (height - h) / 2, w, h)
if item_path_bbox.InsideXY(x, y):
@@ -253,11 +252,11 @@
dragSource = wx.DropSource(self)
dragSource.SetData(data)
dragSource.DoDragDrop()
-
+
# In other case handle event normally
else:
event.Skip()
-
+
def OnLeftUp(self, event):
"""
Function called when mouse left button is released
@@ -267,7 +266,7 @@
x, y = event.GetPosition()
wx.CallAfter(self.HandleButton, x, y)
event.Skip()
-
+
def OnLeftDClick(self, event):
"""
Function called when mouse left button is double clicked
@@ -276,7 +275,7 @@
# Only numeric variables can be toggled to graph canvas
if self.ItemsDict.values()[0].IsNumVariable():
self.ParentWindow.ToggleViewerType(self)
-
+
def OnPaint(self, event):
"""
Function called when redrawing Viewer content is needed
--- a/controls/DebugVariablePanel/DebugVariableViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/DebugVariableViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -46,17 +46,17 @@
HIGHLIGHT_RESIZE_PEN = wx.Pen(wx.Colour(200, 200, 200))
HIGHLIGHT_RESIZE_BRUSH = wx.Brush(wx.Colour(200, 200, 200))
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Base Debug Variable Viewer Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a generic viewer that display a list of variable values
-This class has to be inherited to effectively display variable values
-"""
+# -------------------------------------------------------------------------------
+
class DebugVariableViewer:
-
+ """
+ Class that implements a generic viewer that display a list of variable values
+ This class has to be inherited to effectively display variable values
+ """
+
def __init__(self, window, items=[]):
"""
Constructor
@@ -67,26 +67,26 @@
self.ItemsDict = OrderedDict([(item.GetVariable(), item)
for item in items])
self.Items = self.ItemsDict.viewvalues()
-
+
# Variable storing current highlight displayed in Viewer
self.Highlight = HIGHLIGHT_NONE
# List of buttons
self.Buttons = []
-
+
def __del__(self):
"""
Destructor
"""
# Remove reference to Debug Variable Panel
self.ParentWindow = None
-
+
def GetIndex(self):
"""
Return position of Viewer in Debug Variable Panel
@return: Position of Viewer
"""
return self.ParentWindow.GetViewerIndex(self)
-
+
def GetItem(self, variable):
"""
Return item storing values of a variable
@@ -94,28 +94,28 @@
@return: Item storing values of this variable
"""
return self.ItemsDict.get(variable, None)
-
+
def GetItems(self):
"""
Return items displayed by Viewer
@return: List of items displayed in Viewer
"""
return self.ItemsDict.values()
-
+
def AddItem(self, item):
"""
Add an item to the list of items displayed by Viewer
@param item: Item to add to the list
"""
self.ItemsDict[item.GetVariable()] = item
-
+
def RemoveItem(self, item):
"""
Remove an item from the list of items displayed by Viewer
@param item: Item to remove from the list
"""
self.ItemsDict.pop(item.GetVariable(), None)
-
+
def ClearItems(self):
"""
Clear list of items displayed by Viewer
@@ -123,17 +123,17 @@
# Unsubscribe every items of the list
for item in self.Items:
self.ParentWindow.RemoveDataConsumer(item)
-
+
# Clear list
self.ItemsDict.clear()
-
+
def ItemsIsEmpty(self):
"""
Return if list of items displayed by Viewer is empty
@return: True if list is empty
"""
return len(self.Items) == 0
-
+
def SubscribeAllDataConsumers(self):
"""
Function that unsubscribe and remove every item that store values of
@@ -141,7 +141,7 @@
"""
for item in self.ItemsDict.values()[:]:
iec_path = item.GetVariable()
-
+
# Check that variablepath exist in PLC
if self.ParentWindow.GetDataType(iec_path) is None:
# If not, unsubscribe and remove it
@@ -151,30 +151,30 @@
# If it exist, resubscribe and refresh data type
self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
item.RefreshVariableType()
-
+
def ResetItemsData(self):
"""
Reset data stored in every items displayed in Viewer
"""
for item in self.Items:
item.ResetData()
-
+
def GetItemsMinCommonTick(self):
"""
Return the minimum tick common to all iems displayed in Viewer
@return: Minimum common tick between items
"""
- return reduce(max, [item.GetData()[0, 0]
+ return reduce(max, [item.GetData()[0, 0]
for item in self.Items
if len(item.GetData()) > 0], 0)
-
+
def RefreshViewer(self):
"""
Method that refresh the content displayed by Viewer
Need to be overridden by inherited classes
"""
pass
-
+
def SetHighlight(self, highlight):
"""
Set Highlight type displayed in Viewer
@@ -183,17 +183,17 @@
# Return immediately if highlight don't change
if self.Highlight == highlight:
return False
-
+
self.Highlight = highlight
return True
-
+
def GetButtons(self):
"""
Return list of buttons defined in Viewer
@return: List of buttons
"""
return self.Buttons
-
+
def IsOverButton(self, x, y):
"""
Return if point is over one button of Viewer
@@ -205,7 +205,7 @@
if button.HitTest(x, y):
return button
return None
-
+
def HandleButton(self, x, y):
"""
Search for the button under point and if found execute associated
@@ -217,10 +217,10 @@
button = self.IsOverButton(x, y)
if button is None:
return False
-
+
button.ProcessCallback()
return True
-
+
def ShowButtons(self, show):
"""
Set display state of buttons in Viewer
@@ -229,27 +229,27 @@
# Change display of every buttons
for button in self.Buttons:
button.Show(show)
-
+
# Refresh button positions
self.RefreshButtonsPosition()
self.RefreshViewer()
-
+
def RefreshButtonsPosition(self):
"""
Function that refresh buttons position in Viewer
"""
# Get Viewer size
width, height = self.GetSize()
-
+
# Buttons are align right so we calculate buttons positions in
# reverse order
buttons = self.Buttons[:]
buttons.reverse()
-
+
# Position offset on x coordinate
x_offset = 0
for button in buttons:
- # Buttons are stacked right, removing those that are not active
+ # Buttons are stacked right, removing those that are not active
if button.IsEnabled():
# Update button position according to button width and offset
# on x coordinate
@@ -257,7 +257,7 @@
button.SetPosition(width - 5 - w - x_offset, 5)
# Update offset on x coordinate
x_offset += w + 2
-
+
def DrawCommonElements(self, dc, buttons=None):
"""
Function that draw common graphics for every Viewers
@@ -268,26 +268,26 @@
"""
# Get Viewer size
width, height = self.GetSize()
-
+
# Set dc styling for drop before or drop after highlight
dc.SetPen(HIGHLIGHT_DROP_PEN)
dc.SetBrush(HIGHLIGHT_DROP_BRUSH)
-
+
# Draw line at upper side of Viewer if highlight is drop before
if self.Highlight == HIGHLIGHT_BEFORE:
dc.DrawLine(0, 1, width - 1, 1)
-
+
# Draw line at lower side of Viewer if highlight is drop before
elif self.Highlight == HIGHLIGHT_AFTER:
dc.DrawLine(0, height - 1, width - 1, height - 1)
-
+
# If no specific buttons are defined, get default buttons
if buttons is None:
buttons = self.Buttons
# Draw buttons
for button in buttons:
button.Draw(dc)
-
+
# If graph dragging is processing
if self.ParentWindow.IsDragging():
destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self)
@@ -295,55 +295,55 @@
if destBBox.width > 0 and destBBox.height > 0:
srcPanel = self.ParentWindow.DraggingAxesPanel
srcBBox = srcPanel.GetAxesBoundingBox()
-
+
srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0)
srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0)
-
+
srcBmp = _convert_agg_to_wx_bitmap(
srcPanel.get_renderer(), None)
srcDC = wx.MemoryDC()
srcDC.SelectObject(srcBmp)
-
- dc.Blit(destBBox.x, destBBox.y,
- int(destBBox.width), int(destBBox.height),
+
+ dc.Blit(destBBox.x, destBBox.y,
+ int(destBBox.width), int(destBBox.height),
srcDC, srcX, srcY)
-
+
def OnEnter(self, event):
"""
Function called when entering Viewer
- @param event: wx.MouseEvent
+ @param event: wx.MouseEvent
"""
# Display buttons
self.ShowButtons(True)
event.Skip()
-
+
def OnLeave(self, event):
"""
Function called when leaving Viewer
- @param event: wx.MouseEvent
+ @param event: wx.MouseEvent
"""
# Hide buttons
self.ShowButtons(False)
event.Skip()
-
+
def OnCloseButton(self):
"""
Function called when Close button is pressed
"""
wx.CallAfter(self.ParentWindow.DeleteValue, self)
-
+
def OnForceButton(self):
"""
Function called when Force button is pressed
"""
self.ForceValue(self.ItemsDict.values()[0])
-
+
def OnReleaseButton(self):
"""
Function called when Release button is pressed
"""
self.ReleaseValue(self.ItemsDict.values()[0])
-
+
def OnMouseDragging(self, x, y):
"""
Function called when mouse is dragged over Viewer
@@ -354,7 +354,7 @@
# Refresh highlight in Debug Variable Panel (highlight can be displayed
# in another Viewer
self.ParentWindow.RefreshHighlight(x + xw, y + yw)
-
+
def RefreshHighlight(self, x, y):
"""
Function called by Debug Variable Panel asking Viewer to refresh
@@ -364,22 +364,22 @@
"""
# Get Viewer size
width, height = self.GetSize()
-
+
# Mouse is in the first half of Viewer
if y < height / 2:
# If Viewer is the upper one, draw drop before highlight
if self.ParentWindow.IsViewerFirst(self):
self.SetHighlight(HIGHLIGHT_BEFORE)
-
+
# Else draw drop after highlight in previous Viewer
else:
self.SetHighlight(HIGHLIGHT_NONE)
self.ParentWindow.HighlightPreviousViewer(self)
-
- # Mouse is in the second half of Viewer, draw drop after highlight
+
+ # Mouse is in the second half of Viewer, draw drop after highlight
else:
self.SetHighlight(HIGHLIGHT_AFTER)
-
+
def OnEraseBackground(self, event):
"""
Function called when Viewer background is going to be erase
@@ -387,7 +387,7 @@
"""
# Prevent flicker on Windows
pass
-
+
def OnResize(self, event):
"""
Function called when Viewer size changed
@@ -397,7 +397,7 @@
self.RefreshButtonsPosition()
self.ParentWindow.ForceRefresh()
event.Skip()
-
+
def ForceValue(self, item):
"""
Force value of item given
@@ -409,13 +409,13 @@
# Return immediately if not found
if iec_type is None:
return
-
+
# Open a dialog to enter varaible forced value
dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
if dialog.ShowModal() == wx.ID_OK:
self.ParentWindow.ForceDataValue(iec_path.upper(),
dialog.GetValue())
-
+
def ReleaseValue(self, item):
"""
Release value of item given
--- a/controls/DebugVariablePanel/GraphButton.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DebugVariablePanel/GraphButton.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,16 +26,16 @@
from util.BitmapLibrary import GetBitmap
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Custom button for Graphic Viewer Class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a custom button for graphic Viewer
-"""
class GraphButton():
-
+ """
+ Class that implements a custom button for graphic Viewer
+ """
+
def __init__(self, x, y, bitmap, callback):
"""
Constructor
@@ -48,21 +48,21 @@
self.SetPosition(x, y)
# Set button bitmap
self.SetBitmap(bitmap)
-
+
# By default button is hide and enabled
self.Shown = False
self.Enabled = True
-
+
# Save reference to callback function
self.Callback = callback
-
+
def __del__(self):
"""
Destructor
"""
# Remove reference to callback function
self.callback = None
-
+
def SetBitmap(self, bitmap):
"""
Set bitmap to use for button
@@ -70,7 +70,7 @@
"""
# Get wx.Bitmap object corresponding to bitmap
self.Bitmap = GetBitmap(bitmap)
-
+
def GetSize(self):
"""
Return size of button
@@ -78,7 +78,7 @@
"""
# Button size is size of bitmap
return self.Bitmap.GetSize()
-
+
def SetPosition(self, x, y):
"""
Set button position
@@ -86,7 +86,7 @@
@param y: Y coordinate of Button in Graphic Viewer
"""
self.Position = wx.Point(x, y)
-
+
def Show(self, show=True):
"""
Mark if button to be displayed in Graphic Viewer
@@ -94,20 +94,20 @@
(default True)
"""
self.Shown = show
-
+
def Hide(self):
"""
Hide button from Graphic Viewer
"""
self.Show(False)
-
+
def IsShown(self):
"""
Return if button is displayed in Graphic Viewer
@return: True if button is displayed in Graphic Viewer
"""
return self.Shown
-
+
def Enable(self, enable=True):
"""
Mark if button is active in Graphic Viewer
@@ -115,44 +115,44 @@
(default True)
"""
self.Enabled = enable
-
+
def Disable(self):
"""
Deactivate button in Graphic Viewer
"""
self.Enabled = False
-
+
def IsEnabled(self):
"""
Return if button is active in Graphic Viewer
@return: True if button is active in Graphic Viewer
"""
return self.Enabled
-
+
def HitTest(self, x, y):
"""
Test if point is inside button
@param x: X coordinate of point
@param y: Y coordinate of point
@return: True if button is active and displayed and point is inside
- button
+ button
"""
# Return immediately if button is hidden or inactive
if not (self.IsShown() and self.IsEnabled()):
return False
-
+
# Test if point is inside button
w, h = self.Bitmap.GetSize()
rect = wx.Rect(self.Position.x, self.Position.y, w, h)
return rect.InsideXY(x, y)
-
+
def ProcessCallback(self):
"""
Call callback function if defined
"""
if self.Callback is not None:
self.Callback()
-
+
def Draw(self, dc):
"""
Draw button in Graphic Viewer
--- a/controls/DurationCellEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/DurationCellEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,40 +26,41 @@
from dialogs.DurationEditorDialog import DurationEditorDialog
+
class DurationCellControl(wx.PyControl):
-
+
'''
Custom cell editor control with a text box and a button that launches
the DurationEditorDialog.
'''
def __init__(self, parent):
wx.Control.__init__(self, parent)
-
+
main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
# create location text control
- self.Duration = wx.TextCtrl(self, size=wx.Size(0, -1),
- style=wx.TE_PROCESS_ENTER)
+ self.Duration = wx.TextCtrl(self, size=wx.Size(0, -1),
+ style=wx.TE_PROCESS_ENTER)
self.Duration.Bind(wx.EVT_KEY_DOWN, self.OnDurationChar)
main_sizer.AddWindow(self.Duration, flag=wx.GROW)
-
+
# create browse button
self.EditButton = wx.Button(self, label='...', size=wx.Size(30, -1))
self.Bind(wx.EVT_BUTTON, self.OnEditButtonClick, self.EditButton)
main_sizer.AddWindow(self.EditButton, flag=wx.GROW)
-
+
self.Bind(wx.EVT_SIZE, self.OnSize)
-
+
self.SetSizer(main_sizer)
-
+
self.Default = None
-
+
def SetValue(self, value):
self.Default = value
self.Duration.SetValue(value)
-
+
def GetValue(self):
return self.Duration.GetValue()
@@ -90,23 +91,24 @@
def SetInsertionPoint(self, i):
self.Duration.SetInsertionPoint(i)
-
+
def SetFocus(self):
self.Duration.SetFocus()
+
class DurationCellEditor(wx.grid.PyGridCellEditor):
'''
Grid cell editor that uses DurationCellControl to display an edit button.
'''
def __init__(self, table, colname):
wx.grid.PyGridCellEditor.__init__(self)
-
+
self.Table = table
self.Colname = colname
-
+
def __del__(self):
self.CellControl = None
-
+
def Create(self, parent, id, evt_handler):
self.CellControl = DurationCellControl(parent)
self.SetControl(self.CellControl)
@@ -131,13 +133,13 @@
return self.EndEditInternal(row, col, grid, oldval)
else:
def EndEdit(self, row, col, grid):
- oldval = self.Table.GetValueByName(row, self.Colname)
- return self.EndEditInternal(row, col, grid, oldval)
+ oldval = self.Table.GetValueByName(row, self.Colname)
+ return self.EndEditInternal(row, col, grid, oldval)
def SetSize(self, rect):
self.CellControl.SetDimensions(rect.x + 1, rect.y,
- rect.width, rect.height,
- wx.SIZE_ALLOW_MINUS_ONE)
+ rect.width, rect.height,
+ wx.SIZE_ALLOW_MINUS_ONE)
def Clone(self):
return DurationCellEditor(self.Table)
--- a/controls/EnhancedStatusBar.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/EnhancedStatusBar.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,248 +1,246 @@
-# --------------------------------------------------------------------------- #
-# ENHANCEDSTATUSBAR wxPython IMPLEMENTATION
-# Python Code By:
-#
-# Andrea Gavana, @ 31 May 2005
-# Nitro, @ 21 September 2005
-# Latest Revision: 21 September 2005, 19.57.20 GMT+2
-# Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
-# Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET
-#
-#
-# TODO List/Caveats
-#
-# 1. Some Requests/Features To Add?
-#
-#
-# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
-# Write To Me At:
-#
-#
-# andrea.gavana@agip.it
-# andrea_gavan@tin.it
-#
-# Or, Obviously, To The wxPython Mailing List!!!
-#
-#
-# licensed under wxWidgets License (GPL compatible)
-# End Of Comments
-# --------------------------------------------------------------------------- #
-
-""" Description:
-
-EnhancedStatusBar Is A Slight Modification (Actually A Subclassing) Of wx.StatusBar.
-It Allows You To Add Almost Any Widget You Like To The wx.StatusBar Of Your Main
-Frame Application And Also To Layout Them Properly.
-
-
-What It Can Do:
-
-1) Almost All The Functionalities Of wx.StatusBar Are Still Present;
-2) You Can Add Different Kind Of Widgets Into Every Field Of The EnhancedStatusBar;
-3) The AddWidget() Methods Accepts 2 Layout Inputs:
- - horizontalalignment: This Specify The Horizontal Alignment For Your Widget,
- And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_HORIZONTAL, ESB_ALIGN_LEFT And
- ESB_ALIGN_RIGHT;
- - varticalalignment: This Specify The Vertical Alignment For Your Widget,
- And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_VERTICAL, ESB_ALIGN_BOTTOM And
- ESB_ALIGN_LEFT;
-
-EnhancedStatusBar Is Freeware And Distributed Under The wxPython License.
-
-Latest Revision: 21 September 2005, 19.57.20 GMT+2
-Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
-Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET
-
-"""
-
-import wx
-
-# Horizontal Alignment Constants
-ESB_ALIGN_CENTER_VERTICAL = 1
-ESB_ALIGN_TOP = 2
-ESB_ALIGN_BOTTOM = 3
-
-# Vertical Alignment Constants
-ESB_ALIGN_CENTER_HORIZONTAL = 11
-ESB_ALIGN_LEFT = 12
-ESB_ALIGN_RIGHT = 13
-
-# Exact Fit (Either Horizontal Or Vertical Or Both) Constant
-ESB_EXACT_FIT = 20
-
-
-# ---------------------------------------------------------------
-# Class EnhancedStatusBar
-# ---------------------------------------------------------------
-# This Is The Main Class Implementation. See The Demo For Details
-# ---------------------------------------------------------------
-class EnhancedStatusBarItem(object):
- def __init__(self, widget, pos, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL, verticalalignment=ESB_ALIGN_CENTER_VERTICAL):
- self.__dict__.update( locals() )
-
-class EnhancedStatusBar(wx.StatusBar):
-
- def __init__(self, parent, id=wx.ID_ANY, style=wx.ST_SIZEGRIP,
- name="EnhancedStatusBar"):
- """Default Class Constructor.
-
- EnhancedStatusBar.__init__(self, parent, id=wx.ID_ANY,
- style=wx.ST_SIZEGRIP,
- name="EnhancedStatusBar")
- """
-
- wx.StatusBar.__init__(self, parent, id, style, name)
-
- self._items = {}
- self._curPos = 0
- self._parent = parent
-
- wx.EVT_SIZE(self, self.OnSize)
- wx.CallAfter(self.OnSize, None)
-
-
- def OnSize(self, event):
- """Handles The wx.EVT_SIZE Events For The StatusBar.
-
- Actually, All The Calculations Linked To HorizontalAlignment And
- VerticalAlignment Are Done In This Function."""
-
- for pos, item in self._items.items():
- widget, horizontalalignment, verticalalignment = item.widget, item.horizontalalignment, item.verticalalignment
-
- rect = self.GetFieldRect(pos)
- widgetpos = widget.GetPosition()
- widgetsize = widget.GetSize()
-
- rect = self.GetFieldRect(pos)
-
- if horizontalalignment == ESB_EXACT_FIT:
-
- if verticalalignment == ESB_EXACT_FIT:
- """ 1 September 2015 Fix fit align """
- widget.SetSize((rect.width-4, rect.height-4))
- widget.SetPosition((rect.x+2, rect.y+2))
- elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
- if widgetsize[1] < rect.width - 1:
- diffs = (rect.height - widgetsize[1])/2
- widget.SetSize((rect.width-2, widgetsize[1]))
- widget.SetPosition((rect.x-1, rect.y+diffs))
- else:
- widget.SetSize((rect.width-2, widgetsize[1]))
- widget.SetPosition((rect.x-1, rect.y-1))
- elif verticalalignment == ESB_ALIGN_TOP:
- widget.SetSize((rect.width-2, widgetsize[1]))
- widget.SetPosition((rect.x-1, rect.y))
- elif verticalalignment == ESB_ALIGN_BOTTOM:
- widget.SetSize((rect.width-2, widgetsize[1]))
- widget.SetPosition((rect.x-1, rect.height-widgetsize[1]))
-
- elif horizontalalignment == ESB_ALIGN_LEFT:
-
- xpos = rect.x - 1
- if verticalalignment == ESB_EXACT_FIT:
- widget.SetSize((widgetsize[0], rect.height-2))
- widget.SetPosition((xpos, rect.y-1))
- elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
- if widgetsize[1] < rect.height - 1:
- diffs = (rect.height - widgetsize[1])/2
- widget.SetPosition((xpos, rect.y+diffs))
- else:
- widget.SetSize((widgetsize[0], rect.height-2))
- widget.SetPosition((xpos, rect.y-1))
- elif verticalalignment == ESB_ALIGN_TOP:
- widget.SetPosition((xpos, rect.y))
- elif verticalalignment == ESB_ALIGN_BOTTOM:
- widget.SetPosition((xpos, rect.height-widgetsize[1]))
-
- elif horizontalalignment == ESB_ALIGN_RIGHT:
-
- xpos = rect.x + rect.width - widgetsize[0] - 1
- if verticalalignment == ESB_EXACT_FIT:
- widget.SetSize((widgetsize[0], rect.height-2))
- widget.SetPosition((xpos, rect.y-1))
- elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
- if widgetsize[1] < rect.height - 1:
- diffs = (rect.height - widgetsize[1])/2
- widget.SetPosition((xpos, rect.y+diffs))
- else:
- widget.SetSize((widgetsize[0], rect.height-2))
- widget.SetPosition((xpos, rect.y-1))
- elif verticalalignment == ESB_ALIGN_TOP:
- widget.SetPosition((xpos, rect.y))
- elif verticalalignment == ESB_ALIGN_BOTTOM:
- widget.SetPosition((xpos, rect.height-widgetsize[1]))
-
- elif horizontalalignment == ESB_ALIGN_CENTER_HORIZONTAL:
-
- xpos = rect.x + (rect.width - widgetsize[0])/2 - 1
- if verticalalignment == ESB_EXACT_FIT:
- widget.SetSize((widgetsize[0], rect.height))
- widget.SetPosition((xpos, rect.y))
- elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
- if widgetsize[1] < rect.height - 1:
- diffs = (rect.height - widgetsize[1])/2
- widget.SetPosition((xpos, rect.y+diffs))
- else:
- widget.SetSize((widgetsize[0], rect.height-1))
- widget.SetPosition((xpos, rect.y+1))
- elif verticalalignment == ESB_ALIGN_TOP:
- widget.SetPosition((xpos, rect.y))
- elif verticalalignment == ESB_ALIGN_BOTTOM:
- widget.SetPosition((xpos, rect.height-widgetsize[1]))
-
-
- if event is not None:
- event.Skip()
-
-
- def AddWidget(self, widget, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL,
- verticalalignment=ESB_ALIGN_CENTER_VERTICAL, pos = -1):
- """Add A Widget To The EnhancedStatusBar.
-
- Parameters:
-
- - horizontalalignment: This Can Be One Of:
- a) ESB_EXACT_FIT: The Widget Will Fit Horizontally The StatusBar Field Width;
- b) ESB_ALIGN_CENTER_HORIZONTAL: The Widget Will Be Centered Horizontally In
- The StatusBar Field;
- c) ESB_ALIGN_LEFT: The Widget Will Be Left Aligned In The StatusBar Field;
- d) ESB_ALIGN_RIGHT: The Widget Will Be Right Aligned In The StatusBar Field;
-
- - verticalalignment:
- a) ESB_EXACT_FIT: The Widget Will Fit Vertically The StatusBar Field Height;
- b) ESB_ALIGN_CENTER_VERTICAL: The Widget Will Be Centered Vertically In
- The StatusBar Field;
- c) ESB_ALIGN_BOTTOM: The Widget Will Be Bottom Aligned In The StatusBar Field;
- d) ESB_ALIGN_TOP: The Widget Will Be TOP Aligned In The StatusBar Field;
-
- """
-
- if pos == -1:
- pos = self._curPos
- self._curPos += 1
-
- if self.GetFieldsCount() <= pos:
- raise "\nERROR: EnhancedStatusBar has a max of %d items, you tried to set item #%d" % (self.GetFieldsCount(), pos)
-
- if horizontalalignment not in [ESB_ALIGN_CENTER_HORIZONTAL, ESB_EXACT_FIT,
- ESB_ALIGN_LEFT, ESB_ALIGN_RIGHT]:
- raise '\nERROR: Parameter "horizontalalignment" Should Be One Of '\
- '"ESB_ALIGN_CENTER_HORIZONTAL", "ESB_ALIGN_LEFT", "ESB_ALIGN_RIGHT"' \
- '"ESB_EXACT_FIT"'
-
- if verticalalignment not in [ESB_ALIGN_CENTER_VERTICAL, ESB_EXACT_FIT,
- ESB_ALIGN_TOP, ESB_ALIGN_BOTTOM]:
- raise '\nERROR: Parameter "verticalalignment" Should Be One Of '\
- '"ESB_ALIGN_CENTER_VERTICAL", "ESB_ALIGN_TOP", "ESB_ALIGN_BOTTOM"' \
- '"ESB_EXACT_FIT"'
-
-
- try:
- self.RemoveChild(self._items[pos].widget)
- self._items[pos].widget.Destroy()
- except KeyError: pass
-
- self._items[pos] = EnhancedStatusBarItem(widget, pos, horizontalalignment, verticalalignment)
-
- wx.CallAfter(self.OnSize, None)
+# --------------------------------------------------------------------------- #
+# ENHANCEDSTATUSBAR wxPython IMPLEMENTATION
+# Python Code By:
+#
+# Andrea Gavana, @ 31 May 2005
+# Nitro, @ 21 September 2005
+# Latest Revision: 21 September 2005, 19.57.20 GMT+2
+# Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
+# Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET
+#
+#
+# TODO List/Caveats
+#
+# 1. Some Requests/Features To Add?
+#
+#
+# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
+# Write To Me At:
+#
+#
+# andrea.gavana@agip.it
+# andrea_gavan@tin.it
+#
+# Or, Obviously, To The wxPython Mailing List!!!
+#
+#
+# licensed under wxWidgets License (GPL compatible)
+# End Of Comments
+# --------------------------------------------------------------------------- #
+
+""" Description:
+
+EnhancedStatusBar Is A Slight Modification (Actually A Subclassing) Of wx.StatusBar.
+It Allows You To Add Almost Any Widget You Like To The wx.StatusBar Of Your Main
+Frame Application And Also To Layout Them Properly.
+
+
+What It Can Do:
+
+1) Almost All The Functionalities Of wx.StatusBar Are Still Present;
+2) You Can Add Different Kind Of Widgets Into Every Field Of The EnhancedStatusBar;
+3) The AddWidget() Methods Accepts 2 Layout Inputs:
+ - horizontalalignment: This Specify The Horizontal Alignment For Your Widget,
+ And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_HORIZONTAL, ESB_ALIGN_LEFT And
+ ESB_ALIGN_RIGHT;
+ - varticalalignment: This Specify The Vertical Alignment For Your Widget,
+ And Can Be ESB_EXACT_FIT, ESB_ALIGN_CENTER_VERTICAL, ESB_ALIGN_BOTTOM And
+ ESB_ALIGN_LEFT;
+
+EnhancedStatusBar Is Freeware And Distributed Under The wxPython License.
+
+Latest Revision: 21 September 2005, 19.57.20 GMT+2
+Latest Revision before Latest Revision: 21 September 2005, 18.29.35 GMT+2
+Latest Revision before Latest Revision before Latest Revision: 31 May 2005, 23.17 CET
+
+"""
+
+import wx
+
+# Horizontal Alignment Constants
+ESB_ALIGN_CENTER_VERTICAL = 1
+ESB_ALIGN_TOP = 2
+ESB_ALIGN_BOTTOM = 3
+
+# Vertical Alignment Constants
+ESB_ALIGN_CENTER_HORIZONTAL = 11
+ESB_ALIGN_LEFT = 12
+ESB_ALIGN_RIGHT = 13
+
+# Exact Fit (Either Horizontal Or Vertical Or Both) Constant
+ESB_EXACT_FIT = 20
+
+
+# ---------------------------------------------------------------
+# Class EnhancedStatusBar
+# ---------------------------------------------------------------
+# This Is The Main Class Implementation. See The Demo For Details
+# ---------------------------------------------------------------
+class EnhancedStatusBarItem(object):
+ def __init__(self, widget, pos, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL, verticalalignment=ESB_ALIGN_CENTER_VERTICAL):
+ self.__dict__.update(locals())
+
+
+class EnhancedStatusBar(wx.StatusBar):
+
+ def __init__(self, parent, id=wx.ID_ANY, style=wx.ST_SIZEGRIP,
+ name="EnhancedStatusBar"):
+ """Default Class Constructor.
+
+ EnhancedStatusBar.__init__(self, parent, id=wx.ID_ANY,
+ style=wx.ST_SIZEGRIP,
+ name="EnhancedStatusBar")
+ """
+
+ wx.StatusBar.__init__(self, parent, id, style, name)
+
+ self._items = {}
+ self._curPos = 0
+ self._parent = parent
+
+ wx.EVT_SIZE(self, self.OnSize)
+ wx.CallAfter(self.OnSize, None)
+
+ def OnSize(self, event):
+ """Handles The wx.EVT_SIZE Events For The StatusBar.
+
+ Actually, All The Calculations Linked To HorizontalAlignment And
+ VerticalAlignment Are Done In This Function."""
+
+ for pos, item in self._items.items():
+ widget, horizontalalignment, verticalalignment = item.widget, item.horizontalalignment, item.verticalalignment
+
+ rect = self.GetFieldRect(pos)
+ widgetpos = widget.GetPosition()
+ widgetsize = widget.GetSize()
+
+ rect = self.GetFieldRect(pos)
+
+ if horizontalalignment == ESB_EXACT_FIT:
+
+ if verticalalignment == ESB_EXACT_FIT:
+ """ 1 September 2015 Fix fit align """
+ widget.SetSize((rect.width-4, rect.height-4))
+ widget.SetPosition((rect.x+2, rect.y+2))
+ elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
+ if widgetsize[1] < rect.width - 1:
+ diffs = (rect.height - widgetsize[1])/2
+ widget.SetSize((rect.width-2, widgetsize[1]))
+ widget.SetPosition((rect.x-1, rect.y+diffs))
+ else:
+ widget.SetSize((rect.width-2, widgetsize[1]))
+ widget.SetPosition((rect.x-1, rect.y-1))
+ elif verticalalignment == ESB_ALIGN_TOP:
+ widget.SetSize((rect.width-2, widgetsize[1]))
+ widget.SetPosition((rect.x-1, rect.y))
+ elif verticalalignment == ESB_ALIGN_BOTTOM:
+ widget.SetSize((rect.width-2, widgetsize[1]))
+ widget.SetPosition((rect.x-1, rect.height-widgetsize[1]))
+
+ elif horizontalalignment == ESB_ALIGN_LEFT:
+
+ xpos = rect.x - 1
+ if verticalalignment == ESB_EXACT_FIT:
+ widget.SetSize((widgetsize[0], rect.height-2))
+ widget.SetPosition((xpos, rect.y-1))
+ elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
+ if widgetsize[1] < rect.height - 1:
+ diffs = (rect.height - widgetsize[1])/2
+ widget.SetPosition((xpos, rect.y+diffs))
+ else:
+ widget.SetSize((widgetsize[0], rect.height-2))
+ widget.SetPosition((xpos, rect.y-1))
+ elif verticalalignment == ESB_ALIGN_TOP:
+ widget.SetPosition((xpos, rect.y))
+ elif verticalalignment == ESB_ALIGN_BOTTOM:
+ widget.SetPosition((xpos, rect.height-widgetsize[1]))
+
+ elif horizontalalignment == ESB_ALIGN_RIGHT:
+
+ xpos = rect.x + rect.width - widgetsize[0] - 1
+ if verticalalignment == ESB_EXACT_FIT:
+ widget.SetSize((widgetsize[0], rect.height-2))
+ widget.SetPosition((xpos, rect.y-1))
+ elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
+ if widgetsize[1] < rect.height - 1:
+ diffs = (rect.height - widgetsize[1])/2
+ widget.SetPosition((xpos, rect.y+diffs))
+ else:
+ widget.SetSize((widgetsize[0], rect.height-2))
+ widget.SetPosition((xpos, rect.y-1))
+ elif verticalalignment == ESB_ALIGN_TOP:
+ widget.SetPosition((xpos, rect.y))
+ elif verticalalignment == ESB_ALIGN_BOTTOM:
+ widget.SetPosition((xpos, rect.height-widgetsize[1]))
+
+ elif horizontalalignment == ESB_ALIGN_CENTER_HORIZONTAL:
+
+ xpos = rect.x + (rect.width - widgetsize[0])/2 - 1
+ if verticalalignment == ESB_EXACT_FIT:
+ widget.SetSize((widgetsize[0], rect.height))
+ widget.SetPosition((xpos, rect.y))
+ elif verticalalignment == ESB_ALIGN_CENTER_VERTICAL:
+ if widgetsize[1] < rect.height - 1:
+ diffs = (rect.height - widgetsize[1])/2
+ widget.SetPosition((xpos, rect.y+diffs))
+ else:
+ widget.SetSize((widgetsize[0], rect.height-1))
+ widget.SetPosition((xpos, rect.y+1))
+ elif verticalalignment == ESB_ALIGN_TOP:
+ widget.SetPosition((xpos, rect.y))
+ elif verticalalignment == ESB_ALIGN_BOTTOM:
+ widget.SetPosition((xpos, rect.height-widgetsize[1]))
+
+ if event is not None:
+ event.Skip()
+
+ def AddWidget(self, widget, horizontalalignment=ESB_ALIGN_CENTER_HORIZONTAL,
+ verticalalignment=ESB_ALIGN_CENTER_VERTICAL, pos=-1):
+ """Add A Widget To The EnhancedStatusBar.
+
+ Parameters:
+
+ - horizontalalignment: This Can Be One Of:
+ a) ESB_EXACT_FIT: The Widget Will Fit Horizontally The StatusBar Field Width;
+ b) ESB_ALIGN_CENTER_HORIZONTAL: The Widget Will Be Centered Horizontally In
+ The StatusBar Field;
+ c) ESB_ALIGN_LEFT: The Widget Will Be Left Aligned In The StatusBar Field;
+ d) ESB_ALIGN_RIGHT: The Widget Will Be Right Aligned In The StatusBar Field;
+
+ - verticalalignment:
+ a) ESB_EXACT_FIT: The Widget Will Fit Vertically The StatusBar Field Height;
+ b) ESB_ALIGN_CENTER_VERTICAL: The Widget Will Be Centered Vertically In
+ The StatusBar Field;
+ c) ESB_ALIGN_BOTTOM: The Widget Will Be Bottom Aligned In The StatusBar Field;
+ d) ESB_ALIGN_TOP: The Widget Will Be TOP Aligned In The StatusBar Field;
+
+ """
+
+ if pos == -1:
+ pos = self._curPos
+ self._curPos += 1
+
+ if self.GetFieldsCount() <= pos:
+ raise "\nERROR: EnhancedStatusBar has a max of %d items, you tried to set item #%d" % (self.GetFieldsCount(), pos)
+
+ if horizontalalignment not in [ESB_ALIGN_CENTER_HORIZONTAL, ESB_EXACT_FIT,
+ ESB_ALIGN_LEFT, ESB_ALIGN_RIGHT]:
+ raise '\nERROR: Parameter "horizontalalignment" Should Be One Of '\
+ '"ESB_ALIGN_CENTER_HORIZONTAL", "ESB_ALIGN_LEFT", "ESB_ALIGN_RIGHT"' \
+ '"ESB_EXACT_FIT"'
+
+ if verticalalignment not in [ESB_ALIGN_CENTER_VERTICAL, ESB_EXACT_FIT,
+ ESB_ALIGN_TOP, ESB_ALIGN_BOTTOM]:
+ raise '\nERROR: Parameter "verticalalignment" Should Be One Of '\
+ '"ESB_ALIGN_CENTER_VERTICAL", "ESB_ALIGN_TOP", "ESB_ALIGN_BOTTOM"' \
+ '"ESB_EXACT_FIT"'
+
+ try:
+ self.RemoveChild(self._items[pos].widget)
+ self._items[pos].widget.Destroy()
+ except KeyError:
+ pass
+
+ self._items[pos] = EnhancedStatusBarItem(widget, pos, horizontalalignment, verticalalignment)
+
+ wx.CallAfter(self.OnSize, None)
--- a/controls/FolderTree.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/FolderTree.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,6 +30,7 @@
DRIVE, FOLDER, FILE = range(3)
+
def sort_folder(x, y):
if x[1] == y[1]:
return cmp(x[0], y[0])
@@ -38,6 +39,7 @@
else:
return 1
+
def splitpath(path):
head, tail = os.path.split(path)
if head == "":
@@ -46,20 +48,21 @@
return splitpath(head)
return splitpath(head) + [tail]
+
class FolderTree(wx.Panel):
-
+
def __init__(self, parent, folder, filter=None, editable=True):
wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
-
+
main_sizer = wx.BoxSizer(wx.VERTICAL)
-
- self.Tree = wx.TreeCtrl(self,
- style=wx.TR_HAS_BUTTONS|
- wx.TR_SINGLE|
- wx.SUNKEN_BORDER|
- wx.TR_HIDE_ROOT|
- wx.TR_LINES_AT_ROOT|
- wx.TR_EDIT_LABELS)
+
+ self.Tree = wx.TreeCtrl(self,
+ style=(wx.TR_HAS_BUTTONS |
+ wx.TR_SINGLE |
+ wx.SUNKEN_BORDER |
+ wx.TR_HIDE_ROOT |
+ wx.TR_LINES_AT_ROOT |
+ wx.TR_EDIT_LABELS))
if wx.Platform == '__WXMSW__':
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnTreeItemExpanded, self.Tree)
self.Tree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeLeftDown)
@@ -69,19 +72,19 @@
self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnTreeBeginLabelEdit, self.Tree)
self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnTreeEndLabelEdit, self.Tree)
main_sizer.AddWindow(self.Tree, 1, flag=wx.GROW)
-
+
if filter is not None:
self.Filter = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnFilterChanged, self.Filter)
main_sizer.AddWindow(self.Filter, flag=wx.GROW)
else:
self.Filter = None
-
+
self.SetSizer(main_sizer)
-
+
self.Folder = folder
self.Editable = editable
-
+
self.TreeImageList = wx.ImageList(16, 16)
self.TreeImageDict = {}
for item_type, bitmap in [(DRIVE, "tree_drive"),
@@ -89,7 +92,7 @@
(FILE, "tree_file")]:
self.TreeImageDict[item_type] = self.TreeImageList.Add(GetBitmap(bitmap))
self.Tree.SetImageList(self.TreeImageList)
-
+
self.Filters = {}
if self.Filter is not None:
filter_parts = filter.split("|")
@@ -101,11 +104,11 @@
self.Filter.Append(filter_parts[idx])
if idx == 0:
self.Filter.SetStringSelection(filter_parts[idx])
-
+
self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
else:
self.CurrentFilter = ""
-
+
def _GetFolderChildren(self, folderpath, recursive=True):
items = []
if wx.Platform == '__WXMSW__' and folderpath == "/":
@@ -116,7 +119,7 @@
else:
try:
files = os.listdir(folderpath)
- except:
+ except Exception:
return []
for filename in files:
if not filename.startswith("."):
@@ -127,25 +130,25 @@
else:
children = 0
items.append((filename, FOLDER, children))
- elif (self.CurrentFilter == "" or
+ elif (self.CurrentFilter == "" or
os.path.splitext(filename)[1] == self.CurrentFilter):
items.append((filename, FILE, None))
if recursive:
items.sort(sort_folder)
return items
-
+
def SetFilter(self, filter):
self.CurrentFilter = filter
-
+
def GetTreeCtrl(self):
return self.Tree
-
+
def RefreshTree(self):
root = self.Tree.GetRootItem()
if not root.IsOk():
root = self.Tree.AddRoot("")
self.GenerateTreeBranch(root, self.Folder)
-
+
def GenerateTreeBranch(self, root, folderpath):
item, item_cookie = self.Tree.GetFirstChild(root)
for idx, (filename, item_type, children) in enumerate(self._GetFolderChildren(folderpath)):
@@ -172,18 +175,18 @@
def ExpandItem(self, item):
self.GenerateTreeBranch(item, self.GetPath(item))
self.Tree.Expand(item)
-
+
def OnTreeItemActivated(self, event):
self.ExpandItem(event.GetItem())
event.Skip()
-
+
def OnTreeLeftDown(self, event):
item, flags = self.Tree.HitTest(event.GetPosition())
if flags & wx.TREE_HITTEST_ONITEMBUTTON and not self.Tree.IsExpanded(item):
self.ExpandItem(item)
else:
event.Skip()
-
+
def OnTreeItemExpanded(self, event):
item = event.GetItem()
self.GenerateTreeBranch(item, self.GetPath(item))
@@ -201,7 +204,7 @@
event.Skip()
else:
event.Veto()
-
+
def OnTreeEndLabelEdit(self, event):
new_name = event.GetLabel()
if new_name != "":
@@ -212,20 +215,20 @@
os.rename(old_filepath, new_filepath)
event.Skip()
else:
- message = wx.MessageDialog(self,
- _("File '%s' already exists!") % new_name,
- _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self,
+ _("File '%s' already exists!") % new_name,
+ _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
event.Veto()
else:
event.Skip()
-
+
def OnFilterChanged(self, event):
self.CurrentFilter = self.Filters[self.Filter.GetStringSelection()]
self.RefreshTree()
event.Skip()
-
+
def _SelectItem(self, root, parts):
if len(parts) == 0:
self.Tree.SelectItem(root)
@@ -233,22 +236,22 @@
item, item_cookie = self.Tree.GetFirstChild(root)
while item.IsOk():
if self.Tree.GetItemText(item) == parts[0]:
- if (self.Tree.ItemHasChildren(item) and
- not self.Tree.IsExpanded(item)):
+ if self.Tree.ItemHasChildren(item) and \
+ not self.Tree.IsExpanded(item):
self.Tree.Expand(item)
wx.CallAfter(self._SelectItem, item, parts[1:])
else:
self._SelectItem(item, parts[1:])
return
item, item_cookie = self.Tree.GetNextChild(root, item_cookie)
-
+
def SetPath(self, path):
if path.startswith(self.Folder):
root = self.Tree.GetRootItem()
if root.IsOk():
relative_path = path.replace(os.path.join(self.Folder, ""), "")
self._SelectItem(root, splitpath(relative_path))
-
+
def GetPath(self, item=None):
if item is None:
item = self.Tree.GetSelection()
--- a/controls/LibraryPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/LibraryPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,25 +24,27 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
[CATEGORY, BLOCK] = range(2)
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Library Panel
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a panel displaying a tree containing an hierarchical list
-of functions and function blocks available in project an a search control for
-quickly find one functions or function blocks in this list and a text control
-displaying informations about selected functions or function blocks
-"""
+# -------------------------------------------------------------------------------
+
class LibraryPanel(wx.Panel):
-
+ """
+ Class that implements a panel displaying a tree containing an hierarchical list
+ of functions and function blocks available in project an a search control for
+ quickly find one functions or function blocks in this list and a text control
+ displaying informations about selected functions or function blocks
+ """
+
def __init__(self, parent, enable_drag=False):
"""
Constructor
@@ -51,19 +53,19 @@
be drag'n drop from LibraryPanel (default: False)
"""
wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
-
+
# Define LibraryPanel main sizer
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
# Add SearchCtrl to main sizer
self.SearchCtrl = wx.SearchCtrl(self)
# Add a button with a magnifying glass, essentially to show that this
# control is for searching in tree
self.SearchCtrl.ShowSearchButton(True)
self.Bind(wx.EVT_TEXT, self.OnSearchCtrlChanged, self.SearchCtrl)
- self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
+ self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
self.OnSearchButtonClick, self.SearchCtrl)
# Bind keyboard event on SearchCtrl text control to catch UP and DOWN
# for search previous and next occurrence
@@ -74,56 +76,56 @@
search_textctrl.Bind(wx.EVT_CHAR, self.OnKeyDown)
main_sizer.AddWindow(self.SearchCtrl, flag=wx.GROW)
-
+
# Add Splitter window for tree and block comment to main sizer
splitter_window = wx.SplitterWindow(self)
splitter_window.SetSashGravity(1.0)
main_sizer.AddWindow(splitter_window, flag=wx.GROW)
-
+
# Add TreeCtrl for functions and function blocks library in splitter
# window
self.Tree = wx.TreeCtrl(splitter_window,
- size=wx.Size(0, 0),
- style=wx.TR_HAS_BUTTONS|
- wx.TR_SINGLE|
- wx.SUNKEN_BORDER|
- wx.TR_HIDE_ROOT|
- wx.TR_LINES_AT_ROOT)
+ size=wx.Size(0, 0),
+ style=(wx.TR_HAS_BUTTONS |
+ wx.TR_SINGLE |
+ wx.SUNKEN_BORDER |
+ wx.TR_HIDE_ROOT |
+ wx.TR_LINES_AT_ROOT))
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemSelected, self.Tree)
self.Tree.Bind(wx.EVT_CHAR, self.OnKeyDown)
# If drag'n drop is enabled, bind event generated when a drag begins on
# tree to start a drag'n drop
if enable_drag:
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, self.Tree)
-
+
# Add TextCtrl for function and function block informations
- self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80),
- style=wx.TE_READONLY|wx.TE_MULTILINE)
-
+ self.Comment = wx.TextCtrl(splitter_window, size=wx.Size(0, 80),
+ style=wx.TE_READONLY | wx.TE_MULTILINE)
+
splitter_window.SplitHorizontally(self.Tree, self.Comment, -80)
-
+
self.SetSizer(main_sizer)
-
+
# Reference to the project controller
self.Controller = None
-
+
# Variable storing functions and function blocks library to display
self.BlockList = None
-
+
def __del__(self):
"""
Destructor
"""
# Remove reference to project controller
self.Controller = None
-
+
def SetController(self, controller):
"""
Set reference to project controller
@param controller: Reference to project controller
"""
self.Controller = controller
-
+
def SetBlockList(self, blocklist):
"""
Set function and function block library to display in TreeCtrl
@@ -133,15 +135,15 @@
self.BlockList = blocklist
# Refresh TreeCtrl values
self.RefreshTree()
-
+
def SetFocus(self):
"""
Called to give focus to LibraryPanel
- Override wx.Window SetFocus method
+ Override wx.Window SetFocus method
"""
# Give focus to SearchCtrl
self.SearchCtrl.SetFocus()
-
+
def ResetTree(self):
"""
Reset LibraryPanel values displayed in controls
@@ -150,7 +152,7 @@
self.SearchCtrl.SetValue("")
self.Tree.DeleteAllItems()
self.Comment.SetValue("")
-
+
def RefreshTree(self):
"""
Refresh LibraryPanel values displayed in controls
@@ -160,35 +162,35 @@
if blocktypes is None and self.Controller is not None:
# Get library from project controller if not defined
blocktypes = self.Controller.GetBlockTypes()
-
+
# Refresh TreeCtrl values if a library is defined
if blocktypes is not None:
# List that will contain tree items to be deleted when TreeCtrl
# will be refreshed
items_to_delete = []
-
+
# Get current selected item for selected it when values refreshed
selected_item = self.Tree.GetSelection()
selected_pydata = (self.Tree.GetPyData(selected_item)
- if selected_item.IsOk() and
- selected_item != self.Tree.GetRootItem()
+ if (selected_item.IsOk() and
+ selected_item != self.Tree.GetRootItem())
else None)
# Don't save selected item if it is a category
selected_infos = ((self.Tree.GetItemText(selected_item),
selected_pydata["inputs"])
- if selected_pydata is not None and
- selected_pydata["type"] == BLOCK
- else (None, None))
-
+ if (selected_pydata is not None and
+ selected_pydata["type"] == BLOCK)
+ else (None, None))
+
# Get TreeCtrl root item (hidden)
root = self.Tree.GetRootItem()
if not root.IsOk():
# Create root if not present
root = self.Tree.AddRoot("")
-
+
# Iterate over functions and function blocks library categories and
# add a tree item to root item for each of them
-
+
# Get first child under root item
category_item, root_cookie = self.Tree.GetFirstChild(root)
for category in blocktypes:
@@ -196,11 +198,11 @@
# extracting translated strings for gettext to consider "name"
# to be translated
category_name = category["name"]
-
+
# Tree item already exists, set item label
if category_item.IsOk():
self.Tree.SetItemText(category_item, _(category_name))
-
+
# Tree item doesn't exist, add new one to root
else:
category_item = self.Tree.AppendItem(root, _(category_name))
@@ -209,24 +211,24 @@
if wx.Platform != '__WXMSW__':
category_item, root_cookie = \
self.Tree.GetNextChild(root, root_cookie)
-
- # Set data associated to tree item (only save that item is a
+
+ # Set data associated to tree item (only save that item is a
# category)
- self.Tree.SetPyData(category_item, {"type" : CATEGORY})
-
+ self.Tree.SetPyData(category_item, {"type": CATEGORY})
+
# Iterate over functions and function blocks defined in library
- # category add a tree item to category tree item for each of
+ # category add a tree item to category tree item for each of
# them
-
+
# Get first child under category tree item
blocktype_item, category_cookie = \
self.Tree.GetFirstChild(category_item)
for blocktype in category["list"]:
-
+
# Tree item already exists, set item label
if blocktype_item.IsOk():
self.Tree.SetItemText(blocktype_item, blocktype["name"])
-
+
# Tree item doesn't exist, add new one to category item
else:
blocktype_item = self.Tree.AppendItem(
@@ -234,58 +236,58 @@
# See comment when adding category
if wx.Platform != '__WXMSW__':
blocktype_item, category_cookie = \
- self.Tree.GetNextChild(category_item,
+ self.Tree.GetNextChild(category_item,
category_cookie)
-
+
# Define data to associate to block tree item
comment = blocktype["comment"]
- block_data = {"type" : BLOCK,
- "block_type" : blocktype["type"],
- "inputs" : tuple([type
- for name, type, modifier
- in blocktype["inputs"]]),
- "extension" : (len(blocktype["inputs"])
- if blocktype["extensible"]
- else None),
- "comment": _(comment) +
- blocktype.get("usage", "")}
+ block_data = {
+ "type": BLOCK,
+ "block_type": blocktype["type"],
+ "inputs": tuple([type
+ for name, type, modifier
+ in blocktype["inputs"]]),
+ "extension": (len(blocktype["inputs"])
+ if blocktype["extensible"] else None),
+ "comment": _(comment) + blocktype.get("usage", "")
+ }
self.Tree.SetPyData(blocktype_item, block_data)
-
+
# Select block tree item in tree if it corresponds to
# previously selected one
- if selected_infos == (blocktype["name"],
+ if selected_infos == (blocktype["name"],
blocktype["inputs"]):
self.Tree.SelectItem(blocktype_item)
-
+
# Update TextCtrl value
self.Comment.SetValue(block_data["comment"])
-
+
# Get next block tree item under category tree item
blocktype_item, category_cookie = \
self.Tree.GetNextChild(category_item, category_cookie)
-
+
# Add every remaining tree item under category tree item after
# updating all block items to the list of items to delete
while blocktype_item.IsOk():
items_to_delete.append(blocktype_item)
blocktype_item, category_cookie = \
self.Tree.GetNextChild(category_item, category_cookie)
-
+
# Get next category tree item under root item
category_item, root_cookie = \
self.Tree.GetNextChild(root, root_cookie)
-
- # Add every remaining tree item under root item after updating all
+
+ # Add every remaining tree item under root item after updating all
# category items to the list of items to delete
while category_item.IsOk():
items_to_delete.append(category_item)
category_item, root_cookie = \
self.Tree.GetNextChild(root, root_cookie)
-
+
# Remove all items in list of items to delete from TreeCtrl
for item in items_to_delete:
self.Tree.Delete(item)
-
+
def GetSelectedBlock(self):
"""
Get selected block informations
@@ -295,20 +297,20 @@
# Get selected item associated data in tree
selected_item = self.Tree.GetSelection()
selected_pydata = (self.Tree.GetPyData(selected_item)
- if selected_item.IsOk() and
- selected_item != self.Tree.GetRootItem()
+ if (selected_item.IsOk() and
+ selected_item != self.Tree.GetRootItem())
else None)
-
+
# Return value is None if selected tree item is root or a category
- return ({"type": self.Tree.GetItemText(selected_item),
+ return ({"type": self.Tree.GetItemText(selected_item),
"inputs": selected_pydata["inputs"]}
- if selected_pydata is not None and
- selected_pydata["type"] == BLOCK
+ if (selected_pydata is not None and
+ selected_pydata["type"] == BLOCK)
else None)
-
+
def SelectTreeItem(self, name, inputs):
"""
- Select Tree item corresponding to block informations given
+ Select Tree item corresponding to block informations given
@param name: Block type name
@param inputs: List of block inputs type [input_type,...]
"""
@@ -318,8 +320,8 @@
# Select tree item found
self.Tree.SelectItem(item)
self.Tree.EnsureVisible(item)
-
- def FindTreeItem(self, item, name, inputs = None):
+
+ def FindTreeItem(self, item, name, inputs=None):
"""
Find Tree item corresponding to block informations given
Function is recursive
@@ -330,12 +332,12 @@
# Return immediately if item isn't valid
if not item.IsOk():
return None
-
+
# Get data associated to item to test
item_pydata = self.Tree.GetPyData(item)
if item_pydata is not None and item_pydata["type"] == BLOCK:
# Only test item corresponding to block
-
+
# Test if block inputs type are the same than those given
type_inputs = item_pydata.get("inputs", None)
type_extension = item_pydata.get("extension", None)
@@ -343,7 +345,7 @@
same_inputs = reduce(
lambda x, y: x and y,
map(
- lambda x: x[0]==x[1] or x[0]=='ANY' or x[1]=='ANY',
+ lambda x: x[0] == x[1] or x[0] == 'ANY' or x[1] == 'ANY',
zip(type_inputs,
(inputs[:type_extension]
if type_extension is not None
@@ -351,11 +353,11 @@
True)
else:
same_inputs = True
-
+
# Return item if block data corresponds to informations given
if self.Tree.GetItemText(item) == name and same_inputs:
return item
-
+
# Test item children if item doesn't correspond
child, child_cookie = self.Tree.GetFirstChild(item)
while child.IsOk():
@@ -363,9 +365,9 @@
if result:
return result
child, child_cookie = self.Tree.GetNextChild(item, child_cookie)
-
+
return None
-
+
def SearchInTree(self, value, mode="first"):
"""
Search in Tree and select item that name contains string given
@@ -378,13 +380,13 @@
root = self.Tree.GetRootItem()
if not root.IsOk():
return False
-
+
# Set function to navigate in Tree item sibling according to search
- # mode defined
+ # mode defined
sibling_function = (self.Tree.GetPrevSibling
if mode == "previous"
else self.Tree.GetNextSibling)
-
+
# Get current selected item (for next and previous mode)
item = self.Tree.GetSelection()
if not item.IsOk() or mode == "first":
@@ -392,29 +394,29 @@
selected = None
else:
selected = item
-
+
# Navigate through tree items until one matching found or reach tree
# starting or ending
while item.IsOk():
-
+
# Get item data to get item type
item_pydata = self.Tree.GetPyData(item)
-
+
# Item is a block category
if (item == root) or item_pydata["type"] == CATEGORY:
-
- # Get category first or last child according to search mode
+
+ # Get category first or last child according to search mode
# defined
child = (self.Tree.GetLastChild(item)
if mode == "previous"
else self.Tree.GetFirstChild(item)[0])
-
+
# If category has no child, go to sibling category
item = (child if child.IsOk() else sibling_function(item))
-
+
# Item is a block
else:
-
+
# Extract item block name
name = self.Tree.GetItemText(item)
# Test if block name contains string given
@@ -428,17 +430,17 @@
self.Tree.SelectItem(item)
self.Tree.EnsureVisible(item)
return True
-
+
# Go to next item sibling if block not found
next = sibling_function(item)
-
+
# If category has no other child, go to next category sibling
item = (next
if next.IsOk()
else sibling_function(self.Tree.GetItemParent(item)))
-
+
return False
-
+
def OnSearchCtrlChanged(self, event):
"""
Called when SearchCtrl text control value changed
@@ -447,7 +449,7 @@
# Search for block containing SearchCtrl value in 'first' mode
self.SearchInTree(self.SearchCtrl.GetValue())
event.Skip()
-
+
def OnSearchButtonClick(self, event):
"""
Called when SearchCtrl search button was clicked
@@ -456,7 +458,7 @@
# Search for block containing SearchCtrl value in 'next' mode
self.SearchInTree(self.SearchCtrl.GetValue(), "next")
event.Skip()
-
+
def OnTreeItemSelected(self, event):
"""
Called when tree item is selected
@@ -468,13 +470,13 @@
item_pydata["comment"]
if item_pydata is not None and item_pydata["type"] == BLOCK
else "")
-
+
# Call extra function defined when tree item is selected
if getattr(self, "_OnTreeItemSelected", None) is not None:
self._OnTreeItemSelected(event)
-
+
event.Skip()
-
+
def OnTreeBeginDrag(self, event):
"""
Called when a drag is started in tree
@@ -482,19 +484,19 @@
"""
selected_item = event.GetItem()
item_pydata = self.Tree.GetPyData(selected_item)
-
+
# Item dragged is a block
if item_pydata is not None and item_pydata["type"] == BLOCK:
# Start a drag'n drop
data = wx.TextDataObject(str(
- (self.Tree.GetItemText(selected_item),
- item_pydata["block_type"],
- "",
+ (self.Tree.GetItemText(selected_item),
+ item_pydata["block_type"],
+ "",
item_pydata["inputs"])))
dragSource = wx.DropSource(self.Tree)
dragSource.SetData(data)
dragSource.DoDragDrop()
-
+
def OnKeyDown(self, event):
"""
Called when key is pressed in SearchCtrl text control
@@ -503,17 +505,17 @@
# Get event keycode and value in SearchCtrl
keycode = event.GetKeyCode()
search_value = self.SearchCtrl.GetValue()
-
+
# Up key was pressed and SearchCtrl isn't empty, search for block in
- # 'previous' mode
+ # 'previous' mode
if keycode == wx.WXK_UP and search_value != "":
self.SearchInTree(search_value, "previous")
-
+
# Down key was pressed and SearchCtrl isn't empty, search for block in
- # 'next' mode
+ # 'next' mode
elif keycode == wx.WXK_DOWN and search_value != "":
self.SearchInTree(search_value, "next")
-
+
# Handle key normally
else:
event.Skip()
--- a/controls/LocationCellEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/LocationCellEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,32 +26,33 @@
from dialogs.BrowseLocationsDialog import BrowseLocationsDialog
+
class LocationCellControl(wx.PyControl):
-
+
'''
Custom cell editor control with a text box and a button that launches
the BrowseLocationsDialog.
'''
def __init__(self, parent):
wx.Control.__init__(self, parent)
-
+
main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
# create location text control
- self.Location = wx.TextCtrl(self, size=wx.Size(0, -1),
- style=wx.TE_PROCESS_ENTER)
+ self.Location = wx.TextCtrl(self, size=wx.Size(0, -1),
+ style=wx.TE_PROCESS_ENTER)
self.Location.Bind(wx.EVT_KEY_DOWN, self.OnLocationChar)
main_sizer.AddWindow(self.Location, flag=wx.GROW)
-
+
# create browse button
self.BrowseButton = wx.Button(self, label='...', size=wx.Size(30, -1))
self.BrowseButton.Bind(wx.EVT_BUTTON, self.OnBrowseButtonClick)
main_sizer.AddWindow(self.BrowseButton, flag=wx.GROW)
-
+
self.Bind(wx.EVT_SIZE, self.OnSize)
-
+
self.SetSizer(main_sizer)
self.Controller = None
@@ -73,7 +74,7 @@
def SetValue(self, value):
self.Default = value
self.Location.SetValue(value)
-
+
def GetValue(self):
return self.Location.GetValue()
@@ -88,15 +89,17 @@
else:
infos = None
dialog.Destroy()
-
+
if infos is not None:
location = infos["location"]
# set the location
if not infos["location"].startswith("%"):
- dialog = wx.SingleChoiceDialog(self,
- _("Select a variable class:"), _("Variable class"),
- [_("Input"), _("Output"), _("Memory")],
- wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(
+ self,
+ _("Select a variable class:"),
+ _("Variable class"),
+ [_("Input"), _("Output"), _("Memory")],
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetSelection()
else:
@@ -111,7 +114,7 @@
location = "%Q" + location
else:
location = "%M" + location
-
+
self.Location.SetValue(location)
self.VarType = infos["IEC_type"]
@@ -129,24 +132,25 @@
def SetInsertionPoint(self, i):
self.Location.SetInsertionPoint(i)
-
+
def SetFocus(self):
self.Location.SetFocus()
+
class LocationCellEditor(wx.grid.PyGridCellEditor):
'''
Grid cell editor that uses LocationCellControl to display a browse button.
'''
def __init__(self, table, controller):
wx.grid.PyGridCellEditor.__init__(self)
-
+
self.Table = table
self.Controller = controller
def __del__(self):
self.CellControl = None
self.Controller = None
-
+
def Create(self, parent, id, evt_handler):
self.CellControl = LocationCellControl(parent)
self.SetControl(self.CellControl)
@@ -169,20 +173,19 @@
self.Table.SetValueByName(row, 'Type', self.CellControl.GetVarType())
self.CellControl.Disable()
return changed
-
+
if wx.VERSION >= (3, 0, 0):
def EndEdit(self, row, col, grid, oldval):
return self.EndEditInternal(row, col, grid, oldval)
else:
def EndEdit(self, row, col, grid):
- old_loc = self.Table.GetValueByName(row, 'Location')
+ old_loc = self.Table.GetValueByName(row, 'Location')
return self.EndEditInternal(row, col, grid, old_loc)
-
+
def SetSize(self, rect):
self.CellControl.SetDimensions(rect.x + 1, rect.y,
- rect.width, rect.height,
- wx.SIZE_ALLOW_MINUS_ONE)
+ rect.width, rect.height,
+ wx.SIZE_ALLOW_MINUS_ONE)
def Clone(self):
return LocationCellEditor(self.Table, self.Controller)
-
--- a/controls/LogViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/LogViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -37,6 +37,7 @@
THUMB_SIZE_RATIO = 1. / 8.
+
def ArrowPoints(direction, width, height, xoffset, yoffset):
if direction == wx.TOP:
return [wx.Point(xoffset + 1, yoffset + height - 2),
@@ -47,6 +48,7 @@
wx.Point(xoffset + width / 2, yoffset - 2),
wx.Point(xoffset + width - 1, yoffset - height + 1)]
+
class LogScrollBar(wx.Panel):
def __init__(self, parent, size):
@@ -58,7 +60,7 @@
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_SIZE, self.OnResize)
- self.ThumbPosition = 0. # -1 <= ThumbPosition <= 1
+ self.ThumbPosition = 0. # -1 <= ThumbPosition <= 1
self.ThumbScrollingStartPos = None
def GetRangeRect(self):
@@ -177,8 +179,10 @@
dc.EndDrawing()
event.Skip()
+
BUTTON_SIZE = (70, 15)
+
class LogButton():
def __init__(self, label, callback):
@@ -217,12 +221,14 @@
w, h = dc.GetTextExtent(self.Label)
dc.DrawText(self.Label,
- self.Position.x + (self.Size.width - w) / 2,
- self.Position.y + (self.Size.height - h) / 2)
+ self.Position.x + (self.Size.width - w) / 2,
+ self.Position.y + (self.Size.height - h) / 2)
+
DATE_INFO_SIZE = 10
MESSAGE_INFO_SIZE = 18
+
class LogMessage:
def __init__(self, tv_sec, tv_nsec, level, level_bitmap, msg):
@@ -271,6 +277,7 @@
return DATE_INFO_SIZE + MESSAGE_INFO_SIZE
return MESSAGE_INFO_SIZE
+
SECOND = 1
MINUTE = 60 * SECOND
HOUR = 60 * MINUTE
@@ -281,10 +288,11 @@
(_("1m"), MINUTE),
(_("1s"), SECOND)]
+
class LogViewer(DebugViewer, wx.Panel):
def __init__(self, parent, window):
- wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER)
+ wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL | wx.SUNKEN_BORDER)
DebugViewer.__init__(self, None, False, False)
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
@@ -292,7 +300,7 @@
main_sizer.AddGrowableRow(1)
filter_sizer = wx.BoxSizer(wx.HORIZONTAL)
- main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
+ main_sizer.AddSizer(filter_sizer, border=5, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)
self.MessageFilter = wx.ComboBox(self, style=wx.CB_READONLY)
self.MessageFilter.Append(_("All"))
@@ -301,20 +309,20 @@
for level in levels:
self.MessageFilter.Append(_(level))
self.Bind(wx.EVT_COMBOBOX, self.OnMessageFilterChanged, self.MessageFilter)
- filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+ filter_sizer.AddWindow(self.MessageFilter, 1, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)
self.SearchMessage = wx.SearchCtrl(self, style=wx.TE_PROCESS_ENTER)
self.SearchMessage.ShowSearchButton(True)
self.SearchMessage.ShowCancelButton(True)
self.Bind(wx.EVT_TEXT_ENTER, self.OnSearchMessageChanged, self.SearchMessage)
self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN,
- self.OnSearchMessageSearchButtonClick, self.SearchMessage)
+ self.OnSearchMessageSearchButtonClick, self.SearchMessage)
self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN,
- self.OnSearchMessageCancelButtonClick, self.SearchMessage)
- filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+ self.OnSearchMessageCancelButtonClick, self.SearchMessage)
+ filter_sizer.AddWindow(self.SearchMessage, 3, border=5, flag=wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)
self.CleanButton = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap("Clean"),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
self.CleanButton.SetToolTipString(_("Clean log messages"))
self.Bind(wx.EVT_BUTTON, self.OnCleanButton, self.CleanButton)
filter_sizer.AddWindow(self.CleanButton)
@@ -322,7 +330,7 @@
message_panel_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
message_panel_sizer.AddGrowableCol(0)
message_panel_sizer.AddGrowableRow(0)
- main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)
+ main_sizer.AddSizer(message_panel_sizer, border=5, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)
self.MessagePanel = wx.Panel(self)
if wx.Platform == '__WXMSW__':
@@ -403,7 +411,7 @@
def ResetLogCounters(self):
self.previous_log_count = [None]*LogLevelsCount
-
+
def SetLogCounters(self, log_count):
new_messages = []
for level, count, prev in zip(xrange(LogLevelsCount), log_count, self.previous_log_count):
@@ -413,7 +421,7 @@
oldest_message = (-1, None)
else:
dump_end = prev - 1
- for msgidx in xrange(count-1, dump_end,-1):
+ for msgidx in xrange(count-1, dump_end, -1):
new_message = self.GetLogMessageFromSource(msgidx, level)
if new_message is None:
if prev is None:
@@ -553,13 +561,13 @@
self.MessageScrollBar.RefreshThumbPosition()
def IsPLCLogEmpty(self):
- empty=True
+ empty = True
for level, prev in zip(xrange(LogLevelsCount), self.previous_log_count):
if prev is not None:
- empty=False
+ empty = False
break
return empty
-
+
def IsMessagePanelTop(self, message_idx=None):
if message_idx is None:
message_idx = self.CurrentMessage
--- a/controls/PouInstanceVariablesPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/PouInstanceVariablesPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,15 +28,32 @@
import wx.lib.agw.customtreectrl as CT
import wx.lib.buttons
+from PLCControler import \
+ ITEMS_VARIABLE, \
+ ITEM_CONFIGURATION, \
+ ITEM_RESOURCE, \
+ ITEM_POU, \
+ ITEM_TRANSITION, \
+ ITEM_ACTION
+
+from util.BitmapLibrary import GetBitmap
+
+
# Customize CustomTreeItem for adding icon on item right
CT.GenericTreeItem._rightimages = []
+
def SetRightImages(self, images):
self._rightimages = images
+
+
CT.GenericTreeItem.SetRightImages = SetRightImages
+
def GetRightImages(self):
return self._rightimages
+
+
CT.GenericTreeItem.GetRightImages = GetRightImages
@@ -59,14 +76,14 @@
w, h = self.GetClientSize()
total_h = self.GetLineHeight(item)
r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0])
-
+
bbox_width = (r_image_w + 4) * len(rightimages) + 4
bbox_height = r_image_h + 8
bbox_x = w - bbox_width
bbox_y = item.GetY() + ((total_h > r_image_h) and [(total_h-r_image_h)/2] or [0])[0]
-
+
return wx.Rect(bbox_x, bbox_y, bbox_width, bbox_height)
-
+
return None
def IsOverItemRightImage(self, item, point):
@@ -75,30 +92,30 @@
point = self.CalcUnscrolledPosition(point)
r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0])
images_bbx = self.GetItemRightImagesBBox(item)
-
+
rect = wx.Rect(images_bbx.x + 4, images_bbx.y + 4,
r_image_w, r_image_h)
for r_image in rightimages:
if rect.Inside(point):
return r_image
rect.x += r_image_w + 4
-
+
return None
-
+
def PaintItem(self, item, dc, level, align):
CT.CustomTreeCtrl.PaintItem(self, item, dc, level, align)
-
+
rightimages = item.GetRightImages()
if len(rightimages) > 0:
images_bbx = self.GetItemRightImagesBBox(item)
r_image_w, r_image_h = self._imageListRight.GetSize(rightimages[0])
-
+
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetPen(wx.TRANSPARENT_PEN)
-
+
bg_width = (r_image_w + 4) * len(rightimages) + 4
bg_height = r_image_h + 8
- dc.DrawRectangle(images_bbx.x, images_bbx.y,
+ dc.DrawRectangle(images_bbx.x, images_bbx.y,
images_bbx.width, images_bbx.height)
x_pos = images_bbx.x + 4
for r_image in rightimages:
@@ -106,98 +123,98 @@
r_image, dc, x_pos, images_bbx.y + 4,
wx.IMAGELIST_DRAW_TRANSPARENT)
x_pos += r_image_w + 4
-
+
+
_ButtonCallbacks = namedtuple("ButtonCallbacks", ["leftdown", "dclick"])
-from PLCControler import ITEMS_VARIABLE, ITEM_CONFIGURATION, ITEM_RESOURCE, ITEM_POU, ITEM_TRANSITION, ITEM_ACTION
-from util.BitmapLibrary import GetBitmap
class PouInstanceVariablesPanel(wx.Panel):
def __init__(self, parent, window, controller, debug):
- wx.Panel.__init__(self, name='PouInstanceTreePanel',
- parent=parent, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
-
- self.ParentButton = wx.lib.buttons.GenBitmapButton(self,
- bitmap=GetBitmap("top"), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ wx.Panel.__init__(self, name='PouInstanceTreePanel',
+ parent=parent, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+ self.ParentButton = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap("top"), size=wx.Size(28, 28), style=wx.NO_BORDER)
self.ParentButton.SetToolTipString(_("Parent instance"))
- self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick,
- self.ParentButton)
-
+ self.Bind(wx.EVT_BUTTON, self.OnParentButtonClick,
+ self.ParentButton)
+
self.InstanceChoice = wx.ComboBox(self, size=wx.Size(0, 0), style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnInstanceChoiceChanged,
- self.InstanceChoice)
-
- self.DebugButton = wx.lib.buttons.GenBitmapButton(self,
- bitmap=GetBitmap("debug_instance"), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ self.InstanceChoice)
+
+ self.DebugButton = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap("debug_instance"), size=wx.Size(28, 28), style=wx.NO_BORDER)
self.DebugButton.SetToolTipString(_("Debug instance"))
- self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick,
- self.DebugButton)
-
- self.VariablesList = CustomTreeCtrlWithRightImage(self,
- style=wx.SUNKEN_BORDER,
- agwStyle=CT.TR_NO_BUTTONS|
- CT.TR_SINGLE|
- CT.TR_HAS_VARIABLE_ROW_HEIGHT|
- CT.TR_HIDE_ROOT|
- CT.TR_NO_LINES|
- getattr(CT, "TR_ALIGN_WINDOWS_RIGHT", CT.TR_ALIGN_WINDOWS))
+ self.Bind(wx.EVT_BUTTON, self.OnDebugButtonClick,
+ self.DebugButton)
+
+ self.VariablesList = CustomTreeCtrlWithRightImage(
+ self,
+ style=wx.SUNKEN_BORDER,
+ agwStyle=(CT.TR_NO_BUTTONS |
+ CT.TR_SINGLE |
+ CT.TR_HAS_VARIABLE_ROW_HEIGHT |
+ CT.TR_HIDE_ROOT |
+ CT.TR_NO_LINES |
+ getattr(CT, "TR_ALIGN_WINDOWS_RIGHT", CT.TR_ALIGN_WINDOWS)))
self.VariablesList.SetIndent(0)
self.VariablesList.SetSpacing(5)
- self.VariablesList.DoSelectItem = lambda *x,**y:True
+ self.VariablesList.DoSelectItem = lambda *x, **y: True
self.VariablesList.Bind(CT.EVT_TREE_ITEM_ACTIVATED,
- self.OnVariablesListItemActivated)
+ self.OnVariablesListItemActivated)
self.VariablesList.Bind(wx.EVT_LEFT_DOWN, self.OnVariablesListLeftDown)
self.VariablesList.Bind(wx.EVT_KEY_DOWN, self.OnVariablesListKeyDown)
-
+
self.TreeRightImageList = wx.ImageList(24, 24)
self.EditImage = self.TreeRightImageList.Add(GetBitmap("edit"))
self.DebugInstanceImage = self.TreeRightImageList.Add(GetBitmap("debug_instance"))
self.VariablesList.SetRightImageList(self.TreeRightImageList)
-
+
self.ButtonCallBacks = {
self.EditImage: _ButtonCallbacks(
self.EditButtonCallback, None),
self.DebugInstanceImage: _ButtonCallbacks(
self.DebugButtonCallback, self.DebugButtonDClickCallback)}
-
+
buttons_sizer = wx.FlexGridSizer(cols=3, hgap=0, rows=1, vgap=0)
buttons_sizer.AddWindow(self.ParentButton)
buttons_sizer.AddWindow(self.InstanceChoice, flag=wx.GROW)
buttons_sizer.AddWindow(self.DebugButton)
buttons_sizer.AddGrowableCol(1)
buttons_sizer.AddGrowableRow(0)
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
main_sizer.AddSizer(buttons_sizer, flag=wx.GROW)
main_sizer.AddWindow(self.VariablesList, flag=wx.GROW)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
self.SetSizer(main_sizer)
-
+
self.ParentWindow = window
self.Controller = controller
self.Debug = debug
if not self.Debug:
self.DebugButton.Hide()
-
+
self.PouTagName = None
self.PouInfos = None
self.PouInstance = None
-
+
def __del__(self):
self.Controller = None
-
+
def SetTreeImageList(self, tree_image_list):
self.VariablesList.SetImageList(tree_image_list)
-
+
def SetController(self, controller):
self.Controller = controller
-
+
self.RefreshView()
-
+
def SetPouType(self, tagname, pou_instance=None):
if self.Controller is not None:
if tagname == "Project":
@@ -206,7 +223,7 @@
tagname = self.Controller.ComputeConfigurationName(config_name)
if pou_instance is not None:
self.PouInstance = pou_instance
-
+
if self.PouTagName != tagname:
self.PouTagName = tagname
self.RefreshView()
@@ -214,20 +231,20 @@
self.RefreshInstanceChoice()
else:
self.RefreshView()
-
+
def ResetView(self):
self.Controller = None
-
+
self.PouTagName = None
self.PouInfos = None
self.PouInstance = None
-
+
self.RefreshView()
-
+
def RefreshView(self):
self.Freeze()
self.VariablesList.DeleteAllItems()
-
+
if self.Controller is not None and self.PouTagName is not None:
if self.PouTagName.split('::')[0] in ['A', 'T']:
self.PouInfos = self.Controller.GetPouVariables('P::%s' % self.PouTagName.split('::')[1], self.Debug)
@@ -244,24 +261,24 @@
text = "%s (%s)" % (var_infos.name, var_infos.type)
else:
text = var_infos.name
-
+
right_images = []
if var_infos.edit:
right_images.append(self.EditImage)
-
+
if var_infos.debug and self.Debug:
right_images.append(self.DebugInstanceImage)
-
+
item = self.VariablesList.AppendItem(root, text)
item.SetRightImages(right_images)
self.VariablesList.SetItemImage(item, self.ParentWindow.GetTreeImage(var_infos.var_class))
self.VariablesList.SetPyData(item, var_infos)
-
+
self.RefreshInstanceChoice()
self.RefreshButtons()
-
+
self.Thaw()
-
+
def RefreshInstanceChoice(self):
self.InstanceChoice.Clear()
self.InstanceChoice.SetValue("")
@@ -279,12 +296,12 @@
else:
self.PouInstance = None
self.InstanceChoice.SetValue(_("Select an instance"))
-
+
def RefreshButtons(self):
enabled = self.InstanceChoice.GetSelection() != -1
self.ParentButton.Enable(enabled and self.PouInfos.var_class != ITEM_CONFIGURATION)
self.DebugButton.Enable(enabled and self.PouInfos.debug and self.Debug)
-
+
root = self.VariablesList.GetRootItem()
if root is not None and root.IsOk():
item, item_cookie = self.VariablesList.GetFirstChild(root)
@@ -295,12 +312,12 @@
if child.GetName() != "edit":
child.Enable(enabled)
item, item_cookie = self.VariablesList.GetNextChild(root, item_cookie)
-
+
def EditButtonCallback(self, infos):
var_class = infos.var_class
if var_class == ITEM_RESOURCE:
tagname = self.Controller.ComputeConfigurationResourceName(
- self.InstanceChoice.GetStringSelection(),
+ self.InstanceChoice.GetStringSelection(),
infos.name)
elif var_class == ITEM_TRANSITION:
tagname = self.Controller.ComputePouTransitionName(
@@ -314,7 +331,7 @@
var_class = ITEM_POU
tagname = self.Controller.ComputePouName(infos.type)
self.ParentWindow.EditProjectElement(var_class, tagname)
-
+
def DebugButtonCallback(self, infos):
if self.InstanceChoice.GetSelection() != -1:
var_class = infos.var_class
@@ -344,16 +361,16 @@
var_class,
var_path,
self.Controller.ComputePouName(infos.type))
-
+
def DebugButtonDClickCallback(self, infos):
if self.InstanceChoice.GetSelection() != -1:
if infos.var_class in ITEMS_VARIABLE:
self.ParentWindow.AddDebugVariable(
- "%s.%s" % (self.InstanceChoice.GetStringSelection(),
- infos.name),
+ "%s.%s" % (self.InstanceChoice.GetStringSelection(),
+ infos.name),
force=True,
graph=True)
-
+
def ShowInstanceChoicePopup(self):
self.InstanceChoice.SetFocusFromKbd()
size = self.InstanceChoice.GetSize()
@@ -361,10 +378,10 @@
event.x = size.width / 2
event.y = size.height / 2
event.SetEventObject(self.InstanceChoice)
- #event = wx.KeyEvent(wx.EVT_KEY_DOWN._getEvtType())
- #event.m_keyCode = wx.WXK_SPACE
+ # event = wx.KeyEvent(wx.EVT_KEY_DOWN._getEvtType())
+ # event.m_keyCode = wx.WXK_SPACE
self.InstanceChoice.GetEventHandler().ProcessEvent(event)
-
+
def OnParentButtonClick(self, event):
if self.InstanceChoice.GetSelection() != -1:
parent_path = self.InstanceChoice.GetStringSelection().rsplit(".", 1)[0]
@@ -373,11 +390,11 @@
wx.CallAfter(self.SetPouType, tagname, parent_path)
wx.CallAfter(self.ParentWindow.SelectProjectTreeItem, tagname)
event.Skip()
-
+
def OnInstanceChoiceChanged(self, event):
self.RefreshButtons()
event.Skip()
-
+
def OnDebugButtonClick(self, event):
if self.InstanceChoice.GetSelection() != -1:
self.ParentWindow.OpenDebugViewer(
@@ -385,26 +402,26 @@
self.InstanceChoice.GetStringSelection(),
self.PouTagName)
event.Skip()
-
+
def OnVariablesListItemActivated(self, event):
selected_item = event.GetItem()
if selected_item is not None and selected_item.IsOk():
item_infos = self.VariablesList.GetPyData(selected_item)
if item_infos is not None:
-
+
item_button = self.VariablesList.IsOverItemRightImage(
selected_item, event.GetPoint())
if item_button is not None:
callback = self.ButtonCallBacks[item_button].dclick
if callback is not None:
callback(item_infos)
-
+
elif item_infos.var_class not in ITEMS_VARIABLE:
instance_path = self.InstanceChoice.GetStringSelection()
if item_infos.var_class == ITEM_RESOURCE:
if instance_path != "":
tagname = self.Controller.ComputeConfigurationResourceName(
- instance_path,
+ instance_path,
item_infos.name)
else:
tagname = None
@@ -424,7 +441,7 @@
self.SetPouType(tagname, item_path)
self.ParentWindow.SelectProjectTreeItem(tagname)
event.Skip()
-
+
def OnVariablesListLeftDown(self, event):
if self.InstanceChoice.GetSelection() == -1:
wx.CallAfter(self.ShowInstanceChoicePopup)
@@ -434,15 +451,15 @@
if item is not None:
item_infos = self.VariablesList.GetPyData(item)
if item_infos is not None:
-
+
item_button = self.VariablesList.IsOverItemRightImage(
item, event.GetPosition())
if item_button is not None:
callback = self.ButtonCallBacks[item_button].leftdown
if callback is not None:
callback(item_infos)
-
- elif (flags & CT.TREE_HITTEST_ONITEMLABEL and
+
+ elif (flags & CT.TREE_HITTEST_ONITEMLABEL and
item_infos.var_class in ITEMS_VARIABLE):
self.ParentWindow.EnsureTabVisible(
self.ParentWindow.DebugVariablePanel)
@@ -457,4 +474,3 @@
keycode = event.GetKeyCode()
if keycode != wx.WXK_LEFT:
event.Skip()
-
--- a/controls/ProjectPropertiesPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/ProjectPropertiesPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,22 +25,25 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
REQUIRED_PARAMS = ["projectName", "productName", "productVersion", "companyName"]
-[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
- POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
+[
+ TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
+ POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
] = range(10)
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Project Properties Panel
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ProjectPropertiesPanel(wx.Notebook):
-
+
def AddSizerParams(self, parent, sizer, params):
for idx, (name, label) in enumerate(params):
border = 0
@@ -48,18 +51,18 @@
border |= wx.TOP
elif idx == len(params) - 1:
border |= wx.BOTTOM
-
+
st = wx.StaticText(parent, label=label)
- sizer.AddWindow(st, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT)
-
+ sizer.AddWindow(st, border=10,
+ flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT)
+
tc = wx.TextCtrl(parent, style=wx.TE_PROCESS_ENTER)
setattr(self, name, tc)
callback = self.GetTextCtrlChangedFunction(tc, name)
self.Bind(wx.EVT_TEXT_ENTER, callback, tc)
tc.Bind(wx.EVT_KILL_FOCUS, callback)
- sizer.AddWindow(tc, border=10,
- flag=wx.GROW|border|wx.RIGHT)
+ sizer.AddWindow(tc, border=10,
+ flag=wx.GROW | border | wx.RIGHT)
def __init__(self, parent, controller=None, window=None, enable_required=True):
wx.Notebook.__init__(self, parent)
@@ -67,36 +70,36 @@
self.Controller = controller
self.ParentWindow = window
self.Values = None
-
+
# Project Panel elements
self.ProjectPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
projectpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=5, vgap=15)
projectpanel_sizer.AddGrowableCol(1)
self.ProjectPanel.SetSizer(projectpanel_sizer)
-
+
self.AddSizerParams(self.ProjectPanel, projectpanel_sizer,
- [("projectName", _('Project Name (required):')),
- ("projectVersion", _('Project Version (optional):')),
- ("productName", _('Product Name (required):')),
- ("productVersion", _('Product Version (required):')),
- ("productRelease", _('Product Release (optional):'))])
-
+ [("projectName", _('Project Name (required):')),
+ ("projectVersion", _('Project Version (optional):')),
+ ("productName", _('Product Name (required):')),
+ ("productVersion", _('Product Version (required):')),
+ ("productRelease", _('Product Release (optional):'))])
+
self.AddPage(self.ProjectPanel, _("Project"))
-
+
# Author Panel elements
self.AuthorPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
authorpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=4, vgap=15)
authorpanel_sizer.AddGrowableCol(1)
self.AuthorPanel.SetSizer(authorpanel_sizer)
-
+
self.AddSizerParams(self.AuthorPanel, authorpanel_sizer,
- [("companyName", _('Company Name (required):')),
- ("companyURL", _('Company URL (optional):')),
- ("authorName", _('Author Name (optional):')),
- ("organization", _('Organization (optional):'))])
-
+ [("companyName", _('Company Name (required):')),
+ ("companyURL", _('Company URL (optional):')),
+ ("authorName", _('Author Name (optional):')),
+ ("organization", _('Organization (optional):'))])
+
self.AddPage(self.AuthorPanel, _("Author"))
# Graphics Panel elements
@@ -106,47 +109,48 @@
graphicpanel_sizer.AddGrowableCol(0)
graphicpanel_sizer.AddGrowableRow(3)
self.GraphicsPanel.SetSizer(graphicpanel_sizer)
-
+
pageSize_st = wx.StaticText(self.GraphicsPanel,
- label=_('Page Size (optional):'))
- graphicpanel_sizer.AddWindow(pageSize_st, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ label=_('Page Size (optional):'))
+ graphicpanel_sizer.AddWindow(
+ pageSize_st, border=10,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT | wx.RIGHT)
+
pageSize_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
pageSize_sizer.AddGrowableCol(1)
- graphicpanel_sizer.AddSizer(pageSize_sizer, border=10,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
+ graphicpanel_sizer.AddSizer(pageSize_sizer, border=10,
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
for name, label in [('PageWidth', _('Width:')),
('PageHeight', _('Height:'))]:
st = wx.StaticText(self.GraphicsPanel, label=label)
- pageSize_sizer.AddWindow(st, border=12,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT)
-
- sp = wx.SpinCtrl(self.GraphicsPanel,
- min=0, max=2**16, style=wx.TE_PROCESS_ENTER)
+ pageSize_sizer.AddWindow(st, border=12,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT)
+
+ sp = wx.SpinCtrl(self.GraphicsPanel,
+ min=0, max=2**16, style=wx.TE_PROCESS_ENTER)
setattr(self, name, sp)
callback = self.GetPageSizeChangedFunction(sp, name)
self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
sp.Bind(wx.EVT_KILL_FOCUS, callback)
pageSize_sizer.AddWindow(sp, flag=wx.GROW)
-
+
scaling_st = wx.StaticText(self.GraphicsPanel,
- label=_('Grid Resolution:'))
- graphicpanel_sizer.AddWindow(scaling_st, border=10,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
+ label=_('Grid Resolution:'))
+ graphicpanel_sizer.AddWindow(scaling_st, border=10,
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
scaling_nb = wx.Notebook(self.GraphicsPanel)
- graphicpanel_sizer.AddWindow(scaling_nb, border=10,
- flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ graphicpanel_sizer.AddWindow(scaling_nb, border=10,
+ flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.Scalings = {}
- for language, translation in [("FBD",_("FBD")), ("LD",_("LD")), ("SFC",_("SFC"))]:
+ for language, translation in [("FBD", _("FBD")), ("LD", _("LD")), ("SFC", _("SFC"))]:
scaling_panel = wx.Panel(scaling_nb, style=wx.TAB_TRAVERSAL)
scalingpanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
scalingpanel_sizer.AddGrowableCol(1)
scaling_panel.SetSizer(scalingpanel_sizer)
-
+
scaling_controls = []
for idx, (name, label) in enumerate([('XScale', _('Horizontal:')),
('YScale', _('Vertical:'))]):
@@ -154,67 +158,69 @@
border = wx.TOP
else:
border = wx.BOTTOM
-
+
st = wx.StaticText(scaling_panel, label=label)
- scalingpanel_sizer.AddWindow(st, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL|border|wx.LEFT)
-
- sp = wx.SpinCtrl(scaling_panel,
- min=0, max=2**16, style=wx.TE_PROCESS_ENTER)
+ scalingpanel_sizer.AddWindow(
+ st, border=10,
+ flag=wx.ALIGN_CENTER_VERTICAL | border | wx.LEFT)
+
+ sp = wx.SpinCtrl(scaling_panel,
+ min=0, max=2**16, style=wx.TE_PROCESS_ENTER)
scaling_controls.append(sp)
callback = self.GetScalingChangedFunction(sp, language, name)
self.Bind(wx.EVT_TEXT_ENTER, callback, sp)
sp.Bind(wx.EVT_KILL_FOCUS, callback)
- scalingpanel_sizer.AddWindow(sp, border=10,
- flag=wx.GROW|border|wx.RIGHT)
-
+ scalingpanel_sizer.AddWindow(sp, border=10,
+ flag=wx.GROW | border | wx.RIGHT)
+
self.Scalings[language] = scaling_controls
scaling_nb.AddPage(scaling_panel, translation)
-
+
self.AddPage(self.GraphicsPanel, _("Graphics"))
# Miscellaneous Panel elements
- self.MiscellaneousPanel = wx.Panel(id=-1, parent=self,
- name='MiscellaneousPanel', pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+ self.MiscellaneousPanel = wx.Panel(
+ id=-1, parent=self, name='MiscellaneousPanel', pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
miscellaneouspanel_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=15)
miscellaneouspanel_sizer.AddGrowableCol(1)
miscellaneouspanel_sizer.AddGrowableRow(1)
self.MiscellaneousPanel.SetSizer(miscellaneouspanel_sizer)
-
+
language_label = wx.StaticText(self.MiscellaneousPanel,
- label=_('Language (optional):'))
- miscellaneouspanel_sizer.AddWindow(language_label, border=10,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP|wx.LEFT)
-
- self.Language = wx.ComboBox(self.MiscellaneousPanel,
- style=wx.CB_READONLY)
+ label=_('Language (optional):'))
+ miscellaneouspanel_sizer.AddWindow(language_label, border=10,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.LEFT)
+
+ self.Language = wx.ComboBox(self.MiscellaneousPanel,
+ style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnLanguageChanged, self.Language)
- miscellaneouspanel_sizer.AddWindow(self.Language, border=10,
- flag=wx.GROW|wx.TOP|wx.RIGHT)
-
- description_label = wx.StaticText(self.MiscellaneousPanel,
- label=_('Content Description (optional):'))
- miscellaneouspanel_sizer.AddWindow(description_label, border=10,
- flag=wx.BOTTOM|wx.LEFT)
-
- self.ContentDescription = wx.TextCtrl(self.MiscellaneousPanel,
- size=wx.Size(240,150), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER)
- self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged,
- self.ContentDescription)
- self.ContentDescription.Bind(wx.EVT_KILL_FOCUS,
- self.OnContentDescriptionChanged)
- miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10,
- flag=wx.GROW|wx.BOTTOM|wx.RIGHT)
-
+ miscellaneouspanel_sizer.AddWindow(self.Language, border=10,
+ flag=wx.GROW | wx.TOP | wx.RIGHT)
+
+ description_label = wx.StaticText(
+ self.MiscellaneousPanel, label=_('Content Description (optional):'))
+ miscellaneouspanel_sizer.AddWindow(description_label, border=10,
+ flag=wx.BOTTOM | wx.LEFT)
+
+ self.ContentDescription = wx.TextCtrl(
+ self.MiscellaneousPanel, size=wx.Size(240, 150),
+ style=wx.TE_MULTILINE | wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_TEXT_ENTER, self.OnContentDescriptionChanged,
+ self.ContentDescription)
+ self.ContentDescription.Bind(wx.EVT_KILL_FOCUS,
+ self.OnContentDescriptionChanged)
+ miscellaneouspanel_sizer.AddWindow(self.ContentDescription, border=10,
+ flag=wx.GROW | wx.BOTTOM | wx.RIGHT)
+
self.AddPage(self.MiscellaneousPanel, _("Miscellaneous"))
-
+
for param in REQUIRED_PARAMS:
getattr(self, param).Enable(enable_required)
-
+
languages = ["", "en-US", "fr-FR", "zh-CN", "ru-RU"]
-
+
for language in languages:
self.Language.Append(language)
@@ -241,13 +247,13 @@
tc = getattr(self, item, None)
if tc is not None:
tc.SetValue(value)
-
+
def GetValues(self):
values = {}
for param in ["projectName", "projectVersion",
"productName", "productVersion",
"productRelease", "companyName",
- "companyURL", "authorName",
+ "companyURL", "authorName",
"organization"]:
value = getattr(self, param).GetValue()
if param in REQUIRED_PARAMS or value != "":
@@ -270,7 +276,7 @@
values["scaling"][language] = (self.Scalings[language][0].GetValue(),
self.Scalings[language][1].GetValue())
return values
-
+
def GetTextCtrlChangedFunction(self, textctrl, name):
def TextCtrlChangedFunction(event):
if self.Controller is not None and self.Values is not None:
@@ -281,7 +287,7 @@
if old_value != new_value:
self.Controller.SetProjectProperties(properties={name: new_value})
self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU,
- PROJECTTREE, PAGETITLES)
+ PROJECTTREE, PAGETITLES)
wx.CallAfter(self.RefreshView)
event.Skip()
return TextCtrlChangedFunction
@@ -300,11 +306,11 @@
if old_value != new_value:
self.Controller.SetProjectProperties(properties={"pageSize": new_value})
self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU,
- PAGETITLES, SCALING)
+ PAGETITLES, SCALING)
wx.CallAfter(self.RefreshView)
event.Skip()
return PageSizeChangedFunction
-
+
def GetScalingChangedFunction(self, spinctrl, language, name):
def ScalingChangedFunction(event):
if self.Controller is not None:
@@ -320,11 +326,11 @@
if old_value != new_value:
self.Controller.SetProjectProperties(properties={"scaling": {language: new_value}})
self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU,
- PAGETITLES, SCALING)
+ PAGETITLES, SCALING)
wx.CallAfter(self.RefreshView)
event.Skip()
return ScalingChangedFunction
-
+
def OnLanguageChanged(self, event):
if self.Controller is not None:
if self.Values is not None:
@@ -339,7 +345,7 @@
self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
wx.CallAfter(self.RefreshView)
event.Skip()
-
+
def OnContentDescriptionChanged(self, event):
if self.Controller is not None:
if self.Values is not None:
--- a/controls/SearchResultPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/SearchResultPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -31,6 +31,7 @@
from PLCControler import *
from util.BitmapLibrary import GetBitmap
+
def GenerateName(infos):
if infos[0] in ["input", "output", "value"]:
return "%s %d:" % (infos[0], infos[1])
@@ -40,18 +41,22 @@
return "element %d %s" % (infos[1], infos[2])
return "%s:" % infos[0]
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Search Result Panel
-#-------------------------------------------------------------------------------
-
-[ID_SEARCHRESULTPANEL, ID_SEARCHRESULTPANELHEADERLABEL,
- ID_SEARCHRESULTPANELSEARCHRESULTSTREE, ID_SEARCHRESULTPANELRESETBUTTON,
+# -------------------------------------------------------------------------------
+
+
+[
+ ID_SEARCHRESULTPANEL, ID_SEARCHRESULTPANELHEADERLABEL,
+ ID_SEARCHRESULTPANELSEARCHRESULTSTREE, ID_SEARCHRESULTPANELRESETBUTTON,
] = [wx.NewId() for _init_ctrls in range(4)]
+
class SearchResultPanel(wx.Panel):
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
@@ -60,109 +65,110 @@
def _init_coll_MainSizer_Items(self, parent):
parent.AddSizer(self.HeaderSizer, 0, border=0, flag=wx.GROW)
parent.AddWindow(self.SearchResultsTree, 1, border=0, flag=wx.GROW)
-
+
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(1)
def _init_coll_HeaderSizer_Items(self, parent):
- parent.AddWindow(self.HeaderLabel, 1, border=5, flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+ parent.AddWindow(self.HeaderLabel, 1, border=5, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)
parent.AddWindow(self.ResetButton, 0, border=0, flag=0)
-
+
def _init_coll_HeaderSizer_Growables(self, parent):
parent.AddGrowableCol(0)
-
+
def _init_sizers(self):
self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=0)
self.HeaderSizer = wx.BoxSizer(wx.HORIZONTAL)
-
+
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self._init_coll_HeaderSizer_Items(self.HeaderSizer)
-
+
self.SetSizer(self.MainSizer)
def _init_ctrls(self, prnt):
wx.Panel.__init__(self, id=ID_SEARCHRESULTPANEL,
- name='SearchResultPanel', parent=prnt, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+ name='SearchResultPanel', parent=prnt, pos=wx.Point(0, 0),
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.HeaderLabel = wx.StaticText(id=ID_SEARCHRESULTPANELHEADERLABEL,
- name='HeaderLabel', parent=self,
- pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0)
-
- search_results_tree_style = CT.TR_HAS_BUTTONS|CT.TR_NO_LINES|CT.TR_HAS_VARIABLE_ROW_HEIGHT
+ name='HeaderLabel', parent=self,
+ pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0)
+
+ search_results_tree_style = CT.TR_HAS_BUTTONS | CT.TR_NO_LINES | CT.TR_HAS_VARIABLE_ROW_HEIGHT
self.SearchResultsTree = CT.CustomTreeCtrl(id=ID_SEARCHRESULTPANELSEARCHRESULTSTREE,
- name="SearchResultsTree", parent=self,
- pos=wx.Point(0, 0), style=search_results_tree_style)
+ name="SearchResultsTree", parent=self,
+ pos=wx.Point(0, 0), style=search_results_tree_style)
if wx.VERSION >= (2, 8, 11):
self.SearchResultsTree.SetAGWWindowStyleFlag(search_results_tree_style)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnSearchResultsTreeItemActivated,
- id=ID_SEARCHRESULTPANELSEARCHRESULTSTREE)
-
- self.ResetButton = wx.lib.buttons.GenBitmapButton(self,
- bitmap=GetBitmap("reset"), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ id=ID_SEARCHRESULTPANELSEARCHRESULTSTREE)
+
+ self.ResetButton = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap("reset"),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
self.ResetButton.SetToolTipString(_("Reset search result"))
self.Bind(wx.EVT_BUTTON, self.OnResetButton, self.ResetButton)
-
+
self._init_sizers()
def __init__(self, parent, window):
self.ParentWindow = window
-
+
self._init_ctrls(parent)
-
+
# Define Tree item icon list
self.TreeImageList = wx.ImageList(16, 16)
self.TreeImageDict = {}
-
+
# Icons for other items
for imgname, itemtype in [
- #editables
- ("PROJECT", ITEM_PROJECT),
- ("TRANSITION", ITEM_TRANSITION),
- ("ACTION", ITEM_ACTION),
- ("CONFIGURATION", ITEM_CONFIGURATION),
- ("RESOURCE", ITEM_RESOURCE),
- ("DATATYPE", ITEM_DATATYPE),
- ("ACTION", "action_block"),
- ("IL", "IL"),
- ("ST", "ST")]:
+ # editables
+ ("PROJECT", ITEM_PROJECT),
+ ("TRANSITION", ITEM_TRANSITION),
+ ("ACTION", ITEM_ACTION),
+ ("CONFIGURATION", ITEM_CONFIGURATION),
+ ("RESOURCE", ITEM_RESOURCE),
+ ("DATATYPE", ITEM_DATATYPE),
+ ("ACTION", "action_block"),
+ ("IL", "IL"),
+ ("ST", "ST")]:
self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
-
+
for itemtype in ["function", "functionBlock", "program",
"comment", "block", "io_variable",
"connector", "contact", "coil",
- "step", "transition", "jump",
- "var_local", "var_input",
+ "step", "transition", "jump",
+ "var_local", "var_input",
"var_inout", "var_output"]:
self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(itemtype.upper()))
-
+
# Assign icon list to TreeCtrl
self.SearchResultsTree.SetImageList(self.TreeImageList)
-
+
self.ResetSearchResults()
def SetSearchResults(self, criteria, search_results):
self.Criteria = criteria
self.SearchResults = {}
self.ElementsOrder = []
-
+
for infos, start, end, text in search_results:
if infos[0] not in self.ElementsOrder:
self.ElementsOrder.append(infos[0])
-
+
results = self.SearchResults.setdefault(infos[0], [])
results.append((infos, start, end, text))
-
+
self.RefreshView()
-
+
def ResetSearchResults(self):
self.Criteria = None
self.ElementsOrder = []
self.SearchResults = {}
self.RefreshView()
-
+
def RefreshView(self):
self.SearchResultsTree.DeleteAllItems()
if self.Criteria is None:
@@ -170,29 +176,30 @@
self.ResetButton.Enable(False)
else:
matches_number = 0
- search_results_tree_infos = {"name": _("Project '%s':") % self.ParentWindow.Controler.GetProjectName(),
- "type": ITEM_PROJECT,
- "data": None,
- "text": None,
- "matches": None,
- }
+ search_results_tree_infos = {
+ "name": _("Project '%s':") % self.ParentWindow.Controler.GetProjectName(),
+ "type": ITEM_PROJECT,
+ "data": None,
+ "text": None,
+ "matches": None,
+ }
search_results_tree_children = search_results_tree_infos.setdefault("children", [])
for tagname in self.ElementsOrder:
results = self.SearchResults.get(tagname, [])
matches_number += len(results)
-
+
words = tagname.split("::")
-
+
element_type = self.ParentWindow.Controler.GetElementType(tagname)
if element_type == ITEM_POU:
element_type = self.ParentWindow.Controler.GetPouType(words[1])
-
+
element_infos = {"name": words[-1],
"type": element_type,
"data": tagname,
"text": None,
"matches": len(results)}
-
+
children = element_infos.setdefault("children", [])
for infos, start, end, text in results:
if infos[1] == "name" or element_type == ITEM_DATATYPE:
@@ -215,15 +222,16 @@
child_type = self.ParentWindow.Controler.GetPouBodyType(words[1])
else:
child_name = GenerateName(infos[3:])
- child_infos = {"name": child_name,
- "type": child_type,
- "data": (infos, start, end ,None),
- "text": text,
- "matches": 1,
- "children": [],
- }
+ child_infos = {
+ "name": child_name,
+ "type": child_type,
+ "data": (infos, start, end, None),
+ "text": text,
+ "matches": 1,
+ "children": [],
+ }
children.append(child_infos)
-
+
if len(words) > 2:
for _element_infos in search_results_tree_children:
if _element_infos["name"] == words[1]:
@@ -234,41 +242,41 @@
search_results_tree_children.append(element_infos)
else:
search_results_tree_children.append(element_infos)
-
+
if matches_number < 2:
header_format = _("'{a1}' - {a2} match in project")
else:
header_format = _("'{a1}' - {a2} matches in project")
-
- self.HeaderLabel.SetLabel(header_format.format(a1 = self.Criteria["find_pattern"], a2 = matches_number))
+
+ self.HeaderLabel.SetLabel(header_format.format(a1=self.Criteria["find_pattern"], a2=matches_number))
self.ResetButton.Enable(True)
-
+
if matches_number > 0:
root = self.SearchResultsTree.GetRootItem()
if root is None:
root = self.SearchResultsTree.AddRoot(search_results_tree_infos["name"])
self.GenerateSearchResultsTreeBranch(root, search_results_tree_infos)
self.SearchResultsTree.Expand(root)
-
+
def GetTextCtrlClickFunction(self, item):
def OnTextCtrlClick(event):
self.SearchResultsTree.SelectItem(item)
event.Skip()
return OnTextCtrlClick
-
+
def GetTextCtrlDClickFunction(self, item):
def OnTextCtrlDClick(event):
self.ShowSearchResults(item)
event.Skip()
return OnTextCtrlDClick
-
+
def GenerateSearchResultsTreeBranch(self, root, infos):
to_delete = []
if infos["name"] == "body":
item_name = "%d:" % infos["data"][1][0]
else:
item_name = infos["name"]
-
+
self.SearchResultsTree.SetItemText(root, item_name)
self.SearchResultsTree.SetPyData(root, infos["data"])
self.SearchResultsTree.SetItemBackgroundColour(root, wx.WHITE)
@@ -278,7 +286,7 @@
self.SearchResultsTree.SetItemImage(root, self.TreeImageDict[self.ParentWindow.Controler.GetPouType(infos["name"])])
else:
self.SearchResultsTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
-
+
text = None
if infos["text"] is not None:
text = infos["text"]
@@ -291,13 +299,13 @@
text = _("(%d matches)") % infos["matches"]
start_idx, end_idx = 0, len(text)
style = wx.TextAttr(wx.Colour(0, 127, 174))
-
+
if text is not None:
- text_ctrl_style = wx.BORDER_NONE|wx.TE_READONLY|wx.TE_RICH2
+ text_ctrl_style = wx.BORDER_NONE | wx.TE_READONLY | wx.TE_RICH2
if wx.Platform != '__WXMSW__' or len(text.splitlines()) > 1:
text_ctrl_style |= wx.TE_MULTILINE
- text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0),
- value=text, style=text_ctrl_style)
+ text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0),
+ value=text, style=text_ctrl_style)
width, height = text_ctrl.GetTextExtent(text)
text_ctrl.SetClientSize(wx.Size(width + 1, height))
text_ctrl.SetBackgroundColour(self.SearchResultsTree.GetBackgroundColour())
@@ -306,7 +314,7 @@
text_ctrl.SetInsertionPoint(0)
text_ctrl.SetStyle(start_idx, end_idx, style)
self.SearchResultsTree.SetItemWindow(root, text_ctrl)
-
+
if wx.VERSION >= (2, 6, 0):
item, root_cookie = self.SearchResultsTree.GetFirstChild(root)
else:
@@ -317,7 +325,7 @@
item, root_cookie = self.SearchResultsTree.GetNextChild(root, root_cookie)
self.GenerateSearchResultsTreeBranch(item, child)
item, root_cookie = self.SearchResultsTree.GetNextChild(root, root_cookie)
-
+
def ShowSearchResults(self, item):
data = self.SearchResultsTree.GetPyData(item)
if isinstance(data, TupleType):
@@ -327,11 +335,11 @@
self.ParentWindow.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)
for infos, start, end, text in search_results:
self.ParentWindow.ShowSearchResult(infos, start, end)
-
+
def OnSearchResultsTreeItemActivated(self, event):
self.ShowSearchResults(event.GetItem())
event.Skip()
-
+
def OnResetButton(self, event):
self.ResetSearchResults()
self.ParentWindow.ClearSearchResults()
--- a/controls/TextCtrlAutoComplete.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/TextCtrlAutoComplete.py Mon Aug 21 23:22:58 2017 +0300
@@ -34,34 +34,36 @@
LISTBOX_BORDER_HEIGHT = 4
LISTBOX_INTERVAL_HEIGHT = 6
+
class PopupWithListbox(wx.PopupWindow):
-
+
def __init__(self, parent, choices=[]):
wx.PopupWindow.__init__(self, parent, wx.BORDER_SIMPLE)
-
- self.ListBox = wx.ListBox(self, -1, style=wx.LB_HSCROLL|wx.LB_SINGLE|wx.LB_SORT)
-
+
+ self.ListBox = wx.ListBox(self, -1, style=wx.LB_HSCROLL | wx.LB_SINGLE | wx.LB_SORT)
+
self.SetChoices(choices)
-
+
self.ListBox.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
self.ListBox.Bind(wx.EVT_MOTION, self.OnMotion)
-
+
def SetChoices(self, choices):
max_text_width = 0
max_text_height = 0
-
+
self.ListBox.Clear()
for choice in choices:
self.ListBox.Append(choice)
w, h = self.ListBox.GetTextExtent(choice)
max_text_width = max(max_text_width, w)
max_text_height = max(max_text_height, h)
-
+
itemcount = min(len(choices), MAX_ITEM_SHOWN)
width = self.Parent.GetSize()[0]
- height = max_text_height * itemcount + \
- LISTBOX_INTERVAL_HEIGHT * max(0, itemcount - 1) + \
- 2 * LISTBOX_BORDER_HEIGHT
+ height = \
+ max_text_height * itemcount + \
+ LISTBOX_INTERVAL_HEIGHT * max(0, itemcount - 1) + \
+ 2 * LISTBOX_BORDER_HEIGHT
if max_text_width + 10 > width:
height += 15
size = wx.Size(width, height)
@@ -69,7 +71,7 @@
size.width -= 2
self.ListBox.SetSize(size)
self.SetClientSize(size)
-
+
def MoveSelection(self, direction):
selected = self.ListBox.GetSelection()
if selected == wx.NOT_FOUND:
@@ -82,10 +84,10 @@
if selected == self.ListBox.GetCount():
selected = wx.NOT_FOUND
self.ListBox.SetSelection(selected)
-
+
def GetSelection(self):
return self.ListBox.GetStringSelection()
-
+
def OnLeftDown(self, event):
selected = self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY()))
parent_size = self.Parent.GetSize()
@@ -99,16 +101,17 @@
else:
wx.CallAfter(self.Parent.DismissListBox)
event.Skip()
-
+
def OnMotion(self, event):
self.ListBox.SetSelection(
self.ListBox.HitTest(wx.Point(event.GetX(), event.GetY())))
event.Skip()
-
+
+
class TextCtrlAutoComplete(wx.TextCtrl):
- def __init__ (self, parent, choices=None, dropDownClick=True,
- element_path=None, **therest):
+ def __init__(self, parent, choices=None, dropDownClick=True,
+ element_path=None, **therest):
"""
Constructor works just like wx.TextCtrl except you can pass in a
list of choices. You can also change the choice list at any time
@@ -118,21 +121,21 @@
therest['style'] = wx.TE_PROCESS_ENTER | therest.get('style', 0)
wx.TextCtrl.__init__(self, parent, **therest)
-
- #Some variables
+
+ # Some variables
self._dropDownClick = dropDownClick
self._lastinsertionpoint = None
self._hasfocus = False
-
+
self._screenheight = wx.SystemSettings.GetMetric(wx.SYS_SCREEN_Y)
self.element_path = element_path
-
+
self.listbox = None
-
+
self.SetChoices(choices)
- #gp = self
- #while ( gp != None ) :
+ # gp = self
+ # while ( gp != None ) :
# gp.Bind ( wx.EVT_MOVE , self.onControlChanged, gp )
# gp.Bind ( wx.EVT_SIZE , self.onControlChanged, gp )
# gp = gp.GetParent()
@@ -142,7 +145,7 @@
self.Bind(wx.EVT_TEXT, self.OnEnteredText)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
- #If need drop down on left click
+ # If need drop down on left click
if dropDownClick:
self.Bind(wx.EVT_LEFT_DOWN, self.OnClickToggleDown)
self.Bind(wx.EVT_LEFT_UP, self.OnClickToggleUp)
@@ -201,14 +204,14 @@
self.DismissListBox()
self._hasfocus = False
event.Skip()
-
+
def SetChoices(self, choices):
self._choices = choices
self.RefreshListBoxChoices()
-
+
def GetChoices(self):
return self._choices
-
+
def SetValueFromSelected(self, selected):
"""
Sets the wx.TextCtrl value from the selected wx.ListCtrl item.
@@ -217,7 +220,7 @@
if selected != "":
self.SetValue(selected)
self.DismissListBox()
-
+
def RefreshListBoxChoices(self):
if self.listbox is not None:
text = self.GetValue()
@@ -227,7 +230,7 @@
def PopupListBox(self):
if self.listbox is None:
self.listbox = PopupWithListbox(self)
-
+
# Show the popup right below or above the button
# depending on available screen space...
pos = self.ClientToScreen((0, 0))
@@ -236,9 +239,9 @@
pos.x -= 2
pos.y -= 2
self.listbox.Position(pos, (0, sz[1]))
-
+
self.RefreshListBoxChoices()
-
+
self.listbox.Show()
def DismissListBox(self):
--- a/controls/VariablePanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/controls/VariablePanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,984 +1,1019 @@
-#!/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 program 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
-# of the License, or (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import os
-import re
-from types import TupleType, StringType, UnicodeType
-
-import wx
-import wx.grid
-import wx.lib.buttons
-
-from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS, DefaultType
-from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD, ERROR_HIGHLIGHT
-from dialogs.ArrayTypeDialog import ArrayTypeDialog
-from CustomGrid import CustomGrid
-from CustomTable import CustomTable
-from LocationCellEditor import LocationCellEditor
-from util.BitmapLibrary import GetBitmap
-from PLCControler import _VariableInfos
-
-#-------------------------------------------------------------------------------
-# Helpers
-#-------------------------------------------------------------------------------
-
-[TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
- POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
-] = range(10)
-
-def GetVariableTableColnames(location):
- _ = lambda x : x
- if location:
- return ["#", _("Name"), _("Class"), _("Type"), _("Location"), _("Initial Value"), _("Option"), _("Documentation")]
- return ["#", _("Name"), _("Class"), _("Type"), _("Initial Value"), _("Option"), _("Documentation")]
-
-def GetOptions(constant=True, retain=True, non_retain=True):
- _ = lambda x : x
- options = [""]
- if constant:
- options.append(_("Constant"))
- if retain:
- options.append(_("Retain"))
- if non_retain:
- options.append(_("Non-Retain"))
- return options
-OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()])
-
-def GetFilterChoiceTransfer():
- _ = lambda x : x
- return {_("All"): _("All"), _("Interface"): _("Interface"),
- _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"),
- _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"),
- _(" Temp"): _("Temp"), _("Global"): _("Global")}#, _("Access") : _("Access")}
-VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()])
-VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()])
-
-CheckOptionForClass = {"Local": lambda x: x,
- "Temp": lambda x: "",
- "Input": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
- "InOut": lambda x: "",
- "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
- "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""),
- "External": lambda x: {"Constant": "Constant"}.get(x, "")
- }
-
-LOCATION_MODEL = re.compile("((?:%[IQM](?:\*|(?:[XBWLD]?[0-9]+(?:\.[0-9]+)*)))?)$")
-VARIABLE_NAME_SUFFIX_MODEL = re.compile("([0-9]*)$")
-
-#-------------------------------------------------------------------------------
-# Variables Panel Table
-#-------------------------------------------------------------------------------
-
-class VariableTable(CustomTable):
-
- """
- A custom wx.grid.Grid Table using user supplied data
- """
- def __init__(self, parent, data, colnames):
- # The base class must be initialized *first*
- CustomTable.__init__(self, parent, data, colnames)
- self.old_value = None
-
- def GetValueByName(self, row, colname):
- if row < self.GetNumberRows():
- return getattr(self.data[row], colname)
-
- def SetValueByName(self, row, colname, value):
- if row < self.GetNumberRows():
- setattr(self.data[row], colname, value)
-
- def GetValue(self, row, col):
- if row < self.GetNumberRows():
- if col == 0:
- return self.data[row].Number
- colname = self.GetColLabelValue(col, False)
- if colname == "Initial Value":
- colname = "InitialValue"
- value = getattr(self.data[row], colname, "")
- if colname == "Type" and isinstance(value, TupleType):
- if value[0] == "array":
- return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1])
- if not isinstance(value, (StringType, UnicodeType)):
- value = str(value)
- if colname in ["Class", "Option"]:
- return _(value)
- return value
-
- def SetValue(self, row, col, value):
- if col < len(self.colnames):
- colname = self.GetColLabelValue(col, False)
- if colname == "Name":
- self.old_value = getattr(self.data[row], colname)
- elif colname == "Class":
- value = VARIABLE_CLASSES_DICT[value]
- self.SetValueByName(row, "Option", CheckOptionForClass[value](self.GetValueByName(row, "Option")))
- if value == "External":
- self.SetValueByName(row, "InitialValue", "")
- elif colname == "Option":
- value = OPTIONS_DICT[value]
- elif colname == "Initial Value":
- colname = "InitialValue"
- setattr(self.data[row], colname, value)
-
- def GetOldValue(self):
- return self.old_value
-
- def _GetRowEdit(self, row):
- row_edit = self.GetValueByName(row, "Edit")
- var_type = self.Parent.GetTagName()
- bodytype = self.Parent.Controler.GetEditedElementBodyType(var_type)
- if bodytype in ["ST", "IL"]:
- row_edit = True;
- return row_edit
-
- def _updateColAttrs(self, grid):
- """
- wx.grid.Grid -> update the column attributes to add the
- appropriate renderer given the column name.
-
- Otherwise default to the default renderer.
- """
- for row in range(self.GetNumberRows()):
- var_class = self.GetValueByName(row, "Class")
- var_type = self.GetValueByName(row, "Type")
- row_highlights = self.Highlights.get(row, {})
- for col in range(self.GetNumberCols()):
- editor = None
- renderer = None
- colname = self.GetColLabelValue(col, False)
- if self.Parent.Debug:
- grid.SetReadOnly(row, col, True)
- else:
- if colname == "Option":
- options = GetOptions(constant = var_class in ["Local", "External", "Global"],
- retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"],
- non_retain = self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"])
- if len(options) > 1:
- editor = wx.grid.GridCellChoiceEditor()
- editor.SetParameters(",".join(map(_, options)))
- else:
- grid.SetReadOnly(row, col, True)
- elif col != 0 and self._GetRowEdit(row):
- grid.SetReadOnly(row, col, False)
- if colname == "Name":
- editor = wx.grid.GridCellTextEditor()
- renderer = wx.grid.GridCellStringRenderer()
- elif colname == "Initial Value":
- if var_class not in ["External", "InOut"]:
- if self.Parent.Controler.IsEnumeratedType(var_type):
- editor = wx.grid.GridCellChoiceEditor()
- editor.SetParameters(",".join([""] + self.Parent.Controler.GetEnumeratedDataValues(var_type)))
- else:
- editor = wx.grid.GridCellTextEditor()
- renderer = wx.grid.GridCellStringRenderer()
- else:
- grid.SetReadOnly(row, col, True)
- elif colname == "Location":
- if var_class in ["Local", "Global"] and self.Parent.Controler.IsLocatableType(var_type):
- editor = LocationCellEditor(self, self.Parent.Controler)
- renderer = wx.grid.GridCellStringRenderer()
- else:
- grid.SetReadOnly(row, col, True)
- elif colname == "Class":
- if len(self.Parent.ClassList) == 1:
- grid.SetReadOnly(row, col, True)
- else:
- editor = wx.grid.GridCellChoiceEditor()
- excluded = []
- if self.Parent.IsFunctionBlockType(var_type):
- excluded.extend(["Local","Temp"])
- editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded]))
- elif colname != "Documentation":
- grid.SetReadOnly(row, col, True)
-
- grid.SetCellEditor(row, col, editor)
- grid.SetCellRenderer(row, col, renderer)
-
- if colname == "Location" and LOCATION_MODEL.match(self.GetValueByName(row, colname)) is None:
- highlight_colours = ERROR_HIGHLIGHT
- else:
- highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
- grid.SetCellBackgroundColour(row, col, highlight_colours[0])
- grid.SetCellTextColour(row, col, highlight_colours[1])
- self.ResizeRow(grid, row)
-
-#-------------------------------------------------------------------------------
-# Variable Panel Drop Target
-#-------------------------------------------------------------------------------
-
-class VariableDropTarget(wx.TextDropTarget):
- '''
- This allows dragging a variable location from somewhere to the Location
- column of a variable row.
-
- The drag source should be a TextDataObject containing a Python tuple like:
- ('%ID0.0.0', 'location', 'REAL')
-
- c_ext/CFileEditor.py has an example of this (you can drag a C extension
- variable to the Location column of the variable panel).
- '''
- def __init__(self, parent):
- wx.TextDropTarget.__init__(self)
- self.ParentWindow = parent
-
- def OnDropText(self, x, y, data):
- self.ParentWindow.ParentWindow.Select()
- x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
- col = self.ParentWindow.VariablesGrid.XToCol(x)
- row = self.ParentWindow.VariablesGrid.YToRow(y)
- message = None
- element_type = self.ParentWindow.ElementType
- try:
- values = eval(data)
- except:
- message = _("Invalid value \"%s\" for variable grid element")%data
- values = None
- if not isinstance(values, TupleType):
- message = _("Invalid value \"%s\" for variable grid element")%data
- values = None
- if values is not None:
- if col != wx.NOT_FOUND and row != wx.NOT_FOUND:
- colname = self.ParentWindow.Table.GetColLabelValue(col, False)
- if colname == "Location" and values[1] == "location":
- if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
- message = _("Can't give a location to a function block instance")
- elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]:
- message = _("Can only give a location to local or global variables")
- else:
- location = values[0]
- variable_type = self.ParentWindow.Table.GetValueByName(row, "Type")
- base_type = self.ParentWindow.Controler.GetBaseType(variable_type)
-
- if values[2] is not None:
- base_location_type = self.ParentWindow.Controler.GetBaseType(values[2])
- if values[2] != variable_type and base_type != base_location_type:
- message = _("Incompatible data types between \"{a1}\" and \"{a2}\"").\
- format(a1 = values[2], a2 = variable_type)
-
- if message is None:
- if not location.startswith("%"):
- if location[0].isdigit() and base_type != "BOOL":
- message = _("Incompatible size of data between \"%s\" and \"BOOL\"")%location
- elif location[0] not in LOCATIONDATATYPES:
- message = _("Unrecognized data size \"%s\"")%location[0]
- elif base_type not in LOCATIONDATATYPES[location[0]]:
- message = _("Incompatible size of data between \"{a1}\" and \"{a2}\"").\
- format(a1 = location, a2 = variable_type)
- else:
- dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow,
- _("Select a variable class:"), _("Variable class"),
- [_("Input"), _("Output"), _("Memory")],
- wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
- if dialog.ShowModal() == wx.ID_OK:
- selected = dialog.GetSelection()
- else:
- selected = None
- dialog.Destroy()
- if selected is None:
- return
- if selected == 0:
- location = "%I" + location
- elif selected == 1:
- location = "%Q" + location
- else:
- location = "%M" + location
-
- if message is None:
- self.ParentWindow.Table.SetValue(row, col, location)
- self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
- self.ParentWindow.SaveValues()
- elif colname == "Initial Value" and values[1] == "Constant":
- if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
- message = _("Can't set an initial value to a function block instance")
- else:
- self.ParentWindow.Table.SetValue(row, col, values[0])
- self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
- self.ParentWindow.SaveValues()
- elif (element_type not in ["config", "resource", "function"] and values[1] == "Global" and
- self.ParentWindow.Filter in ["All", "Interface", "External"] or
- element_type != "function" and values[1] in ["location", "NamedConstant"]):
- if values[1] in ["location","NamedConstant"]:
- var_name = values[3]
- else:
- var_name = values[0]
- tagname = self.ParentWindow.GetTagName()
- dlg = wx.TextEntryDialog(
- self.ParentWindow.ParentWindow.ParentWindow,
- _("Confirm or change variable name"),
- _('Variable Drop'), var_name)
- dlg.SetValue(var_name)
- var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None
- dlg.Destroy()
- if var_name is None:
- return
- elif var_name.upper() in [name.upper()
- for name in self.ParentWindow.Controler.\
- GetProjectPouNames(self.ParentWindow.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
- elif not var_name.upper() in [name.upper()
- for name in self.ParentWindow.Controler.\
- GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
- var_infos = self.ParentWindow.DefaultValue.copy()
- var_infos.Name = var_name
- var_infos.Type = values[2]
- var_infos.Documentation = values[4]
- if values[1] == "location":
- location = values[0]
- if not location.startswith("%"):
- dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow.ParentWindow,
- _("Select a variable class:"), _("Variable class"),
- [_("Input"), _("Output"), _("Memory")],
- wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
- if dialog.ShowModal() == wx.ID_OK:
- selected = dialog.GetSelection()
- else:
- selected = None
- dialog.Destroy()
- if selected is None:
- return
- if selected == 0:
- location = "%I" + location
- elif selected == 1:
- location = "%Q" + location
- else:
- location = "%M" + location
- if element_type == "functionBlock":
- configs = self.ParentWindow.Controler.GetProjectConfigNames(
- self.ParentWindow.Debug)
- if len(configs) == 0:
- return
- if not var_name.upper() in [name.upper()
- for name in self.ParentWindow.Controler.\
- GetConfigurationVariableNames(configs[0])]:
- self.ParentWindow.Controler.AddConfigurationGlobalVar(
- configs[0], values[2], var_name, location, "")
- var_infos.Class = "External"
- else:
- if element_type == "program":
- var_infos.Class = "Local"
- else:
- var_infos.Class = "Global"
- var_infos.Location = location
- elif values[1] == "NamedConstant":
- if element_type in ["functionBlock","program"]:
- var_infos.Class = "Local"
- var_infos.InitialValue = values[0]
- else :
- return
- else:
- var_infos.Class = "External"
- var_infos.Number = len(self.ParentWindow.Values)
- self.ParentWindow.Values.append(var_infos)
- self.ParentWindow.SaveValues()
- self.ParentWindow.RefreshValues()
- else:
- message = _("\"%s\" element for this pou already exists!")%var_name
-
- if message is not None:
- wx.CallAfter(self.ShowMessage, message)
-
- def ShowMessage(self, message):
- message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
- message.ShowModal()
- message.Destroy()
-
-#-------------------------------------------------------------------------------
-# Variable Panel
-#-------------------------------------------------------------------------------
-
-class VariablePanel(wx.Panel):
-
- def __init__(self, parent, window, controler, element_type, debug=False):
- wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
-
- self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
- self.MainSizer.AddGrowableCol(0)
- self.MainSizer.AddGrowableRow(1)
-
- controls_sizer = wx.FlexGridSizer(cols=10, hgap=5, rows=1, vgap=5)
- controls_sizer.AddGrowableCol(5)
- controls_sizer.AddGrowableRow(0)
- self.MainSizer.AddSizer(controls_sizer, border=5, flag=wx.GROW|wx.ALL)
-
- self.ReturnTypeLabel = wx.StaticText(self, label=_('Return Type:'))
- controls_sizer.AddWindow(self.ReturnTypeLabel, flag=wx.ALIGN_CENTER_VERTICAL)
-
- self.ReturnType = wx.ComboBox(self,
- size=wx.Size(145, -1), style=wx.CB_READONLY)
- self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, self.ReturnType)
- controls_sizer.AddWindow(self.ReturnType)
-
- self.DescriptionLabel = wx.StaticText(self, label=_('Description:'))
- controls_sizer.AddWindow(self.DescriptionLabel, flag=wx.ALIGN_CENTER_VERTICAL)
-
- self.Description = wx.TextCtrl(self,
- size=wx.Size(250, -1), style=wx.TE_PROCESS_ENTER)
- self.Bind(wx.EVT_TEXT_ENTER, self.OnDescriptionChanged, self.Description)
- self.Description.Bind(wx.EVT_KILL_FOCUS, self.OnDescriptionChanged)
- controls_sizer.AddWindow(self.Description)
-
- class_filter_label = wx.StaticText(self, label=_('Class Filter:'))
- controls_sizer.AddWindow(class_filter_label, flag=wx.ALIGN_CENTER_VERTICAL)
-
- self.ClassFilter = wx.ComboBox(self,
- size=wx.Size(145, -1), style=wx.CB_READONLY)
- self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, self.ClassFilter)
- controls_sizer.AddWindow(self.ClassFilter)
-
- for name, bitmap, help in [
- ("AddButton", "add_element", _("Add variable")),
- ("DeleteButton", "remove_element", _("Remove variable")),
- ("UpButton", "up", _("Move variable up")),
- ("DownButton", "down", _("Move variable down"))]:
- button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
- button.SetToolTipString(help)
- setattr(self, name, button)
- controls_sizer.AddWindow(button)
-
- self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL | wx.HSCROLL)
- self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
- 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)
- self.MainSizer.AddWindow(self.VariablesGrid, flag=wx.GROW)
-
- self.SetSizer(self.MainSizer)
-
- self.ParentWindow = window
- self.Controler = controler
- self.ElementType = element_type
- self.Debug = debug
-
- self.RefreshHighlightsTimer = wx.Timer(self, -1)
- self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer,
- self.RefreshHighlightsTimer)
-
- self.Filter = "All"
- self.FilterChoices = []
- self.FilterChoiceTransfer = GetFilterChoiceTransfer()
-
- self.DefaultValue = _VariableInfos("", "", "", "", "", True, "", DefaultType, ([], []), 0)
-
- if element_type in ["config", "resource"]:
- self.DefaultTypes = {"All" : "Global"}
- else:
- self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
-
- if element_type in ["config", "resource"] \
- or element_type in ["program", "transition", "action"]:
- # this is an element that can have located variables
- self.Table = VariableTable(self, [], GetVariableTableColnames(True))
-
- if element_type in ["config", "resource"]:
- self.FilterChoices = ["All", "Global"]#,"Access"]
- else:
- self.FilterChoices = ["All",
- "Interface", " Input", " Output", " InOut", " External",
- "Variables", " Local", " Temp"]#,"Access"]
-
- # these condense the ColAlignements list
- l = wx.ALIGN_LEFT
- c = wx.ALIGN_CENTER
-
- # Num Name Class Type Loc Init Option Doc
- self.ColSizes = [40, 80, 100, 80, 110, 120, 100, 160]
- self.ColAlignements = [c, l, l, l, l, l, l, l]
- self.ColFixedSizeFlag=[True,False, True, False, True, True, True, False]
-
- else:
- # this is an element that cannot have located variables
- self.Table = VariableTable(self, [], GetVariableTableColnames(False))
-
- if element_type == "function":
- self.FilterChoices = ["All",
- "Interface", " Input", " Output", " InOut",
- "Variables", " Local"]
- else:
- self.FilterChoices = ["All",
- "Interface", " Input", " Output", " InOut", " External",
- "Variables", " Local", " Temp"]
-
- # these condense the ColAlignements list
- l = wx.ALIGN_LEFT
- c = wx.ALIGN_CENTER
-
- # Num Name Class Type Init Option Doc
- self.ColSizes = [40, 80, 100, 80, 120, 100, 160]
- self.ColAlignements = [c, l, l, l, l, l, l]
- self.ColFixedSizeFlag=[True,False, True, False, True, True, False]
-
- self.PanelWidthMin = sum(self.ColSizes)
-
- self.ElementType = element_type
- self.BodyType = None
-
- for choice in self.FilterChoices:
- self.ClassFilter.Append(_(choice))
-
- reverse_transfer = {}
- for filter, choice in self.FilterChoiceTransfer.items():
- reverse_transfer[choice] = filter
- self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter]))
- self.RefreshTypeList()
-
- self.VariablesGrid.SetTable(self.Table)
- self.VariablesGrid.SetButtons({"Add": self.AddButton,
- "Delete": self.DeleteButton,
- "Up": self.UpButton,
- "Down": self.DownButton})
- self.VariablesGrid.SetEditable(not self.Debug)
-
- def _AddVariable(new_row):
- if new_row > 0:
- row_content = self.Values[new_row - 1].copy()
-
- result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content.Name)
- if result is not None:
- name = row_content.Name[:result.start(1)]
- suffix = result.group(1)
- if suffix != "":
- start_idx = int(suffix)
- else:
- start_idx = 0
- else:
- name = row_content.Name
- start_idx = 0
- else:
- row_content = None
- start_idx = 0
- name = "LocalVar"
-
- if row_content is not None and row_content.Edit:
- row_content = self.Values[new_row - 1].copy()
- else:
- row_content = self.DefaultValue.copy()
- if self.Filter in self.DefaultTypes:
- row_content.Class = self.DefaultTypes[self.Filter]
- else:
- row_content.Class = self.Filter
-
- row_content.Name = self.Controler.GenerateNewName(
- self.TagName, None, name + "%d", start_idx)
-
- if self.Filter == "All" and len(self.Values) > 0:
- self.Values.insert(new_row, row_content)
- else:
- self.Values.append(row_content)
- new_row = self.Table.GetNumberRows()
- self.SaveValues()
- if self.ElementType == "resource":
- self.ParentWindow.RefreshView(variablepanel = False)
- self.RefreshValues()
- return new_row
- setattr(self.VariablesGrid, "_AddRow", _AddVariable)
-
- def _DeleteVariable(row):
- if _GetRowEdit(row):
- self.Values.remove(self.Table.GetRow(row))
- self.SaveValues()
- if self.ElementType == "resource":
- self.ParentWindow.RefreshView(variablepanel = False)
- self.RefreshValues()
- setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
-
- def _MoveVariable(row, move):
- if self.Filter == "All":
- new_row = max(0, min(row + move, len(self.Values) - 1))
- if new_row != row:
- self.Values.insert(new_row, self.Values.pop(row))
- self.SaveValues()
- self.RefreshValues()
- return new_row
- return row
- setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
-
- def _GetRowEdit(row):
- row_edit = False
- if self:
- row_edit = self.Table.GetValueByName(row, "Edit")
- bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
- row_edit = row_edit or (bodytype in ["ST", "IL"])
- return row_edit
-
- def _RefreshButtons():
- if self:
- table_length = len(self.Table.data)
- row_class = None
- row_edit = True
- row = 0
- if table_length > 0:
- row = self.VariablesGrid.GetGridCursorRow()
- row_edit = _GetRowEdit(row)
- self.AddButton.Enable(not self.Debug)
- self.DeleteButton.Enable(not self.Debug and (table_length > 0 and row_edit))
- self.UpButton.Enable(not self.Debug and (table_length > 0 and row > 0 and self.Filter == "All"))
- self.DownButton.Enable(not self.Debug and (table_length > 0 and row < table_length - 1 and self.Filter == "All"))
- setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons)
-
- panel_width = window.Parent.ScreenRect.Width - 35
- if panel_width > self.PanelWidthMin:
- stretch_cols_width = panel_width
- stretch_cols_sum = 0
- for col in range(len(self.ColFixedSizeFlag)):
- if self.ColFixedSizeFlag[col]:
- stretch_cols_width -= self.ColSizes[col]
- else:
- stretch_cols_sum += self.ColSizes[col]
-
- 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.SetColMinimalWidth(col, self.ColSizes[col])
- if (panel_width > self.PanelWidthMin) and not self.ColFixedSizeFlag[col]:
- self.VariablesGrid.SetColSize(col, int((float(self.ColSizes[col])/stretch_cols_sum)*stretch_cols_width))
- else:
- self.VariablesGrid.SetColSize(col, self.ColSizes[col])
-
- def __del__(self):
- self.RefreshHighlightsTimer.Stop()
-
- def SetTagName(self, tagname):
- self.TagName = tagname
- self.BodyType = self.Controler.GetEditedElementBodyType(self.TagName)
-
- def GetTagName(self):
- return self.TagName
-
- def IsFunctionBlockType(self, name):
- if (isinstance(name, TupleType) or
- self.ElementType != "function" and self.BodyType in ["ST", "IL"]):
- return False
- else:
- return self.Controler.GetBlockType(name, debug=self.Debug) is not None
-
- def RefreshView(self):
- self.PouNames = self.Controler.GetProjectPouNames(self.Debug)
- returnType = None
- description = None
-
- words = self.TagName.split("::")
- if self.ElementType == "config":
- self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.Debug)
- elif self.ElementType == "resource":
- self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2], self.Debug)
- else:
- if self.ElementType == "function":
- self.ReturnType.Clear()
- for data_type in self.Controler.GetDataTypes(self.TagName, debug=self.Debug):
- self.ReturnType.Append(data_type)
- returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, debug=self.Debug)
- description = self.Controler.GetPouDescription(words[1])
- self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug)
-
- if returnType is not None:
- self.ReturnType.SetStringSelection(returnType)
- self.ReturnType.Enable(not self.Debug)
- self.ReturnTypeLabel.Show()
- self.ReturnType.Show()
- else:
- self.ReturnType.Enable(False)
- self.ReturnTypeLabel.Hide()
- self.ReturnType.Hide()
-
- if description is not None:
- self.Description.SetValue(description)
- self.Description.Enable(not self.Debug)
- self.DescriptionLabel.Show()
- self.Description.Show()
- else:
- self.Description.Enable(False)
- self.DescriptionLabel.Hide()
- self.Description.Hide()
-
- self.RefreshValues()
- self.VariablesGrid.RefreshButtons()
- self.MainSizer.Layout()
-
- def OnReturnTypeChanged(self, event):
- words = self.TagName.split("::")
- self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
- self.Controler.BufferProject()
- self.ParentWindow.RefreshView(variablepanel = False)
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- event.Skip()
-
- def OnDescriptionChanged(self, event):
- words = self.TagName.split("::")
- old_description = self.Controler.GetPouDescription(words[1])
- new_description = self.Description.GetValue()
- if new_description != old_description:
- self.Controler.SetPouDescription(words[1], new_description)
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- event.Skip()
-
- def OnClassFilter(self, event):
- self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]]
- self.RefreshTypeList()
- self.RefreshValues()
- self.VariablesGrid.RefreshButtons()
- event.Skip()
-
- def RefreshTypeList(self):
- if self.Filter == "All":
- self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All","Interface","Variables"]]
- elif self.Filter == "Interface":
- self.ClassList = ["Input","Output","InOut","External"]
- elif self.Filter == "Variables":
- self.ClassList = ["Local","Temp"]
- else:
- self.ClassList = [self.Filter]
-
- def ShowErrorMessage(self, message):
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
- dialog.ShowModal()
- dialog.Destroy()
-
- def OnVariablesGridCellChange(self, event):
- row, col = event.GetRow(), event.GetCol()
- colname = self.Table.GetColLabelValue(col, False)
- value = self.Table.GetValue(row, col)
- message = None
-
- if colname == "Name" and value != "":
- if not TestIdentifier(value):
- message = _("\"%s\" is not a valid identifier!") % value
- elif value.upper() in IEC_KEYWORDS:
- message = _("\"%s\" is a keyword. It can't be used!") % value
- elif value.upper() in self.PouNames:
- message = _("A POU named \"%s\" already exists!") % value
- elif value.upper() in [var.Name.upper() for var in self.Values if var != self.Table.data[row]]:
- message = _("A variable with \"%s\" as name already exists in this pou!") % value
- else:
- self.SaveValues(False)
- old_value = self.Table.GetOldValue()
- if old_value != "":
- self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
- self.Controler.BufferProject()
- wx.CallAfter(self.ParentWindow.RefreshView, False)
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- else:
- self.SaveValues()
- if colname == "Class":
- self.ClearLocation(row, col, value)
- wx.CallAfter(self.ParentWindow.RefreshView)
- elif colname == "Location":
- wx.CallAfter(self.ParentWindow.RefreshView)
-
- if message is not None:
- wx.CallAfter(self.ShowErrorMessage, message)
- event.Veto()
- else:
- event.Skip()
-
- def ClearLocation(self, row, col, value):
- if self.Values[row].Location != '':
- if self.Table.GetColLabelValue(col, False) == 'Class' and value not in ["Local", "Global"] or \
- self.Table.GetColLabelValue(col, False) == 'Type' and not self.Controler.IsLocatableType(value):
- self.Values[row].Location = ''
- self.RefreshValues()
- self.SaveValues()
-
- def BuildStdIECTypesMenu(self,type_menu):
- # build a submenu containing standard IEC types
- base_menu = wx.Menu(title='')
- for base_type in self.Controler.GetBaseTypes():
- new_id = wx.NewId()
- base_menu.Append(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)
-
- def BuildUserTypesMenu(self,type_menu):
- # build a submenu containing user-defined types
- datatype_menu = wx.Menu(title='')
- datatypes = self.Controler.GetDataTypes(basetypes = False, confnodetypes = False)
- for datatype in datatypes:
- new_id = wx.NewId()
- datatype_menu.Append(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)
-
- def BuildLibsTypesMenu(self, type_menu):
- for category in self.Controler.GetConfNodeDataTypes():
- if len(category["list"]) > 0:
- # build a submenu containing confnode types
- confnode_datatype_menu = wx.Menu(title='')
- for datatype in category["list"]:
- new_id = wx.NewId()
- confnode_datatype_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
- self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
-
- type_menu.AppendMenu(wx.NewId(), category["name"], confnode_datatype_menu)
-
- def BuildProjectTypesMenu(self, type_menu, classtype):
- # build a submenu containing function block types
- bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
- pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
- if classtype in ["Input", "Output", "InOut", "External", "Global"] or \
- poutype != "function" and bodytype in ["ST", "IL"]:
- functionblock_menu = wx.Menu(title='')
- fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName)
- for functionblock_type in fbtypes:
- new_id = wx.NewId()
- functionblock_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
- self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
-
- type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
-
- def BuildArrayTypesMenu(self, type_menu):
- new_id = wx.NewId()
- type_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array"))
- self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id)
-
- def OnVariablesGridEditorShown(self, event):
- row, col = event.GetRow(), event.GetCol()
-
- label_value = self.Table.GetColLabelValue(col, False)
- if label_value == "Type":
- old_value = self.Values[row].Type
- classtype = self.Table.GetValueByName(row, "Class")
- type_menu = wx.Menu(title='') # the root menu
-
- self.BuildStdIECTypesMenu(type_menu)
-
- self.BuildUserTypesMenu(type_menu)
-
- self.BuildLibsTypesMenu(type_menu)
-
- self.BuildProjectTypesMenu(type_menu,classtype)
-
- self.BuildArrayTypesMenu(type_menu)
-
- rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
- corner_x = rect.x + rect.width
- corner_y = rect.y + self.VariablesGrid.GetColLabelSize()
-
- # pop up this new menu
- self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y)
- type_menu.Destroy()
- event.Veto()
- value = self.Values[row].Type
- if old_value != value:
- self.ClearLocation(row, col, value)
- 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.SaveValues(False)
- self.ParentWindow.RefreshView(variablepanel = False)
- self.Controler.BufferProject()
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- return VariableTypeFunction
-
- def VariableArrayTypeFunction(self, event):
- row = self.VariablesGrid.GetGridCursorRow()
- dialog = ArrayTypeDialog(self,
- self.Controler.GetDataTypes(self.TagName),
- self.Table.GetValueByName(row, "Type"))
- if dialog.ShowModal() == wx.ID_OK:
- self.Table.SetValueByName(row, "Type", dialog.GetValue())
- self.Table.ResetView(self.VariablesGrid)
- self.SaveValues(False)
- self.ParentWindow.RefreshView(variablepanel = False)
- self.Controler.BufferProject()
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- dialog.Destroy()
-
- def OnVariablesGridCellLeftClick(self, event):
- row = event.GetRow()
- if not self.Debug and (event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit")):
- var_name = self.Table.GetValueByName(row, "Name")
- var_class = self.Table.GetValueByName(row, "Class")
- var_type = self.Table.GetValueByName(row, "Type")
- data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName)))
- dragSource = wx.DropSource(self.VariablesGrid)
- dragSource.SetData(data)
- dragSource.DoDragDrop()
- event.Skip()
-
- def RefreshValues(self):
- data = []
- for num, variable in enumerate(self.Values):
- if variable.Class in self.ClassList:
- variable.Number = num + 1
- data.append(variable)
- self.Table.SetData(data)
- self.Table.ResetView(self.VariablesGrid)
-
- def SaveValues(self, buffer = True):
- words = self.TagName.split("::")
- if self.ElementType == "config":
- self.Controler.SetConfigurationGlobalVars(words[1], self.Values)
- elif self.ElementType == "resource":
- self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values)
- else:
- if self.ReturnType.IsEnabled():
- self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
- self.Controler.SetPouInterfaceVars(words[1], self.Values)
- if buffer:
- self.Controler.BufferProject()
- self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
-
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
-
- def OnRefreshHighlightsTimer(self, event):
- self.Table.ResetView(self.VariablesGrid)
- event.Skip()
-
- def AddVariableHighlight(self, infos, highlight_type):
- if isinstance(infos[0], TupleType):
- for i in xrange(*infos[0]):
- self.Table.AddHighlight((i,) + infos[1:], highlight_type)
- cell_visible = infos[0][0]
- else:
- self.Table.AddHighlight(infos, highlight_type)
- cell_visible = infos[0]
- colnames = [colname.lower() for colname in self.Table.colnames]
- self.VariablesGrid.MakeCellVisible(cell_visible, colnames.index(infos[1]))
- self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
-
- def RemoveVariableHighlight(self, infos, highlight_type):
- if isinstance(infos[0], TupleType):
- for i in xrange(*infos[0]):
- self.Table.RemoveHighlight((i,) + infos[1:], highlight_type)
- else:
- self.Table.RemoveHighlight(infos, highlight_type)
- self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
-
- def ClearHighlights(self, highlight_type=None):
- self.Table.ClearHighlights(highlight_type)
- self.Table.ResetView(self.VariablesGrid)
+#!/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 program 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import os
+import re
+from types import TupleType, StringType, UnicodeType
+
+import wx
+import wx.grid
+import wx.lib.buttons
+
+from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS, DefaultType
+from graphics.GraphicCommons import REFRESH_HIGHLIGHT_PERIOD, ERROR_HIGHLIGHT
+from dialogs.ArrayTypeDialog import ArrayTypeDialog
+from CustomGrid import CustomGrid
+from CustomTable import CustomTable
+from LocationCellEditor import LocationCellEditor
+from util.BitmapLibrary import GetBitmap
+from PLCControler import _VariableInfos
+from util.TranslationCatalogs import NoTranslate
+
+
+# -------------------------------------------------------------------------------
+# Helpers
+# -------------------------------------------------------------------------------
+
+
+[
+ TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, PROJECTTREE,
+ POUINSTANCEVARIABLESPANEL, LIBRARYTREE, SCALING, PAGETITLES
+] = range(10)
+
+
+def GetVariableTableColnames(location):
+ _ = NoTranslate
+ cols = ["#",
+ _("Name"),
+ _("Class"),
+ _("Type"),
+ _("Location"),
+ _("Initial Value"),
+ _("Option"),
+ _("Documentation")]
+ if not location:
+ del cols[4] # remove 'Location' column
+ return cols
+
+
+def GetOptions(constant=True, retain=True, non_retain=True):
+ _ = NoTranslate
+ options = [""]
+ if constant:
+ options.append(_("Constant"))
+ if retain:
+ options.append(_("Retain"))
+ if non_retain:
+ options.append(_("Non-Retain"))
+ return options
+
+
+OPTIONS_DICT = dict([(_(option), option) for option in GetOptions()])
+
+
+def GetFilterChoiceTransfer():
+ _ = NoTranslate
+ return {_("All"): _("All"), _("Interface"): _("Interface"),
+ _(" Input"): _("Input"), _(" Output"): _("Output"), _(" InOut"): _("InOut"),
+ _(" External"): _("External"), _("Variables"): _("Variables"), _(" Local"): _("Local"),
+ _(" Temp"): _("Temp"), _("Global"): _("Global")} # , _("Access") : _("Access")}
+
+
+VARIABLE_CHOICES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().iterkeys()])
+VARIABLE_CLASSES_DICT = dict([(_(_class), _class) for _class in GetFilterChoiceTransfer().itervalues()])
+
+CheckOptionForClass = {
+ "Local": lambda x: x,
+ "Temp": lambda x: "",
+ "Input": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
+ "InOut": lambda x: "",
+ "Output": lambda x: {"Retain": "Retain", "Non-Retain": "Non-Retain"}.get(x, ""),
+ "Global": lambda x: {"Constant": "Constant", "Retain": "Retain"}.get(x, ""),
+ "External": lambda x: {"Constant": "Constant"}.get(x, "")
+}
+
+LOCATION_MODEL = re.compile("((?:%[IQM](?:\*|(?:[XBWLD]?[0-9]+(?:\.[0-9]+)*)))?)$")
+VARIABLE_NAME_SUFFIX_MODEL = re.compile("([0-9]*)$")
+
+
+# -------------------------------------------------------------------------------
+# Variables Panel Table
+# -------------------------------------------------------------------------------
+
+
+class VariableTable(CustomTable):
+
+ """
+ A custom wx.grid.Grid Table using user supplied data
+ """
+ def __init__(self, parent, data, colnames):
+ # The base class must be initialized *first*
+ CustomTable.__init__(self, parent, data, colnames)
+ self.old_value = None
+
+ def GetValueByName(self, row, colname):
+ if row < self.GetNumberRows():
+ return getattr(self.data[row], colname)
+
+ def SetValueByName(self, row, colname, value):
+ if row < self.GetNumberRows():
+ setattr(self.data[row], colname, value)
+
+ def GetValue(self, row, col):
+ if row < self.GetNumberRows():
+ if col == 0:
+ return self.data[row].Number
+ colname = self.GetColLabelValue(col, False)
+ if colname == "Initial Value":
+ colname = "InitialValue"
+ value = getattr(self.data[row], colname, "")
+ if colname == "Type" and isinstance(value, TupleType):
+ if value[0] == "array":
+ return "ARRAY [%s] OF %s" % (",".join(map(lambda x: "..".join(x), value[2])), value[1])
+ if not isinstance(value, (StringType, UnicodeType)):
+ value = str(value)
+ if colname in ["Class", "Option"]:
+ return _(value)
+ return value
+
+ def SetValue(self, row, col, value):
+ if col < len(self.colnames):
+ colname = self.GetColLabelValue(col, False)
+ if colname == "Name":
+ self.old_value = getattr(self.data[row], colname)
+ elif colname == "Class":
+ value = VARIABLE_CLASSES_DICT[value]
+ self.SetValueByName(row, "Option", CheckOptionForClass[value](self.GetValueByName(row, "Option")))
+ if value == "External":
+ self.SetValueByName(row, "InitialValue", "")
+ elif colname == "Option":
+ value = OPTIONS_DICT[value]
+ elif colname == "Initial Value":
+ colname = "InitialValue"
+ setattr(self.data[row], colname, value)
+
+ def GetOldValue(self):
+ return self.old_value
+
+ def _GetRowEdit(self, row):
+ row_edit = self.GetValueByName(row, "Edit")
+ var_type = self.Parent.GetTagName()
+ bodytype = self.Parent.Controler.GetEditedElementBodyType(var_type)
+ if bodytype in ["ST", "IL"]:
+ row_edit = True
+ return row_edit
+
+ def _updateColAttrs(self, grid):
+ """
+ wx.grid.Grid -> update the column attributes to add the
+ appropriate renderer given the column name.
+
+ Otherwise default to the default renderer.
+ """
+ for row in range(self.GetNumberRows()):
+ var_class = self.GetValueByName(row, "Class")
+ var_type = self.GetValueByName(row, "Type")
+ row_highlights = self.Highlights.get(row, {})
+ for col in range(self.GetNumberCols()):
+ editor = None
+ renderer = None
+ colname = self.GetColLabelValue(col, False)
+ if self.Parent.Debug:
+ grid.SetReadOnly(row, col, True)
+ else:
+ if colname == "Option":
+ options = GetOptions(constant=var_class in ["Local", "External", "Global"],
+ retain=self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output", "Global"],
+ non_retain=self.Parent.ElementType != "function" and var_class in ["Local", "Input", "Output"])
+ if len(options) > 1:
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(",".join(map(_, options)))
+ else:
+ grid.SetReadOnly(row, col, True)
+ elif col != 0 and self._GetRowEdit(row):
+ grid.SetReadOnly(row, col, False)
+ if colname == "Name":
+ editor = wx.grid.GridCellTextEditor()
+ renderer = wx.grid.GridCellStringRenderer()
+ elif colname == "Initial Value":
+ if var_class not in ["External", "InOut"]:
+ if self.Parent.Controler.IsEnumeratedType(var_type):
+ editor = wx.grid.GridCellChoiceEditor()
+ editor.SetParameters(",".join([""] + self.Parent.Controler.GetEnumeratedDataValues(var_type)))
+ else:
+ editor = wx.grid.GridCellTextEditor()
+ renderer = wx.grid.GridCellStringRenderer()
+ else:
+ grid.SetReadOnly(row, col, True)
+ elif colname == "Location":
+ if var_class in ["Local", "Global"] and self.Parent.Controler.IsLocatableType(var_type):
+ editor = LocationCellEditor(self, self.Parent.Controler)
+ renderer = wx.grid.GridCellStringRenderer()
+ else:
+ grid.SetReadOnly(row, col, True)
+ elif colname == "Class":
+ if len(self.Parent.ClassList) == 1:
+ grid.SetReadOnly(row, col, True)
+ else:
+ editor = wx.grid.GridCellChoiceEditor()
+ excluded = []
+ if self.Parent.IsFunctionBlockType(var_type):
+ excluded.extend(["Local", "Temp"])
+ editor.SetParameters(",".join([_(choice) for choice in self.Parent.ClassList if choice not in excluded]))
+ elif colname != "Documentation":
+ grid.SetReadOnly(row, col, True)
+
+ grid.SetCellEditor(row, col, editor)
+ grid.SetCellRenderer(row, col, renderer)
+
+ if colname == "Location" and LOCATION_MODEL.match(self.GetValueByName(row, colname)) is None:
+ highlight_colours = ERROR_HIGHLIGHT
+ else:
+ highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
+ grid.SetCellBackgroundColour(row, col, highlight_colours[0])
+ grid.SetCellTextColour(row, col, highlight_colours[1])
+ self.ResizeRow(grid, row)
+
+
+# -------------------------------------------------------------------------------
+# Variable Panel Drop Target
+# -------------------------------------------------------------------------------
+
+
+class VariableDropTarget(wx.TextDropTarget):
+ '''
+ This allows dragging a variable location from somewhere to the Location
+ column of a variable row.
+
+ The drag source should be a TextDataObject containing a Python tuple like:
+ ('%ID0.0.0', 'location', 'REAL')
+
+ c_ext/CFileEditor.py has an example of this (you can drag a C extension
+ variable to the Location column of the variable panel).
+ '''
+ def __init__(self, parent):
+ wx.TextDropTarget.__init__(self)
+ self.ParentWindow = parent
+
+ def OnDropText(self, x, y, data):
+ self.ParentWindow.ParentWindow.Select()
+ x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
+ col = self.ParentWindow.VariablesGrid.XToCol(x)
+ row = self.ParentWindow.VariablesGrid.YToRow(y)
+ message = None
+ element_type = self.ParentWindow.ElementType
+ try:
+ values = eval(data)
+ except Exception:
+ message = _("Invalid value \"%s\" for variable grid element") % data
+ values = None
+ if not isinstance(values, TupleType):
+ message = _("Invalid value \"%s\" for variable grid element") % data
+ values = None
+ if values is not None:
+ if col != wx.NOT_FOUND and row != wx.NOT_FOUND:
+ colname = self.ParentWindow.Table.GetColLabelValue(col, False)
+ if colname == "Location" and values[1] == "location":
+ if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
+ message = _("Can't give a location to a function block instance")
+ elif self.ParentWindow.Table.GetValueByName(row, "Class") not in ["Local", "Global"]:
+ message = _("Can only give a location to local or global variables")
+ else:
+ location = values[0]
+ variable_type = self.ParentWindow.Table.GetValueByName(row, "Type")
+ base_type = self.ParentWindow.Controler.GetBaseType(variable_type)
+
+ if values[2] is not None:
+ base_location_type = self.ParentWindow.Controler.GetBaseType(values[2])
+ if values[2] != variable_type and base_type != base_location_type:
+ message = _("Incompatible data types between \"{a1}\" and \"{a2}\"").\
+ format(a1=values[2], a2=variable_type)
+
+ if message is None:
+ if not location.startswith("%"):
+ if location[0].isdigit() and base_type != "BOOL":
+ message = _("Incompatible size of data between \"%s\" and \"BOOL\"") % location
+ elif location[0] not in LOCATIONDATATYPES:
+ message = _("Unrecognized data size \"%s\"") % location[0]
+ elif base_type not in LOCATIONDATATYPES[location[0]]:
+ message = _("Incompatible size of data between \"{a1}\" and \"{a2}\"").\
+ format(a1=location, a2=variable_type)
+ else:
+ dialog = wx.SingleChoiceDialog(
+ self.ParentWindow.ParentWindow.ParentWindow,
+ _("Select a variable class:"),
+ _("Variable class"),
+ [_("Input"), _("Output"), _("Memory")],
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
+ if dialog.ShowModal() == wx.ID_OK:
+ selected = dialog.GetSelection()
+ else:
+ selected = None
+ dialog.Destroy()
+ if selected is None:
+ return
+ if selected == 0:
+ location = "%I" + location
+ elif selected == 1:
+ location = "%Q" + location
+ else:
+ location = "%M" + location
+
+ if message is None:
+ self.ParentWindow.Table.SetValue(row, col, location)
+ self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
+ self.ParentWindow.SaveValues()
+ elif colname == "Initial Value" and values[1] == "Constant":
+ if not self.ParentWindow.Table.GetValueByName(row, "Edit"):
+ message = _("Can't set an initial value to a function block instance")
+ else:
+ self.ParentWindow.Table.SetValue(row, col, values[0])
+ self.ParentWindow.Table.ResetView(self.ParentWindow.VariablesGrid)
+ self.ParentWindow.SaveValues()
+ elif (element_type not in ["config", "resource", "function"] and values[1] == "Global" and
+ self.ParentWindow.Filter in ["All", "Interface", "External"] or
+ element_type != "function" and values[1] in ["location", "NamedConstant"]):
+ if values[1] in ["location", "NamedConstant"]:
+ var_name = values[3]
+ else:
+ var_name = values[0]
+ tagname = self.ParentWindow.GetTagName()
+ dlg = wx.TextEntryDialog(
+ self.ParentWindow.ParentWindow.ParentWindow,
+ _("Confirm or change variable name"),
+ _('Variable Drop'), var_name)
+ dlg.SetValue(var_name)
+ var_name = dlg.GetValue() if dlg.ShowModal() == wx.ID_OK else None
+ dlg.Destroy()
+ if var_name is None:
+ return
+ elif var_name.upper() in [
+ name.upper() for name in
+ self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]:
+ message = _("\"%s\" pou already exists!") % var_name
+ elif not var_name.upper() in [
+ name.upper()
+ for name in self.ParentWindow.Controler.
+ GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
+ var_infos = self.ParentWindow.DefaultValue.copy()
+ var_infos.Name = var_name
+ var_infos.Type = values[2]
+ var_infos.Documentation = values[4]
+ if values[1] == "location":
+ location = values[0]
+ if not location.startswith("%"):
+ dialog = wx.SingleChoiceDialog(
+ self.ParentWindow.ParentWindow.ParentWindow,
+ _("Select a variable class:"),
+ _("Variable class"),
+ [_("Input"), _("Output"), _("Memory")],
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
+ if dialog.ShowModal() == wx.ID_OK:
+ selected = dialog.GetSelection()
+ else:
+ selected = None
+ dialog.Destroy()
+ if selected is None:
+ return
+ if selected == 0:
+ location = "%I" + location
+ elif selected == 1:
+ location = "%Q" + location
+ else:
+ location = "%M" + location
+ if element_type == "functionBlock":
+ configs = self.ParentWindow.Controler.GetProjectConfigNames(
+ self.ParentWindow.Debug)
+ if len(configs) == 0:
+ return
+ if not var_name.upper() in [
+ name.upper() for name in
+ self.ParentWindow.Controler.GetConfigurationVariableNames(configs[0])]:
+ self.ParentWindow.Controler.AddConfigurationGlobalVar(
+ configs[0], values[2], var_name, location, "")
+ var_infos.Class = "External"
+ else:
+ if element_type == "program":
+ var_infos.Class = "Local"
+ else:
+ var_infos.Class = "Global"
+ var_infos.Location = location
+ elif values[1] == "NamedConstant":
+ if element_type in ["functionBlock", "program"]:
+ var_infos.Class = "Local"
+ var_infos.InitialValue = values[0]
+ else:
+ return
+ else:
+ var_infos.Class = "External"
+ var_infos.Number = len(self.ParentWindow.Values)
+ self.ParentWindow.Values.append(var_infos)
+ self.ParentWindow.SaveValues()
+ self.ParentWindow.RefreshValues()
+ else:
+ message = _("\"%s\" element for this pou already exists!") % var_name
+
+ if message is not None:
+ wx.CallAfter(self.ShowMessage, message)
+
+ def ShowMessage(self, message):
+ message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK | wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+
+
+# -------------------------------------------------------------------------------
+# Variable Panel
+# -------------------------------------------------------------------------------
+
+
+class VariablePanel(wx.Panel):
+
+ def __init__(self, parent, window, controler, element_type, debug=False):
+ wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL)
+
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
+ self.MainSizer.AddGrowableCol(0)
+ self.MainSizer.AddGrowableRow(1)
+
+ controls_sizer = wx.FlexGridSizer(cols=10, hgap=5, rows=1, vgap=5)
+ controls_sizer.AddGrowableCol(5)
+ controls_sizer.AddGrowableRow(0)
+ self.MainSizer.AddSizer(controls_sizer, border=5, flag=wx.GROW | wx.ALL)
+
+ self.ReturnTypeLabel = wx.StaticText(self, label=_('Return Type:'))
+ controls_sizer.AddWindow(self.ReturnTypeLabel, flag=wx.ALIGN_CENTER_VERTICAL)
+
+ self.ReturnType = wx.ComboBox(self,
+ size=wx.Size(145, -1), style=wx.CB_READONLY)
+ self.Bind(wx.EVT_COMBOBOX, self.OnReturnTypeChanged, self.ReturnType)
+ controls_sizer.AddWindow(self.ReturnType)
+
+ self.DescriptionLabel = wx.StaticText(self, label=_('Description:'))
+ controls_sizer.AddWindow(self.DescriptionLabel, flag=wx.ALIGN_CENTER_VERTICAL)
+
+ self.Description = wx.TextCtrl(self,
+ size=wx.Size(250, -1), style=wx.TE_PROCESS_ENTER)
+ self.Bind(wx.EVT_TEXT_ENTER, self.OnDescriptionChanged, self.Description)
+ self.Description.Bind(wx.EVT_KILL_FOCUS, self.OnDescriptionChanged)
+ controls_sizer.AddWindow(self.Description)
+
+ class_filter_label = wx.StaticText(self, label=_('Class Filter:'))
+ controls_sizer.AddWindow(class_filter_label, flag=wx.ALIGN_CENTER_VERTICAL)
+
+ self.ClassFilter = wx.ComboBox(self,
+ size=wx.Size(145, -1), style=wx.CB_READONLY)
+ self.Bind(wx.EVT_COMBOBOX, self.OnClassFilter, self.ClassFilter)
+ controls_sizer.AddWindow(self.ClassFilter)
+
+ for name, bitmap, help in [
+ ("AddButton", "add_element", _("Add variable")),
+ ("DeleteButton", "remove_element", _("Remove variable")),
+ ("UpButton", "up", _("Move variable up")),
+ ("DownButton", "down", _("Move variable down"))]:
+ button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button.SetToolTipString(help)
+ setattr(self, name, button)
+ controls_sizer.AddWindow(button)
+
+ self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL | wx.HSCROLL)
+ self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
+ 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)
+ self.MainSizer.AddWindow(self.VariablesGrid, flag=wx.GROW)
+
+ self.SetSizer(self.MainSizer)
+
+ self.ParentWindow = window
+ self.Controler = controler
+ self.ElementType = element_type
+ self.Debug = debug
+
+ self.RefreshHighlightsTimer = wx.Timer(self, -1)
+ self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer,
+ self.RefreshHighlightsTimer)
+
+ self.Filter = "All"
+ self.FilterChoices = []
+ self.FilterChoiceTransfer = GetFilterChoiceTransfer()
+
+ self.DefaultValue = _VariableInfos("", "", "", "", "", True, "", DefaultType, ([], []), 0)
+
+ if element_type in ["config", "resource"]:
+ self.DefaultTypes = {"All": "Global"}
+ else:
+ self.DefaultTypes = {"All": "Local", "Interface": "Input", "Variables": "Local"}
+
+ if element_type in ["config", "resource"] \
+ or element_type in ["program", "transition", "action"]:
+ # this is an element that can have located variables
+ self.Table = VariableTable(self, [], GetVariableTableColnames(True))
+
+ if element_type in ["config", "resource"]:
+ self.FilterChoices = ["All", "Global"] # ,"Access"]
+ else:
+ self.FilterChoices = ["All",
+ "Interface", " Input", " Output", " InOut", " External",
+ "Variables", " Local", " Temp"] # ,"Access"]
+
+ # these condense the ColAlignements list
+ left = wx.ALIGN_LEFT
+ center = wx.ALIGN_CENTER
+
+ # Num Name Class Type Loc Init Option Doc
+ self.ColSettings = {
+ "size": [40, 80, 100, 80, 110, 120, 100, 160],
+ "alignement": [center, left, left, left, left, left, left, left],
+ "fixed_size": [True, False, True, False, True, True, True, False],
+ }
+
+ else:
+ # this is an element that cannot have located variables
+ self.Table = VariableTable(self, [], GetVariableTableColnames(False))
+
+ if element_type == "function":
+ self.FilterChoices = ["All",
+ "Interface", " Input", " Output", " InOut",
+ "Variables", " Local"]
+ else:
+ self.FilterChoices = ["All",
+ "Interface", " Input", " Output", " InOut", " External",
+ "Variables", " Local", " Temp"]
+
+ # these condense the alignements list
+ left = wx.ALIGN_LEFT
+ center = wx.ALIGN_CENTER
+
+ # Num Name Class Type Init Option Doc
+ self.ColSettings = {
+ "size": [40, 80, 100, 80, 120, 100, 160],
+ "alignement": [center, left, left, left, left, left, left],
+ "fixed_size": [True, False, True, False, True, True, False],
+ }
+
+ self.PanelWidthMin = sum(self.ColSettings["size"])
+
+ self.ElementType = element_type
+ self.BodyType = None
+
+ for choice in self.FilterChoices:
+ self.ClassFilter.Append(_(choice))
+
+ reverse_transfer = {}
+ for filter, choice in self.FilterChoiceTransfer.items():
+ reverse_transfer[choice] = filter
+ self.ClassFilter.SetStringSelection(_(reverse_transfer[self.Filter]))
+ self.RefreshTypeList()
+
+ self.VariablesGrid.SetTable(self.Table)
+ self.VariablesGrid.SetButtons({"Add": self.AddButton,
+ "Delete": self.DeleteButton,
+ "Up": self.UpButton,
+ "Down": self.DownButton})
+ self.VariablesGrid.SetEditable(not self.Debug)
+
+ def _AddVariable(new_row):
+ if new_row > 0:
+ row_content = self.Values[new_row - 1].copy()
+
+ result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content.Name)
+ if result is not None:
+ name = row_content.Name[:result.start(1)]
+ suffix = result.group(1)
+ if suffix != "":
+ start_idx = int(suffix)
+ else:
+ start_idx = 0
+ else:
+ name = row_content.Name
+ start_idx = 0
+ else:
+ row_content = None
+ start_idx = 0
+ name = "LocalVar"
+
+ if row_content is not None and row_content.Edit:
+ row_content = self.Values[new_row - 1].copy()
+ else:
+ row_content = self.DefaultValue.copy()
+ if self.Filter in self.DefaultTypes:
+ row_content.Class = self.DefaultTypes[self.Filter]
+ else:
+ row_content.Class = self.Filter
+
+ row_content.Name = self.Controler.GenerateNewName(
+ self.TagName, None, name + "%d", start_idx)
+
+ if self.Filter == "All" and len(self.Values) > 0:
+ self.Values.insert(new_row, row_content)
+ else:
+ self.Values.append(row_content)
+ new_row = self.Table.GetNumberRows()
+ self.SaveValues()
+ if self.ElementType == "resource":
+ self.ParentWindow.RefreshView(variablepanel=False)
+ self.RefreshValues()
+ return new_row
+ setattr(self.VariablesGrid, "_AddRow", _AddVariable)
+
+ def _DeleteVariable(row):
+ if _GetRowEdit(row):
+ self.Values.remove(self.Table.GetRow(row))
+ self.SaveValues()
+ if self.ElementType == "resource":
+ self.ParentWindow.RefreshView(variablepanel=False)
+ self.RefreshValues()
+ setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
+
+ def _MoveVariable(row, move):
+ if self.Filter == "All":
+ new_row = max(0, min(row + move, len(self.Values) - 1))
+ if new_row != row:
+ self.Values.insert(new_row, self.Values.pop(row))
+ self.SaveValues()
+ self.RefreshValues()
+ return new_row
+ return row
+ setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
+
+ def _GetRowEdit(row):
+ row_edit = False
+ if self:
+ row_edit = self.Table.GetValueByName(row, "Edit")
+ bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
+ row_edit = row_edit or (bodytype in ["ST", "IL"])
+ return row_edit
+
+ def _RefreshButtons():
+ if self:
+ table_length = len(self.Table.data)
+ row_class = None
+ row_edit = True
+ row = 0
+ if table_length > 0:
+ row = self.VariablesGrid.GetGridCursorRow()
+ row_edit = _GetRowEdit(row)
+ self.AddButton.Enable(not self.Debug)
+ self.DeleteButton.Enable(not self.Debug and (table_length > 0 and row_edit))
+ self.UpButton.Enable(not self.Debug and (table_length > 0 and row > 0 and self.Filter == "All"))
+ self.DownButton.Enable(not self.Debug and (table_length > 0 and row < table_length - 1 and self.Filter == "All"))
+ setattr(self.VariablesGrid, "RefreshButtons", _RefreshButtons)
+
+ panel_width = window.Parent.ScreenRect.Width - 35
+ if panel_width > self.PanelWidthMin:
+ stretch_cols_width = panel_width
+ stretch_cols_sum = 0
+ for col in range(len(self.ColSettings["fixed_size"])):
+ if self.ColSettings["fixed_size"][col]:
+ stretch_cols_width -= self.ColSettings["size"][col]
+ else:
+ stretch_cols_sum += self.ColSettings["size"][col]
+
+ self.VariablesGrid.SetRowLabelSize(0)
+ for col in range(self.Table.GetNumberCols()):
+ attr = wx.grid.GridCellAttr()
+ attr.SetAlignment(self.ColSettings["alignement"][col], wx.ALIGN_CENTRE)
+ self.VariablesGrid.SetColAttr(col, attr)
+ self.VariablesGrid.SetColMinimalWidth(col, self.ColSettings["size"][col])
+ if (panel_width > self.PanelWidthMin) and not self.ColSettings["fixed_size"][col]:
+ self.VariablesGrid.SetColSize(col, int((float(self.ColSettings["size"][col])/stretch_cols_sum)*stretch_cols_width))
+ else:
+ self.VariablesGrid.SetColSize(col, self.ColSettings["size"][col])
+
+ def __del__(self):
+ self.RefreshHighlightsTimer.Stop()
+
+ def SetTagName(self, tagname):
+ self.TagName = tagname
+ self.BodyType = self.Controler.GetEditedElementBodyType(self.TagName)
+
+ def GetTagName(self):
+ return self.TagName
+
+ def IsFunctionBlockType(self, name):
+ if isinstance(name, TupleType) or \
+ self.ElementType != "function" and self.BodyType in ["ST", "IL"]:
+ return False
+ else:
+ return self.Controler.GetBlockType(name, debug=self.Debug) is not None
+
+ def RefreshView(self):
+ self.PouNames = self.Controler.GetProjectPouNames(self.Debug)
+ returnType = None
+ description = None
+
+ words = self.TagName.split("::")
+ if self.ElementType == "config":
+ self.Values = self.Controler.GetConfigurationGlobalVars(words[1], self.Debug)
+ elif self.ElementType == "resource":
+ self.Values = self.Controler.GetConfigurationResourceGlobalVars(words[1], words[2], self.Debug)
+ else:
+ if self.ElementType == "function":
+ self.ReturnType.Clear()
+ for data_type in self.Controler.GetDataTypes(self.TagName, debug=self.Debug):
+ self.ReturnType.Append(data_type)
+ returnType = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, debug=self.Debug)
+ description = self.Controler.GetPouDescription(words[1])
+ self.Values = self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug)
+
+ if returnType is not None:
+ self.ReturnType.SetStringSelection(returnType)
+ self.ReturnType.Enable(not self.Debug)
+ self.ReturnTypeLabel.Show()
+ self.ReturnType.Show()
+ else:
+ self.ReturnType.Enable(False)
+ self.ReturnTypeLabel.Hide()
+ self.ReturnType.Hide()
+
+ if description is not None:
+ self.Description.SetValue(description)
+ self.Description.Enable(not self.Debug)
+ self.DescriptionLabel.Show()
+ self.Description.Show()
+ else:
+ self.Description.Enable(False)
+ self.DescriptionLabel.Hide()
+ self.Description.Hide()
+
+ self.RefreshValues()
+ self.VariablesGrid.RefreshButtons()
+ self.MainSizer.Layout()
+
+ def OnReturnTypeChanged(self, event):
+ words = self.TagName.split("::")
+ self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
+ self.Controler.BufferProject()
+ self.ParentWindow.RefreshView(variablepanel=False)
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ event.Skip()
+
+ def OnDescriptionChanged(self, event):
+ words = self.TagName.split("::")
+ old_description = self.Controler.GetPouDescription(words[1])
+ new_description = self.Description.GetValue()
+ if new_description != old_description:
+ self.Controler.SetPouDescription(words[1], new_description)
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ event.Skip()
+
+ def OnClassFilter(self, event):
+ self.Filter = self.FilterChoiceTransfer[VARIABLE_CHOICES_DICT[self.ClassFilter.GetStringSelection()]]
+ self.RefreshTypeList()
+ self.RefreshValues()
+ self.VariablesGrid.RefreshButtons()
+ event.Skip()
+
+ def RefreshTypeList(self):
+ if self.Filter == "All":
+ self.ClassList = [self.FilterChoiceTransfer[choice] for choice in self.FilterChoices if self.FilterChoiceTransfer[choice] not in ["All", "Interface", "Variables"]]
+ elif self.Filter == "Interface":
+ self.ClassList = ["Input", "Output", "InOut", "External"]
+ elif self.Filter == "Variables":
+ self.ClassList = ["Local", "Temp"]
+ else:
+ self.ClassList = [self.Filter]
+
+ def ShowErrorMessage(self, message):
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
+ dialog.ShowModal()
+ dialog.Destroy()
+
+ def OnVariablesGridCellChange(self, event):
+ row, col = event.GetRow(), event.GetCol()
+ colname = self.Table.GetColLabelValue(col, False)
+ value = self.Table.GetValue(row, col)
+ message = None
+
+ if colname == "Name" and value != "":
+ if not TestIdentifier(value):
+ message = _("\"%s\" is not a valid identifier!") % value
+ elif value.upper() in IEC_KEYWORDS:
+ message = _("\"%s\" is a keyword. It can't be used!") % value
+ elif value.upper() in self.PouNames:
+ message = _("A POU named \"%s\" already exists!") % value
+ elif value.upper() in [var.Name.upper() for var in self.Values if var != self.Table.data[row]]:
+ message = _("A variable with \"%s\" as name already exists in this pou!") % value
+ else:
+ self.SaveValues(False)
+ old_value = self.Table.GetOldValue()
+ if old_value != "":
+ self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
+ self.Controler.BufferProject()
+ wx.CallAfter(self.ParentWindow.RefreshView, False)
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ else:
+ self.SaveValues()
+ if colname == "Class":
+ self.ClearLocation(row, col, value)
+ wx.CallAfter(self.ParentWindow.RefreshView)
+ elif colname == "Location":
+ wx.CallAfter(self.ParentWindow.RefreshView)
+
+ if message is not None:
+ wx.CallAfter(self.ShowErrorMessage, message)
+ event.Veto()
+ else:
+ event.Skip()
+
+ def ClearLocation(self, row, col, value):
+ if self.Values[row].Location != '':
+ if self.Table.GetColLabelValue(col, False) == 'Class' and value not in ["Local", "Global"] or \
+ self.Table.GetColLabelValue(col, False) == 'Type' and not self.Controler.IsLocatableType(value):
+ self.Values[row].Location = ''
+ self.RefreshValues()
+ self.SaveValues()
+
+ def BuildStdIECTypesMenu(self, type_menu):
+ # build a submenu containing standard IEC types
+ base_menu = wx.Menu(title='')
+ for base_type in self.Controler.GetBaseTypes():
+ new_id = wx.NewId()
+ base_menu.Append(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)
+
+ def BuildUserTypesMenu(self, type_menu):
+ # build a submenu containing user-defined types
+ datatype_menu = wx.Menu(title='')
+ datatypes = self.Controler.GetDataTypes(basetypes=False, confnodetypes=False)
+ for datatype in datatypes:
+ new_id = wx.NewId()
+ datatype_menu.Append(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)
+
+ def BuildLibsTypesMenu(self, type_menu):
+ for category in self.Controler.GetConfNodeDataTypes():
+ if len(category["list"]) > 0:
+ # build a submenu containing confnode types
+ confnode_datatype_menu = wx.Menu(title='')
+ for datatype in category["list"]:
+ new_id = wx.NewId()
+ confnode_datatype_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=datatype)
+ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(datatype), id=new_id)
+
+ type_menu.AppendMenu(wx.NewId(), category["name"], confnode_datatype_menu)
+
+ def BuildProjectTypesMenu(self, type_menu, classtype):
+ # build a submenu containing function block types
+ bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
+ pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
+ if classtype in ["Input", "Output", "InOut", "External", "Global"] or \
+ poutype != "function" and bodytype in ["ST", "IL"]:
+ functionblock_menu = wx.Menu(title='')
+ fbtypes = self.Controler.GetFunctionBlockTypes(self.TagName)
+ for functionblock_type in fbtypes:
+ new_id = wx.NewId()
+ functionblock_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
+ self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
+
+ type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
+
+ def BuildArrayTypesMenu(self, type_menu):
+ new_id = wx.NewId()
+ type_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array"))
+ self.Bind(wx.EVT_MENU, self.VariableArrayTypeFunction, id=new_id)
+
+ def OnVariablesGridEditorShown(self, event):
+ row, col = event.GetRow(), event.GetCol()
+
+ label_value = self.Table.GetColLabelValue(col, False)
+ if label_value == "Type":
+ old_value = self.Values[row].Type
+ classtype = self.Table.GetValueByName(row, "Class")
+ type_menu = wx.Menu(title='') # the root menu
+
+ self.BuildStdIECTypesMenu(type_menu)
+
+ self.BuildUserTypesMenu(type_menu)
+
+ self.BuildLibsTypesMenu(type_menu)
+
+ self.BuildProjectTypesMenu(type_menu, classtype)
+
+ self.BuildArrayTypesMenu(type_menu)
+
+ rect = self.VariablesGrid.BlockToDeviceRect((row, col), (row, col))
+ corner_x = rect.x + rect.width
+ corner_y = rect.y + self.VariablesGrid.GetColLabelSize()
+
+ # pop up this new menu
+ self.VariablesGrid.PopupMenuXY(type_menu, corner_x, corner_y)
+ type_menu.Destroy()
+ event.Veto()
+ value = self.Values[row].Type
+ if old_value != value:
+ self.ClearLocation(row, col, value)
+ 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.SaveValues(False)
+ self.ParentWindow.RefreshView(variablepanel=False)
+ self.Controler.BufferProject()
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ return VariableTypeFunction
+
+ def VariableArrayTypeFunction(self, event):
+ row = self.VariablesGrid.GetGridCursorRow()
+ dialog = ArrayTypeDialog(self,
+ self.Controler.GetDataTypes(self.TagName),
+ self.Table.GetValueByName(row, "Type"))
+ if dialog.ShowModal() == wx.ID_OK:
+ self.Table.SetValueByName(row, "Type", dialog.GetValue())
+ self.Table.ResetView(self.VariablesGrid)
+ self.SaveValues(False)
+ self.ParentWindow.RefreshView(variablepanel=False)
+ self.Controler.BufferProject()
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+ dialog.Destroy()
+
+ def OnVariablesGridCellLeftClick(self, event):
+ row = event.GetRow()
+ if not self.Debug and (event.GetCol() == 0 and self.Table.GetValueByName(row, "Edit")):
+ var_name = self.Table.GetValueByName(row, "Name")
+ var_class = self.Table.GetValueByName(row, "Class")
+ var_type = self.Table.GetValueByName(row, "Type")
+ data = wx.TextDataObject(str((var_name, var_class, var_type, self.TagName)))
+ dragSource = wx.DropSource(self.VariablesGrid)
+ dragSource.SetData(data)
+ dragSource.DoDragDrop()
+ event.Skip()
+
+ def RefreshValues(self):
+ data = []
+ for num, variable in enumerate(self.Values):
+ if variable.Class in self.ClassList:
+ variable.Number = num + 1
+ data.append(variable)
+ self.Table.SetData(data)
+ self.Table.ResetView(self.VariablesGrid)
+
+ def SaveValues(self, buffer=True):
+ words = self.TagName.split("::")
+ if self.ElementType == "config":
+ self.Controler.SetConfigurationGlobalVars(words[1], self.Values)
+ elif self.ElementType == "resource":
+ self.Controler.SetConfigurationResourceGlobalVars(words[1], words[2], self.Values)
+ else:
+ if self.ReturnType.IsEnabled():
+ self.Controler.SetPouInterfaceReturnType(words[1], self.ReturnType.GetStringSelection())
+ self.Controler.SetPouInterfaceVars(words[1], self.Values)
+ if buffer:
+ self.Controler.BufferProject()
+ self.ParentWindow._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
+
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
+
+ def OnRefreshHighlightsTimer(self, event):
+ self.Table.ResetView(self.VariablesGrid)
+ event.Skip()
+
+ def AddVariableHighlight(self, infos, highlight_type):
+ if isinstance(infos[0], TupleType):
+ for i in xrange(*infos[0]):
+ self.Table.AddHighlight((i,) + infos[1:], highlight_type)
+ cell_visible = infos[0][0]
+ else:
+ self.Table.AddHighlight(infos, highlight_type)
+ cell_visible = infos[0]
+ colnames = [colname.lower() for colname in self.Table.colnames]
+ self.VariablesGrid.MakeCellVisible(cell_visible, colnames.index(infos[1]))
+ self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
+
+ def RemoveVariableHighlight(self, infos, highlight_type):
+ if isinstance(infos[0], TupleType):
+ for i in xrange(*infos[0]):
+ self.Table.RemoveHighlight((i,) + infos[1:], highlight_type)
+ else:
+ self.Table.RemoveHighlight(infos, highlight_type)
+ self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
+
+ def ClearHighlights(self, highlight_type=None):
+ self.Table.ClearHighlights(highlight_type)
+ self.Table.ResetView(self.VariablesGrid)
--- a/dialogs/AboutDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/AboutDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -37,8 +37,6 @@
from wx.lib.agw.hyperlink import HyperLinkCtrl
-#----------------------------------------------------------------------
-
class AboutDialog(wx.Dialog):
"""
A replacement About Dialog for Windows, as it uses a generic frame that
@@ -106,8 +104,6 @@
CreditsDialog(self, self.info)
-#----------------------------------------------------------------------
-
class CreditsDialog(wx.Dialog):
def __init__(self, parent, info):
wx.Dialog.__init__(self, parent, title=_("Credits"), size=(475, 320),
@@ -144,8 +140,6 @@
close.Bind(wx.EVT_BUTTON, lambda evt: self.Destroy())
-#----------------------------------------------------------------------
-
class LicenseDialog(wx.Dialog):
def __init__(self, parent, info):
wx.Dialog.__init__(self, parent, title=_("License"), size=(500, 400),
@@ -173,7 +167,6 @@
close.Bind(wx.EVT_BUTTON, lambda evt: self.Destroy())
-#----------------------------------------------------------------------
def ShowAboutDialog(parent, info):
if os.name == "nt":
--- a/dialogs/ActionBlockDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/ActionBlockDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,25 +29,28 @@
from controls import CustomGrid, CustomTable
from util.BitmapLibrary import GetBitmap
from PLCControler import _ActionInfos
-
-#-------------------------------------------------------------------------------
+from util.TranslationCatalogs import NoTranslate
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def GetActionTableColnames():
- _ = lambda x: x
+ _ = NoTranslate
return [_("Qualifier"), _("Duration"), _("Type"), _("Value"), _("Indicator")]
+
def GetTypeList():
- _ = lambda x: x
+ _ = NoTranslate
return [_("Action"), _("Variable"), _("Inline")]
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Action Table
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ActionTable(CustomTable):
-
+
def GetValue(self, row, col):
if row < self.GetNumberRows():
colname = self.GetColLabelValue(col, False)
@@ -55,7 +58,7 @@
if colname == "Type":
return _(value)
return value
-
+
def SetValue(self, row, col, value):
if col < len(self.colnames):
colname = self.GetColLabelValue(col, False)
@@ -64,7 +67,7 @@
elif colname == "Qualifier" and not self.Parent.DurationList[value]:
self.data[row].duration = ""
setattr(self.data[row], colname.lower(), value)
-
+
def _updateColAttrs(self, grid):
"""
wx.Grid -> update the column attributes to add the
@@ -72,7 +75,7 @@
Otherwise default to the default renderer.
"""
-
+
for row in range(self.GetNumberRows()):
for col in range(self.GetNumberCols()):
editor = None
@@ -103,69 +106,71 @@
elif colname == "Indicator":
editor = wx.grid.GridCellChoiceEditor()
editor.SetParameters(self.Parent.VariableList)
-
+
grid.SetCellEditor(row, col, editor)
grid.SetCellRenderer(row, col, renderer)
grid.SetReadOnly(row, col, readonly)
-
+
grid.SetCellBackgroundColour(row, col, wx.WHITE)
self.ResizeRow(grid, row)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Action Block Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ActionBlockDialog(wx.Dialog):
-
+
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title=_('Edit action block properties'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
top_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
top_sizer.AddGrowableCol(0)
top_sizer.AddGrowableRow(0)
main_sizer.AddSizer(top_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
actions_label = wx.StaticText(self, label=_('Actions:'))
top_sizer.AddWindow(actions_label, flag=wx.ALIGN_BOTTOM)
-
+
for name, bitmap, help in [
("AddButton", "add_element", _("Add action")),
("DeleteButton", "remove_element", _("Remove action")),
("UpButton", "up", _("Move action up")),
("DownButton", "down", _("Move action down"))]:
- button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button = wx.lib.buttons.GenBitmapButton(
+ self, bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
top_sizer.AddWindow(button)
-
+
self.ActionsGrid = CustomGrid(self, size=wx.Size(-1, 250), style=wx.VSCROLL)
self.ActionsGrid.DisableDragGridSize()
self.ActionsGrid.EnableScrolling(False, True)
- self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
+ self.ActionsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
self.OnActionsGridCellChange)
main_sizer.AddSizer(self.ActionsGrid, border=20,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
- main_sizer.AddSizer(button_sizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(button_sizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.SetSizer(main_sizer)
-
+
self.Table = ActionTable(self, [], GetActionTableColnames())
- typelist = GetTypeList()
- self.TypeList = ",".join(map(_,typelist))
+ typelist = GetTypeList()
+ self.TypeList = ",".join(map(_, typelist))
self.TranslateType = dict([(_(value), value) for value in typelist])
self.ColSizes = [60, 90, 130, 200, 50]
self.ColAlignements = [wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
-
+
self.ActionsGrid.SetTable(self.Table)
self.ActionsGrid.SetDefaultValue(_ActionInfos("N", "Action", "", "", ""))
self.ActionsGrid.SetButtons({"Add": self.AddButton,
@@ -173,19 +178,19 @@
"Up": self.UpButton,
"Down": self.DownButton})
self.ActionsGrid.SetRowLabelSize(0)
-
+
for col in range(self.Table.GetNumberCols()):
attr = wx.grid.GridCellAttr()
attr.SetAlignment(self.ColAlignements[col], wx.ALIGN_CENTRE)
self.ActionsGrid.SetColAttr(col, attr)
self.ActionsGrid.SetColMinimalWidth(col, self.ColSizes[col])
self.ActionsGrid.AutoSizeColumn(col, False)
-
+
self.Table.ResetView(self.ActionsGrid)
self.ActionsGrid.SetFocus()
self.ActionsGrid.RefreshButtons()
self.Fit()
-
+
def OnOK(self, event):
self.ActionsGrid.CloseEditControl()
self.EndModal(wx.ID_OK)
@@ -193,14 +198,14 @@
def OnActionsGridCellChange(self, event):
wx.CallAfter(self.Table.ResetView, self.ActionsGrid)
event.Skip()
-
+
def SetQualifierList(self, list):
self.QualifierList = ",".join(list)
self.DurationList = list
def SetVariableList(self, list):
self.VariableList = "," + ",".join([variable.Name for variable in list])
-
+
def SetActionList(self, list):
self.ActionList = "," + ",".join(list)
@@ -218,7 +223,7 @@
if len(actions) > 0:
self.ActionsGrid.SetGridCursor(0, 0)
self.ActionsGrid.RefreshButtons()
-
+
def GetValues(self):
actions = self.Table.GetData()
for action in actions:
--- a/dialogs/ArrayTypeDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/ArrayTypeDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,67 +28,68 @@
from controls import CustomEditableListBox
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
DIMENSION_MODEL = re.compile("([0-9]+)\.\.([0-9]+)$")
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Array Type Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ArrayTypeDialog(wx.Dialog):
-
+
def __init__(self, parent, datatypes, infos):
wx.Dialog.__init__(self, parent, title=_('Edit array type properties'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
top_sizer = wx.BoxSizer(wx.HORIZONTAL)
- main_sizer.AddSizer(top_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(top_sizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
basetype_label = wx.StaticText(self, label=_('Base Type:'))
top_sizer.AddWindow(basetype_label, 1, flag=wx.ALIGN_BOTTOM)
-
+
self.BaseType = wx.ComboBox(self, style=wx.CB_READONLY)
top_sizer.AddWindow(self.BaseType, 1, flag=wx.GROW)
-
- self.Dimensions = CustomEditableListBox(self, label=_("Dimensions:"),
- style=wx.gizmos.EL_ALLOW_NEW|
- wx.gizmos.EL_ALLOW_EDIT|
- wx.gizmos.EL_ALLOW_DELETE)
- for func in ["_OnLabelEndEdit",
- "_OnAddButton",
- "_OnDelButton",
- "_OnUpButton",
+
+ self.Dimensions = CustomEditableListBox(self, label=_("Dimensions:"),
+ style=(wx.gizmos.EL_ALLOW_NEW |
+ wx.gizmos.EL_ALLOW_EDIT |
+ wx.gizmos.EL_ALLOW_DELETE))
+ for func in ["_OnLabelEndEdit",
+ "_OnAddButton",
+ "_OnDelButton",
+ "_OnUpButton",
"_OnDownButton"]:
setattr(self.Dimensions, func, self.OnDimensionsChanged)
- main_sizer.AddSizer(self.Dimensions, border=20,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ main_sizer.AddSizer(self.Dimensions, border=20,
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
- main_sizer.AddSizer(button_sizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(button_sizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.SetSizer(main_sizer)
-
+
for datatype in datatypes:
self.BaseType.Append(datatype)
-
+
if isinstance(infos, TupleType) and infos[0] == "array":
self.BaseType.SetStringSelection(infos[1])
- self.Dimensions.SetStrings(map(lambda x : "..".join(x), infos[2]))
+ self.Dimensions.SetStrings(map(lambda x: "..".join(x), infos[2]))
elif infos in datatypes:
self.BaseType.SetStringSelection(infos)
-
+
self.BaseType.SetFocus()
self.Fit()
-
+
def GetDimensions(self):
message = None
dimensions_list = []
@@ -99,28 +100,28 @@
for dimensions in dimension_strings:
result = DIMENSION_MODEL.match(dimensions)
if result is None:
- message = _("\"%s\" value isn't a valid array dimension!")%dimensions
+ message = _("\"%s\" value isn't a valid array dimension!") % dimensions
break
bounds = result.groups()
if int(bounds[0]) >= int(bounds[1]):
- message = _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.")%dimensions
+ message = _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.") % dimensions
break
dimensions_list.append(bounds)
if message is not None:
- dlg = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dlg = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dlg.ShowModal()
dlg.Destroy()
return None
return dimensions_list
-
+
def OnDimensionsChanged(self, event):
wx.CallAfter(self.GetDimensions)
event.Skip()
-
+
def OnOK(self, event):
if self.GetDimensions() is not None:
self.EndModal(wx.ID_OK)
-
+
def GetValue(self):
return "array", self.BaseType.GetStringSelection(), self.GetDimensions()
--- a/dialogs/BlockPreviewDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/BlockPreviewDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,17 +28,17 @@
from plcopen.structures import TestIdentifier, IEC_KEYWORDS
from graphics.GraphicCommons import FREEDRAWING_MODE
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Dialog with preview for graphic block
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a generic dialog containing a preview panel for displaying
-graphic created by dialog
-"""
+# -------------------------------------------------------------------------------
+
class BlockPreviewDialog(wx.Dialog):
-
+ """
+ Class that implements a generic dialog containing a preview panel for displaying
+ graphic created by dialog
+ """
+
def __init__(self, parent, controller, tagname, title):
"""
Constructor
@@ -48,53 +48,54 @@
@param title: Title of dialog frame
"""
wx.Dialog.__init__(self, parent, title=title)
-
+
# Save reference to
self.Controller = controller
self.TagName = tagname
-
+
# Label for preview
self.PreviewLabel = wx.StaticText(self, label=_('Preview:'))
-
+
# Create Preview panel
self.Preview = wx.Panel(self, style=wx.SIMPLE_BORDER)
self.Preview.SetBackgroundColour(wx.WHITE)
-
+
# Add function to preview panel so that it answers to graphic elements
# like Viewer
- setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
- setattr(self.Preview, "GetScaling", lambda:None)
+ setattr(self.Preview, "GetDrawingMode", lambda: FREEDRAWING_MODE)
+ setattr(self.Preview, "GetScaling", lambda: None)
setattr(self.Preview, "GetBlockType", controller.GetBlockType)
setattr(self.Preview, "IsOfType", controller.IsOfType)
-
+
# Bind paint event on Preview panel
self.Preview.Bind(wx.EVT_PAINT, self.OnPaint)
-
+
# Add default dialog buttons sizer
- self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
- self.Bind(wx.EVT_BUTTON, self.OnOK,
+ self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
self.ButtonSizer.GetAffirmativeButton())
-
+
self.Element = None # Graphic element to display in preview
self.MinElementSize = None # Graphic element minimal size
-
+
# Variable containing the graphic element name when dialog is opened
self.DefaultElementName = None
self.Fit()
-
+
# List of variables defined in POU {var_name: (var_class, var_type),...}
self.VariableList = {}
-
+
def __del__(self):
"""
Destructor
"""
# Remove reference to project controller
self.Controller = None
-
- def _init_sizers(self, main_rows, main_growable_row,
- left_rows, left_growable_row,
- right_rows, right_growable_row):
+
+ def _init_sizers(self,
+ main_rows, main_growable_row,
+ left_rows, left_growable_row,
+ right_rows, right_growable_row):
"""
Initialize common sizers
@param main_rows: Number of rows in main sizer
@@ -108,44 +109,44 @@
None if no row is growable
"""
# Create dialog main sizer
- self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0,
+ self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0,
rows=main_rows, vgap=10)
self.MainSizer.AddGrowableCol(0)
if main_growable_row is not None:
self.MainSizer.AddGrowableRow(main_growable_row)
-
+
# Create a sizer for dividing parameters in two columns
self.ColumnSizer = wx.BoxSizer(wx.HORIZONTAL)
- self.MainSizer.AddSizer(self.ColumnSizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(self.ColumnSizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
# Create a sizer for left column
- self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
+ self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
rows=left_rows, vgap=5)
self.LeftGridSizer.AddGrowableCol(0)
if left_growable_row is not None:
self.LeftGridSizer.AddGrowableRow(left_growable_row)
- self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5,
- flag=wx.GROW|wx.RIGHT|wx.EXPAND)
-
+ self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5,
+ flag=wx.GROW | wx.RIGHT | wx.EXPAND)
+
# Create a sizer for right column
- self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
+ self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
rows=right_rows, vgap=0)
self.RightGridSizer.AddGrowableCol(0)
if right_growable_row is not None:
self.RightGridSizer.AddGrowableRow(right_growable_row)
- self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5,
- flag=wx.GROW|wx.LEFT)
-
+ self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5,
+ flag=wx.GROW | wx.LEFT)
+
self.SetSizer(self.MainSizer)
-
+
def SetMinElementSize(self, size):
"""
Define minimal graphic element size
@param size: Tuple containing minimal size (width, height)
"""
self.MinElementSize = size
-
+
def GetMinElementSize(self):
"""
Get minimal graphic element size
@@ -155,16 +156,16 @@
"""
if self.Element is None:
return None
-
+
return self.Element.GetMinSize()
-
+
def SetPreviewFont(self, font):
"""
Set font of Preview panel
@param font: wx.Font object containing font style
"""
self.Preview.SetFont(font)
-
+
def RefreshVariableList(self):
"""
Extract list of variables defined in POU
@@ -175,20 +176,20 @@
for var in self.Controller.GetEditedElementInterfaceVars(
self.TagName)
if var.Edit}
-
- # Add POU name to variable list if POU is a function
+
+ # Add POU name to variable list if POU is a function
returntype = self.Controller.GetEditedElementInterfaceReturnType(
self.TagName)
if returntype is not None:
self.VariableList[
self.Controller.GetEditedElementName(self.TagName)] = \
("Output", returntype)
-
+
# Add POU name if POU is a transition
words = self.TagName.split("::")
if words[0] == "T":
self.VariableList[words[2]] = ("Output", "BOOL")
-
+
def TestElementName(self, element_name):
"""
Test displayed graphic element name
@@ -198,47 +199,46 @@
message_format = None
# Get graphic element name in upper case
uppercase_element_name = element_name.upper()
-
+
# Test if graphic element name is a valid identifier
if not TestIdentifier(element_name):
message_format = _("\"%s\" is not a valid identifier!")
-
+
# Test that graphic element name isn't a keyword
elif uppercase_element_name in IEC_KEYWORDS:
message_format = _("\"%s\" is a keyword. It can't be used!")
-
+
# Test that graphic element name isn't a POU name
elif uppercase_element_name in self.Controller.GetProjectPouNames():
message_format = _("\"%s\" pou already exists!")
-
+
# Test that graphic element name isn't already used in POU by a variable
# or another graphic element
- elif ((self.DefaultElementName is None or
- self.DefaultElementName.upper() != uppercase_element_name) and
- uppercase_element_name in self.Controller.\
- GetEditedElementVariables(self.TagName)):
+ elif ((self.DefaultElementName is None or
+ self.DefaultElementName.upper() != uppercase_element_name) and
+ uppercase_element_name in self.Controller.GetEditedElementVariables(self.TagName)):
message_format = _("\"%s\" element for this pou already exists!")
-
+
# If an error have been identify, show error message dialog
if message_format is not None:
self.ShowErrorMessage(message_format % element_name)
# Test failed
return False
-
+
# Test succeed
return True
-
+
def ShowErrorMessage(self, message):
"""
Show an error message dialog over this dialog
@param message: Error message to display
"""
- dialog = wx.MessageDialog(self, message,
- _("Error"),
- wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message,
+ _("Error"),
+ wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
-
+
def OnOK(self, event):
"""
Called when dialog OK button is pressed
@@ -248,7 +248,7 @@
"""
# Close dialog
self.EndModal(wx.ID_OK)
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
@@ -258,42 +258,42 @@
dc = wx.ClientDC(self.Preview)
dc.SetFont(self.Preview.GetFont())
dc.Clear()
-
+
# Return immediately if no graphic element defined
if self.Element is None:
return
-
+
# Calculate block size according to graphic element min size due to its
# parameters and graphic element min size defined
min_width, min_height = self.GetMinElementSize()
width = max(self.MinElementSize[0], min_width)
height = max(self.MinElementSize[1], min_height)
self.Element.SetSize(width, height)
-
+
# Get element position and bounding box to center in preview
posx, posy = self.Element.GetPosition()
bbox = self.Element.GetBoundingBox()
-
+
# Get Preview panel size
client_size = self.Preview.GetClientSize()
-
+
# If graphic element is too big to be displayed in preview panel,
# calculate preview panel scale so that graphic element fit inside
- scale = (max(float(bbox.width) / client_size.width,
- float(bbox.height) / client_size.height) * 1.1
- if bbox.width * 1.1 > client_size.width or
- bbox.height * 1.1 > client_size.height
- else 1.0)
+ k = 1.1 if (bbox.width * 1.1 > client_size.width or
+ bbox.height * 1.1 > client_size.height) \
+ else 1.0
+ scale = (max(float(bbox.width) / client_size.width,
+ float(bbox.height) / client_size.height) * k)
dc.SetUserScale(1.0 / scale, 1.0 / scale)
-
+
# Center graphic element in preview panel
x = int(client_size.width * scale - bbox.width) / 2 + posx - bbox.x
y = int(client_size.height * scale - bbox.height) / 2 + posy - bbox.y
self.Element.SetPosition(x, y)
-
+
# Draw graphic element
self.Element.Draw(dc)
-
+
def OnPaint(self, event):
"""
Called when Preview panel need to be redraw
@@ -301,4 +301,3 @@
"""
self.RefreshPreview()
event.Skip()
-
--- a/dialogs/BrowseLocationsDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/BrowseLocationsDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,111 +30,122 @@
from plcopen.structures import LOCATIONDATATYPES
from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
from util.BitmapLibrary import GetBitmap
-
-#-------------------------------------------------------------------------------
+from util.TranslationCatalogs import NoTranslate
+
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def GetDirFilterChoiceOptions():
- _ = lambda x : x
- return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]),
- (_("Input"), [LOCATION_VAR_INPUT]),
- (_("Output"), [LOCATION_VAR_OUTPUT]),
+ _ = NoTranslate
+ return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]),
+ (_("Input"), [LOCATION_VAR_INPUT]),
+ (_("Output"), [LOCATION_VAR_OUTPUT]),
(_("Memory"), [LOCATION_VAR_MEMORY])]
+
+
DIRFILTERCHOICE_OPTIONS = dict([(_(option), filter) for option, filter in GetDirFilterChoiceOptions()])
+
def GetTypeFilterChoiceOptions():
- _ = lambda x : x
- return [_("All"),
- _("Type and derivated"),
+ _ = NoTranslate
+ return [_("All"),
+ _("Type and derivated"),
_("Type strict")]
+
# turn LOCATIONDATATYPES inside-out
LOCATION_SIZES = {}
for size, types in LOCATIONDATATYPES.iteritems():
for type in types:
LOCATION_SIZES[type] = size
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Browse Locations Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class BrowseLocationsDialog(wx.Dialog):
-
+
def __init__(self, parent, var_type, controller):
wx.Dialog.__init__(self, parent, title=_('Browse Locations'),
- style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
-
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
locations_label = wx.StaticText(self, label=_('Locations available:'))
- main_sizer.AddWindow(locations_label, border=20,
- flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
-
- self.LocationsTree = wx.TreeCtrl(self,
- style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT)
+ main_sizer.AddWindow(locations_label, border=20,
+ flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)
+
+ self.LocationsTree = wx.TreeCtrl(self,
+ style=(wx.TR_HAS_BUTTONS |
+ wx.TR_SINGLE |
+ wx.SUNKEN_BORDER |
+ wx.TR_HIDE_ROOT |
+ wx.TR_LINES_AT_ROOT))
self.LocationsTree.SetInitialSize(wx.Size(-1, 300))
- self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated,
+ self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated,
self.LocationsTree)
- main_sizer.AddWindow(self.LocationsTree, border=20,
- flag=wx.LEFT|wx.RIGHT|wx.GROW)
-
+ main_sizer.AddWindow(self.LocationsTree, border=20,
+ flag=wx.LEFT | wx.RIGHT | wx.GROW)
+
button_gridsizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
button_gridsizer.AddGrowableCol(1)
button_gridsizer.AddGrowableCol(3)
button_gridsizer.AddGrowableRow(0)
- main_sizer.AddSizer(button_gridsizer, border=20,
- flag=wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.GROW)
-
+ main_sizer.AddSizer(button_gridsizer, border=20,
+ flag=wx.BOTTOM | wx.LEFT | wx.RIGHT | wx.GROW)
+
direction_label = wx.StaticText(self, label=_('Direction:'))
button_gridsizer.AddWindow(direction_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
self.DirFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.DirFilterChoice)
button_gridsizer.AddWindow(self.DirFilterChoice,
- flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL)
-
+ flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL)
+
filter_label = wx.StaticText(self, label=_('Type:'))
button_gridsizer.AddWindow(filter_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
self.TypeFilterChoice = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnFilterChoice, self.TypeFilterChoice)
button_gridsizer.AddWindow(self.TypeFilterChoice,
- flag=wx.GROW|wx.ALIGN_CENTER_VERTICAL)
-
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ flag=wx.GROW | wx.ALIGN_CENTER_VERTICAL)
+
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
button_gridsizer.AddSizer(button_sizer, flag=wx.ALIGN_RIGHT)
-
+
self.SetSizer(main_sizer)
-
+
self.Controller = controller
self.VarType = var_type
self.BaseVarType = self.Controller.GetBaseType(self.VarType)
self.VarTypeSize = LOCATION_SIZES[self.BaseVarType]
self.Locations = self.Controller.GetVariableLocationTree()
-
+
# Define Tree item icon list
self.TreeImageList = wx.ImageList(16, 16)
self.TreeImageDict = {}
-
+
# Icons for items
for imgname, itemtype in [
- ("CONFIGURATION", LOCATION_CONFNODE),
- ("RESOURCE", LOCATION_MODULE),
- ("PROGRAM", LOCATION_GROUP),
- ("VAR_INPUT", LOCATION_VAR_INPUT),
- ("VAR_OUTPUT", LOCATION_VAR_OUTPUT),
- ("VAR_LOCAL", LOCATION_VAR_MEMORY)]:
- self.TreeImageDict[itemtype]=self.TreeImageList.Add(GetBitmap(imgname))
-
+ ("CONFIGURATION", LOCATION_CONFNODE),
+ ("RESOURCE", LOCATION_MODULE),
+ ("PROGRAM", LOCATION_GROUP),
+ ("VAR_INPUT", LOCATION_VAR_INPUT),
+ ("VAR_OUTPUT", LOCATION_VAR_OUTPUT),
+ ("VAR_LOCAL", LOCATION_VAR_MEMORY)]:
+ self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
+
# Assign icon list to TreeCtrls
self.LocationsTree.SetImageList(self.TreeImageList)
-
+
# Set a options for the choice
for option, filter in GetDirFilterChoiceOptions():
self.DirFilterChoice.Append(_(option))
@@ -143,34 +154,34 @@
self.TypeFilterChoice.Append(_(option))
self.TypeFilterChoice.SetStringSelection(_("All"))
self.RefreshFilters()
-
+
self.RefreshLocationsTree()
self.Fit()
-
+
def RefreshFilters(self):
self.DirFilter = DIRFILTERCHOICE_OPTIONS[self.DirFilterChoice.GetStringSelection()]
self.TypeFilter = self.TypeFilterChoice.GetSelection()
-
+
def RefreshLocationsTree(self):
root = self.LocationsTree.GetRootItem()
if not root.IsOk():
root = self.LocationsTree.AddRoot("")
self.GenerateLocationsTreeBranch(root, self.Locations)
-
+
def FilterType(self, location_type, location_size):
if self.TypeFilter == 0:
return True
-
+
if location_size != self.VarTypeSize:
return False
-
+
if self.TypeFilter == 1:
return self.Controller.IsOfType(location_type, self.BaseVarType)
elif self.TypeFilter == 2:
return location_type == self.VarType
-
+
return True
-
+
def GenerateLocationsTreeBranch(self, root, locations):
to_delete = []
item, root_cookie = self.LocationsTree.GetFirstChild(root)
@@ -194,28 +205,28 @@
item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie)
for item in to_delete:
self.LocationsTree.Delete(item)
-
+
def OnLocationsTreeItemActivated(self, event):
infos = self.LocationsTree.GetPyData(event.GetItem())
if infos["type"] not in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]:
wx.CallAfter(self.EndModal, wx.ID_OK)
event.Skip()
-
+
def OnFilterChoice(self, event):
self.RefreshFilters()
self.RefreshLocationsTree()
-
+
def GetValues(self):
selected = self.LocationsTree.GetSelection()
return self.LocationsTree.GetPyData(selected)
-
+
def OnOK(self, event):
selected = self.LocationsTree.GetSelection()
var_infos = None
if selected.IsOk():
var_infos = self.LocationsTree.GetPyData(selected)
if var_infos is None or var_infos["type"] in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]:
- dialog = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/dialogs/BrowseValuesLibraryDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/BrowseValuesLibraryDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,38 +29,38 @@
class BrowseValuesLibraryDialog(wx.Dialog):
"""
Modal dialog that helps in selecting predefined XML attributes sets out of hierarchically organized list
- """
+ """
def __init__(self, parent, name, library, default=None):
wx.Dialog.__init__(self,
- name='BrowseValueDialog', parent=parent,
- style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
- title=_('Browse %s values library') % name)
+ name='BrowseValueDialog', parent=parent,
+ style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
+ title=_('Browse %s values library') % name)
self.staticText1 = wx.StaticText(
label=_('Choose a value for %s:') % name, name='staticText1', parent=self,
pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
-
+
self.ValuesLibrary = wx.TreeCtrl(
name='ValuesLibrary', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(400, 200), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT)
-
- self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ size=wx.Size(400, 200), style=wx.TR_HAS_BUTTONS | wx.TR_SINGLE | wx.SUNKEN_BORDER | wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT)
+
+ self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId())
-
+
self.flexGridSizer1 = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
-
- self.flexGridSizer1.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
- self.flexGridSizer1.AddWindow(self.ValuesLibrary, 0, border=20, flag=wx.GROW|wx.LEFT|wx.RIGHT)
- self.flexGridSizer1.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+
+ self.flexGridSizer1.AddWindow(self.staticText1, 0, border=20, flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+ self.flexGridSizer1.AddWindow(self.ValuesLibrary, 0, border=20, flag=wx.GROW | wx.LEFT | wx.RIGHT)
+ self.flexGridSizer1.AddSizer(self.ButtonSizer, 0, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.flexGridSizer1.AddGrowableCol(0)
self.flexGridSizer1.AddGrowableRow(1)
-
+
self.SetSizer(self.flexGridSizer1)
self.Fit()
-
+
root = self.ValuesLibrary.AddRoot("")
self.GenerateValuesLibraryBranch(root, library, default)
@@ -80,9 +80,8 @@
def OnOK(self, event):
selected = self.ValuesLibrary.GetSelection()
if not selected.IsOk() or self.ValuesLibrary.GetPyData(selected) is None:
- message = wx.MessageDialog(self, _("No valid value selected!"), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("No valid value selected!"), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
self.EndModal(wx.ID_OK)
-
--- a/dialogs/ConnectionDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/ConnectionDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,17 +29,17 @@
from graphics.FBD_Objects import FBD_Connector
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Connection Parameters Dialog
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a dialog for defining parameters of a connection graphic
-element
-"""
+# -------------------------------------------------------------------------------
+
class ConnectionDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a connection graphic
+ element
+ """
+
def __init__(self, parent, controller, tagname, apply_button=False):
"""
Constructor
@@ -49,49 +49,50 @@
@param apply_button: Enable button for applying connector modification
to all connector having the same name in POU (default: False)
"""
- BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Connection Properties'))
-
+ BlockPreviewDialog.__init__(self, parent, controller, tagname,
+ title=_('Connection Properties'))
+
# Init common sizers
self._init_sizers(2, 0, 7, 1, 0, None)
-
+
# Create label for connection type
type_label = wx.StaticText(self, label=_('Type:'))
self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW)
-
+
# Create radio buttons for selecting connection type
self.TypeRadioButtons = {}
first = True
for type, label in [(CONNECTOR, _('Connector')),
(CONTINUATION, _('Continuation'))]:
- radio_button = wx.RadioButton(self, label=label,
- style=(wx.RB_GROUP if first else 0))
+ radio_button = wx.RadioButton(self, label=label,
+ style=(wx.RB_GROUP if first else 0))
radio_button.SetValue(first)
self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button)
self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
self.TypeRadioButtons[type] = radio_button
first = False
-
+
# Create label for connection name
name_label = wx.StaticText(self, label=_('Name:'))
self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW)
-
+
# Create text control for defining connection name
self.ConnectionName = wx.TextCtrl(self)
- self.ConnectionName.SetMinSize(wx.Size(200,-1))
+ self.ConnectionName.SetMinSize(wx.Size(200, -1))
self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.ConnectionName)
self.LeftGridSizer.AddWindow(self.ConnectionName, flag=wx.GROW)
-
+
# Add preview panel and associated label to sizers
- self.Preview.SetMinSize(wx.Size(-1,100))
+ self.Preview.SetMinSize(wx.Size(-1, 100))
self.LeftGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.LeftGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
self.ColumnSizer.RemoveSizer(self.RightGridSizer)
-
+
# Add button for applying connection name modification to all connection
# of POU
if apply_button:
@@ -105,10 +106,10 @@
controller.GenerateNewName(
tagname, None, "Connection%d", 0))
self.Fit()
-
+
# Connector radio button is default control having keyboard focus
self.TypeRadioButtons[CONNECTOR].SetFocus()
-
+
def GetConnectionType(self):
"""
Return type selected for connection
@@ -117,7 +118,7 @@
return (CONNECTOR
if self.TypeRadioButtons[CONNECTOR].GetValue()
else CONTINUATION)
-
+
def SetValues(self, values):
"""
Set default connection parameters
@@ -125,18 +126,18 @@
"""
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is connection type
if name == "type":
self.TypeRadioButtons[value].SetValue(True)
-
+
# Parameter is connection name
elif name == "name":
self.ConnectionName.SetValue(value)
-
+
# Refresh preview panel
self.RefreshPreview()
-
+
def GetValues(self):
"""
Return connection parameters defined in dialog
@@ -154,23 +155,23 @@
@return: True if connection name is valid
"""
message = None
-
+
# Get connection name typed by user
connection_name = self.ConnectionName.GetValue()
-
+
# Test that a name have been defined
if connection_name == "":
message = _("Form isn't complete. Name must be filled!")
-
+
# If an error have been identify, show error message dialog
if message is not None:
self.ShowErrorMessage(message)
# Test failed
return False
-
+
# Return result of element name test
return self.TestElementName(connection_name)
-
+
def OnOK(self, event):
"""
Called when dialog OK button is pressed
@@ -206,17 +207,16 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
Override BlockPreviewDialog function
"""
# Set graphic element displayed, creating a FBD connection element
- self.Element = FBD_Connector(self.Preview,
- self.GetConnectionType(),
- self.ConnectionName.GetValue())
-
+ self.Element = FBD_Connector(self.Preview,
+ self.GetConnectionType(),
+ self.ConnectionName.GetValue())
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
-
--- a/dialogs/DiscoveryDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/DiscoveryDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,70 +25,77 @@
import socket
import wx
-import wx.lib.mixins.listctrl as listmix
+import wx.lib.mixins.listctrl as listmix
from util.Zeroconf import *
import connectors
service_type = '_PYRO._tcp.local.'
+
class AutoWidthListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
def __init__(self, parent, id, name, pos=wx.DefaultPosition,
size=wx.DefaultSize, style=0):
wx.ListCtrl.__init__(self, parent, id, pos, size, style, name=name)
listmix.ListCtrlAutoWidthMixin.__init__(self)
-[ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1,
- ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON,
- ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON,
+
+[
+ ID_DISCOVERYDIALOG, ID_DISCOVERYDIALOGSTATICTEXT1,
+ ID_DISCOVERYDIALOGSERVICESLIST, ID_DISCOVERYDIALOGREFRESHBUTTON,
+ ID_DISCOVERYDIALOGLOCALBUTTON, ID_DISCOVERYDIALOGIPBUTTON,
] = [wx.NewId() for _init_ctrls in range(6)]
+
class DiscoveryDialog(wx.Dialog, listmix.ColumnSorterMixin):
-
+
def _init_coll_MainSizer_Items(self, parent):
- parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
- parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW)
- parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)
-
+ parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)
+ parent.AddWindow(self.ServicesList, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.GROW)
+ parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)
+
def _init_coll_MainSizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableRow(1)
-
+
def _init_coll_ButtonGridSizer_Items(self, parent):
parent.AddWindow(self.RefreshButton, 0, border=0, flag=0)
parent.AddWindow(self.LocalButton, 0, border=0, flag=0)
parent.AddWindow(self.IpButton, 0, border=0, flag=0)
parent.AddSizer(self.ButtonSizer, 0, border=0, flag=0)
-
+
def _init_coll_ButtonGridSizer_Growables(self, parent):
parent.AddGrowableCol(0)
parent.AddGrowableCol(1)
parent.AddGrowableRow(0)
-
+
def _init_sizers(self):
self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
self.ButtonGridSizer = wx.FlexGridSizer(cols=4, hgap=5, rows=1, vgap=0)
-
+
self._init_coll_MainSizer_Items(self.MainSizer)
self._init_coll_MainSizer_Growables(self.MainSizer)
self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer)
self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer)
-
+
self.SetSizer(self.MainSizer)
-
+
def _init_ctrls(self, prnt):
- wx.Dialog.__init__(self, id=ID_DISCOVERYDIALOG,
- name='DiscoveryDialog', parent=prnt, style=wx.DEFAULT_DIALOG_STYLE,
- title=_('Service Discovery'))
-
- self.staticText1 = wx.StaticText(id=ID_DISCOVERYDIALOGSTATICTEXT1,
- label=_('Services available:'), name='staticText1', parent=self,
- pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
-
+ wx.Dialog.__init__(
+ self, id=ID_DISCOVERYDIALOG,
+ name='DiscoveryDialog', parent=prnt, style=wx.DEFAULT_DIALOG_STYLE,
+ title=_('Service Discovery'))
+
+ self.staticText1 = wx.StaticText(
+ id=ID_DISCOVERYDIALOGSTATICTEXT1,
+ label=_('Services available:'), name='staticText1', parent=self,
+ pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+
# Set up list control
- self.ServicesList = AutoWidthListCtrl(id=ID_DISCOVERYDIALOGSERVICESLIST,
- name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0),
- style=wx.LC_REPORT|wx.LC_EDIT_LABELS|wx.LC_SORT_ASCENDING|wx.LC_SINGLE_SEL)
+ self.ServicesList = AutoWidthListCtrl(
+ id=ID_DISCOVERYDIALOGSERVICESLIST,
+ name='ServicesList', parent=self, pos=wx.Point(0, 0), size=wx.Size(0, 0),
+ style=wx.LC_REPORT | wx.LC_EDIT_LABELS | wx.LC_SORT_ASCENDING | wx.LC_SINGLE_SEL)
self.ServicesList.InsertColumn(0, _('NAME'))
self.ServicesList.InsertColumn(1, _('TYPE'))
self.ServicesList.InsertColumn(2, _('IP'))
@@ -100,48 +107,53 @@
self.ServicesList.SetInitialSize(wx.Size(-1, 300))
self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, id=ID_DISCOVERYDIALOGSERVICESLIST)
self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, id=ID_DISCOVERYDIALOGSERVICESLIST)
-
+
listmix.ColumnSorterMixin.__init__(self, 4)
-
- self.RefreshButton = wx.Button(id=ID_DISCOVERYDIALOGREFRESHBUTTON,
- label=_('Refresh'), name='RefreshButton', parent=self,
- pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+
+ self.RefreshButton = wx.Button(
+ id=ID_DISCOVERYDIALOGREFRESHBUTTON,
+ label=_('Refresh'), name='RefreshButton', parent=self,
+ pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Bind(wx.EVT_BUTTON, self.OnRefreshButton, id=ID_DISCOVERYDIALOGREFRESHBUTTON)
-
- self.LocalButton = wx.Button(id=ID_DISCOVERYDIALOGLOCALBUTTON,
- label=_('Local'), name='LocalButton', parent=self,
- pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+
+ self.LocalButton = wx.Button(
+ id=ID_DISCOVERYDIALOGLOCALBUTTON,
+ label=_('Local'), name='LocalButton', parent=self,
+ pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Bind(wx.EVT_BUTTON, self.OnLocalButton, id=ID_DISCOVERYDIALOGLOCALBUTTON)
- self.IpButton = wx.Button(id=ID_DISCOVERYDIALOGIPBUTTON,
- label=_('Add IP'), name='IpButton', parent=self,
- pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
+ self.IpButton = wx.Button(
+ id=ID_DISCOVERYDIALOGIPBUTTON,
+ label=_('Add IP'), name='IpButton', parent=self,
+ pos=wx.Point(0, 0), size=wx.DefaultSize, style=0)
self.Bind(wx.EVT_BUTTON, self.OnIpButton, id=ID_DISCOVERYDIALOGIPBUTTON)
-
- self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTER)
-
+
+ self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTER)
+
self._init_sizers()
self.Fit()
-
+
def __init__(self, parent):
self._init_ctrls(parent)
-
+
self.itemDataMap = {}
self.nextItemId = 0
-
+
self.URI = None
self.Browser = None
-
+
self.ZeroConfInstance = Zeroconf()
self.RefreshList()
- self.LatestSelection=None
-
+ self.LatestSelection = None
+
def __del__(self):
- if self.Browser is not None : self.Browser.cancel()
+ if self.Browser is not None:
+ self.Browser.cancel()
self.ZeroConfInstance.close()
-
+
def RefreshList(self):
- if self.Browser is not None : self.Browser.cancel()
+ if self.Browser is not None:
+ self.Browser.cancel()
self.Browser = ServiceBrowser(self.ZeroConfInstance, service_type, self)
def OnRefreshButton(self, event):
@@ -154,9 +166,11 @@
event.Skip()
def OnIpButton(self, event):
+ def GetColText(col):
+ return self.getColumnText(self.LatestSelection, col)
+
if self.LatestSelection is not None:
- l = lambda col : self.getColumnText(self.LatestSelection,col)
- self.URI = "%s://%s:%s"%tuple(map(l,(1,2,3)))
+ self.URI = "%s://%s:%s" % tuple(map(GetColText, (1, 2, 3)))
self.EndModal(wx.ID_OK)
event.Skip()
@@ -181,27 +195,26 @@
# connect_type = self.getColumnText(idx, 1)
# connect_address = self.getColumnText(idx, 2)
# connect_port = self.getColumnText(idx, 3)
-#
+#
# self.URI = "%s://%s:%s"%(connect_type, connect_address, connect_port)
def SetURI(self, idx):
self.LatestSelection = idx
- svcname = self.getColumnText(idx, 0)
+ svcname = self.getColumnText(idx, 0)
connect_type = self.getColumnText(idx, 1)
- self.URI = "%s://%s"%(connect_type, svcname + '.' + service_type)
-
+ self.URI = "%s://%s" % (connect_type, svcname + '.' + service_type)
+
def GetURI(self):
return self.URI
-
+
def removeService(self, zeroconf, _type, name):
wx.CallAfter(self._removeService, name)
-
def _removeService(self, name):
'''
called when a service with the desired type goes offline.
'''
-
+
# loop through the list items looking for the service that went offline
for idx in xrange(self.ServicesList.GetItemCount()):
# this is the unique identifier assigned to the item
@@ -213,7 +226,7 @@
if item_name == name:
self.ServicesList.DeleteItem(idx)
break
-
+
def addService(self, zeroconf, _type, name):
wx.CallAfter(self._addService, _type, name)
@@ -223,10 +236,10 @@
'''
info = self.ZeroConfInstance.getServiceInfo(_type, name)
- svcname = name.split(".")[0]
+ svcname = name.split(".")[0]
typename = _type.split(".")[0][1:]
- ip = str(socket.inet_ntoa(info.getAddress()))
- port = info.getPort()
+ ip = str(socket.inet_ntoa(info.getAddress()))
+ port = info.getPort()
num_items = self.ServicesList.GetItemCount()
@@ -240,13 +253,12 @@
# we assign every list item a unique id (that won't change when items
# are added or removed)
self.ServicesList.SetItemData(new_item, self.nextItemId)
-
+
# the value of each column has to be stored in the itemDataMap
# so that ColumnSorterMixin knows how to sort the column.
# "name" is included at the end so that self.removeService
# can access it.
- self.itemDataMap[self.nextItemId] = [ svcname, typename, ip, port, name ]
+ self.itemDataMap[self.nextItemId] = [svcname, typename, ip, port, name]
self.nextItemId += 1
-
--- a/dialogs/DurationEditorDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/DurationEditorDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,9 +27,9 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
MICROSECONDS = 0.001
MILLISECONDS = 1
@@ -49,51 +49,52 @@
("Microseconds", _('Microseconds:')),
]
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Edit Duration Value Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class DurationEditorDialog(wx.Dialog):
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title=_('Edit Duration'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
controls_sizer = wx.FlexGridSizer(cols=len(CONTROLS), hgap=10, rows=2, vgap=10)
- main_sizer.AddSizer(controls_sizer, border=20,
- flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW)
-
+ main_sizer.AddSizer(controls_sizer, border=20,
+ flag=wx.TOP | wx.LEFT | wx.RIGHT | wx.GROW)
+
controls = []
for i, (name, label) in enumerate(CONTROLS):
controls_sizer.AddGrowableCol(i)
-
+
st = wx.StaticText(self, label=label)
txtctrl = wx.TextCtrl(self, value='0', style=wx.TE_PROCESS_ENTER)
- self.Bind(wx.EVT_TEXT_ENTER,
- self.GetControlValueTestFunction(txtctrl),
+ self.Bind(wx.EVT_TEXT_ENTER,
+ self.GetControlValueTestFunction(txtctrl),
txtctrl)
setattr(self, name, txtctrl)
-
+
controls.append((st, txtctrl))
-
+
for st, txtctrl in controls:
controls_sizer.AddWindow(st, flag=wx.GROW)
-
+
for st, txtctrl in controls:
controls_sizer.AddWindow(txtctrl, flag=wx.GROW)
-
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
- main_sizer.AddSizer(button_sizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(button_sizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.SetSizer(main_sizer)
self.Fit()
self.Days.SetFocus()
-
+
def SetDuration(self, value):
result = IEC_TIME_MODEL.match(value.upper())
if result is not None:
@@ -112,13 +113,13 @@
else:
self.Milliseconds.SetValue("0")
self.Microseconds.SetValue("0")
-
+
def GetControlValueTestFunction(self, control):
def OnValueChanged(event):
try:
value = float(control.GetValue())
except ValueError, e:
- message = wx.MessageDialog(self, _("Invalid value!\nYou must fill a numeric value."), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("Invalid value!\nYou must fill a numeric value."), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
event.Skip()
@@ -130,29 +131,29 @@
for control, factor in [(self.Days, DAY), (self.Hours, HOUR),
(self.Minutes, MINUTE), (self.Seconds, SECOND),
(self.Milliseconds, MILLISECONDS), (self.Microseconds, MICROSECONDS)]:
-
+
milliseconds += float(control.GetValue()) * factor
-
+
not_null = False
duration = "T#"
- for value, format in [(int(milliseconds) / DAY, "%dd"),
- ((int(milliseconds) % DAY) / HOUR, "%dh"),
- ((int(milliseconds) % HOUR) / MINUTE, "%dm"),
- ((int(milliseconds) % MINUTE) / SECOND, "%ds")]:
-
+ for value, format in [((int(milliseconds) / DAY), "%dd"),
+ ((int(milliseconds) % DAY) / HOUR, "%dh"),
+ ((int(milliseconds) % HOUR) / MINUTE, "%dm"),
+ ((int(milliseconds) % MINUTE) / SECOND, "%ds")]:
+
if value > 0 or not_null:
duration += format % value
not_null = True
-
+
duration += "%gms" % (milliseconds % SECOND)
return duration
-
+
def OnOK(self, event):
self.OnCloseDialog()
def OnCloseDialog(self):
errors = []
- for control, name in [(self.Days, _("days")), (self.Hours, _("hours")),
+ for control, name in [(self.Days, _("days")), (self.Hours, _("hours")),
(self.Minutes, _("minutes")), (self.Seconds, _("seconds")),
(self.Milliseconds, _("milliseconds"))]:
try:
@@ -164,7 +165,7 @@
message = _("Field %s hasn't a valid value!") % errors[0]
else:
message = _("Fields %s haven't a valid value!") % ",".join(errors)
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/dialogs/FBDBlockDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/FBDBlockDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -31,24 +31,25 @@
from controls.LibraryPanel import LibraryPanel
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def GetBlockTypeDefaultNameModel(blocktype):
return re.compile("%s[0-9]+" % blocktype if blocktype is not None else ".*")
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Block Parameters Dialog
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a dialog for defining parameters of a FBD block graphic
-element
-"""
+# -------------------------------------------------------------------------------
+
class FBDBlockDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a FBD block graphic
+ element
+ """
+
def __init__(self, parent, controller, tagname):
"""
Constructor
@@ -57,84 +58,84 @@
@param tagname: Tagname of project POU edited
"""
BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Block Properties'))
-
+ title=_('Block Properties'))
+
# Init common sizers
self._init_sizers(2, 0, 1, 0, 3, 2)
-
+
# Create static box around library panel
type_staticbox = wx.StaticBox(self, label=_('Type:'))
left_staticboxsizer = wx.StaticBoxSizer(type_staticbox, wx.VERTICAL)
self.LeftGridSizer.AddSizer(left_staticboxsizer, border=5, flag=wx.GROW)
-
+
# Create Library panel and add it to static box
self.LibraryPanel = LibraryPanel(self)
self.LibraryPanel.SetInitialSize(wx.Size(-1, 400))
-
+
# Set function to call when selection in Library panel changed
- setattr(self.LibraryPanel, "_OnTreeItemSelected",
- self.OnLibraryTreeItemSelected)
- left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5,
- flag=wx.GROW|wx.TOP)
-
+ setattr(self.LibraryPanel, "_OnTreeItemSelected",
+ self.OnLibraryTreeItemSelected)
+ left_staticboxsizer.AddWindow(self.LibraryPanel, 1, border=5,
+ flag=wx.GROW | wx.TOP)
+
# Create sizer for other block parameters
top_right_gridsizer = wx.FlexGridSizer(cols=2, hgap=0, rows=4, vgap=5)
top_right_gridsizer.AddGrowableCol(1)
self.RightGridSizer.AddSizer(top_right_gridsizer, flag=wx.GROW)
-
+
# Create label for block name
name_label = wx.StaticText(self, label=_('Name:'))
- top_right_gridsizer.AddWindow(name_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ top_right_gridsizer.AddWindow(name_label,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
# Create text control for defining block name
self.BlockName = wx.TextCtrl(self)
self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.BlockName)
top_right_gridsizer.AddWindow(self.BlockName, flag=wx.GROW)
-
+
# Create label for extended block input number
inputs_label = wx.StaticText(self, label=_('Inputs:'))
- top_right_gridsizer.AddWindow(inputs_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ top_right_gridsizer.AddWindow(inputs_label,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
# Create spin control for defining extended block input number
self.Inputs = wx.SpinCtrl(self, min=2, max=20,
- style=wx.SP_ARROW_KEYS)
+ style=wx.SP_ARROW_KEYS)
self.Bind(wx.EVT_SPINCTRL, self.OnInputsChanged, self.Inputs)
top_right_gridsizer.AddWindow(self.Inputs, flag=wx.GROW)
-
+
# Create label for block execution order
- execution_order_label = wx.StaticText(self,
- label=_('Execution Order:'))
- top_right_gridsizer.AddWindow(execution_order_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ execution_order_label = wx.StaticText(self,
+ label=_('Execution Order:'))
+ top_right_gridsizer.AddWindow(execution_order_label,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
# Create spin control for defining block execution order
self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS)
- self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged,
+ self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged,
self.ExecutionOrder)
top_right_gridsizer.AddWindow(self.ExecutionOrder, flag=wx.GROW)
-
+
# Create label for block execution control
- execution_control_label = wx.StaticText(self,
- label=_('Execution Control:'))
- top_right_gridsizer.AddWindow(execution_control_label,
- flag=wx.ALIGN_CENTER_VERTICAL)
-
+ execution_control_label = wx.StaticText(self,
+ label=_('Execution Control:'))
+ top_right_gridsizer.AddWindow(execution_control_label,
+ flag=wx.ALIGN_CENTER_VERTICAL)
+
# Create check box to enable block execution control
self.ExecutionControl = wx.CheckBox(self)
- self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged,
+ self.Bind(wx.EVT_CHECKBOX, self.OnExecutionOrderChanged,
self.ExecutionControl)
top_right_gridsizer.AddWindow(self.ExecutionControl, flag=wx.GROW)
-
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
# Dictionary containing correspondence between parameter exchanged and
# control to fill with parameter value
self.ParamsControl = {
@@ -142,20 +143,20 @@
"executionOrder": self.ExecutionOrder,
"executionControl": self.ExecutionControl
}
-
+
# Init controls value and sensibility
self.BlockName.SetValue("")
self.BlockName.Enable(False)
self.Inputs.Enable(False)
-
+
# Variable containing last name typed
self.CurrentBlockName = None
-
+
# Refresh Library panel values
self.LibraryPanel.SetBlockList(controller.GetBlockTypes(tagname))
self.Fit()
self.LibraryPanel.SetFocus()
-
+
def SetValues(self, values):
"""
Set default block parameters
@@ -163,38 +164,38 @@
"""
# Extract block type defined in parameters
blocktype = values.get("type", None)
-
- # Select block type in library panel
+
+ # Select block type in library panel
if blocktype is not None:
- self.LibraryPanel.SelectTreeItem(blocktype,
+ self.LibraryPanel.SelectTreeItem(blocktype,
values.get("inputs", None))
-
+
# Define regular expression for determine if block name is block
# default name
default_name_model = GetBlockTypeDefaultNameModel(blocktype)
-
+
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is block name
if name == "name":
if value != "":
# Set default graphic element name for testing
self.DefaultElementName = value
-
+
# Test if block name is type default block name and save
# block name if not (name have been typed by user)
if default_name_model.match(value) is None:
self.CurrentBlockName = value
-
+
self.BlockName.ChangeValue(value)
-
+
# Set value of other controls
else:
control = self.ParamsControl.get(name, None)
if control is not None:
control.SetValue(value)
-
+
# Refresh preview panel
self.RefreshPreview()
@@ -211,7 +212,7 @@
name: control.GetValue()
for name, control in self.ParamsControl.iteritems()})
return values
-
+
def OnOK(self, event):
"""
Called when dialog OK button is pressed
@@ -219,31 +220,31 @@
@param event: wx.Event from OK button
"""
message = None
-
+
# Get block type selected
selected = self.LibraryPanel.GetSelectedBlock()
-
+
# Get block type name and if block is a function block
block_name = self.BlockName.GetValue()
name_enabled = self.BlockName.IsEnabled()
-
+
# Test that a type has been selected for block
if selected is None:
message = _("Form isn't complete. Valid block type must be selected!")
-
+
# Test, if block is a function block, that a name have been defined
elif name_enabled and block_name == "":
message = _("Form isn't complete. Name must be filled!")
-
+
# Show error message if an error is detected
if message is not None:
self.ShowErrorMessage(message)
-
+
# Test block name validity if necessary
elif not name_enabled or self.TestElementName(block_name):
# Call BlockPreviewDialog function
BlockPreviewDialog.OnOK(self, event)
-
+
def OnLibraryTreeItemSelected(self, event):
"""
Called when block type selected in library panel
@@ -251,12 +252,12 @@
"""
# Get type selected in library panel
values = self.LibraryPanel.GetSelectedBlock()
-
+
# Get block type informations
- blocktype = (self.Controller.GetBlockType(values["type"],
+ blocktype = (self.Controller.GetBlockType(values["type"],
values["inputs"])
if values is not None else None)
-
+
# Set input number spin control according to block type informations
if blocktype is not None:
self.Inputs.SetValue(len(blocktype["inputs"]))
@@ -264,12 +265,12 @@
else:
self.Inputs.SetValue(2)
self.Inputs.Enable(False)
-
+
# Update block name with default value if block type is a function and
# current block name wasn't typed by user
if blocktype is not None and blocktype["type"] != "function":
self.BlockName.Enable(True)
-
+
if self.CurrentBlockName is None:
# Generate new block name according to block type, taking
# default element name if it was already a default name for this
@@ -277,21 +278,21 @@
default_name_model = GetBlockTypeDefaultNameModel(values["type"])
block_name = (
self.DefaultElementName
- if (self.DefaultElementName is not None and
+ if (self.DefaultElementName is not None and
default_name_model.match(self.DefaultElementName))
else self.Controller.GenerateNewName(
self.TagName, None, values["type"]+"%d", 0))
else:
block_name = self.CurrentBlockName
-
+
self.BlockName.ChangeValue(block_name)
else:
self.BlockName.Enable(False)
self.BlockName.ChangeValue("")
-
+
# Refresh preview panel
self.RefreshPreview()
-
+
def OnNameChanged(self, event):
"""
Called when block name value changed
@@ -302,7 +303,7 @@
self.CurrentBlockName = self.BlockName.GetValue()
self.RefreshPreview()
event.Skip()
-
+
def OnInputsChanged(self, event):
"""
Called when block inputs number changed
@@ -311,7 +312,7 @@
if self.Inputs.IsEnabled():
self.RefreshPreview()
event.Skip()
-
+
def OnExecutionOrderChanged(self, event):
"""
Called when block execution order value changed
@@ -319,7 +320,7 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def OnExecutionControlChanged(self, event):
"""
Called when block execution control value changed
@@ -327,7 +328,7 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
@@ -335,22 +336,21 @@
"""
# Get type selected in library panel
values = self.LibraryPanel.GetSelectedBlock()
-
+
# If a block type is selected in library panel
if values is not None:
# Set graphic element displayed, creating a FBD block element
- self.Element = FBD_Block(self.Preview, values["type"],
- (self.BlockName.GetValue()
- if self.BlockName.IsEnabled()
- else ""),
- extension = self.Inputs.GetValue(),
- inputs = values["inputs"],
- executionControl = self.ExecutionControl.GetValue(),
- executionOrder = self.ExecutionOrder.GetValue())
-
+ self.Element = FBD_Block(
+ self.Preview, values["type"],
+ (self.BlockName.GetValue() if self.BlockName.IsEnabled() else ""),
+ extension=self.Inputs.GetValue(),
+ inputs=values["inputs"],
+ executionControl=self.ExecutionControl.GetValue(),
+ executionOrder=self.ExecutionOrder.GetValue())
+
# Reset graphic element displayed
else:
- self.Element = None
-
+ self.Element = None
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
--- a/dialogs/FBDVariableDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/FBDVariableDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,28 +29,31 @@
from graphics.FBD_Objects import FBD_Variable
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Dictionaries containing correspondence between variable block class and string
# to be shown in Class combo box in both sense
-VARIABLE_CLASSES_DICT = {INPUT : _("Input"),
- INOUT : _("InOut"),
- OUTPUT : _("Output")}
+VARIABLE_CLASSES_DICT = {
+ INPUT: _("Input"),
+ INOUT: _("InOut"),
+ OUTPUT: _("Output")
+}
+
VARIABLE_CLASSES_DICT_REVERSE = dict(
[(value, key) for key, value in VARIABLE_CLASSES_DICT.iteritems()])
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Variable Parameters Dialog
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a dialog for defining parameters of a FBD variable graphic
-element
-"""
+# -------------------------------------------------------------------------------
+
class FBDVariableDialog(BlockPreviewDialog):
+ """
+ Class that implements a dialog for defining parameters of a FBD variable graphic
+ element
+ """
def __init__(self, parent, controller, tagname, exclude_input=False):
"""
@@ -61,70 +64,71 @@
@param exclude_input: Exclude input from variable class selection
"""
BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Variable Properties'))
-
+ title=_('Variable Properties'))
+
# Init common sizers
self._init_sizers(4, 2, 4, None, 3, 2)
-
+
# Create label for variable class
class_label = wx.StaticText(self, label=_('Class:'))
self.LeftGridSizer.AddWindow(class_label, flag=wx.GROW)
-
+
# Create a combo box for defining variable class
self.Class = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnClassChanged, self.Class)
self.LeftGridSizer.AddWindow(self.Class, flag=wx.GROW)
-
+
# Create label for variable execution order
- execution_order_label = wx.StaticText(self,
- label=_('Execution Order:'))
+ execution_order_label = wx.StaticText(self,
+ label=_('Execution Order:'))
self.LeftGridSizer.AddWindow(execution_order_label, flag=wx.GROW)
-
+
# Create spin control for defining variable execution order
self.ExecutionOrder = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS)
- self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged,
+ self.Bind(wx.EVT_SPINCTRL, self.OnExecutionOrderChanged,
self.ExecutionOrder)
self.LeftGridSizer.AddWindow(self.ExecutionOrder, flag=wx.GROW)
-
+
# Create label for variable expression
name_label = wx.StaticText(self, label=_('Expression:'))
- self.RightGridSizer.AddWindow(name_label, border=5,
- flag=wx.GROW|wx.BOTTOM)
-
+ self.RightGridSizer.AddWindow(name_label, border=5,
+ flag=wx.GROW | wx.BOTTOM)
+
# Create text control for defining variable expression
self.Expression = wx.TextCtrl(self)
self.Bind(wx.EVT_TEXT, self.OnExpressionChanged, self.Expression)
self.RightGridSizer.AddWindow(self.Expression, flag=wx.GROW)
-
+
# Create a list box to selected variable expression in the list of
# variables defined in POU
- self.VariableName = wx.ListBox(self, size=wx.Size(-1,120),
- style=wx.LB_SINGLE|wx.LB_SORT)
+ self.VariableName = wx.ListBox(self, size=wx.Size(-1, 120),
+ style=wx.LB_SINGLE | wx.LB_SORT)
self.Bind(wx.EVT_LISTBOX, self.OnNameChanged, self.VariableName)
- self.RightGridSizer.AddWindow(self.VariableName, border=4, flag=wx.GROW|wx.TOP)
-
+ self.RightGridSizer.AddWindow(self.VariableName, border=4, flag=wx.GROW | wx.TOP)
+
# Add preview panel and associated label to sizers
self.MainSizer.AddWindow(self.PreviewLabel, border=20,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
self.MainSizer.AddWindow(self.Preview, border=20,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
# Set options that can be selected in class combo box
for var_class, choice in VARIABLE_CLASSES_DICT.iteritems():
if not exclude_input or var_class != INPUT:
self.Class.Append(choice)
self.Class.SetSelection(0)
-
+
# Extract list of variables defined in POU
self.RefreshVariableList()
-
+
# Refresh values in name list box
self.RefreshNameList()
-
+
self.Preview.SetInitialSize(wx.Size(-1, 60))
self.Fit()
@@ -138,32 +142,31 @@
# Get variable class to select POU variable applicable
var_class = VARIABLE_CLASSES_DICT_REVERSE[
self.Class.GetStringSelection()]
-
+
# Refresh names in name list box by selecting variables in POU variables
# list that can be applied to variable class
self.VariableName.Clear()
for name, (var_type, value_type) in self.VariableList.iteritems():
if var_type != "Input" or var_class == INPUT:
self.VariableName.Append(name)
-
+
# Get variable expression and select corresponding value in name list
# box if it exists
selected = self.Expression.GetValue()
- if (selected != "" and
- self.VariableName.FindString(selected) != wx.NOT_FOUND):
+ if selected != "" and self.VariableName.FindString(selected) != wx.NOT_FOUND:
self.VariableName.SetStringSelection(selected)
else:
self.VariableName.SetSelection(wx.NOT_FOUND)
-
+
# Disable name list box if no name present inside
self.VariableName.Enable(self.VariableName.GetCount() > 0)
-
+
def SetValues(self, values):
"""
Set default variable parameters
@param values: Variable parameters values
"""
-
+
# Get class parameter value
var_class = values.get("class", None)
if var_class is not None:
@@ -171,10 +174,10 @@
self.Class.SetStringSelection(VARIABLE_CLASSES_DICT[var_class])
# Refresh names in name list box according to var class
self.RefreshNameList()
-
+
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is variable expression
if name == "expression":
# Set expression text control value
@@ -184,15 +187,15 @@
self.VariableName.SetStringSelection(value)
else:
self.VariableName.SetSelection(wx.NOT_FOUND)
-
+
# Parameter is variable execution order
elif name == "executionOrder":
self.ExecutionOrder.SetValue(value)
-
+
# Refresh preview panel
self.RefreshPreview()
self.Fit()
-
+
def GetValues(self):
"""
Return block parameters defined in dialog
@@ -215,16 +218,16 @@
@param event: wx.Event from OK button
"""
message = None
-
+
# Test that an expression have been selected or typed by user
value = self.Expression.GetValue()
if value == "":
message = _("At least a variable or an expression must be selected!")
-
+
# Show error message if an error is detected
if message is not None:
self.ShowErrorMessage(message)
-
+
else:
# Call BlockPreviewDialog function
BlockPreviewDialog.OnOK(self, event)
@@ -236,7 +239,7 @@
"""
# Refresh name list box values
self.RefreshNameList()
-
+
self.RefreshPreview()
event.Skip()
@@ -249,10 +252,10 @@
# list box if value selected is valid
if self.VariableName.GetSelection() != wx.NOT_FOUND:
self.Expression.ChangeValue(self.VariableName.GetStringSelection())
-
- self.RefreshPreview()
- event.Skip()
-
+
+ self.RefreshPreview()
+ event.Skip()
+
def OnExpressionChanged(self, event):
"""
Called when expression text control is changed by user
@@ -261,10 +264,10 @@
# Select the corresponding value in name list box if it exists
self.VariableName.SetSelection(
self.VariableName.FindString(self.Expression.GetValue()))
-
- self.RefreshPreview()
- event.Skip()
-
+
+ self.RefreshPreview()
+ event.Skip()
+
def OnExecutionOrderChanged(self, event):
"""
Called when block execution control value changed
@@ -272,7 +275,7 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
@@ -280,16 +283,14 @@
"""
# Get expression value to put in FBD variable element
name = self.Expression.GetValue()
-
+
# Set graphic element displayed, creating a FBD variable element
- self.Element = FBD_Variable(self.Preview,
- VARIABLE_CLASSES_DICT_REVERSE[
- self.Class.GetStringSelection()],
- name,
- self.VariableList.get(name, ("", ""))[1],
- executionOrder = self.ExecutionOrder.GetValue())
-
+ self.Element = FBD_Variable(
+ self.Preview,
+ VARIABLE_CLASSES_DICT_REVERSE[self.Class.GetStringSelection()],
+ name,
+ self.VariableList.get(name, ("", ""))[1],
+ executionOrder=self.ExecutionOrder.GetValue())
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
-
-
--- a/dialogs/FindInPouDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/FindInPouDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,86 +26,87 @@
import wx
from plcopen.plcopen import *
+
class FindInPouDialog(wx.Dialog):
def _init_icon(self, parent):
if parent and parent.icon:
self.SetIcon(parent.icon)
-
def __init__(self, parent):
- wx.Dialog.__init__(self, parent, title=_("Find"),
- style=wx.CAPTION|wx.CLOSE_BOX|wx.CLIP_CHILDREN|wx.RESIZE_BORDER)
-
+ wx.Dialog.__init__(
+ self, parent, title=_("Find"),
+ style=wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.RESIZE_BORDER)
+
self._init_icon(parent)
panel = wx.Panel(self, style=wx.TAB_TRAVERSAL)
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=5, rows=2, vgap=5)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
controls_sizer = wx.BoxSizer(wx.VERTICAL)
- main_sizer.AddSizer(controls_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(controls_sizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
patterns_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=1, vgap=5)
patterns_sizer.AddGrowableCol(1)
- controls_sizer.AddSizer(patterns_sizer, border=5, flag=wx.GROW|wx.BOTTOM)
-
+ controls_sizer.AddSizer(patterns_sizer, border=5, flag=wx.GROW | wx.BOTTOM)
+
find_label = wx.StaticText(panel, label=_("Find:"))
patterns_sizer.AddWindow(find_label, flag=wx.ALIGN_CENTER_VERTICAL)
-
+
self.FindPattern = wx.TextCtrl(panel)
self.Bind(wx.EVT_TEXT, self.OnFindPatternChanged, self.FindPattern)
self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey)
patterns_sizer.AddWindow(self.FindPattern, flag=wx.GROW)
-
+
params_sizer = wx.BoxSizer(wx.HORIZONTAL)
- controls_sizer.AddSizer(params_sizer, border=5, flag=wx.GROW|wx.BOTTOM)
-
+ controls_sizer.AddSizer(params_sizer, border=5, flag=wx.GROW | wx.BOTTOM)
+
direction_staticbox = wx.StaticBox(panel, label=_("Direction"))
direction_staticboxsizer = wx.StaticBoxSizer(
direction_staticbox, wx.VERTICAL)
- params_sizer.AddSizer(direction_staticboxsizer, 1, border=5,
- flag=wx.GROW|wx.RIGHT)
-
- self.Forward = wx.RadioButton(panel, label=_("Forward"),
- style=wx.RB_GROUP)
- direction_staticboxsizer.AddWindow(self.Forward, border=5,
- flag=wx.ALL|wx.GROW)
-
+ params_sizer.AddSizer(direction_staticboxsizer, 1, border=5,
+ flag=wx.GROW | wx.RIGHT)
+
+ self.Forward = wx.RadioButton(panel, label=_("Forward"),
+ style=wx.RB_GROUP)
+ direction_staticboxsizer.AddWindow(self.Forward, border=5,
+ flag=wx.ALL | wx.GROW)
+
self.Backward = wx.RadioButton(panel, label=_("Backward"))
- direction_staticboxsizer.AddWindow(self.Backward, border=5,
- flag=wx.ALL|wx.GROW)
-
+ direction_staticboxsizer.AddWindow(self.Backward, border=5,
+ flag=wx.ALL | wx.GROW)
+
options_staticbox = wx.StaticBox(panel, label=_("Options"))
options_staticboxsizer = wx.StaticBoxSizer(
options_staticbox, wx.VERTICAL)
params_sizer.AddSizer(options_staticboxsizer, 1, flag=wx.GROW)
-
+
self.CaseSensitive = wx.CheckBox(panel, label=_("Case sensitive"))
self.CaseSensitive.SetValue(True)
- options_staticboxsizer.AddWindow(self.CaseSensitive, border=5,
- flag=wx.ALL|wx.GROW)
-
+ options_staticboxsizer.AddWindow(self.CaseSensitive, border=5,
+ flag=wx.ALL | wx.GROW)
+
self.WrapSearch = wx.CheckBox(panel, label=_("Wrap search"))
self.WrapSearch.SetValue(True)
- options_staticboxsizer.AddWindow(self.WrapSearch, border=5,
- flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)
-
+ options_staticboxsizer.AddWindow(self.WrapSearch, border=5,
+ flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)
+
self.RegularExpressions = wx.CheckBox(panel, label=_("Regular expressions"))
- options_staticboxsizer.AddWindow(self.RegularExpressions, border=5,
- flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW)
-
+ options_staticboxsizer.AddWindow(self.RegularExpressions, border=5,
+ flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.GROW)
+
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
- main_sizer.AddSizer(buttons_sizer, border=20,
- flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_RIGHT)
-
+ main_sizer.AddSizer(buttons_sizer, border=20,
+ flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT)
+
self.FindButton = wx.Button(panel, label=_("Find"))
self.FindButton.SetDefault()
self.Bind(wx.EVT_BUTTON, self.OnFindButton, self.FindButton)
buttons_sizer.AddWindow(self.FindButton, border=5, flag=wx.RIGHT)
-
+
self.CloseButton = wx.Button(panel, label=_("Close"))
self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton)
buttons_sizer.AddWindow(self.CloseButton)
@@ -113,32 +114,31 @@
# set the longest message here, to use it length to calculate
# optimal size of dialog window
self.RegExpSyntaxErrMsg = _("Syntax error in regular expression of pattern to search!")
- self.StatusLabel = wx.StaticText(panel, label= self.RegExpSyntaxErrMsg)
+ self.StatusLabel = wx.StaticText(panel, label=self.RegExpSyntaxErrMsg)
controls_sizer.AddWindow(self.StatusLabel, flag=wx.ALIGN_CENTER_VERTICAL)
-
+
panel.SetSizer(main_sizer)
main_sizer.Fit(self)
# clear message after dialog size calculation
self.SetStatusText("")
-
self.ParentWindow = parent
-
+
self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
self.infosPrev = {}
self.criteria = {}
self.FindPattern.SetFocus()
self.RefreshButtonsState()
-
+
def RefreshButtonsState(self):
find_pattern = self.FindPattern.GetValue()
self.FindButton.Enable(find_pattern != "")
-
+
def OnCloseFrame(self, event):
self.Hide()
event.Veto()
-
+
def OnCloseButton(self, event):
self.Hide()
event.Skip()
@@ -157,7 +157,7 @@
def SetStatusText(self, msg):
self.StatusLabel.SetLabel(msg)
self.Layout()
-
+
def OnFindButton(self, event):
infos = {
"find_pattern": self.FindPattern.GetValue(),
@@ -172,12 +172,12 @@
try:
self.criteria = infos
CompilePattern(self.criteria)
- except:
+ except Exception:
self.criteria.clear()
message = self.RegExpSyntaxErrMsg
self.SetStatusText(message)
if len(self.criteria) > 0:
wx.CallAfter(self.ParentWindow.FindInPou,
- {True: 1, False:-1}[self.Forward.GetValue()],
- self.criteria)
+ {True: 1, False: -1}[self.Forward.GetValue()],
+ self.criteria)
event.Skip()
--- a/dialogs/ForceVariableDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/ForceVariableDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,26 +26,29 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
-
-LOCATIONDATATYPES = {"X" : ["BOOL"],
- "B" : ["SINT", "USINT", "BYTE", "STRING"],
- "W" : ["INT", "UINT", "WORD", "WSTRING"],
- "D" : ["DINT", "UDINT", "REAL", "DWORD"],
- "L" : ["LINT", "ULINT", "LREAL", "LWORD"]}
+# -------------------------------------------------------------------------------
+
+LOCATIONDATATYPES = {"X": ["BOOL"],
+ "B": ["SINT", "USINT", "BYTE", "STRING"],
+ "W": ["INT", "UINT", "WORD", "WSTRING"],
+ "D": ["DINT", "UDINT", "REAL", "DWORD"],
+ "L": ["LINT", "ULINT", "LREAL", "LWORD"]}
+
def gen_get_function(f):
def get_function(v):
try:
return f(v)
- except:
+ except Exception:
return None
return get_function
+
def gen_get_string(delimiter):
STRING_MODEL = re.compile("%(delimiter)s([^%(delimiter)s]*)%(delimiter)s$" % {"delimiter": delimiter})
+
def get_string(v):
result = STRING_MODEL.match(v)
if result is not None:
@@ -53,6 +56,7 @@
return None
return get_string
+
getinteger = gen_get_function(int)
getfloat = gen_get_function(float)
getstring = gen_get_string("'")
@@ -68,7 +72,8 @@
IEC_DATETIME_MODEL = re.compile("(?:(?:DT|DATE_AND_TIME)#)?([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$")
IEC_TIMEOFDAY_MODEL = re.compile("(?:(?:TOD|TIME_OF_DAY)#)?([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]+)?)$")
-def gettime(v):
+
+def gettime(v):
result = IEC_TIME_MODEL.match(v.upper())
if result is not None:
negative, days, hours, minutes, seconds, milliseconds = result.groups()
@@ -87,9 +92,10 @@
if negative is not None:
microseconds = -microseconds
return datetime.timedelta(microseconds=microseconds)
-
- else:
- return None
+
+ else:
+ return None
+
def getdate(v):
result = IEC_DATE_MODEL.match(v.upper())
@@ -101,8 +107,9 @@
return None
base_date = datetime.datetime(1970, 1, 1)
return date - base_date
- else:
- return None
+ else:
+ return None
+
def getdatetime(v):
result = IEC_DATETIME_MODEL.match(v.upper())
@@ -114,8 +121,9 @@
return None
base_date = datetime.datetime(1970, 1, 1)
return date - base_date
- else:
- return None
+ else:
+ return None
+
def gettimeofday(v):
result = IEC_TIMEOFDAY_MODEL.match(v.upper())
@@ -130,6 +138,7 @@
else:
return None
+
GetTypeValue = {"BOOL": lambda x: {"TRUE": True, "FALSE": False, "0": False, "1": True}.get(x.upper(), None),
"SINT": getinteger,
"INT": getinteger,
@@ -152,38 +161,43 @@
"DT": getdatetime,
"TOD": gettimeofday}
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Force Variable Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ForceVariableDialog(wx.TextEntryDialog):
def __init__(self, parent, iec_type, defaultValue=""):
- wx.TextEntryDialog.__init__(self, parent, message = _("Forcing Variable Value"),
- caption = _("Please enter value for a \"%s\" variable:") % iec_type, defaultValue = defaultValue,
- style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition)
-
- self.IEC_Type = iec_type
-
- self.Bind(wx.EVT_BUTTON, self.OnOK,
- self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton())
- self.ValueTextCtrl=self.GetSizer().GetItem(1).GetWindow()
+ wx.TextEntryDialog.__init__(
+ self, parent,
+ message=_("Forcing Variable Value"),
+ caption=_("Please enter value for a \"%s\" variable:") % iec_type,
+ defaultValue=defaultValue,
+ style=wx.OK | wx.CANCEL | wx.CENTRE, pos=wx.DefaultPosition)
+
+ self.IEC_Type = iec_type
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
+ self.GetSizer().GetItem(2).GetSizer().GetItem(1).
+ GetSizer().GetAffirmativeButton())
+ self.ValueTextCtrl = self.GetSizer().GetItem(1).GetWindow()
if self.IEC_Type == "BOOL":
self.ToggleButton = wx.ToggleButton(self, label=_("Toggle value"))
- value=GetTypeValue[self.IEC_Type](defaultValue)
+ value = GetTypeValue[self.IEC_Type](defaultValue)
if value is not None:
self.ToggleButton.SetValue(value)
- border=self.GetSizer().GetItem(1).GetBorder()
+ border = self.GetSizer().GetItem(1).GetBorder()
self.GetSizer().Insert(before=2, item=self.ToggleButton,
border=border,
- flag=wx.LEFT|wx.RIGHT|wx.EXPAND)
+ flag=wx.LEFT | wx.RIGHT | wx.EXPAND)
self.Bind(wx.EVT_TOGGLEBUTTON, self.ToggleBoolValue, self.ToggleButton)
self.Fit()
def ToggleBoolValue(self, event):
- value=self.ToggleButton.GetValue()
+ value = self.ToggleButton.GetValue()
self.ValueTextCtrl.SetValue(unicode(value))
def OnOK(self, event):
@@ -192,9 +206,9 @@
if value == "":
message = _("You must type a value!")
elif GetTypeValue[self.IEC_Type](value) is None:
- message = _("Invalid value \"{a1}\" for \"{a2}\" variable!").format(a1 = value, a2 = self.IEC_Type)
+ message = _("Invalid value \"{a1}\" for \"{a2}\" variable!").format(a1=value, a2=self.IEC_Type)
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/dialogs/LDElementDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/LDElementDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -31,17 +31,17 @@
from graphics.LD_Objects import LD_Contact, LD_Coil
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Ladder Element Parmeters Dialog
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a dialog for defining parameters of a LD contact or coil
-graphic element
-"""
+# -------------------------------------------------------------------------------
+
class LDElementDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a LD contact or coil
+ graphic element
+ """
+
def __init__(self, parent, controller, tagname, type):
"""
Constructor
@@ -50,80 +50,81 @@
@param tagname: Tagname of project POU edited
@param type: Type of LD element ('contact or 'coil')
"""
- BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=(_("Edit Contact Values")
- if type == "contact"
- else _("Edit Coil Values")))
-
+ BlockPreviewDialog.__init__(self, parent, controller, tagname,
+ title=(_("Edit Contact Values")
+ if type == "contact"
+ else _("Edit Coil Values")))
+
# Init common sizers
- self._init_sizers(2, 0,
- (7 if type == "contact" else 9), None, 2, 1)
-
+ self._init_sizers(2, 0, (7 if type == "contact" else 9),
+ None, 2, 1)
+
# Create label for LD element modifier
modifier_label = wx.StaticText(self, label=_('Modifier:'))
- self.LeftGridSizer.AddWindow(modifier_label, border=5,
- flag=wx.GROW|wx.BOTTOM)
-
+ self.LeftGridSizer.AddWindow(modifier_label, border=5,
+ flag=wx.GROW | wx.BOTTOM)
+
# Create radio buttons for selecting LD element modifier
self.ModifierRadioButtons = {}
first = True
- element_modifiers = ([CONTACT_NORMAL, CONTACT_REVERSE,
+ element_modifiers = ([CONTACT_NORMAL, CONTACT_REVERSE,
CONTACT_RISING, CONTACT_FALLING]
if type == "contact"
else [COIL_NORMAL, COIL_REVERSE, COIL_SET,
COIL_RESET, COIL_RISING, COIL_FALLING])
- modifiers_label = [_("Normal"), _("Negated")] + \
- ([_("Set"), _("Reset")] if type == "coil" else []) + \
- [_("Rising Edge"), _("Falling Edge")]
-
+ modifiers_label = \
+ [_("Normal"), _("Negated")] + \
+ ([_("Set"), _("Reset")] if type == "coil" else []) + \
+ [_("Rising Edge"), _("Falling Edge")]
+
for modifier, label in zip(element_modifiers, modifiers_label):
- radio_button = wx.RadioButton(self, label=label,
- style=(wx.RB_GROUP if first else 0))
+ radio_button = wx.RadioButton(self, label=label,
+ style=(wx.RB_GROUP if first else 0))
radio_button.SetValue(first)
self.Bind(wx.EVT_RADIOBUTTON, self.OnModifierChanged, radio_button)
self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
self.ModifierRadioButtons[modifier] = radio_button
first = False
-
+
# Create label for LD element variable
element_variable_label = wx.StaticText(self, label=_('Variable:'))
self.LeftGridSizer.AddWindow(element_variable_label, border=5,
- flag=wx.GROW|wx.TOP)
-
+ flag=wx.GROW | wx.TOP)
+
# Create a combo box for defining LD element variable
self.ElementVariable = wx.ComboBox(self, style=wx.CB_SORT)
- self.Bind(wx.EVT_COMBOBOX, self.OnVariableChanged,
+ self.Bind(wx.EVT_COMBOBOX, self.OnVariableChanged,
self.ElementVariable)
- self.Bind(wx.EVT_TEXT, self.OnVariableChanged,
- self.ElementVariable)
+ self.Bind(wx.EVT_TEXT, self.OnVariableChanged,
+ self.ElementVariable)
self.LeftGridSizer.AddWindow(self.ElementVariable, border=5,
- flag=wx.GROW|wx.TOP)
-
+ flag=wx.GROW | wx.TOP)
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
# Save LD element class
self.ElementClass = (LD_Contact if type == "contact" else LD_Coil)
-
+
# Extract list of variables defined in POU
self.RefreshVariableList()
-
+
# Set values in ElementVariable
for name, (var_type, value_type) in self.VariableList.iteritems():
# Only select BOOL variable and avoid input for coil
if (type == "contact" or var_type != "Input") and \
value_type == "BOOL":
self.ElementVariable.Append(name)
-
+
self.Fit()
# Normal radio button is default control having keyboard focus
self.ModifierRadioButtons[element_modifiers[0]].SetFocus()
-
+
def GetElementModifier(self):
"""
Return modifier selected for LD element
@@ -143,15 +144,15 @@
"""
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is LD element variable
if name == "variable":
self.ElementVariable.SetValue(value)
-
+
# Set value of other controls
elif name == "modifier":
self.ModifierRadioButtons[value].SetValue(True)
-
+
# Refresh preview panel
self.RefreshPreview()
@@ -188,20 +189,19 @@
Override BlockPreviewDialog function
"""
value = self.ElementVariable.GetValue()
-
+
# Set graphic element displayed, creating a LD element
self.Element = self.ElementClass(
- self.Preview,
+ self.Preview,
self.GetElementModifier(),
value)
button = self.ButtonSizer.GetAffirmativeButton()
button.Enable(value != "")
-
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
-
+
def OnOK(self, event):
if self.ElementVariable.GetValue() != "":
self.EndModal(wx.ID_OK)
-
--- a/dialogs/LDPowerRailDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/LDPowerRailDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -29,17 +29,16 @@
from graphics.LD_Objects import LD_PowerRail
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Ladder Power Rail Parameters Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a dialog for defining parameters of a power rail graphic
-element
-"""
class LDPowerRailDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a power rail graphic
+ element
+ """
def __init__(self, parent, controller, tagname):
"""
Constructor
@@ -48,51 +47,52 @@
@param tagname: Tagname of project POU edited
"""
BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Power Rail Properties'))
-
+ title=_('Power Rail Properties'))
+
# Init common sizers
self._init_sizers(2, 0, 5, None, 2, 1)
-
+
# Create label for connection type
type_label = wx.StaticText(self, label=_('Type:'))
self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW)
-
+
# Create radio buttons for selecting power rail type
self.TypeRadioButtons = {}
first = True
for type, label in [(LEFTRAIL, _('Left PowerRail')),
(RIGHTRAIL, _('Right PowerRail'))]:
- radio_button = wx.RadioButton(self, label=label,
- style=(wx.RB_GROUP if first else 0))
+ radio_button = wx.RadioButton(self, label=label,
+ style=(wx.RB_GROUP if first else 0))
radio_button.SetValue(first)
self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button)
self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
self.TypeRadioButtons[type] = radio_button
first = False
-
+
# Create label for power rail pin number
pin_number_label = wx.StaticText(self, label=_('Pin number:'))
self.LeftGridSizer.AddWindow(pin_number_label, flag=wx.GROW)
-
+
# Create spin control for defining power rail pin number
self.PinNumber = wx.SpinCtrl(self, min=1, max=50,
- style=wx.SP_ARROW_KEYS)
+ style=wx.SP_ARROW_KEYS)
self.PinNumber.SetValue(1)
self.Bind(wx.EVT_SPINCTRL, self.OnPinNumberChanged, self.PinNumber)
self.LeftGridSizer.AddWindow(self.PinNumber, flag=wx.GROW)
-
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
self.Fit()
-
+
# Left Power Rail radio button is default control having keyboard focus
self.TypeRadioButtons[LEFTRAIL].SetFocus()
-
+
def GetMinElementSize(self):
"""
Get minimal graphic element size
@@ -100,7 +100,7 @@
element defined
"""
return self.Element.GetMinSize(True)
-
+
def GetPowerRailType(self):
"""
Return type selected for power rail
@@ -109,7 +109,7 @@
return (LEFTRAIL
if self.TypeRadioButtons[LEFTRAIL].GetValue()
else RIGHTRAIL)
-
+
def SetValues(self, values):
"""
Set default power rail parameters
@@ -117,11 +117,11 @@
"""
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is power rail type
if name == "type":
self.TypeRadioButtons[value].SetValue(True)
-
+
# Parameter is power rail pin number
elif name == "pin_number":
self.PinNumber.SetValue(value)
@@ -158,11 +158,11 @@
Refresh preview panel of graphic element
Override BlockPreviewDialog function
"""
-
+
# Set graphic element displayed, creating a power rail element
- self.Element = LD_PowerRail(self.Preview,
- self.GetPowerRailType(),
- connectors = self.PinNumber.GetValue())
-
+ self.Element = LD_PowerRail(self.Preview,
+ self.GetPowerRailType(),
+ connectors=self.PinNumber.GetValue())
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
--- a/dialogs/PouActionDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/PouActionDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,55 +26,60 @@
import wx
from plcopen.structures import TestIdentifier, IEC_KEYWORDS
+from util.TranslationCatalogs import NoTranslate
+
def GetActionLanguages():
- _ = lambda x : x
+ _ = NoTranslate
return [_("IL"), _("ST"), _("LD"), _("FBD")]
+
+
ACTION_LANGUAGES_DICT = dict([(_(language), language) for language in GetActionLanguages()])
+
class PouActionDialog(wx.Dialog):
-
+
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title=_('Create a new action'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15)
infos_sizer.AddGrowableCol(1)
- main_sizer.AddSizer(infos_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(infos_sizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
actionname_label = wx.StaticText(self, label=_('Action Name:'))
- infos_sizer.AddWindow(actionname_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
-
- self.ActionName = wx.TextCtrl(self, size=wx.Size(180,-1))
+ infos_sizer.AddWindow(actionname_label, border=4,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
+
+ self.ActionName = wx.TextCtrl(self, size=wx.Size(180, -1))
infos_sizer.AddWindow(self.ActionName, flag=wx.GROW)
-
+
language_label = wx.StaticText(self, label=_('Language:'))
- infos_sizer.AddWindow(language_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
-
+ infos_sizer.AddWindow(language_label, border=4,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
+
self.Language = wx.ComboBox(self, style=wx.CB_READONLY)
infos_sizer.AddWindow(self.Language, flag=wx.GROW)
-
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
- self.Bind(wx.EVT_BUTTON, self.OnOK,
- button_sizer.GetAffirmativeButton())
- main_sizer.AddSizer(button_sizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
+ button_sizer.GetAffirmativeButton())
+ main_sizer.AddSizer(button_sizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.SetSizer(main_sizer)
-
+
for option in GetActionLanguages():
self.Language.Append(_(option))
-
+
self.Fit()
self.PouNames = []
self.PouElementNames = []
-
+
def OnOK(self, event):
error = []
action_name = self.ActionName.GetValue()
@@ -89,9 +94,9 @@
if i == 0:
text += item
elif i == len(error) - 1:
- text += _(" and %s")%item
+ text += _(" and %s") % item
else:
- text += _(", %s")%item
+ text += _(", %s") % item
message = _("Form isn't complete. %s must be filled!") % text
elif not TestIdentifier(action_name):
message = _("\"%s\" is not a valid identifier!") % action_name
@@ -102,28 +107,27 @@
elif action_name.upper() in self.PouElementNames:
message = _("\"%s\" element for this pou already exists!") % action_name
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
self.EndModal(wx.ID_OK)
-
+
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
-
+
def SetPouElementNames(self, element_names):
self.PouElementNames = [element_name.upper() for element_name in element_names]
-
+
def SetValues(self, values):
for item, value in values.items():
if item == "actionName":
self.ActionName.SetValue(value)
elif item == "language":
self.Language.SetStringSelection(_(value))
-
+
def GetValues(self):
values = {}
values["actionName"] = self.ActionName.GetValue()
values["language"] = ACTION_LANGUAGES_DICT[self.Language.GetStringSelection()]
return values
-
--- a/dialogs/PouDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/PouDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,16 +26,22 @@
import wx
from plcopen.structures import TestIdentifier, IEC_KEYWORDS
+from util.TranslationCatalogs import NoTranslate
+
def GetPouTypes():
- _ = lambda x : x
+ _ = NoTranslate
return [_("function"), _("functionBlock"), _("program")]
+
+
POU_TYPES_DICT = dict([(_(pou_type), pou_type) for pou_type in GetPouTypes()])
+
def GetPouLanguages():
- _ = lambda x : x
+ _ = NoTranslate
return [_("IL"), _("ST"), _("LD"), _("FBD"), _("SFC")]
+
class PouDialog(wx.Dialog):
POU_LANGUAGES = GetPouLanguages()
@@ -43,8 +49,8 @@
def __init__(self, parent, pou_type=None, type_readonly=False):
wx.Dialog.__init__(self, id=-1, parent=parent,
- name='PouDialog', title=_('Create a new POU'),
- style=wx.DEFAULT_DIALOG_STYLE)
+ name='PouDialog', title=_('Create a new POU'),
+ style=wx.DEFAULT_DIALOG_STYLE)
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
@@ -53,18 +59,18 @@
infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=15)
infos_sizer.AddGrowableCol(1)
main_sizer.AddSizer(infos_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
pouname_label = wx.StaticText(self, label=_('POU Name:'))
infos_sizer.AddWindow(pouname_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
self.PouName = wx.TextCtrl(self)
infos_sizer.AddWindow(self.PouName, flag=wx.GROW)
poutype_label = wx.StaticText(self, label=_('POU Type:'))
infos_sizer.AddWindow(poutype_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
self.PouType = wx.ComboBox(self, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnTypeChanged, self.PouType)
@@ -72,15 +78,15 @@
language_label = wx.StaticText(self, label=_('Language:'))
infos_sizer.AddWindow(language_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
self.Language = wx.ComboBox(self, style=wx.CB_READONLY)
infos_sizer.AddWindow(self.Language, flag=wx.GROW)
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
main_sizer.AddSizer(button_sizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
self.SetSizer(main_sizer)
@@ -111,9 +117,9 @@
if i == 0:
text += item
elif i == len(error) - 1:
- text += _(" and %s")%item
+ text += _(" and %s") % item
else:
- text += _(", %s")%item
+ text += _(", %s") % item
message = _("Form isn't complete. %s must be filled!") % text
elif not TestIdentifier(pou_name):
message = _("\"%s\" is not a valid identifier!") % pou_name
@@ -126,13 +132,13 @@
question = True
if message is not None:
if question:
- dialog = wx.MessageDialog(self, message, _("Warning"), wx.YES_NO|wx.ICON_EXCLAMATION)
+ dialog = wx.MessageDialog(self, message, _("Warning"), wx.YES_NO | wx.ICON_EXCLAMATION)
result = dialog.ShowModal()
dialog.Destroy()
if result == wx.ID_YES:
self.EndModal(wx.ID_OK)
else:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/dialogs/PouNameDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/PouNameDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,21 +24,22 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# POU Name Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class PouNameDialog(wx.TextEntryDialog):
- def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
- style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ def __init__(self, parent, message, caption="Please enter text", defaultValue="",
+ style=wx.OK | wx.CANCEL | wx.CENTRE, pos=wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
-
+
self.PouNames = []
-
- self.Bind(wx.EVT_BUTTON, self.OnOK,
- self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton())
-
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
+ self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton())
+
def OnOK(self, event):
message = None
step_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
@@ -51,7 +52,7 @@
elif step_name.upper() in self.PouNames:
message = _("A POU named \"%s\" already exists!") % step_name
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
@@ -60,4 +61,3 @@
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
-
--- a/dialogs/PouTransitionDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/PouTransitionDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,57 +26,62 @@
import wx
from plcopen.structures import TestIdentifier, IEC_KEYWORDS
+from util.TranslationCatalogs import NoTranslate
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# POU Transition Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def GetTransitionLanguages():
- _ = lambda x : x
+ _ = NoTranslate
return [_("IL"), _("ST"), _("LD"), _("FBD")]
+
+
TRANSITION_LANGUAGES_DICT = dict([(_(language), language) for language in GetTransitionLanguages()])
+
class PouTransitionDialog(wx.Dialog):
-
+
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title=_('Create a new transition'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
+
infos_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=3, vgap=10)
infos_sizer.AddGrowableCol(1)
- main_sizer.AddSizer(infos_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(infos_sizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
transitionname_label = wx.StaticText(self, label=_('Transition Name:'))
- infos_sizer.AddWindow(transitionname_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
+ infos_sizer.AddWindow(transitionname_label, border=4,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
- self.TransitionName = wx.TextCtrl(self, size=wx.Size(180,-1))
+ self.TransitionName = wx.TextCtrl(self, size=wx.Size(180, -1))
infos_sizer.AddWindow(self.TransitionName, flag=wx.GROW)
language_label = wx.StaticText(self, label=_('Language:'))
- infos_sizer.AddWindow(language_label, border=4,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.TOP)
-
+ infos_sizer.AddWindow(language_label, border=4,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.TOP)
+
self.Language = wx.ComboBox(self, style=wx.CB_READONLY)
infos_sizer.AddWindow(self.Language, flag=wx.GROW)
- button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
+ button_sizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton())
- main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT|wx.BOTTOM)
-
+ main_sizer.AddSizer(button_sizer, border=20, flag=wx.ALIGN_RIGHT | wx.BOTTOM)
+
self.SetSizer(main_sizer)
-
+
for language in GetTransitionLanguages():
self.Language.Append(_(language))
-
+
self.Fit()
self.PouNames = []
self.PouElementNames = []
-
+
def OnOK(self, event):
error = []
transition_name = self.TransitionName.GetValue()
@@ -91,9 +96,9 @@
if i == 0:
text += item
elif i == len(error) - 1:
- text += _(" and %s")%item
+ text += _(" and %s") % item
else:
- text += _(", %s")%item
+ text += _(", %s") % item
message = _("Form isn't complete. %s must be filled!") % text
elif not TestIdentifier(transition_name):
message = _("\"%s\" is not a valid identifier!") % transition_name
@@ -104,25 +109,25 @@
elif transition_name.upper() in self.PouElementNames:
message = _("\"%s\" element for this pou already exists!") % transition_name
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
self.EndModal(wx.ID_OK)
-
+
def SetPouNames(self, pou_names):
self.PouNames = [pou_name.upper() for pou_name in pou_names]
-
+
def SetPouElementNames(self, pou_names):
self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
-
+
def SetValues(self, values):
for item, value in values.items():
if item == "transitionName":
self.TransitionName.SetValue(value)
elif item == "language":
self.Language.SetSelection(_(value))
-
+
def GetValues(self):
values = {}
values["transitionName"] = self.TransitionName.GetValue()
--- a/dialogs/ProjectDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/ProjectDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,30 +27,33 @@
from controls.ProjectPropertiesPanel import ProjectPropertiesPanel
+
class ProjectDialog(wx.Dialog):
-
+
def __init__(self, parent, enable_required=True):
- wx.Dialog.__init__(self, parent, title=_('Project properties'),
- style=wx.DEFAULT_DIALOG_STYLE)
-
+ wx.Dialog.__init__(self, parent, title=_('Project properties'),
+ style=wx.DEFAULT_DIALOG_STYLE)
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
-
- self.ProjectProperties = ProjectPropertiesPanel(self,
- enable_required=enable_required)
+
+ self.ProjectProperties = ProjectPropertiesPanel(
+ self,
+ enable_required=enable_required)
+
main_sizer.AddWindow(self.ProjectProperties, flag=wx.GROW)
-
- self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
- self.Bind(wx.EVT_BUTTON, self.OnOK,
+
+ self.ButtonSizer = self.CreateButtonSizer(wx.OK | wx.CANCEL | wx.CENTRE)
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
self.ButtonSizer.GetAffirmativeButton())
- main_sizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.SetSizer(main_sizer)
self.ProjectProperties.Fit()
self.Fit()
-
+
def OnOK(self, event):
values = self.ProjectProperties.GetValues()
error = []
@@ -66,12 +69,13 @@
if i == 0:
text += item
elif i == len(error) - 1:
- text += _(" and %s")%item
+ text += _(" and %s") % item
else:
- text += ", %s"%item
- dialog = wx.MessageDialog(self,
- _("Form isn't complete. %s must be filled!") % text,
- _("Error"), wx.OK|wx.ICON_ERROR)
+ text += ", %s" % item
+ dialog = wx.MessageDialog(
+ self,
+ _("Form isn't complete. %s must be filled!") % text,
+ _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
@@ -79,6 +83,6 @@
def SetValues(self, values):
self.ProjectProperties.SetValues(values)
-
+
def GetValues(self):
return self.ProjectProperties.GetValues()
--- a/dialogs/SFCDivergenceDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/SFCDivergenceDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -30,18 +30,18 @@
from graphics.SFC_Objects import SFC_Divergence
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Create New Divergence Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a dialog for defining parameters for creating a new
-divergence graphic element
-"""
class SFCDivergenceDialog(BlockPreviewDialog):
-
- def __init__(self, parent, controller, tagname, poss_div_types = None):
+ """
+ Class that implements a dialog for defining parameters for creating a new
+ divergence graphic element
+ """
+
+ def __init__(self, parent, controller, tagname, poss_div_types=None):
"""
Constructor
@param parent: Parent wx.Window of dialog for modal
@@ -50,15 +50,15 @@
@param poss_div_types: Types of divergence that will be available in the dialog window
"""
BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Create a new divergence or convergence'))
-
+ title=_('Create a new divergence or convergence'))
+
# Init common sizers
self._init_sizers(2, 0, 7, None, 2, 1)
-
+
# Create label for divergence type
type_label = wx.StaticText(self, label=_('Type:'))
self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW)
-
+
# Create radio buttons for selecting divergence type
divergence_buttons = [
(SELECTION_DIVERGENCE, _('Selection Divergence')),
@@ -67,47 +67,49 @@
(SIMULTANEOUS_CONVERGENCE, _('Simultaneous Convergence'))]
poss_div_btns = []
if poss_div_types is not None:
- for val in poss_div_types:
- poss_div_btns.append(divergence_buttons[val])
+ for val in poss_div_types:
+ poss_div_btns.append(divergence_buttons[val])
else:
poss_div_btns = divergence_buttons
self.TypeRadioButtons = {}
first = True
focusbtn = None
for type, label in poss_div_btns:
- radio_button = wx.RadioButton(self, label=label,
- style=(wx.RB_GROUP if first else 0))
+ radio_button = wx.RadioButton(self, label=label,
+ style=(wx.RB_GROUP if first else 0))
radio_button.SetValue(first)
self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button)
self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
self.TypeRadioButtons[type] = radio_button
- if first: focusbtn = type
+ if first:
+ focusbtn = type
first = False
# Create label for number of divergence sequences
- sequences_label = wx.StaticText(self,
- label=_('Number of sequences:'))
+ sequences_label = wx.StaticText(self,
+ label=_('Number of sequences:'))
self.LeftGridSizer.AddWindow(sequences_label, flag=wx.GROW)
-
+
# Create spin control for defining number of divergence sequences
self.Sequences = wx.SpinCtrl(self, min=2, max=20, initial=2)
self.Bind(wx.EVT_SPINCTRL, self.OnSequencesChanged, self.Sequences)
self.LeftGridSizer.AddWindow(self.Sequences, flag=wx.GROW)
-
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
self.Fit()
# Selection divergence radio button is default control having keyboard
# focus
self.TypeRadioButtons[focusbtn].SetFocus()
-
+
def GetMinElementSize(self):
"""
Get minimal graphic element size
@@ -115,7 +117,7 @@
element defined
"""
return self.Element.GetMinSize(True)
-
+
def GetDivergenceType(self):
"""
Return type selected for SFC divergence
@@ -127,7 +129,7 @@
if control.GetValue():
return type
return None
-
+
def GetValues(self):
"""
Set default SFC divergence parameters
@@ -151,17 +153,16 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
Override BlockPreviewDialog function
"""
# Set graphic element displayed, creating a SFC divergence
- self.Element = SFC_Divergence(self.Preview,
- self.GetDivergenceType(),
+ self.Element = SFC_Divergence(self.Preview,
+ self.GetDivergenceType(),
self.Sequences.GetValue())
-
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
-
--- a/dialogs/SFCStepDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/SFCStepDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,17 +28,17 @@
from graphics.SFC_Objects import SFC_Step
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set SFC Step Parameters Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a dialog for defining parameters of a SFC step graphic
-element
-"""
class SFCStepDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a SFC step graphic
+ element
+ """
+
def __init__(self, parent, controller, tagname, initial=False):
"""
Constructor
@@ -47,25 +47,25 @@
@param tagname: Tagname of project POU edited
@param initial: True if step is initial (default: False)
"""
- BlockPreviewDialog.__init__(self,parent, controller, tagname,
- title=_('Edit Step'))
-
+ BlockPreviewDialog.__init__(self, parent, controller, tagname,
+ title=_('Edit Step'))
+
# Init common sizers
self._init_sizers(2, 0, 6, None, 2, 1)
-
+
# Create label for SFC step name
name_label = wx.StaticText(self, label=_('Name:'))
self.LeftGridSizer.AddWindow(name_label, flag=wx.GROW)
-
+
# Create text control for defining SFC step name
self.StepName = wx.TextCtrl(self)
self.Bind(wx.EVT_TEXT, self.OnNameChanged, self.StepName)
self.LeftGridSizer.AddWindow(self.StepName, flag=wx.GROW)
-
+
# Create label for SFC step connectors
connectors_label = wx.StaticText(self, label=_('Connectors:'))
self.LeftGridSizer.AddWindow(connectors_label, flag=wx.GROW)
-
+
# Create check boxes for defining connectors available on SFC step
self.ConnectorsCheckBox = {}
for name, label in [("input", _("Input")),
@@ -77,27 +77,28 @@
self.Bind(wx.EVT_CHECKBOX, self.OnConnectorsChanged, check_box)
self.LeftGridSizer.AddWindow(check_box, flag=wx.GROW)
self.ConnectorsCheckBox[name] = check_box
-
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
-
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
+
# Save flag that indicates that step is initial
self.Initial = initial
-
+
# Set default name for step
self.StepName.ChangeValue(controller.GenerateNewName(
tagname, None, "Step%d", 0))
self.Fit()
-
+
# Step name text control is default control having keyboard focus
self.StepName.SetFocus()
-
+
def SetValues(self, values):
"""
Set default block parameters
@@ -105,20 +106,20 @@
"""
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is step name
if name == "name":
self.StepName.ChangeValue(value)
-
+
# Set value of other controls
else:
control = self.ConnectorsCheckBox.get(name, None)
if control is not None:
control.SetValue(value)
-
+
# Refresh preview panel
self.RefreshPreview()
-
+
def GetValues(self):
"""
Return step parameters defined in dialog
@@ -130,7 +131,7 @@
for name, control in self.ConnectorsCheckBox.iteritems()})
values["width"], values["height"] = self.Element.GetSize()
return values
-
+
def OnOK(self, event):
"""
Called when dialog OK button is pressed
@@ -138,23 +139,23 @@
@param event: wx.Event from OK button
"""
message = None
-
+
# Get step name typed by user
step_name = self.StepName.GetValue()
-
+
# Test that a name have been defined
if step_name == "":
message = _("Form isn't complete. Name must be filled!")
-
+
# If an error have been identify, show error message dialog
if message is not None:
self.ShowErrorMessage(message)
-
+
# Test step name validity
elif self.TestElementName(step_name):
# Call BlockPreviewDialog function
BlockPreviewDialog.OnOK(self, event)
-
+
def OnConnectorsChanged(self, event):
"""
Called when a step connector value changed
@@ -170,23 +171,23 @@
"""
self.RefreshPreview()
event.Skip()
-
+
def RefreshPreview(self):
"""
Refresh preview panel of graphic element
Override BlockPreviewDialog function
"""
# Set graphic element displayed, creating a SFC step element
- self.Element = SFC_Step(self.Preview,
- self.StepName.GetValue(),
+ self.Element = SFC_Step(self.Preview,
+ self.StepName.GetValue(),
self.Initial)
-
+
# Update connectors of SFC step element according to check boxes value
for name, control in self.ConnectorsCheckBox.iteritems():
if control.IsChecked():
getattr(self.Element, "Add" + name.capitalize())()
else:
getattr(self.Element, "Remove" + name.capitalize())()
-
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
--- a/dialogs/SFCStepNameDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/SFCStepNameDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,23 +24,24 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Edit Step Name Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class SFCStepNameDialog(wx.TextEntryDialog):
- def __init__(self, parent, message, caption = "Please enter text", defaultValue = "",
- style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ def __init__(self, parent, message, caption="Please enter text", defaultValue="",
+ style=wx.OK | wx.CANCEL | wx.CENTRE, pos=wx.DefaultPosition):
wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
-
+
self.PouNames = []
self.Variables = []
self.StepNames = []
-
- self.Bind(wx.EVT_BUTTON, self.OnOK,
- self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton())
-
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK,
+ self.GetSizer().GetItem(2).GetSizer().GetItem(1).GetSizer().GetAffirmativeButton())
+
def OnOK(self, event):
message = None
step_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
@@ -57,7 +58,7 @@
elif step_name.upper() in self.StepNames:
message = _("\"%s\" step already exists!") % step_name
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/dialogs/SFCTransitionDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/SFCTransitionDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,17 +28,17 @@
from graphics.SFC_Objects import SFC_Transition
from BlockPreviewDialog import BlockPreviewDialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Set Transition Parameters Dialog
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a dialog for defining parameters of a transition graphic
-element
-"""
+# -------------------------------------------------------------------------------
+
class SFCTransitionDialog(BlockPreviewDialog):
-
+ """
+ Class that implements a dialog for defining parameters of a transition graphic
+ element
+ """
+
def __init__(self, parent, controller, tagname, connection=True):
"""
Constructor
@@ -49,34 +49,34 @@
connection (default: True)
"""
BlockPreviewDialog.__init__(self, parent, controller, tagname,
- title=_('Edit transition'))
-
+ title=_('Edit transition'))
+
# Init common sizers
self._init_sizers(2, 0, 8, None, 2, 1)
-
+
# Create label for transition type
type_label = wx.StaticText(self, label=_('Type:'))
self.LeftGridSizer.AddWindow(type_label, flag=wx.GROW)
-
+
# Create combo box for selecting reference value
reference = wx.ComboBox(self, style=wx.CB_READONLY)
reference.Append("")
for transition in controller.GetEditedElementTransitions(tagname):
reference.Append(transition)
self.Bind(wx.EVT_COMBOBOX, self.OnReferenceChanged, reference)
-
+
# Create Text control for defining inline value
inline = wx.TextCtrl(self)
self.Bind(wx.EVT_TEXT, self.OnInlineChanged, inline)
-
+
# Create radio buttons for selecting power rail type
self.TypeRadioButtons = {}
first = True
for type, label, control in [('reference', _('Reference'), reference),
('inline', _('Inline'), inline),
('connection', _('Connection'), None)]:
- radio_button = wx.RadioButton(self, label=label,
- style=(wx.RB_GROUP if first else 0))
+ radio_button = wx.RadioButton(self, label=label,
+ style=(wx.RB_GROUP if first else 0))
radio_button.SetValue(first)
self.Bind(wx.EVT_RADIOBUTTON, self.OnTypeChanged, radio_button)
self.LeftGridSizer.AddWindow(radio_button, flag=wx.GROW)
@@ -85,29 +85,30 @@
self.LeftGridSizer.AddWindow(control, flag=wx.GROW)
self.TypeRadioButtons[type] = (radio_button, control)
first = False
-
+
# Create label for transition priority
priority_label = wx.StaticText(self, label=_('Priority:'))
self.LeftGridSizer.AddWindow(priority_label, flag=wx.GROW)
-
+
# Create spin control for defining priority value
self.Priority = wx.SpinCtrl(self, min=0, style=wx.SP_ARROW_KEYS)
self.Bind(wx.EVT_TEXT, self.OnPriorityChanged, self.Priority)
self.LeftGridSizer.AddWindow(self.Priority, flag=wx.GROW)
-
+
# Add preview panel and associated label to sizers
self.RightGridSizer.AddWindow(self.PreviewLabel, flag=wx.GROW)
self.RightGridSizer.AddWindow(self.Preview, flag=wx.GROW)
-
+
# Add buttons sizer to sizers
- self.MainSizer.AddSizer(self.ButtonSizer, border=20,
- flag=wx.ALIGN_RIGHT|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ self.MainSizer.AddSizer(
+ self.ButtonSizer, border=20,
+ flag=wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT)
self.Fit()
-
+
# Reference radio button is default control having keyboard focus
self.TypeRadioButtons["reference"][0].SetFocus()
-
+
def GetTransitionType(self):
"""
Return type selected for SFC transition and associated value
@@ -124,7 +125,7 @@
else:
return type, None
return None, None
-
+
def SetValues(self, values):
"""
Set default SFC transition parameters
@@ -132,14 +133,14 @@
"""
# Extract transition value according to type
type_value = values.get("value", None)
-
+
# For each parameters defined, set corresponding control value
for name, value in values.items():
-
+
# Parameter is SFC transition priority
if name == "priority":
self.Priority.SetValue(values["priority"])
-
+
# Parameter is SFC transition type
elif name == "type":
for type, (radio, control) in self.TypeRadioButtons.iteritems():
@@ -152,20 +153,20 @@
control.SetStringSelection(type_value)
elif isinstance(control, wx.TextCtrl):
control.ChangeValue(type_value)
-
+
# Refresh preview panel
self.RefreshPreview()
-
+
def GetValues(self):
"""
Return SFC transition parameters defined in dialog
@return: {parameter_name: parameter_value,...}
"""
- values = {"priority" : self.Priority.GetValue()}
+ values = {"priority": self.Priority.GetValue()}
values["type"], values["value"] = self.GetTransitionType()
values["width"], values["height"] = self.Element.GetSize()
return values
-
+
def OnOK(self, event):
"""
Called when dialog OK button is pressed
@@ -173,18 +174,18 @@
@param event: wx.Event from OK button
"""
message = None
-
+
# Get transition type and value associated
type, value = self.GetTransitionType()
-
+
# Test that value associated to type is defined
if type != "connection" and value == "":
message = _("Form isn't complete. %s must be filled!") % type
-
+
# Show error message if an error is detected
if message is not None:
self.ShowErrorMessage(message)
-
+
else:
# Call BlockPreviewDialog function
BlockPreviewDialog.OnOK(self, event)
@@ -198,7 +199,7 @@
for type, (radio, control) in self.TypeRadioButtons.iteritems():
if control is not None:
control.Enable(radio.GetValue())
-
+
# Refresh preview panel
self.RefreshPreview()
event.Skip()
@@ -236,6 +237,6 @@
self.Element = SFC_Transition(self.Preview)
self.Element.SetType(*self.GetTransitionType())
self.Element.SetPriority(self.Priority.GetValue())
-
+
# Call BlockPreviewDialog function
BlockPreviewDialog.RefreshPreview(self)
--- a/dialogs/SearchInProjectDialog.py Mon Aug 21 20:17:19 2017 +0000
+++ b/dialogs/SearchInProjectDialog.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,72 +24,75 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import re
+import wx
from plcopen.plcopen import *
-import wx
+from util.TranslationCatalogs import NoTranslate
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Search In Project Dialog
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def GetElementsChoices():
- _ = lambda x: x
- return [("datatype", _("Data Type")),
- ("function", _("Function")),
- ("functionBlock", _("Function Block")),
- ("program", _("Program")),
+ _ = NoTranslate
+ return [("datatype", _("Data Type")),
+ ("function", _("Function")),
+ ("functionBlock", _("Function Block")),
+ ("program", _("Program")),
("configuration", _("Configuration"))]
+
class SearchInProjectDialog(wx.Dialog):
-
+
def __init__(self, parent):
wx.Dialog.__init__(self, parent, title=_('Search in Project'))
-
+
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(1)
-
+
pattern_sizer = wx.FlexGridSizer(cols=2, hgap=5, rows=2, vgap=5)
pattern_sizer.AddGrowableCol(0)
- main_sizer.AddSizer(pattern_sizer, border=20,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(pattern_sizer, border=20,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
+
pattern_label = wx.StaticText(self, label=_('Pattern to search:'))
pattern_sizer.AddWindow(pattern_label, flag=wx.ALIGN_BOTTOM)
-
+
self.CaseSensitive = wx.CheckBox(self, label=_('Case sensitive'))
pattern_sizer.AddWindow(self.CaseSensitive, flag=wx.GROW)
-
- self.Pattern = wx.TextCtrl(self, size=wx.Size(250,-1))
+
+ self.Pattern = wx.TextCtrl(self, size=wx.Size(250, -1))
self.Bind(wx.EVT_TEXT, self.FindPatternChanged, self.Pattern)
pattern_sizer.AddWindow(self.Pattern, flag=wx.GROW)
self.Bind(wx.EVT_CHAR_HOOK, self.OnEscapeKey)
self.RegularExpression = wx.CheckBox(self, label=_('Regular expression'))
pattern_sizer.AddWindow(self.RegularExpression, flag=wx.GROW)
-
+
scope_staticbox = wx.StaticBox(self, label=_('Scope'))
scope_sizer = wx.StaticBoxSizer(scope_staticbox, wx.HORIZONTAL)
- main_sizer.AddSizer(scope_sizer, border=20,
- flag=wx.GROW|wx.LEFT|wx.RIGHT)
-
+ main_sizer.AddSizer(scope_sizer, border=20,
+ flag=wx.GROW | wx.LEFT | wx.RIGHT)
+
scope_selection_sizer = wx.BoxSizer(wx.VERTICAL)
- scope_sizer.AddSizer(scope_selection_sizer, 1, border=5,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.BOTTOM)
-
+ scope_sizer.AddSizer(scope_selection_sizer, 1, border=5,
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.BOTTOM)
+
self.WholeProject = wx.RadioButton(self, label=_('Whole Project'), style=wx.RB_GROUP)
self.WholeProject.SetValue(True)
self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.WholeProject)
- scope_selection_sizer.AddWindow(self.WholeProject, border=5,
- flag=wx.GROW|wx.BOTTOM)
-
+ scope_selection_sizer.AddWindow(self.WholeProject, border=5,
+ flag=wx.GROW | wx.BOTTOM)
+
self.OnlyElements = wx.RadioButton(self, label=_('Only Elements'))
self.Bind(wx.EVT_RADIOBUTTON, self.OnScopeChanged, self.OnlyElements)
self.OnlyElements.SetValue(False)
scope_selection_sizer.AddWindow(self.OnlyElements, flag=wx.GROW)
-
+
self.ElementsList = wx.CheckListBox(self)
self.ElementsList.Enable(False)
- scope_sizer.AddWindow(self.ElementsList, 1, border=5,
- flag=wx.GROW|wx.TOP|wx.RIGHT|wx.BOTTOM)
+ scope_sizer.AddWindow(self.ElementsList, 1, border=5,
+ flag=wx.GROW | wx.TOP | wx.RIGHT | wx.BOTTOM)
buttons_sizer = wx.BoxSizer(wx.HORIZONTAL)
main_sizer.AddSizer(buttons_sizer, border=20,
@@ -103,9 +106,9 @@
self.CloseButton = wx.Button(self, label=_("Close"))
self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.CloseButton)
buttons_sizer.AddWindow(self.CloseButton)
-
+
self.SetSizer(main_sizer)
-
+
for name, label in GetElementsChoices():
self.ElementsList.Append(_(label))
@@ -139,7 +142,7 @@
self.OnCloseButton(event)
else:
event.Skip()
-
+
def OnFindButton(self, event):
message = None
infos = {
@@ -160,12 +163,12 @@
self.criteria = infos
CompilePattern(self.criteria)
self.infosPrev = infos
- except:
+ except Exception:
self.criteria.clear()
message = _("Syntax error in regular expression of pattern to search!")
-
+
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
else:
--- a/doc/conf.py Mon Aug 21 20:17:19 2017 +0000
+++ b/doc/conf.py Mon Aug 21 23:22:58 2017 +0300
@@ -11,17 +11,18 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
-import sys, os
+import sys
+import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
-#sys.path.insert(0, os.path.abspath('.'))
+# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
-#needs_sphinx = '1.0'
+# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
@@ -34,7 +35,7 @@
source_suffix = '.rst'
# The encoding of source files.
-#source_encoding = 'utf-8-sig'
+# source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
@@ -54,40 +55,40 @@
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
-#language = None
+# language = None
gettext_compact = False
-locale_dirs = [ "locale/" ]
+locale_dirs = ["locale/"]
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
-#today = ''
+# today = ''
# Else, today_fmt is used as the format for a strftime call.
-#today_fmt = '%B %d, %Y'
+# today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
-#default_role = None
+# default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
-#add_function_parentheses = True
+# add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
-#add_module_names = True
+# add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
-#show_authors = False
+# show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
-#modindex_common_prefix = []
+# modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
@@ -99,26 +100,26 @@
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
-#html_theme_options = {}
+# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+# html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
-#html_title = None
+# html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
-#html_short_title = None
+# html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
-#html_logo = None
+# html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
-#html_favicon = None
+# html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
@@ -127,44 +128,44 @@
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
-#html_last_updated_fmt = '%b %d, %Y'
+# html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
-#html_use_smartypants = True
+# html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
-#html_sidebars = {}
+# html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
-#html_additional_pages = {}
+# html_additional_pages = {}
# If false, no module index is generated.
-#html_domain_indices = True
+# html_domain_indices = True
# If false, no index is generated.
-#html_use_index = True
+# html_use_index = True
# If true, the index is split into individual pages for each letter.
-#html_split_index = False
+# html_split_index = False
# If true, links to the reST sources are added to the pages.
-#html_show_sourcelink = True
+# html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-#html_show_sphinx = True
+# html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-#html_show_copyright = True
+# html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
-#html_use_opensearch = ''
+# html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
-#html_file_suffix = None
+# html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'Beremizdoc'
@@ -173,14 +174,14 @@
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
-# The paper size ('letterpaper' or 'a4paper').
-#'papersize': 'letterpaper',
-
-# The font size ('10pt', '11pt' or '12pt').
-#'pointsize': '10pt',
-
-# Additional stuff for the LaTeX preamble.
-#'preamble': '',
+ # The paper size ('letterpaper' or 'a4paper').
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ # 'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
@@ -192,23 +193,23 @@
# The name of an image file (relative to this directory) to place at the top of
# the title page.
-#latex_logo = None
+# latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
-#latex_use_parts = False
+# latex_use_parts = False
# If true, show page references after internal links.
-#latex_show_pagerefs = False
+# latex_show_pagerefs = False
# If true, show URL addresses after external links.
-#latex_show_urls = False
+# latex_show_urls = False
# Documents to append as an appendix to all manuals.
-#latex_appendices = []
+# latex_appendices = []
# If false, no module index is generated.
-#latex_domain_indices = True
+# latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
@@ -221,7 +222,7 @@
]
# If true, show URL addresses after external links.
-#man_show_urls = False
+# man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
@@ -236,10 +237,10 @@
]
# Documents to append as an appendix to all manuals.
-#texinfo_appendices = []
+# texinfo_appendices = []
# If false, no module index is generated.
-#texinfo_domain_indices = True
+# texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
-#texinfo_show_urls = 'footnote'
+# texinfo_show_urls = 'footnote'
--- a/docutil/dochtml.py Mon Aug 21 20:17:19 2017 +0000
+++ b/docutil/dochtml.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,10 +22,14 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import wx, os, wx.html, subprocess
+import os
+import subprocess
+import wx
+import wx.html
HtmlFrameOpened = []
+
def OpenHtmlFrame(self, title, file, size):
if title not in HtmlFrameOpened:
HtmlFrameOpened.append(title)
@@ -35,15 +39,18 @@
window.SetClientSize(size)
window.Show()
+
[ID_HTMLFRAME, ID_HTMLFRAMEHTMLCONTENT] = [wx.NewId() for _init_ctrls in range(2)]
EVT_HTML_URL_CLICK = wx.NewId()
+
class HtmlWindowUrlClick(wx.PyEvent):
def __init__(self, linkinfo):
wx.PyEvent.__init__(self)
self.SetEventType(EVT_HTML_URL_CLICK)
self.linkinfo = (linkinfo.GetHref(), linkinfo.GetTarget())
-
+
+
class UrlClickHtmlWindow(wx.html.HtmlWindow):
""" HTML window that generates and OnLinkClicked event.
@@ -51,47 +58,48 @@
"""
def OnLinkClicked(self, linkinfo):
wx.PostEvent(self, HtmlWindowUrlClick(linkinfo))
-
+
def Bind(self, event, handler, source=None, id=wx.ID_ANY, id2=wx.ID_ANY):
if event == HtmlWindowUrlClick:
self.Connect(-1, -1, EVT_HTML_URL_CLICK, handler)
else:
wx.html.HtmlWindow.Bind(event, handler, source=source, id=id, id2=id2)
+
class HtmlFrame(wx.Frame):
def _init_ctrls(self, prnt):
wx.Frame.__init__(self, id=ID_HTMLFRAME, name='HtmlFrame',
- parent=prnt, pos=wx.Point(320, 231), size=wx.Size(853, 616),
- style=wx.DEFAULT_FRAME_STYLE, title='')
+ parent=prnt, pos=wx.Point(320, 231), size=wx.Size(853, 616),
+ style=wx.DEFAULT_FRAME_STYLE, title='')
self.SetIcon(prnt.icon)
self.Bind(wx.EVT_CLOSE, self.OnCloseFrame)
-
+
self.HtmlContent = UrlClickHtmlWindow(id=ID_HTMLFRAMEHTMLCONTENT,
- name='HtmlContent', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.html.HW_SCROLLBAR_AUTO|wx.html.HW_NO_SELECTION)
+ name='HtmlContent', parent=self, pos=wx.Point(0, 0),
+ size=wx.Size(-1, -1), style=wx.html.HW_SCROLLBAR_AUTO | wx.html.HW_NO_SELECTION)
self.HtmlContent.Bind(HtmlWindowUrlClick, self.OnLinkClick)
def __init__(self, parent, opened):
self._init_ctrls(parent)
self.HtmlFrameOpened = opened
-
+
def SetHtmlCode(self, htmlcode):
self.HtmlContent.SetPage(htmlcode)
-
+
def SetHtmlPage(self, htmlpage):
self.HtmlContent.LoadPage(htmlpage)
-
+
def OnCloseFrame(self, event):
self.HtmlFrameOpened.remove(self.GetTitle())
event.Skip()
-
+
def OnLinkClick(self, event):
url = event.linkinfo[0]
try:
if wx.Platform == '__WXMSW__':
import webbrowser
webbrowser.open(url)
- elif subprocess.call("firefox %s"%url, shell=True) != 0:
+ elif subprocess.call("firefox %s" % url, shell=True) != 0:
wx.MessageBox("""Firefox browser not found.\nPlease point your browser at :\n%s""" % url)
except ImportError:
wx.MessageBox('Please point your browser at: %s' % url)
--- a/docutil/docpdf.py Mon Aug 21 20:17:19 2017 +0000
+++ b/docutil/docpdf.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,10 +22,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import wx, os
+import os
+import wx
+
readerexepath = None
-
+
+
def get_acroversion():
" Return version of Adobe Acrobat executable or None"
import _winreg
@@ -39,38 +42,41 @@
try:
res = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE, 'Software\\Adobe\\%s\\%s\\InstallPath' % (key, numver))
return res
- except:
+ except Exception:
pass
return None
-def open_win_pdf(readerexepath, pdffile, pagenum = None):
- if pagenum != None :
- os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", "/A", "page=%d=OpenActions" % pagenum, '"%s"'%pdffile)
+
+def open_win_pdf(readerexepath, pdffile, pagenum=None):
+ if pagenum is not None:
+ os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", "/A", "page=%d=OpenActions" % pagenum, '"%s"' % pdffile)
else:
- os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", '"%s"'%pdffile)
+ os.spawnl(os.P_DETACH, readerexepath, "AcroRd32.exe", '"%s"' % pdffile)
-def open_lin_pdf(readerexepath, pdffile, pagenum = None):
- if pagenum == None :
- os.system("%s -remote DS301 %s &"%(readerexepath, pdffile))
+
+def open_lin_pdf(readerexepath, pdffile, pagenum=None):
+ if pagenum is None:
+ os.system("%s -remote DS301 %s &" % (readerexepath, pdffile))
else:
- print "Open pdf %s at page %d"%(pdffile, pagenum)
- os.system("%s -remote DS301 %s %d &"%(readerexepath, pdffile, pagenum))
+ print "Open pdf %s at page %d" % (pdffile, pagenum)
+ os.system("%s -remote DS301 %s %d &" % (readerexepath, pdffile, pagenum))
-def open_pdf(pdffile, pagenum = None):
- if wx.Platform == '__WXMSW__' :
+
+def open_pdf(pdffile, pagenum=None):
+ if wx.Platform == '__WXMSW__':
try:
readerpath = get_acroversion()
- except:
+ except Exception:
wx.MessageBox("Acrobat Reader is not found or installed !")
return None
-
+
readerexepath = os.path.join(readerpath, "AcroRd32.exe")
if(os.path.isfile(readerexepath)):
open_win_pdf(readerexepath, pdffile, pagenum)
else:
return None
else:
- readerexepath = os.path.join("/usr/bin","xpdf")
+ readerexepath = os.path.join("/usr/bin", "xpdf")
if(os.path.isfile(readerexepath)):
open_lin_pdf(readerexepath, pdffile, pagenum)
else:
--- a/docutil/docsvg.py Mon Aug 21 20:17:19 2017 +0000
+++ b/docutil/docsvg.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,41 +22,46 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import wx, os, subprocess
+import wx
+import os
+import subprocess
+
def get_inkscape_path():
""" Return the Inkscape path """
import _winreg
svgexepath = _winreg.QueryValue(_winreg.HKEY_LOCAL_MACHINE,
- 'Software\\Classes\\svgfile\\shell\\Inkscape\\command')
+ 'Software\\Classes\\svgfile\\shell\\Inkscape\\command')
svgexepath = svgexepath.replace('"%1"', '')
return svgexepath.replace('"', '')
+
def open_win_svg(svgexepath, svgfile):
""" Open Inkscape on Windows platform """
popenargs = [svgexepath]
- if svgfile is not None :
+ if svgfile is not None:
popenargs.append(svgfile)
subprocess.Popen(popenargs).pid
+
def open_lin_svg(svgexepath, svgfile):
""" Open Inkscape on Linux platform """
if os.path.isfile("/usr/bin/inkscape"):
- os.system("%s %s &"%(svgexepath , svgfile))
-
+ os.system("%s %s &" % (svgexepath, svgfile))
+
+
def open_svg(svgfile):
""" Generic function to open SVG file """
- if wx.Platform == '__WXMSW__' :
+ if wx.Platform == '__WXMSW__':
try:
open_win_svg(get_inkscape_path(), svgfile)
- except:
+ except Exception:
wx.MessageBox("Inkscape is not found or installed !")
return None
else:
- svgexepath = os.path.join("/usr/bin","inkscape")
+ svgexepath = os.path.join("/usr/bin", "inkscape")
if(os.path.isfile(svgexepath)):
open_lin_svg(svgexepath, svgfile)
else:
wx.MessageBox("Inkscape is not found or installed !")
return None
-
--- a/editors/CodeFileEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/CodeFileEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -37,6 +37,7 @@
from controls.CustomStyledTextCtrl import CustomStyledTextCtrl, faces, GetCursorPos, NAVIGATION_KEYS
from controls.VariablePanel import VARIABLE_NAME_SUFFIX_MODEL
from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD
+from util.TranslationCatalogs import NoTranslate
[STC_CODE_ERROR, STC_CODE_SEARCH_RESULT,
STC_CODE_SECTION] = range(15, 18)
@@ -48,6 +49,7 @@
EDGE_COLUMN = 80
+
class CodeEditor(CustomStyledTextCtrl):
KEYWORDS = []
@@ -55,14 +57,14 @@
def __init__(self, parent, window, controler):
CustomStyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition,
- wx.Size(-1, 300), 0)
+ wx.Size(-1, 300), 0)
self.SetMarginType(1, stc.STC_MARGIN_NUMBER)
self.SetMarginWidth(1, 25)
self.SetProperty("fold", "1")
self.SetProperty("tab.timmy.whinge.level", "1")
- self.SetMargins(0,0)
+ self.SetMargins(0, 0)
self.SetViewWhiteSpace(False)
@@ -133,9 +135,10 @@
for section in self.Controler.SECTIONS_NAMES:
section_comment = " %s section " % (section)
len_headers = EDGE_COLUMN - len(section_comment)
- section_comment = self.COMMENT_HEADER * (len_headers / 2) + \
- section_comment + \
- self.COMMENT_HEADER * (len_headers - len_headers / 2)
+ section_comment = \
+ self.COMMENT_HEADER * (len_headers / 2) + \
+ section_comment + \
+ self.COMMENT_HEADER * (len_headers - len_headers / 2)
self.SectionsComments[section] = {
"comment": section_comment,
@@ -152,7 +155,7 @@
section_infos["comment"] + "(.*)" +
section_end, re.DOTALL)
- self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE)
+ self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT | wx.stc.STC_MOD_BEFOREDELETE)
self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop)
self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
@@ -170,17 +173,17 @@
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:
+ 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:
+ elif mod_type & wx.stc.STC_MOD_BEFOREDELETE:
+ if self.CurrentAction is None:
self.StartBuffering()
elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
self.Controler.EndBuffering()
@@ -193,7 +196,7 @@
def OnDoDrop(self, event):
try:
values = eval(event.GetDragText())
- except:
+ except Exception:
values = event.GetDragText()
if isinstance(values, tuple):
message = None
@@ -226,7 +229,7 @@
self.ParentWindow.RefreshPageTitles()
def ResetBuffer(self):
- if self.CurrentAction != None:
+ if self.CurrentAction is not None:
self.Controler.EndBuffering()
self.CurrentAction = None
@@ -258,7 +261,7 @@
self.SetText(new_text)
new_cursor_pos = GetCursorPos(old_text, new_text)
self.LineScroll(column, line)
- if new_cursor_pos != None:
+ if new_cursor_pos is not None:
self.GotoPos(new_cursor_pos)
else:
self.GotoPos(old_cursor_pos)
@@ -381,7 +384,7 @@
if braceAtCaret >= 0:
braceOpposite = self.BraceMatch(braceAtCaret)
- if braceAtCaret != -1 and braceOpposite == -1:
+ if braceAtCaret != -1 and braceOpposite == -1:
self.BraceBadLight(braceAtCaret)
else:
self.BraceHighlight(braceAtCaret, braceOpposite)
@@ -443,8 +446,6 @@
lineNum = lineNum + 1
-
-
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
lastChild = self.GetLastChild(line, level)
line = line + 1
@@ -548,9 +549,9 @@
self.RemoveHighlight(*self.CurrentFindHighlight)
self.CurrentFindHighlight = None
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def OnRefreshHighlightsTimer(self, event):
self.RefreshView(True)
@@ -575,8 +576,8 @@
def RemoveHighlight(self, start, end, highlight_type):
highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
- if (highlight_type is not None and
- (start, end, highlight_type) in self.Highlights):
+ if highlight_type is not None and \
+ (start, end, highlight_type) in self.Highlights:
self.Highlights.remove((start, end, highlight_type))
self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
@@ -596,9 +597,9 @@
self.SetStyling(len(self.GetText()) - highlight_end_pos, stc.STC_STYLE_DEFAULT)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Helper for VariablesGrid values
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class VariablesTable(CustomTable):
@@ -660,7 +661,7 @@
("UpVariableButton", "up", _("Move variable up")),
("DownVariableButton", "down", _("Move variable down"))]:
button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM)
@@ -676,8 +677,14 @@
self.ParentWindow = window
self.Controler = controler
- self.VariablesDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial": "",
- "Description":"", "OnChange":"", "Options":""}
+ self.VariablesDefaultValue = {
+ "Name": "",
+ "Type": DefaultType,
+ "Initial": "",
+ "Description": "",
+ "OnChange": "",
+ "Options": ""
+ }
self.Table = VariablesTable(self, [], self.GetVariableTableColnames())
self.ColAlignements = [wx.ALIGN_RIGHT] + \
[wx.ALIGN_LEFT]*(len(self.VariablesDefaultValue))
@@ -735,8 +742,14 @@
self.Table.ResetView(self.VariablesGrid)
def GetVariableTableColnames(self):
- _ = lambda x : x
- return ["#", _("Name"),_("Type"), _("Initial"), _("Description"), _("OnChange"), _("Options")]
+ _ = NoTranslate
+ return ["#",
+ _("Name"),
+ _("Type"),
+ _("Initial"),
+ _("Description"),
+ _("OnChange"),
+ _("Options")]
def RefreshModel(self):
self.Controler.SetVariables(self.Table.GetData())
@@ -759,7 +772,7 @@
return self.ParentWindow.GetPanelBestSize()
def ShowErrorMessage(self, message):
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
@@ -831,7 +844,7 @@
data_type = self.Table.GetValueByName(row, "Type")
var_name = self.Table.GetValueByName(row, "Name")
data = wx.TextDataObject(str((var_name, "Global", data_type,
- self.Controler.GetCurrentLocation())))
+ self.Controler.GetCurrentLocation())))
dragSource = wx.DropSource(self.VariablesGrid)
dragSource.SetData(data)
dragSource.DoDragDrop()
@@ -839,9 +852,9 @@
event.Skip()
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# CodeFileEditor Main Frame Class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class CodeFileEditor(ConfTreeNodeEditor):
@@ -853,14 +866,15 @@
self.CodeEditorPanel.SetMinimumPaneSize(1)
self.VariablesPanel = VariablesEditor(self.CodeEditorPanel,
- self.ParentWindow, self.Controler)
+ self.ParentWindow,
+ self.Controler)
if self.CODE_EDITOR is not None:
self.CodeEditor = self.CODE_EDITOR(self.CodeEditorPanel,
- self.ParentWindow, self.Controler)
+ self.ParentWindow, self.Controler)
self.CodeEditorPanel.SplitHorizontally(self.VariablesPanel,
- self.CodeEditor, 150)
+ self.CodeEditor, 150)
else:
self.CodeEditorPanel.Initialize(self.VariablesPanel)
@@ -890,4 +904,3 @@
def Find(self, direction, search_params):
self.CodeEditor.Find(direction, search_params)
-
--- a/editors/ConfTreeNodeEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/ConfTreeNodeEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -37,22 +37,25 @@
from util.BitmapLibrary import GetBitmap
if wx.Platform == '__WXMSW__':
- faces = { 'times': 'Times New Roman',
- 'mono' : 'Courier New',
- 'helv' : 'Arial',
- 'other': 'Comic Sans MS',
- 'size' : 16,
- }
+ faces = {
+ 'times': 'Times New Roman',
+ 'mono': 'Courier New',
+ 'helv': 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size': 16,
+ }
else:
- faces = { 'times': 'Times',
- 'mono' : 'Courier',
- 'helv' : 'Helvetica',
- 'other': 'new century schoolbook',
- 'size' : 18,
- }
+ faces = {
+ 'times': 'Times',
+ 'mono': 'Courier',
+ 'helv': 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size': 18,
+ }
SCROLLBAR_UNIT = 10
+
class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
def _GetLabelSize(self):
""" used internally """
@@ -71,17 +74,17 @@
def DrawLabel(self, dc, width, height, dw=0, dy=0):
bmp = self.bmpLabel
- if bmp != None: # if the bitmap is used
+ 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()
+ bw, bh = bmp.GetWidth(), bmp.GetHeight()
if not self.up:
dw = dy = self.labelDelta
- hasMask = bmp.GetMask() != None
+ hasMask = bmp.GetMask() is not None
else:
bw = bh = 0 # no bitmap -> size is zero
@@ -98,8 +101,8 @@
pos_x = (width-bw)/2+dw # adjust for bitmap and text to centre
pos_y = (height-bh-th)/2+dy
- if bmp !=None:
- dc.DrawBitmap(bmp, pos_x, pos_y, hasMask) # draw bitmap if available
+ if bmp is not None:
+ dc.DrawBitmap(bmp, pos_x, pos_y, hasMask) # draw bitmap if available
pos_x = (width-tw)/2+dw # adjust for bitmap and text to centre
pos_y += bh + 2
@@ -110,19 +113,20 @@
""" Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32,
and accept image name as __init__ parameter, fail silently if file do not exist"""
def __init__(self, parent, ID, bitmapname,
- pos = wx.DefaultPosition, size = wx.DefaultSize,
- style = 0,
- name = "genstatbmp"):
+ pos=wx.DefaultPosition, size=wx.DefaultSize,
+ style=0,
+ name="genstatbmp"):
bitmap = GetBitmap(bitmapname)
if bitmap is None:
bitmap = wx.EmptyBitmap(0, 0)
wx.StaticBitmap.__init__(self, parent, ID,
- bitmap,
- pos, size,
- style,
- name)
+ bitmap,
+ pos, size,
+ style,
+ name)
+
class ConfTreeNodeEditor(EditorPanel):
@@ -137,48 +141,54 @@
if tabs_num > 1 or self.SHOW_BASE_PARAMS:
self.Editor = wx.Panel(parent,
- style=wx.SUNKEN_BORDER|wx.SP_3D)
+ style=wx.SUNKEN_BORDER | wx.SP_3D)
self.MainSizer = wx.BoxSizer(wx.VERTICAL)
if self.SHOW_BASE_PARAMS:
baseparamseditor_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.MainSizer.AddSizer(baseparamseditor_sizer, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
self.FullIECChannel = wx.StaticText(self.Editor, -1)
self.FullIECChannel.SetFont(
wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL,
- wx.BOLD, faceName = faces["helv"]))
+ wx.BOLD, faceName=faces["helv"]))
baseparamseditor_sizer.AddWindow(self.FullIECChannel,
- flag=wx.ALIGN_CENTER_VERTICAL)
+ flag=wx.ALIGN_CENTER_VERTICAL)
updownsizer = wx.BoxSizer(wx.VERTICAL)
baseparamseditor_sizer.AddSizer(updownsizer, border=5,
- flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL)
-
- self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton(self.Editor,
- bitmap=GetBitmap('IECCDown'), size=wx.Size(16, 16), style=wx.NO_BORDER)
+ flag=wx.LEFT | wx.ALIGN_CENTER_VERTICAL)
+
+ self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton(
+ self.Editor,
+ bitmap=GetBitmap('IECCDown'),
+ size=wx.Size(16, 16),
+ style=wx.NO_BORDER)
self.IECCUpButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(1),
- self.IECCUpButton)
+ self.IECCUpButton)
updownsizer.AddWindow(self.IECCUpButton, flag=wx.ALIGN_LEFT)
- self.IECCDownButton = wx.lib.buttons.GenBitmapButton(self.Editor,
- bitmap=GetBitmap('IECCUp'), size=wx.Size(16, 16), style=wx.NO_BORDER)
+ self.IECCDownButton = wx.lib.buttons.GenBitmapButton(
+ self.Editor, bitmap=GetBitmap('IECCUp'),
+ size=wx.Size(16, 16), style=wx.NO_BORDER)
self.IECCDownButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(-1),
- self.IECCDownButton)
+ self.IECCDownButton)
updownsizer.AddWindow(self.IECCDownButton, flag=wx.ALIGN_LEFT)
self.ConfNodeName = wx.TextCtrl(self.Editor,
- size=wx.Size(150, 25))
+ size=wx.Size(150, 25))
self.ConfNodeName.SetFont(
wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL,
- wx.BOLD, faceName = faces["helv"]))
- self.ConfNodeName.Bind(wx.EVT_TEXT,
- self.GetTextCtrlCallBackFunction(self.ConfNodeName, "BaseParams.Name", True),
- self.ConfNodeName)
- baseparamseditor_sizer.AddWindow(self.ConfNodeName, border=5,
- flag=wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
+ wx.BOLD, faceName=faces["helv"]))
+ self.ConfNodeName.Bind(
+ wx.EVT_TEXT,
+ self.GetTextCtrlCallBackFunction(self.ConfNodeName, "BaseParams.Name", True),
+ self.ConfNodeName)
+ baseparamseditor_sizer.AddWindow(
+ self.ConfNodeName, border=5,
+ flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER_VERTICAL)
buttons_sizer = self.GenerateMethodButtonSizer()
baseparamseditor_sizer.AddSizer(buttons_sizer, flag=wx.ALIGN_CENTER)
@@ -207,11 +217,11 @@
if self.SHOW_PARAMS and len(self.Controler.GetParamsAttributes()) > 0:
- panel_style = wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL
+ panel_style = wx.TAB_TRAVERSAL | wx.HSCROLL | wx.VSCROLL
if self.ConfNodeNoteBook is None and parent != self.Editor:
panel_style |= wx.SUNKEN_BORDER
self.ParamsEditor = wx.ScrolledWindow(parent,
- style=panel_style)
+ style=panel_style)
self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnParamsEditorResize)
self.ParamsEditor.Bind(wx.EVT_SCROLLWIN, self.OnParamsEditorScroll)
@@ -222,7 +232,7 @@
self.ConfNodeParamsSizer = wx.BoxSizer(wx.VERTICAL)
self.ParamsEditorSizer.AddSizer(self.ConfNodeParamsSizer, border=5,
- flag=wx.LEFT|wx.RIGHT|wx.BOTTOM)
+ flag=wx.LEFT | wx.RIGHT | wx.BOTTOM)
self.RefreshConfNodeParamsSizer()
@@ -294,16 +304,17 @@
self.Thaw()
def GenerateMethodButtonSizer(self):
- 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"])
+ 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, faceName=faces["helv"], underline=True)
msizer = wx.BoxSizer(wx.HORIZONTAL)
for confnode_method in self.Controler.ConfNodeMethods:
- if "method" in confnode_method and confnode_method.get("shown",True):
+ if "method" in confnode_method and confnode_method.get("shown", True):
button = GenBitmapTextButton(self.Editor,
- bitmap=GetBitmap(confnode_method.get("bitmap", "Unknown")),
- label=confnode_method["name"], style=wx.NO_BORDER)
+ bitmap=GetBitmap(confnode_method.get("bitmap", "Unknown")),
+ label=confnode_method["name"],
+ style=wx.NO_BORDER)
button.SetFont(normal_bt_font)
button.SetToolTipString(confnode_method["tooltip"])
if confnode_method.get("push", False):
@@ -311,6 +322,7 @@
else:
button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode_method["method"]), button)
# a fancy underline on mouseover
+
def setFontStyle(b, s):
def fn(event):
b.SetFont(s)
@@ -319,19 +331,19 @@
return fn
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 confnode_method.get("enabled",True):
+ # hack to force size to mini
+ if not confnode_method.get("enabled", True):
button.Disable()
msizer.AddWindow(button, flag=wx.ALIGN_CENTER)
return msizer
- def GenerateSizerElements(self, sizer, elements, path, clean = True):
+ def GenerateSizerElements(self, sizer, elements, path, clean=True):
if clean:
sizer.Clear(True)
first = True
for element_infos in elements:
if path:
- element_path = "%s.%s"%(path, element_infos["name"])
+ element_path = "%s.%s" % (path, element_infos["name"])
else:
element_path = element_infos["name"]
if element_infos["type"] == "element":
@@ -341,7 +353,7 @@
if value is not None:
label += " - %s" % _(value)
staticbox = wx.StaticBox(self.ParamsEditor,
- label=_(label), size=wx.Size(10, 0))
+ label=_(label), size=wx.Size(10, 0))
staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
flags = (wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
if first:
@@ -357,15 +369,16 @@
if first:
flags |= wx.TOP
sizer.AddSizer(boxsizer, border=5, flag=flags)
- staticbitmap = GenStaticBitmap(ID=-1, bitmapname=element_infos["name"],
- name="%s_bitmap"%element_infos["name"], parent=self.ParamsEditor,
+ staticbitmap = GenStaticBitmap(
+ ID=-1, bitmapname=element_infos["name"],
+ name="%s_bitmap" % element_infos["name"], parent=self.ParamsEditor,
pos=wx.Point(0, 0), size=wx.Size(24, 24), style=0)
boxsizer.AddWindow(staticbitmap, border=5, flag=wx.RIGHT)
statictext = wx.StaticText(self.ParamsEditor,
- label="%s:"%_(element_infos["name"]))
+ label="%s:" % _(element_infos["name"]))
boxsizer.AddWindow(statictext, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.RIGHT)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT)
if isinstance(element_infos["type"], types.ListType):
if isinstance(element_infos["value"], types.TupleType):
@@ -373,7 +386,7 @@
boxsizer.AddSizer(browse_boxsizer)
textctrl = wx.TextCtrl(self.ParamsEditor,
- size=wx.Size(275, -1), style=wx.TE_READONLY)
+ size=wx.Size(275, -1), style=wx.TE_READONLY)
if element_infos["value"] is not None:
textctrl.SetValue(element_infos["value"][0])
value_infos = element_infos["value"][1]
@@ -389,7 +402,7 @@
button)
else:
combobox = wx.ComboBox(self.ParamsEditor,
- size=wx.Size(300, -1), style=wx.CB_READONLY)
+ size=wx.Size(300, -1), style=wx.CB_READONLY)
boxsizer.AddWindow(combobox)
if element_infos["use"] == "optional":
@@ -401,7 +414,8 @@
value = element_infos["value"]
staticbox = wx.StaticBox(self.ParamsEditor,
- label="%s - %s"%(_(name), _(value)), size=wx.Size(10, 0))
+ label="%s - %s" % (_(name), _(value)),
+ size=wx.Size(10, 0))
staticboxsizer = wx.StaticBoxSizer(staticbox, wx.VERTICAL)
sizer.AddSizer(staticboxsizer, border=5, flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
self.GenerateSizerElements(staticboxsizer, element_infos["children"], element_path)
@@ -424,7 +438,8 @@
if "max" in element_infos["type"]:
scmax = element_infos["type"]["max"]
spinctrl = wx.SpinCtrl(self.ParamsEditor,
- size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
+ size=wx.Size(300, -1),
+ style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT)
spinctrl.SetRange(scmin, scmax)
boxsizer.AddWindow(spinctrl)
if element_infos["value"] is not None:
@@ -443,14 +458,15 @@
self.GetCheckBoxCallBackFunction(checkbox, element_path),
checkbox)
- elif element_infos["type"] in ["unsignedLong", "long","integer"]:
+ elif element_infos["type"] in ["unsignedLong", "long", "integer"]:
if element_infos["type"].startswith("unsigned"):
scmin = 0
else:
scmin = -(2**31)
scmax = 2**31-1
spinctrl = wx.SpinCtrl(self.ParamsEditor,
- size=wx.Size(300, -1), style=wx.SP_ARROW_KEYS|wx.ALIGN_RIGHT)
+ size=wx.Size(300, -1),
+ style=wx.SP_ARROW_KEYS | wx.ALIGN_RIGHT)
spinctrl.SetRange(scmin, scmax)
boxsizer.AddWindow(spinctrl)
if element_infos["value"] is not None:
@@ -477,7 +493,6 @@
sizer.Layout()
self.RefreshScrollbars()
-
def GetItemChannelChangedFunction(self, dir):
def OnConfNodeTreeItemChannelChanged(event):
confnode_IECChannel = self.Controler.BaseParams.getIEC_Channel()
@@ -500,7 +515,7 @@
# Disable button to prevent re-entrant call
event.GetEventObject().Disable()
# Call
- getattr(self.Controler,method)()
+ getattr(self.Controler, method)()
# Re-enable button
event.GetEventObject().Enable()
@@ -547,6 +562,7 @@
def GetBrowseCallBackFunction(self, name, textctrl, library, value_infos, path):
infos = [value_infos]
+
def OnBrowseButton(event):
dialog = BrowseValuesLibraryDialog(self, name, library, infos[0])
if dialog.ShowModal() == wx.ID_OK:
@@ -566,7 +582,8 @@
posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
self.ParamsEditor.Scroll(posx, posy)
self.ParamsEditor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
- maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
+ maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT,
+ posx, posy)
def OnParamsEditorResize(self, event):
self.RefreshScrollbars()
@@ -578,4 +595,3 @@
control.DismissListBox()
self.Refresh()
event.Skip()
-
--- a/editors/DataTypeEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/DataTypeEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -35,28 +35,35 @@
from dialogs import ArrayTypeDialog
from EditorPanel import EditorPanel
from util.BitmapLibrary import GetBitmap
-
-#-------------------------------------------------------------------------------
+from util.TranslationCatalogs import NoTranslate
+
+# -------------------------------------------------------------------------------
# Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
DIMENSION_MODEL = re.compile("([0-9]+)\.\.([0-9]+)$")
+
def AppendMenu(parent, help, id, kind, text):
parent.Append(help=help, id=id, kind=kind, text=text)
+
def GetElementsTableColnames():
- _ = lambda x : x
+ _ = NoTranslate
return ["#", _("Name"), _("Type"), _("Initial Value")]
+
def GetDatatypeTypes():
- _ = lambda x : x
+ _ = NoTranslate
return [_("Directly"), _("Subrange"), _("Enumerated"), _("Array"), _("Structure")]
+
+
DATATYPE_TYPES_DICT = dict([(_(datatype), datatype) for datatype in GetDatatypeTypes()])
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Structure Elements Table
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class ElementsTable(CustomTable):
@@ -74,10 +81,10 @@
return row + 1
colname = self.GetColLabelValue(col, False)
value = self.data[row].get(colname, "")
-
+
if colname == "Type" and isinstance(value, TupleType):
if value[0] == "array":
- return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "..".join(x), value[2])), value[1])
+ return "ARRAY [%s] OF %s" % (",".join(map(lambda x: "..".join(x), value[2])), value[1])
return value
def SetValue(self, row, col, value):
@@ -133,9 +140,10 @@
col_highlights = row_highlights.setdefault(infos[1], [])
col_highlights.append(highlight_type)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Datatype Editor class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
class DataTypeEditor(EditorPanel):
@@ -148,21 +156,21 @@
top_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.MainSizer.AddSizer(top_sizer, border=5,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
derivation_type_label = wx.StaticText(self.Editor, label=_('Derivation Type:'))
top_sizer.AddWindow(derivation_type_label, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT)
self.DerivationType = wx.ComboBox(self.Editor,
- size=wx.Size(200, -1), style=wx.CB_READONLY)
+ size=wx.Size(200, -1), style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnDerivationTypeChanged, self.DerivationType)
- top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW|wx.RIGHT)
+ top_sizer.AddWindow(self.DerivationType, border=5, flag=wx.GROW | wx.RIGHT)
typeinfos_staticbox = wx.StaticBox(self.Editor, label=_('Type infos:'))
typeinfos_sizer = wx.StaticBoxSizer(typeinfos_staticbox, wx.HORIZONTAL)
self.MainSizer.AddSizer(typeinfos_sizer, border=5,
- flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
# Panel for Directly derived data types
@@ -172,25 +180,25 @@
directly_panel_sizer = wx.BoxSizer(wx.HORIZONTAL)
directly_basetype_label = wx.StaticText(self.DirectlyPanel,
- label=_('Base Type:'))
+ label=_('Base Type:'))
directly_panel_sizer.AddWindow(directly_basetype_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.DirectlyBaseType = wx.ComboBox(self.DirectlyPanel, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.DirectlyBaseType)
directly_panel_sizer.AddWindow(self.DirectlyBaseType, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
directly_initialvalue_label = wx.StaticText(self.DirectlyPanel,
- label=_('Initial Value:'))
+ label=_('Initial Value:'))
directly_panel_sizer.AddWindow(directly_initialvalue_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.DirectlyInitialValue = wx.TextCtrl(self.DirectlyPanel,
- style=wx.TE_PROCESS_ENTER|wx.TE_RICH)
+ style=wx.TE_PROCESS_ENTER | wx.TE_RICH)
self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.DirectlyInitialValue)
directly_panel_sizer.AddWindow(self.DirectlyInitialValue, 1, border=5,
- flag=wx.ALL)
+ flag=wx.ALL)
self.DirectlyPanel.SetSizer(directly_panel_sizer)
@@ -202,49 +210,49 @@
subrange_panel_sizer = wx.GridSizer(cols=4, hgap=5, rows=3, vgap=0)
subrange_basetype_label = wx.StaticText(self.SubrangePanel,
- label=_('Base Type:'))
+ label=_('Base Type:'))
subrange_panel_sizer.AddWindow(subrange_basetype_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.SubrangeBaseType = wx.ComboBox(self.SubrangePanel, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnSubrangeBaseTypeChanged,
- self.SubrangeBaseType)
+ self.SubrangeBaseType)
subrange_panel_sizer.AddWindow(self.SubrangeBaseType, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
subrange_initialvalue_label = wx.StaticText(self.SubrangePanel,
- label=_('Initial Value:'))
+ label=_('Initial Value:'))
subrange_panel_sizer.AddWindow(subrange_initialvalue_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.SubrangeInitialValue = wx.SpinCtrl(self.SubrangePanel,
- style=wx.TAB_TRAVERSAL)
+ style=wx.TAB_TRAVERSAL)
self.Bind(wx.EVT_SPINCTRL, self.OnInfosChanged, self.SubrangeInitialValue)
subrange_panel_sizer.AddWindow(self.SubrangeInitialValue, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
subrange_minimum_label = wx.StaticText(self.SubrangePanel, label=_('Minimum:'))
subrange_panel_sizer.AddWindow(subrange_minimum_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.SubrangeMinimum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL)
self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMinimumChanged, self.SubrangeMinimum)
subrange_panel_sizer.AddWindow(self.SubrangeMinimum, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
for i in xrange(2):
subrange_panel_sizer.AddWindow(wx.Size(0, 0), 1)
subrange_maximum_label = wx.StaticText(self.SubrangePanel,
- label=_('Maximum:'))
+ label=_('Maximum:'))
subrange_panel_sizer.AddWindow(subrange_maximum_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.SubrangeMaximum = wx.SpinCtrl(self.SubrangePanel, style=wx.TAB_TRAVERSAL)
self.Bind(wx.EVT_SPINCTRL, self.OnSubrangeMaximumChanged, self.SubrangeMaximum)
subrange_panel_sizer.AddWindow(self.SubrangeMaximum, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
self.SubrangePanel.SetSizer(subrange_panel_sizer)
@@ -255,29 +263,32 @@
enumerated_panel_sizer = wx.BoxSizer(wx.HORIZONTAL)
- self.EnumeratedValues = CustomEditableListBox(self.EnumeratedPanel,
- label=_("Values:"), style=wx.gizmos.EL_ALLOW_NEW|
- wx.gizmos.EL_ALLOW_EDIT|
- wx.gizmos.EL_ALLOW_DELETE)
+ self.EnumeratedValues = CustomEditableListBox(
+ self.EnumeratedPanel,
+ label=_("Values:"),
+ style=(wx.gizmos.EL_ALLOW_NEW |
+ wx.gizmos.EL_ALLOW_EDIT |
+ wx.gizmos.EL_ALLOW_DELETE))
setattr(self.EnumeratedValues, "_OnLabelEndEdit", self.OnEnumeratedValueEndEdit)
for func in ["_OnAddButton", "_OnDelButton", "_OnUpButton", "_OnDownButton"]:
setattr(self.EnumeratedValues, func, self.OnEnumeratedValuesChanged)
enumerated_panel_sizer.AddWindow(self.EnumeratedValues, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
enumerated_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL)
enumerated_panel_sizer.AddSizer(enumerated_panel_rightsizer, 1)
enumerated_initialvalue_label = wx.StaticText(self.EnumeratedPanel,
- label=_('Initial Value:'))
+ label=_('Initial Value:'))
enumerated_panel_rightsizer.AddWindow(enumerated_initialvalue_label, 1,
- border=5, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ border=5,
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.EnumeratedInitialValue = wx.ComboBox(self.EnumeratedPanel,
- style=wx.CB_READONLY)
+ style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.EnumeratedInitialValue)
enumerated_panel_rightsizer.AddWindow(self.EnumeratedInitialValue, 1,
- border=5, flag=wx.ALL)
+ border=5, flag=wx.ALL)
self.EnumeratedPanel.SetSizer(enumerated_panel_sizer)
@@ -296,36 +307,38 @@
array_basetype_label = wx.StaticText(self.ArrayPanel, label=_('Base Type:'))
array_panel_leftSizer.AddWindow(array_basetype_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.ArrayBaseType = wx.ComboBox(self.ArrayPanel, style=wx.CB_READONLY)
self.Bind(wx.EVT_COMBOBOX, self.OnInfosChanged, self.ArrayBaseType)
array_panel_leftSizer.AddWindow(self.ArrayBaseType, 1, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
array_panel_rightsizer = wx.BoxSizer(wx.HORIZONTAL)
array_panel_sizer.AddSizer(array_panel_rightsizer, flag=wx.GROW)
array_initialvalue_label = wx.StaticText(self.ArrayPanel,
- label=_('Initial Value:'))
+ label=_('Initial Value:'))
array_panel_rightsizer.AddWindow(array_initialvalue_label, 1, border=5,
- flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL)
+ flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL)
self.ArrayInitialValue = wx.TextCtrl(self.ArrayPanel,
- style=wx.TE_PROCESS_ENTER|wx.TE_RICH)
+ style=wx.TE_PROCESS_ENTER | wx.TE_RICH)
self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, self.ArrayInitialValue)
array_panel_rightsizer.AddWindow(self.ArrayInitialValue, 1, border=5,
- flag=wx.ALL)
-
- self.ArrayDimensions = CustomEditableListBox(self.ArrayPanel,
- label=_("Dimensions:"), style=wx.gizmos.EL_ALLOW_NEW|
- wx.gizmos.EL_ALLOW_EDIT|
- wx.gizmos.EL_ALLOW_DELETE)
+ flag=wx.ALL)
+
+ self.ArrayDimensions = CustomEditableListBox(
+ self.ArrayPanel,
+ label=_("Dimensions:"),
+ style=(wx.gizmos.EL_ALLOW_NEW |
+ wx.gizmos.EL_ALLOW_EDIT |
+ wx.gizmos.EL_ALLOW_DELETE))
for func in ["_OnLabelEndEdit", "_OnAddButton", "_OnDelButton",
"_OnUpButton", "_OnDownButton"]:
setattr(self.ArrayDimensions, func, self.OnDimensionsChanged)
array_panel_sizer.AddWindow(self.ArrayDimensions, 0, border=5,
- flag=wx.GROW|wx.ALL)
+ flag=wx.GROW | wx.ALL)
self.ArrayPanel.SetSizer(array_panel_sizer)
@@ -342,10 +355,10 @@
structure_button_sizer.AddGrowableCol(0)
structure_button_sizer.AddGrowableRow(0)
structure_panel_sizer.AddSizer(structure_button_sizer, 0, border=5,
- flag=wx.ALL|wx.GROW)
+ flag=wx.ALL | wx.GROW)
structure_elements_label = wx.StaticText(self.StructurePanel,
- label=_('Elements :'))
+ label=_('Elements :'))
structure_button_sizer.AddWindow(structure_elements_label, flag=wx.ALIGN_BOTTOM)
for name, bitmap, help in [
@@ -354,17 +367,19 @@
("StructureUpButton", "up", _("Move element up")),
("StructureDownButton", "down", _("Move element down"))]:
button = wx.lib.buttons.GenBitmapButton(self.StructurePanel,
- bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28),
+ style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
structure_button_sizer.AddWindow(button)
self.StructureElementsGrid = CustomGrid(self.StructurePanel,
- size=wx.Size(0, 150), style=wx.VSCROLL)
+ size=wx.Size(0, 150), style=wx.VSCROLL)
self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
- self.OnStructureElementsGridCellChange)
+ self.OnStructureElementsGridCellChange)
self.StructureElementsGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN,
- self.OnStructureElementsGridEditorShown)
+ self.OnStructureElementsGridEditorShown)
structure_panel_sizer.AddWindow(self.StructureElementsGrid, flag=wx.GROW)
self.StructurePanel.SetSizer(structure_panel_sizer)
@@ -374,7 +389,7 @@
def __init__(self, parent, tagname, window, controler):
EditorPanel.__init__(self, parent, tagname, window, controler)
- self.StructureElementDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial Value" : ""}
+ self.StructureElementDefaultValue = {"Name": "", "Type": DefaultType, "Initial Value": ""}
self.StructureElementsTable = ElementsTable(self, [], GetElementsTableColnames())
self.StructureColSizes = [40, 150, 100, 250]
self.StructureColAlignements = [wx.ALIGN_CENTER, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT]
@@ -496,7 +511,7 @@
self.EnumeratedInitialValue.SetStringSelection(type_infos["initial"])
elif type_infos["type"] == "Array":
self.ArrayBaseType.SetStringSelection(type_infos["base_type"])
- self.ArrayDimensions.SetStrings(map(lambda x : "..".join(x), type_infos["dimensions"]))
+ self.ArrayDimensions.SetStrings(map(lambda x: "..".join(x), type_infos["dimensions"]))
self.ArrayInitialValue.SetValue(type_infos["initial"])
elif type_infos["type"] == "Structure":
self.StructureElementsTable.SetData(type_infos["elements"])
@@ -547,12 +562,12 @@
index = event.GetIndex()
if index >= len(values) or values[index].upper() != text.upper():
if text.upper() in [value.upper() for value in values]:
- message = wx.MessageDialog(self, _("\"%s\" value already defined!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("\"%s\" value already defined!") % text, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
event.Veto()
elif text.upper() in IEC_KEYWORDS:
- message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!")%text, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("\"%s\" is a keyword. It can't be used!") % text, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
@@ -571,10 +586,10 @@
event.Skip()
def ShowErrorMessage(self, message):
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
-
+
def OnStructureElementsGridCellChange(self, event):
row, col = event.GetRow(), event.GetCol()
colname = self.StructureElementsTable.GetColLabelValue(col, False)
@@ -582,20 +597,20 @@
if colname == "Name":
message = None
if not TestIdentifier(value):
- message = _("\"%s\" is not a valid identifier!")%value
+ message = _("\"%s\" is not a valid identifier!") % value
elif value.upper() in IEC_KEYWORDS:
- message = _("\"%s\" is a keyword. It can't be used!")%value
-## elif value.upper() in self.PouNames:
-## message = _("A pou with \"%s\" as name exists!")%value
+ message = _("\"%s\" is a keyword. It can't be used!") % value
+# elif value.upper() in self.PouNames:
+# message = _("A pou with \"%s\" as name exists!")%value
elif value.upper() in [var["Name"].upper() for idx, var in enumerate(self.StructureElementsTable.GetData()) if idx != row]:
- message = _("An element named \"%s\" already exists in this structure!")%value
+ message = _("An element named \"%s\" already exists in this structure!") % value
else:
self.RefreshTypeInfos()
wx.CallAfter(self.StructureElementsTable.ResetView, self.StructureElementsGrid)
-## old_value = self.Table.GetOldValue()
-## if old_value != "":
-## self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
-## self.Controler.BufferProject()
+# old_value = self.Table.GetOldValue()
+# if old_value != "":
+# self.Controler.UpdateEditedElementUsedVariable(self.TagName, old_value, value)
+# self.Controler.BufferProject()
event.Skip()
if message is not None:
@@ -633,15 +648,15 @@
AppendMenu(type_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Array"))
self.Bind(wx.EVT_MENU, self.ElementArrayTypeFunction, id=new_id)
-## functionblock_menu = wx.Menu(title='')
-## bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
-## pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
-## if classtype in ["Input","Output","InOut","External","Global"] or poutype != "function" and bodytype in ["ST", "IL"]:
-## for functionblock_type in self.Controler.GetFunctionBlockTypes(self.TagName):
-## new_id = wx.NewId()
-## AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
-## self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
-## type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
+# functionblock_menu = wx.Menu(title='')
+# bodytype = self.Controler.GetEditedElementBodyType(self.TagName)
+# pouname, poutype = self.Controler.GetEditedElementType(self.TagName)
+# if classtype in ["Input","Output","InOut","External","Global"] or poutype != "function" and bodytype in ["ST", "IL"]:
+# for functionblock_type in self.Controler.GetFunctionBlockTypes(self.TagName):
+# new_id = wx.NewId()
+# AppendMenu(functionblock_menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=functionblock_type)
+# self.Bind(wx.EVT_MENU, self.GetVariableTypeFunction(functionblock_type), id=new_id)
+# type_menu.AppendMenu(wx.NewId(), _("Function Block Types"), functionblock_menu)
rect = self.StructureElementsGrid.BlockToDeviceRect((row, col), (row, col))
self.StructureElementsGrid.PopupMenuXY(type_menu, rect.x + rect.width, rect.y + self.StructureElementsGrid.GetColLabelSize())
@@ -718,7 +733,7 @@
def RefreshTypeInfos(self):
selected = DATATYPE_TYPES_DICT[self.DerivationType.GetStringSelection()]
- infos = {"type" : selected}
+ infos = {"type": selected}
if selected == "Directly":
infos["base_type"] = self.DirectlyBaseType.GetStringSelection()
infos["initial"] = self.DirectlyInitialValue.GetValue()
@@ -740,14 +755,14 @@
for dimensions in self.ArrayDimensions.GetStrings():
result = DIMENSION_MODEL.match(dimensions)
if result is None:
- message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!")%dimensions, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!") % dimensions, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
self.RefreshView()
return
bounds = result.groups()
if int(bounds[0]) >= int(bounds[1]):
- message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.")%dimensions, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("\"%s\" value isn't a valid array dimension!\nRight value must be greater than left value.") % dimensions, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
self.RefreshView()
@@ -762,9 +777,9 @@
self.ParentWindow.RefreshFileMenu()
self.ParentWindow.RefreshEditMenu()
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def OnRefreshHighlightsTimer(self, event):
self.RefreshView()
@@ -790,7 +805,7 @@
self.StructureElementsTable.ClearHighlights(highlight_type)
self.RefreshView()
- def AddHighlight(self, infos, start, end ,highlight_type):
+ def AddHighlight(self, infos, start, end, highlight_type):
self.Highlights.append((infos, start, end, highlight_type))
self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
@@ -812,4 +827,3 @@
listctrl.SetItemBackgroundColour(infos[1], highlight_type[0])
listctrl.SetItemTextColour(infos[1], highlight_type[1])
listctrl.Select(listctrl.FocusedItem, False)
-
--- a/editors/DebugViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/DebugViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,20 +27,20 @@
import wx
-REFRESH_PERIOD = 0.1 # Minimum time between 2 refresh
-DEBUG_REFRESH_LOCK = Lock() # Common refresh lock for all debug viewers
-
-#-------------------------------------------------------------------------------
+REFRESH_PERIOD = 0.1 # Minimum time between 2 refresh
+DEBUG_REFRESH_LOCK = Lock() # Common refresh lock for all debug viewers
+
+# -------------------------------------------------------------------------------
# Debug Viewer Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements common behavior of every viewers able to display debug
-values
-"""
+# -------------------------------------------------------------------------------
+
class DebugViewer:
-
+ """
+ Class that implements common behavior of every viewers able to display debug
+ values
+ """
+
def __init__(self, producer, debug, subscribe_tick=True):
"""
Constructor
@@ -52,49 +52,49 @@
"""
self.Debug = debug
self.SubscribeTick = subscribe_tick
-
+
# Flag indicating that consumer value update inhibited
# (DebugViewer is refreshing)
self.Inhibited = False
-
+
# List of data consumers subscribed to DataProducer
self.DataConsumers = {}
-
+
# Time stamp indicating when last refresh have been initiated
self.LastRefreshTime = gettime()
# Flag indicating that DebugViewer has acquire common debug lock
self.HasAcquiredLock = False
# Lock for access to the two preceding variable
self.AccessLock = Lock()
-
+
# Timer to refresh Debug Viewer one last time in the case that a new
# value have been received during refresh was inhibited and no one
# after refresh was activated
self.LastRefreshTimer = None
# Lock for access to the timer
self.TimerAccessLock = Lock()
-
+
# Set DataProducer and subscribe tick if needed
self.SetDataProducer(producer)
-
+
def __del__(self):
"""
Destructor
"""
# Unsubscribe all data consumers
self.UnsubscribeAllDataConsumers()
-
+
# Delete reference to DataProducer
self.DataProducer = None
-
+
# Stop last refresh timer
if self.LastRefreshTimer is not None:
self.LastRefreshTimer.cancel()
-
+
# Release Common debug lock if DebugViewer has acquired it
if self.HasAcquiredLock:
DEBUG_REFRESH_LOCK.release()
-
+
def SetDataProducer(self, producer):
"""
Set Data Producer
@@ -103,25 +103,25 @@
# In the case that tick need to be subscribed and DebugViewer is
# debugging
if self.SubscribeTick and self.Debug:
-
+
# Subscribe tick to new data producer
if producer is not None:
producer.SubscribeDebugIECVariable("__tick__", self, True)
-
+
# Unsubscribe tick from old data producer
if getattr(self, "DataProducer", None) is not None:
self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self)
-
+
# Save new data producer
self.DataProducer = producer
-
+
def IsDebugging(self):
"""
Get flag indicating if Debug Viewer is debugging
@return: Debugging flag
"""
return self.Debug
-
+
def Inhibit(self, inhibit):
"""
Set consumer value update inhibit flag
@@ -130,10 +130,10 @@
# Inhibit every data consumers in list
for consumer, iec_path in self.DataConsumers.iteritems():
consumer.Inhibit(inhibit)
-
+
# Save inhibit flag
self.Inhibited = inhibit
-
+
def AddDataConsumer(self, iec_path, consumer, buffer_list=False):
"""
Subscribe data consumer to DataProducer
@@ -145,19 +145,19 @@
# Return immediately if no DataProducer defined
if self.DataProducer is None:
return None
-
+
# Subscribe data consumer to DataProducer
result = self.DataProducer.SubscribeDebugIECVariable(
iec_path, consumer, buffer_list)
if result is not None and consumer != self:
-
+
# Store data consumer if successfully subscribed and inform
# consumer of variable data type
self.DataConsumers[consumer] = iec_path
consumer.SetDataType(self.GetDataType(iec_path))
-
+
return result
-
+
def RemoveDataConsumer(self, consumer):
"""
Unsubscribe data consumer from DataProducer
@@ -165,12 +165,12 @@
"""
# Remove consumer from data consumer list
iec_path = self.DataConsumers.pop(consumer, None)
-
+
# Unsubscribe consumer from DataProducer
if iec_path is not None:
self.DataProducer.UnsubscribeDebugIECVariable(
iec_path, consumer)
-
+
def SubscribeAllDataConsumers(self):
"""
Called to Subscribe all data consumers contained in DebugViewer.
@@ -179,24 +179,24 @@
# Subscribe tick if needed
if self.SubscribeTick and self.Debug and self.DataProducer is not None:
self.DataProducer.SubscribeDebugIECVariable("__tick__", self, True)
-
+
def UnsubscribeAllDataConsumers(self, tick=True):
"""
Called to Unsubscribe all data consumers.
"""
if self.DataProducer is not None:
-
+
# Unscribe tick if needed
if self.SubscribeTick and tick and self.Debug:
self.DataProducer.UnsubscribeDebugIECVariable("__tick__", self)
-
+
# Unsubscribe all data consumers in list
for consumer, iec_path in self.DataConsumers.iteritems():
self.DataProducer.UnsubscribeDebugIECVariable(
iec_path, consumer)
-
+
self.DataConsumers = {}
-
+
def GetDataType(self, iec_path):
"""
Return variable data type.
@@ -204,20 +204,20 @@
@return: variable data type (None if not found)
"""
if self.DataProducer is not None:
-
+
# Search for variable informations in project compilation files
data_type = self.DataProducer.GetDebugIECVariableType(
iec_path.upper())
if data_type is not None:
return data_type
-
+
# Search for variable informations in project data
infos = self.DataProducer.GetInstanceInfos(iec_path)
if infos is not None:
return infos.type
-
+
return None
-
+
def IsNumType(self, data_type):
"""
Indicate if data type given is a numeric data type
@@ -226,9 +226,9 @@
"""
if self.DataProducer is not None:
return self.DataProducer.IsNumType(data_type)
-
+
return False
-
+
def ForceDataValue(self, iec_path, value):
"""
Force PLC variable value
@@ -237,7 +237,7 @@
"""
if self.DataProducer is not None:
self.DataProducer.ForceDebugIECVariable(iec_path, value)
-
+
def ReleaseDataValue(self, iec_path):
"""
Release PLC variable value
@@ -245,40 +245,40 @@
"""
if self.DataProducer is not None:
self.DataProducer.ReleaseDebugIECVariable(iec_path)
-
+
def NewDataAvailable(self, ticks):
"""
Called by DataProducer for each tick captured
@param tick: PLC tick captured
- All other parameters are passed to refresh function
+ All other parameters are passed to refresh function
"""
# Stop last refresh timer
self.TimerAccessLock.acquire()
if self.LastRefreshTimer is not None:
self.LastRefreshTimer.cancel()
- self.LastRefreshTimer=None
+ self.LastRefreshTimer = None
self.TimerAccessLock.release()
-
+
# Only try to refresh DebugViewer if it is visible on screen and not
# already refreshing
if self.IsShown() and not self.Inhibited:
-
+
# Try to get acquire common refresh lock if minimum period between
# two refresh has expired
if gettime() - self.LastRefreshTime > REFRESH_PERIOD and \
DEBUG_REFRESH_LOCK.acquire(False):
self.StartRefreshing()
-
+
# If common lock wasn't acquired for any reason, restart last
# refresh timer
else:
self.StartLastRefreshTimer()
-
+
# In the case that DebugViewer isn't visible on screen and has already
# acquired common refresh lock, reset DebugViewer
elif not self.IsShown() and self.HasAcquiredLock:
DebugViewer.RefreshNewData(self)
-
+
def ShouldRefresh(self):
"""
Callback function called when last refresh timer expired
@@ -286,15 +286,15 @@
"""
# Cancel if DebugViewer is not visible on screen
if self and self.IsShown():
-
+
# Try to acquire common refresh lock
if DEBUG_REFRESH_LOCK.acquire(False):
self.StartRefreshing()
-
+
# Restart last refresh timer if common refresh lock acquired failed
else:
self.StartLastRefreshTimer()
-
+
def StartRefreshing(self):
"""
Called to initiate a refresh of DebugViewer
@@ -306,13 +306,13 @@
self.HasAcquiredLock = True
self.LastRefreshTime = gettime()
self.AccessLock.release()
-
+
# Inhibit data consumer value update
self.Inhibit(True)
-
+
# Initiate DebugViewer refresh
wx.CallAfter(self.RefreshNewData)
-
+
def StartLastRefreshTimer(self):
"""
Called to start last refresh timer for the minimum time between 2
@@ -324,19 +324,19 @@
REFRESH_PERIOD, self.ShouldRefresh)
self.LastRefreshTimer.start()
self.TimerAccessLock.release()
-
+
def RefreshNewData(self):
"""
Called to refresh DebugViewer according to values received by data
consumers
May be overridden by inherited classes
Can receive any parameters depending on what is needed by inherited
- class
+ class
"""
if self:
# Activate data consumer value update
self.Inhibit(False)
-
+
# Release common refresh lock if acquired and update
# last refresh time
self.AccessLock.acquire()
--- a/editors/EditorPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/EditorPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,67 +26,68 @@
from controls import VariablePanel
+
class EditorPanel(wx.SplitterWindow):
-
+
VARIABLE_PANEL_TYPE = None
-
+
def _init_Editor(self, prnt):
self.Editor = None
-
+
def _init_MenuItems(self):
self.MenuItems = []
-
+
def _init_ctrls(self, parent):
wx.SplitterWindow.__init__(self, parent,
- style=wx.SUNKEN_BORDER|wx.SP_3D)
+ style=wx.SUNKEN_BORDER | wx.SP_3D)
self.SetMinimumPaneSize(1)
-
+
self._init_MenuItems()
-
+
if self.VARIABLE_PANEL_TYPE is not None:
self.VariableEditor = VariablePanel(self, self, self.Controler, self.VARIABLE_PANEL_TYPE, self.Debug)
self.VariableEditor.SetTagName(self.TagName)
else:
self.VariableEditor = None
-
+
self._init_Editor(self)
-
+
if self.Editor is not None and self.VariableEditor is not None:
self.SplitHorizontally(self.VariableEditor, self.Editor, 200)
elif self.VariableEditor is not None:
self.Initialize(self.VariableEditor)
elif self.Editor is not None:
self.Initialize(self.Editor)
-
+
def __init__(self, parent, tagname, window, controler, debug=False):
self.ParentWindow = window
self.Controler = controler
self.TagName = tagname
self.Icon = None
self.Debug = debug
-
+
self._init_ctrls(parent)
-
+
def SetTagName(self, tagname):
self.TagName = tagname
if self.VARIABLE_PANEL_TYPE is not None:
self.VariableEditor.SetTagName(tagname)
-
+
def GetTagName(self):
return self.TagName
-
+
def Select(self):
self.ParentWindow.EditProjectElement(None, self.GetTagName(), True)
-
+
def GetTitle(self):
return ".".join(self.TagName.split("::")[1:])
-
+
def GetIcon(self):
return self.Icon
-
+
def SetIcon(self, icon):
self.Icon = icon
-
+
def IsViewing(self, tagname):
return self.GetTagName() == tagname
@@ -98,54 +99,54 @@
def ResetBuffer(self):
pass
-
+
def IsModified(self):
return False
-
+
def CheckSaveBeforeClosing(self):
return True
-
+
def Save(self):
pass
-
+
def SaveAs(self):
pass
-
+
def GetBufferState(self):
if self.Controler is not None:
return self.Controler.GetBufferState()
return False, False
-
+
def Undo(self):
if self.Controler is not None:
self.Controler.LoadPrevious()
self.RefreshView()
-
+
def Redo(self):
if self.Controler is not None:
self.Controler.LoadNext()
self.RefreshView()
-
+
def Find(self, direction, search_params):
pass
-
+
def HasNoModel(self):
return False
-
+
def RefreshView(self, variablepanel=True):
if variablepanel:
self.RefreshVariablePanel()
-
+
def RefreshVariablePanel(self):
if self.VariableEditor is not None:
self.VariableEditor.RefreshView()
-
+
def GetConfNodeMenuItems(self):
return self.MenuItems
-
+
def RefreshConfNodeMenu(self, confnode_menu):
pass
-
+
def _Refresh(self, *args):
self.ParentWindow._Refresh(*args)
@@ -159,7 +160,7 @@
def RemoveHighlight(self, infos, start, end, highlight_type):
if self.VariableEditor is not None and infos[0] in ["var_local", "var_input", "var_output", "var_inout"]:
self.VariableEditor.RemoveVariableHighlight(infos[1:], highlight_type)
-
+
def ClearHighlights(self, highlight_type=None):
if self.VariableEditor is not None:
self.VariableEditor.ClearHighlights(highlight_type)
--- a/editors/FileManagementPanel.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/FileManagementPanel.py Mon Aug 21 23:22:58 2017 +0300
@@ -34,39 +34,41 @@
FILTER = _("All files (*.*)|*.*|CSV files (*.csv)|*.csv")
+
class FileManagementPanel(EditorPanel):
-
+
def _init_Editor(self, parent):
self.Editor = wx.Panel(parent)
-
+
main_sizer = wx.BoxSizer(wx.HORIZONTAL)
-
+
left_sizer = wx.BoxSizer(wx.VERTICAL)
- main_sizer.AddSizer(left_sizer, 1, border=5, flag=wx.GROW|wx.ALL)
-
+ main_sizer.AddSizer(left_sizer, 1, border=5, flag=wx.GROW | wx.ALL)
+
managed_dir_label = wx.StaticText(self.Editor, label=_(self.TagName) + ":")
- left_sizer.AddWindow(managed_dir_label, border=5, flag=wx.GROW|wx.BOTTOM)
-
+ left_sizer.AddWindow(managed_dir_label, border=5, flag=wx.GROW | wx.BOTTOM)
+
self.ManagedDir = FolderTree(self.Editor, self.Folder, FILTER)
left_sizer.AddWindow(self.ManagedDir, 1, flag=wx.GROW)
-
+
managed_treectrl = self.ManagedDir.GetTreeCtrl()
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, managed_treectrl)
if self.EnableDragNDrop:
self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnTreeBeginDrag, managed_treectrl)
-
+
button_sizer = wx.BoxSizer(wx.VERTICAL)
- main_sizer.AddSizer(button_sizer, border=5,
- flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL)
-
+ main_sizer.AddSizer(button_sizer, border=5,
+ flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
+
for idx, (name, bitmap, help) in enumerate([
("DeleteButton", "remove_element", _("Remove file from left folder")),
("LeftCopyButton", "LeftCopy", _("Copy file from right folder to left")),
("RightCopyButton", "RightCopy", _("Copy file from left folder to right")),
("EditButton", "edit", _("Edit file"))]):
- button = wx.lib.buttons.GenBitmapButton(self.Editor,
- bitmap=GetBitmap(bitmap),
- size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button = wx.lib.buttons.GenBitmapButton(
+ self.Editor,
+ bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
if idx > 0:
@@ -75,62 +77,62 @@
flag = 0
self.Bind(wx.EVT_BUTTON, getattr(self, "On" + name), button)
button_sizer.AddWindow(button, border=20, flag=flag)
-
+
right_sizer = wx.BoxSizer(wx.VERTICAL)
- main_sizer.AddSizer(right_sizer, 1, border=5, flag=wx.GROW|wx.ALL)
-
+ main_sizer.AddSizer(right_sizer, 1, border=5, flag=wx.GROW | wx.ALL)
+
if wx.Platform == '__WXMSW__':
system_dir_label = wx.StaticText(self.Editor, label=_("My Computer:"))
else:
system_dir_label = wx.StaticText(self.Editor, label=_("Home Directory:"))
- right_sizer.AddWindow(system_dir_label, border=5, flag=wx.GROW|wx.BOTTOM)
-
+ right_sizer.AddWindow(system_dir_label, border=5, flag=wx.GROW | wx.BOTTOM)
+
self.SystemDir = FolderTree(self.Editor, self.HomeDirectory, FILTER, False)
right_sizer.AddWindow(self.SystemDir, 1, flag=wx.GROW)
-
+
system_treectrl = self.SystemDir.GetTreeCtrl()
self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnTreeItemChanged, system_treectrl)
-
+
self.Editor.SetSizer(main_sizer)
-
+
def __init__(self, parent, controler, name, folder, enable_dragndrop=False):
self.Folder = os.path.realpath(folder)
self.EnableDragNDrop = enable_dragndrop
-
+
if wx.Platform == '__WXMSW__':
self.HomeDirectory = "/"
else:
self.HomeDirectory = os.path.expanduser("~")
-
+
EditorPanel.__init__(self, parent, name, None, None)
-
+
self.Controler = controler
-
+
self.EditableFileExtensions = []
self.EditButton.Hide()
-
+
self.SetIcon(GetBitmap("FOLDER"))
-
+
def __del__(self):
self.Controler.OnCloseEditor(self)
-
+
def GetTitle(self):
return _(self.TagName)
-
+
def SetEditableFileExtensions(self, extensions):
self.EditableFileExtensions = extensions
if len(self.EditableFileExtensions) > 0:
self.EditButton.Show()
-
+
def RefreshView(self):
self.ManagedDir.RefreshTree()
self.SystemDir.RefreshTree()
self.RefreshButtonsState()
-
+
def RefreshButtonsState(self):
managed_filepath = self.ManagedDir.GetPath()
system_filepath = self.SystemDir.GetPath()
-
+
self.DeleteButton.Enable(os.path.isfile(managed_filepath))
self.LeftCopyButton.Enable(os.path.isfile(system_filepath))
self.RightCopyButton.Enable(os.path.isfile(managed_filepath))
@@ -138,22 +140,23 @@
self.EditButton.Enable(
os.path.isfile(managed_filepath) and
os.path.splitext(managed_filepath)[1] in self.EditableFileExtensions)
-
+
def OnTreeItemChanged(self, event):
self.RefreshButtonsState()
event.Skip()
-
+
def OnDeleteButton(self, event):
filepath = self.ManagedDir.GetPath()
if os.path.isfile(filepath):
folder, filename = os.path.split(filepath)
-
- dialog = wx.MessageDialog(self,
- _("Do you really want to delete the file '%s'?") % filename,
- _("Delete File"), wx.YES_NO|wx.ICON_QUESTION)
+
+ dialog = wx.MessageDialog(self,
+ _("Do you really want to delete the file '%s'?") % filename,
+ _("Delete File"),
+ wx.YES_NO | wx.ICON_QUESTION)
remove = dialog.ShowModal() == wx.ID_YES
dialog.Destroy()
-
+
if remove:
os.remove(filepath)
self.ManagedDir.RefreshTree()
@@ -161,11 +164,11 @@
def OnEditButton(self, event):
filepath = self.ManagedDir.GetPath()
- if (os.path.isfile(filepath) and
- os.path.splitext(filepath)[1] in self.EditableFileExtensions):
+ if os.path.isfile(filepath) and \
+ os.path.splitext(filepath)[1] in self.EditableFileExtensions:
self.Controler._OpenView(filepath + "::")
event.Skip()
-
+
def CopyFile(self, src, dst):
if os.path.isfile(src):
src_folder, src_filename = os.path.split(src)
@@ -173,17 +176,18 @@
dst_folder, dst_filename = os.path.split(dst)
else:
dst_folder = dst
-
+
dst_filepath = os.path.join(dst_folder, src_filename)
if os.path.isfile(dst_filepath):
- dialog = wx.MessageDialog(self,
- _("The file '%s' already exist.\nDo you want to replace it?") % src_filename,
- _("Replace File"), wx.YES_NO|wx.ICON_QUESTION)
+ dialog = wx.MessageDialog(
+ self,
+ _("The file '%s' already exist.\nDo you want to replace it?") % src_filename,
+ _("Replace File"), wx.YES_NO | wx.ICON_QUESTION)
copy = dialog.ShowModal() == wx.ID_YES
dialog.Destroy()
else:
copy = True
-
+
if copy:
shutil.copyfile(src, dst_filepath)
return dst_filepath
@@ -202,7 +206,7 @@
self.SystemDir.RefreshTree()
self.SystemDir.SetPath(filepath)
event.Skip()
-
+
def OnTreeBeginDrag(self, event):
filepath = self.ManagedDir.GetPath()
if os.path.isfile(filepath):
@@ -211,4 +215,3 @@
dragSource = wx.DropSource(self)
dragSource.SetData(data)
dragSource.DoDragDrop()
-
--- a/editors/IECCodeViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/IECCodeViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,16 +25,17 @@
from editors.TextViewer import TextViewer
from plcopen.plcopen import TestTextElement
+
class IECCodeViewer(TextViewer):
-
+
def __del__(self):
TextViewer.__del__(self)
if getattr(self, "_OnClose"):
self._OnClose(self)
-
+
def Paste(self):
if self.Controler is not None:
TextViewer.Paste(self)
-
+
def Search(self, criteria):
return [((self.TagName, "body", 0),) + result for result in TestTextElement(self.Editor.GetText(), criteria)]
--- a/editors/LDViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/LDViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,6 +28,7 @@
from Viewer import *
+
def ExtractNextBlocks(block, block_list):
current_list = [block]
while len(current_list) > 0:
@@ -49,7 +50,8 @@
block_list.append(next)
next_list.append(next)
current_list = next_list
-
+
+
def CalcBranchSize(elements, stops):
branch_size = 0
stop_list = stops
@@ -58,19 +60,19 @@
element_tree = {}
for element in elements:
if element not in element_tree:
- element_tree[element] = {"parents":["start"], "children":[], "weight":None}
+ element_tree[element] = {"parents": ["start"], "children": [], "weight": None}
GenerateTree(element, element_tree, stop_list)
elif element_tree[element]:
element_tree[element]["parents"].append("start")
- remove_stops = {"start":[], "stop":[]}
+ remove_stops = {"start": [], "stop": []}
for element, values in element_tree.items():
if "stop" in values["children"]:
removed = []
for child in values["children"]:
if child != "stop":
-## if child in elements:
-## RemoveElement(child, element_tree)
-## removed.append(child)
+ # if child in elements:
+ # RemoveElement(child, element_tree)
+ # removed.append(child)
if "start" in element_tree[child]["parents"]:
if element not in remove_stops["stop"]:
remove_stops["stop"].append(element)
@@ -89,16 +91,17 @@
branch_size += values["weight"]
else:
return 1
- #print branch_size
return branch_size
+
def RemoveElement(remove, element_tree):
if remove in element_tree and element_tree[remove]:
for child in element_tree[remove]["children"]:
if child != "stop":
RemoveElement(child, element_tree)
element_tree.pop(remove)
-## element_tree[remove] = None
+# element_tree[remove] = None
+
def GenerateTree(element, element_tree, stop_list):
if element in element_tree:
@@ -115,20 +118,21 @@
for wire, handle in connector.GetWires():
next = wire.EndConnected.GetParentBlock()
if isinstance(next, LD_PowerRail) and next.GetType() == LEFTRAIL or next in stop_list:
-## for remove in element_tree[element]["children"]:
-## RemoveElement(remove, element_tree)
-## element_tree[element]["children"] = ["stop"]
+ # for remove in element_tree[element]["children"]:
+ # RemoveElement(remove, element_tree)
+ # element_tree[element]["children"] = ["stop"]
element_tree[element]["children"].append("stop")
-## elif element_tree[element]["children"] == ["stop"]:
-## element_tree[next] = None
+ # elif element_tree[element]["children"] == ["stop"]:
+ # element_tree[next] = None
elif next not in element_tree or element_tree[next]:
element_tree[element]["children"].append(next)
if next in element_tree:
element_tree[next]["parents"].append(element)
else:
- element_tree[next] = {"parents":[element], "children":[], "weight":None}
+ element_tree[next] = {"parents": [element], "children": [], "weight": None}
GenerateTree(next, element_tree, stop_list)
+
def CalcWeight(element, element_tree):
weight = 0
parts = None
@@ -156,26 +160,25 @@
element_tree[element]["weight"] = max(1, weight / parts)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Ladder Diagram Graphic elements Viewer class
-#-------------------------------------------------------------------------------
-
-
-"""
-Class derived from Viewer class that implements a Viewer of Ladder Diagram
-"""
+# -------------------------------------------------------------------------------
+
class LD_Viewer(Viewer):
-
- def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
+ """
+ Class derived from Viewer class that implements a Viewer of Ladder Diagram
+ """
+
+ def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
self.Rungs = []
self.RungComments = []
self.CurrentLanguage = "LD"
-#-------------------------------------------------------------------------------
-# Refresh functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Refresh functions
+ # -------------------------------------------------------------------------------
def ResetView(self):
self.Rungs = []
@@ -194,7 +197,7 @@
self.RungComments.insert(i, None)
else:
self.RungComments.insert(i, None)
-
+
def loadInstance(self, instance, ids, selection):
Viewer.loadInstance(self, instance, ids, selection)
if self.GetDrawingMode() != FREEDRAWING_MODE:
@@ -212,7 +215,10 @@
if rung not in rungs:
rungs.append(rung)
if len(rungs) > 1:
- raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"]
+ raise ValueError(
+ _("Ladder element with id %d is on more than one rung.")
+ % instance["id"])
+
element = self.FindElementById(instance["id"])
element_connectors = element.GetConnectors()
self.Rungs[rungs[0]].SelectElement(element)
@@ -228,9 +234,12 @@
if rung not in rungs:
rungs.append(rung)
if len(rungs) > 1:
- raise ValueError, _("Ladder element with id %d is on more than one rung.")%instance["id"]
+ raise ValueError(
+ _("Ladder element with id %d is on more than one rung.")
+ % instance["id"])
+
element = self.FindElementById(instance["id"])
- element_connectors = element.GetConnectors()
+ element_connectors = element.GetConnectors()
self.Rungs[rungs[0]].SelectElement(element)
for wire, num in element_connectors["inputs"][0].GetWires():
self.Rungs[rungs[0]].SelectElement(wire)
@@ -240,7 +249,7 @@
pos = element.GetPosition()
i = 0
inserted = False
- while i < len(self.RungComments) and not inserted:
+ while i < len(self.RungComments) and not inserted:
ipos = self.RungComments[i].GetPosition()
if pos[1] < ipos[1]:
self.RungComments.insert(i, element)
@@ -248,10 +257,10 @@
i += 1
if not inserted:
self.RungComments.append(element)
-
-#-------------------------------------------------------------------------------
-# Search Element functions
-#-------------------------------------------------------------------------------
+
+ # -------------------------------------------------------------------------------
+ # Search Element functions
+ # -------------------------------------------------------------------------------
def FindRung(self, element):
for i, rung in enumerate(self.Rungs):
@@ -259,10 +268,10 @@
return i
return None
- def FindElement(self, event, exclude_group = False, connectors = True):
+ def FindElement(self, event, exclude_group=False, connectors=True):
if self.GetDrawingMode() == FREEDRAWING_MODE:
return Viewer.FindElement(self, event, exclude_group, connectors)
-
+
dc = self.GetLogicalDC()
pos = event.GetLogicalPosition(dc)
if self.SelectedElement and not isinstance(self.SelectedElement, (Graphic_Group, Wire)):
@@ -286,16 +295,16 @@
def SearchElements(self, bbox):
if self.GetDrawingMode() == FREEDRAWING_MODE:
return Viewer.SearchElements(self, bbox)
-
+
elements = []
for element in self.Blocks.values() + self.Comments.values():
if element.IsInSelection(bbox):
elements.append(element)
return elements
-#-------------------------------------------------------------------------------
-# Mouse event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Mouse event functions
+ # -------------------------------------------------------------------------------
def OnViewerLeftDown(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -345,7 +354,7 @@
self.SelectedElement.SetElements(elements)
self.SelectedElement.SetSelected(True)
elif self.Mode == MODE_SELECTION and self.SelectedElement:
- dc = self.GetLogicalDC()
+ dc = self.GetLogicalDC()
if not isinstance(self.SelectedElement, Graphic_Group):
if self.IsWire(self.SelectedElement):
result = self.SelectedElement.TestSegment(event.GetLogicalPosition(dc), True)
@@ -383,9 +392,9 @@
wx.CallAfter(self.SetCurrentCursor, 0)
event.Skip()
-#-------------------------------------------------------------------------------
-# Keyboard event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Keyboard event functions
+ # -------------------------------------------------------------------------------
def OnChar(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -434,9 +443,9 @@
else:
event.Skip()
-#-------------------------------------------------------------------------------
-# Model adding functions from Drop Target
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Model adding functions from Drop Target
+ # -------------------------------------------------------------------------------
def AddVariableBlock(self, x, y, scaling, var_class, var_name, var_type):
if var_type == "BOOL":
@@ -474,9 +483,9 @@
else:
Viewer.AddVariableBlock(self, x, y, scaling, var_class, var_name, var_type)
-#-------------------------------------------------------------------------------
-# Adding element functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Adding element functions
+ # -------------------------------------------------------------------------------
def AddLadderRung(self):
dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
@@ -491,7 +500,7 @@
if returntype == "BOOL":
varlist.append(self.Controler.GetEditedElementName(self.TagName))
dialog.SetVariables(varlist)
- dialog.SetValues({"name":"","type":COIL_NORMAL})
+ dialog.SetValues({"name": "", "type": COIL_NORMAL})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
startx, starty = LD_OFFSET[0], 0
@@ -500,7 +509,7 @@
starty = bbox.y + bbox.height
starty += LD_OFFSET[1]
rung = Graphic_Group(self)
-
+
# Create comment
id = self.GetNewId()
comment = Comment(self, _("Comment"), id)
@@ -511,7 +520,7 @@
self.Controler.AddEditedElementComment(self.TagName, id)
self.RefreshCommentModel(comment)
starty += LD_COMMENT_DEFAULTSIZE[1] + LD_OFFSET[1]
-
+
# Create LeftPowerRail
id = self.GetNewId()
leftpowerrail = LD_PowerRail(self, LEFTRAIL, id)
@@ -521,7 +530,7 @@
rung.SelectElement(leftpowerrail)
self.Controler.AddEditedElementPowerRail(self.TagName, id, LEFTRAIL)
self.RefreshPowerRailModel(leftpowerrail)
-
+
# Create Coil
id = self.GetNewId()
coil = LD_Coil(self, values["type"], values["name"], id)
@@ -530,7 +539,7 @@
self.AddBlock(coil)
rung.SelectElement(coil)
self.Controler.AddEditedElementCoil(self.TagName, id)
-
+
# Create Wire between LeftPowerRail and Coil
wire = Wire(self)
start_connector = coil_connectors["inputs"][0]
@@ -541,7 +550,7 @@
wire.ConnectEndPoint(None, end_connector)
self.AddWire(wire)
rung.SelectElement(wire)
-
+
# Create RightPowerRail
id = self.GetNewId()
rightpowerrail = LD_PowerRail(self, RIGHTRAIL, id)
@@ -550,7 +559,7 @@
self.AddBlock(rightpowerrail)
rung.SelectElement(rightpowerrail)
self.Controler.AddEditedElementPowerRail(self.TagName, id, RIGHTRAIL)
-
+
# Create Wire between LeftPowerRail and Coil
wire = Wire(self)
start_connector = rightpowerrail_connectors["inputs"][0]
@@ -574,7 +583,7 @@
left_element = self.SelectedElement.EndConnected
if not isinstance(left_element.GetParentBlock(), LD_Coil):
wires.append(self.SelectedElement)
- elif self.SelectedElement and isinstance(self.SelectedElement,Graphic_Group):
+ elif self.SelectedElement and isinstance(self.SelectedElement, Graphic_Group):
if False not in [self.IsWire(element) for element in self.SelectedElement.GetElements()]:
for element in self.SelectedElement.GetElements():
wires.append(element)
@@ -588,7 +597,7 @@
if var.Class != "Output" and var.Type == "BOOL":
varlist.append(var.Name)
dialog.SetVariables(varlist)
- dialog.SetValues({"name":"","type":CONTACT_NORMAL})
+ dialog.SetValues({"name": "", "type": CONTACT_NORMAL})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
points = wires[0].GetSelectedSegmentPoints()
@@ -663,7 +672,7 @@
self.RefreshVisibleElements()
self.Refresh(False)
else:
- message = wx.MessageDialog(self, _("You must select the wire where a contact should be added!"), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("You must select the wire where a contact should be added!"), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
@@ -683,7 +692,7 @@
right_index = []
for block in blocks:
connectors = block.GetConnectors()
- block_infos = {"lefts":[],"rights":[]}
+ block_infos = {"lefts": [], "rights": []}
block_infos.update(connectors)
for connector in block_infos["inputs"]:
for wire, handle in connector.GetWires():
@@ -778,7 +787,7 @@
if left_powerrail:
powerrail = left_elements[0].GetParentBlock()
index = 0
- for left_element in left_elements:
+ for left_element in left_elements:
index = max(index, powerrail.GetConnectorIndex(left_element))
powerrail.InsertConnector(index + 1)
powerrail.RefreshModel()
@@ -805,17 +814,17 @@
if returntype == "BOOL":
varlist.append(self.Controler.GetEditedElementName(self.TagName))
dialog.SetVariables(varlist)
- dialog.SetValues({"name":"","type":COIL_NORMAL})
+ dialog.SetValues({"name": "", "type": COIL_NORMAL})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
powerrail = right_elements[0].GetParentBlock()
index = 0
- for right_element in right_elements:
+ for right_element in right_elements:
index = max(index, powerrail.GetConnectorIndex(right_element))
powerrail.InsertConnector(index + 1)
powerrail.RefreshModel()
connectors = powerrail.GetConnectors()
-
+
# Create Coil
id = self.GetNewId()
coil = LD_Coil(self, values["type"], values["name"], id)
@@ -825,7 +834,7 @@
rung.SelectElement(coil)
self.Controler.AddEditedElementCoil(self.TagName, id)
coil_connectors = coil.GetConnectors()
-
+
# Create Wire between LeftPowerRail and Coil
wire = Wire(self)
connectors["inputs"][index + 1].Connect((wire, 0), False)
@@ -835,7 +844,7 @@
self.AddWire(wire)
rung.SelectElement(wire)
left_elements.reverse()
-
+
for i, left_element in enumerate(left_elements):
# Create Wire between LeftPowerRail and Coil
new_wire = Wire(self)
@@ -844,7 +853,7 @@
left_element.InsertConnect(left_index[i] + 1, (new_wire, -1), False)
new_wire.ConnectStartPoint(None, coil_connectors["inputs"][0])
new_wire.ConnectEndPoint(None, left_element)
-
+
self.RefreshPosition(coil)
else:
left_elements.reverse()
@@ -879,22 +888,22 @@
self.RefreshVisibleElements()
self.Refresh(False)
else:
- message = wx.MessageDialog(self, _("The group of block must be coherent!"), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("The group of block must be coherent!"), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
else:
- message = wx.MessageDialog(self, _("You must select the block or group of blocks around which a branch should be added!"), _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self, _("You must select the block or group of blocks around which a branch should be added!"), _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
def AddLadderBlock(self):
- message = wx.MessageDialog(self, _("This option isn't available yet!"), _("Warning"), wx.OK|wx.ICON_EXCLAMATION)
+ message = wx.MessageDialog(self, _("This option isn't available yet!"), _("Warning"), wx.OK | wx.ICON_EXCLAMATION)
message.ShowModal()
message.Destroy()
-#-------------------------------------------------------------------------------
-# Delete element functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Delete element functions
+ # -------------------------------------------------------------------------------
def DeleteContact(self, contact):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -1080,16 +1089,16 @@
self.RefreshRungs(new_bbox.height - old_bbox.height, rungindex + 1)
self.SelectedElement = None
-#-------------------------------------------------------------------------------
-# Refresh element position functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Refresh element position functions
+ # -------------------------------------------------------------------------------
def RefreshPosition(self, element, recursive=True):
# If element is LeftPowerRail, no need to update position
if isinstance(element, LD_PowerRail) and element.GetType() == LEFTRAIL:
element.RefreshModel()
return
-
+
# Extract max position of the elements connected to input
connectors = element.GetConnectors()
position = element.GetPosition()
@@ -1103,7 +1112,7 @@
pos = leftblock.GetPosition()
size = leftblock.GetSize()
maxx = max(maxx, pos[0] + size[0])
-
+
# Refresh position of element
if isinstance(element, LD_Coil):
interval = LD_WIRECOIL_SIZE
@@ -1114,13 +1123,13 @@
movex = maxx + interval - position[0]
element.Move(movex, 0)
position = element.GetPosition()
-
+
# Extract blocks connected to inputs
blocks = []
for i, connector in enumerate(connectors["inputs"]):
for j, (wire, handle) in enumerate(connector.GetWires()):
blocks.append(wire.EndConnected.GetParentBlock())
-
+
for i, connector in enumerate(connectors["inputs"]):
startpoint = connector.GetPosition(False)
previous_blocks = []
@@ -1168,13 +1177,13 @@
previous_blocks.append(block)
blocks.remove(block)
ExtractNextBlocks(block, block_list)
-
+
element.RefreshModel(False)
if recursive:
for connector in connectors["outputs"]:
for wire, handle in connector.GetWires():
self.RefreshPosition(wire.StartConnected.GetParentBlock())
-
+
def RefreshRungs(self, movey, fromidx):
if movey != 0:
for i in xrange(fromidx, len(self.Rungs)):
@@ -1185,11 +1194,10 @@
if self.IsBlock(element):
self.RefreshPosition(element)
-#-------------------------------------------------------------------------------
-# Edit element content functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Edit element content functions
+ # -------------------------------------------------------------------------------
def EditPowerRailContent(self, powerrail):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.EditPowerRailContent(self, powerrail)
-
--- a/editors/ProjectNodeEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/ProjectNodeEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,54 +28,55 @@
from EditorPanel import EditorPanel
from ConfTreeNodeEditor import ConfTreeNodeEditor
+
class ProjectNodeEditor(ConfTreeNodeEditor):
-
+
SHOW_BASE_PARAMS = False
ENABLE_REQUIRED = True
CONFNODEEDITOR_TABS = [
(_("Config variables"), "_create_VariablePanel"),
(_("Project properties"), "_create_ProjectPropertiesPanel")]
-
+
def _create_VariablePanel(self, prnt):
self.VariableEditorPanel = VariablePanel(prnt, self, self.Controler, "config", self.Debug)
self.VariableEditorPanel.SetTagName(self.TagName)
-
+
return self.VariableEditorPanel
-
+
def _create_ProjectPropertiesPanel(self, prnt):
self.ProjectProperties = ProjectPropertiesPanel(prnt, self.Controler, self.ParentWindow, self.ENABLE_REQUIRED)
-
+
return self.ProjectProperties
-
+
def __init__(self, parent, controler, window):
configuration = controler.GetProjectMainConfigurationName()
if configuration is not None:
tagname = controler.ComputeConfigurationName(configuration)
else:
tagname = ""
-
+
ConfTreeNodeEditor.__init__(self, parent, controler, window, tagname)
-
+
buttons_sizer = self.GenerateMethodButtonSizer()
self.MainSizer.InsertSizer(0, buttons_sizer, 0, border=5, flag=wx.ALL)
self.MainSizer.Layout()
-
+
self.VariableEditor = self.VariableEditorPanel
def GetTagName(self):
return self.Controler.CTNName()
-
+
def SetTagName(self, tagname):
self.TagName = tagname
if self.VariableEditor is not None:
self.VariableEditor.SetTagName(tagname)
-
+
def GetTitle(self):
fullname = _(self.Controler.CTNName())
if self.Controler.CTNTestModified():
return "~%s~" % fullname
return fullname
-
+
def RefreshView(self, variablepanel=True):
ConfTreeNodeEditor.RefreshView(self)
self.VariableEditorPanel.RefreshView()
@@ -83,12 +84,11 @@
def GetBufferState(self):
return self.Controler.GetBufferState()
-
+
def Undo(self):
self.Controler.LoadPrevious()
self.ParentWindow.CloseTabsWithoutModel()
-
+
def Redo(self):
self.Controler.LoadNext()
self.ParentWindow.CloseTabsWithoutModel()
-
--- a/editors/ResourceEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/ResourceEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -32,13 +32,19 @@
from EditorPanel import EditorPanel
from util.BitmapLibrary import GetBitmap
from plcopen.structures import LOCATIONDATATYPES, TestIdentifier, IEC_KEYWORDS, DefaultType
-#-------------------------------------------------------------------------------
+from util.TranslationCatalogs import NoTranslate
+
+
+# -------------------------------------------------------------------------------
# Configuration Editor class
-#-------------------------------------------------------------------------------
-
-[ID_CONFIGURATIONEDITOR,
+# -------------------------------------------------------------------------------
+
+
+[
+ ID_CONFIGURATIONEDITOR,
] = [wx.NewId() for _init_ctrls in range(1)]
+
class ConfigurationEditor(EditorPanel):
ID = ID_CONFIGURATIONEDITOR
@@ -59,29 +65,36 @@
return self.Controler.GetEditedElement(self.TagName) is None
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Resource Editor class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
def GetTasksTableColnames():
- _ = lambda x : x
+ _ = NoTranslate
return [_("Name"), _("Triggering"), _("Single"), _("Interval"), _("Priority")]
+
def GetTaskTriggeringOptions():
- _ = lambda x : x
+ _ = NoTranslate
return [_("Interrupt"), _("Cyclic")]
+
+
TASKTRIGGERINGOPTIONS_DICT = dict([(_(option), option) for option in GetTaskTriggeringOptions()])
-SingleCellEditor = lambda *x : wx.grid.GridCellChoiceEditor()
+
+def SingleCellEditor(*x):
+ return wx.grid.GridCellChoiceEditor()
+
def CheckSingle(single, varlist):
return single in varlist
def GetInstancesTableColnames():
- _ = lambda x : x
+ _ = NoTranslate
return [_("Name"), _("Type"), _("Task")]
+
class ResourceTable(CustomTable):
"""
@@ -154,12 +167,12 @@
if interval != "" and IEC_TIME_MODEL.match(interval.upper()) is None:
error = True
elif colname == "Single":
- editor = SingleCellEditor(self,colname)
+ editor = SingleCellEditor(self, colname)
editor.SetParameters(self.Parent.VariableList)
if self.GetValueByName(row, "Triggering") != "Interrupt":
grid.SetReadOnly(row, col, True)
single = self.GetValueByName(row, colname)
- if single != "" and not CheckSingle(single,self.Parent.VariableList):
+ if single != "" and not CheckSingle(single, self.Parent.VariableList):
error = True
elif colname == "Triggering":
editor = wx.grid.GridCellChoiceEditor()
@@ -185,10 +198,9 @@
grid.SetCellTextColour(row, col, highlight_colours[1])
self.ResizeRow(grid, row)
-
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def AddHighlight(self, infos, highlight_type):
row_highlights = self.Highlights.setdefault(infos[0], {})
@@ -208,13 +220,12 @@
row_highlights.pop(col)
-
class ResourceEditor(EditorPanel):
VARIABLE_PANEL_TYPE = "resource"
def _init_Editor(self, parent):
- self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL)
+ self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER | wx.TAB_TRAVERSAL)
main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5)
main_sizer.AddGrowableCol(0)
@@ -225,7 +236,7 @@
tasks_sizer.AddGrowableCol(0)
tasks_sizer.AddGrowableRow(1)
main_sizer.AddSizer(tasks_sizer, border=5,
- flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.TOP | wx.LEFT | wx.RIGHT)
tasks_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
tasks_buttons_sizer.AddGrowableCol(0)
@@ -241,7 +252,9 @@
("UpTaskButton", "up", _("Move task up")),
("DownTaskButton", "down", _("Move task down"))]:
button = wx.lib.buttons.GenBitmapButton(self.Editor,
- bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28),
+ style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
tasks_buttons_sizer.AddWindow(button)
@@ -254,7 +267,7 @@
instances_sizer.AddGrowableCol(0)
instances_sizer.AddGrowableRow(1)
main_sizer.AddSizer(instances_sizer, border=5,
- flag=wx.GROW|wx.BOTTOM|wx.LEFT|wx.RIGHT)
+ flag=wx.GROW | wx.BOTTOM | wx.LEFT | wx.RIGHT)
instances_buttons_sizer = wx.FlexGridSizer(cols=5, hgap=5, rows=1, vgap=0)
instances_buttons_sizer.AddGrowableCol(0)
@@ -269,15 +282,15 @@
("DeleteInstanceButton", "remove_element", _("Remove instance")),
("UpInstanceButton", "up", _("Move instance up")),
("DownInstanceButton", "down", _("Move instance down"))]:
- button = wx.lib.buttons.GenBitmapButton(self.Editor,
- bitmap=GetBitmap(bitmap), size=wx.Size(28, 28), style=wx.NO_BORDER)
+ button = wx.lib.buttons.GenBitmapButton(
+ self.Editor, bitmap=GetBitmap(bitmap),
+ size=wx.Size(28, 28), style=wx.NO_BORDER)
button.SetToolTipString(help)
setattr(self, name, button)
instances_buttons_sizer.AddWindow(button)
self.InstancesGrid = CustomGrid(self.Editor, style=wx.VSCROLL)
- self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE,
- self.OnInstancesGridCellChange)
+ self.InstancesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnInstancesGridCellChange)
instances_sizer.AddWindow(self.InstancesGrid, flag=wx.GROW)
self.Editor.SetSizer(main_sizer)
@@ -288,7 +301,7 @@
self.RefreshHighlightsTimer = wx.Timer(self, -1)
self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)
- self.TasksDefaultValue = {"Name" : "", "Triggering" : "", "Single" : "", "Interval" : "", "Priority" : 0}
+ self.TasksDefaultValue = {"Name": "", "Triggering": "", "Single": "", "Interval": "", "Priority": 0}
self.TasksTable = ResourceTable(self, [], GetTasksTableColnames())
self.TasksTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_RIGHT, wx.ALIGN_RIGHT])
self.TasksTable.SetColSizes([200, 100, 100, 150, 100])
@@ -323,7 +336,7 @@
self.TasksTable.ResetView(self.TasksGrid)
self.TasksGrid.RefreshButtons()
- self.InstancesDefaultValue = {"Name" : "", "Type" : "", "Task" : ""}
+ self.InstancesDefaultValue = {"Name": "", "Type": "", "Task": ""}
self.InstancesTable = ResourceTable(self, [], GetInstancesTableColnames())
self.InstancesTable.SetColAlignements([wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT])
self.InstancesTable.SetColSizes([200, 150, 150])
@@ -362,9 +375,11 @@
rows = self.InstancesTable.GetNumberRows()
row = self.InstancesGrid.GetGridCursorRow()
self.DeleteInstanceButton.Enable(rows > 0)
- self.UpInstanceButton.Enable(row > 0 and
+ self.UpInstanceButton.Enable(
+ row > 0 and
self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row - 1, "Task"))
- self.DownInstanceButton.Enable(0 <= row < rows - 1 and
+ self.DownInstanceButton.Enable(
+ 0 <= row < rows - 1 and
self.InstancesTable.GetValueByName(row, "Task") == self.InstancesTable.GetValueByName(row + 1, "Task"))
setattr(self.InstancesGrid, "RefreshButtons", _RefreshInstanceButtons)
@@ -381,17 +396,17 @@
self.TypeList = ""
blocktypes = self.Controler.GetBlockResource()
for blocktype in blocktypes:
- self.TypeList += ",%s"%blocktype
+ self.TypeList += ",%s" % blocktype
def RefreshTaskList(self):
self.TaskList = ""
for row in xrange(self.TasksTable.GetNumberRows()):
- self.TaskList += ",%s"%self.TasksTable.GetValueByName(row, "Name")
+ self.TaskList += ",%s" % self.TasksTable.GetValueByName(row, "Name")
def RefreshVariableList(self):
self.VariableList = ""
for variable in self.Controler.GetEditedResourceVariables(self.TagName):
- self.VariableList += ",%s"%variable
+ self.VariableList += ",%s" % variable
def RefreshModel(self):
self.Controler.SetEditedResourceInfos(self.TagName, self.TasksTable.GetData(), self.InstancesTable.GetData())
@@ -433,7 +448,7 @@
self.InstancesGrid.RefreshButtons()
def ShowErrorMessage(self, message):
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
@@ -447,7 +462,7 @@
message = _("\"%s\" is not a valid identifier!") % value
elif value.upper() in IEC_KEYWORDS:
message = _("\"%s\" is a keyword. It can't be used!") % value
- elif value.upper() in [var["Name"].upper() for i, var in enumerate(self.TasksTable.data) if i!=row]:
+ elif value.upper() in [var["Name"].upper() for i, var in enumerate(self.TasksTable.data) if i != row]:
message = _("A task with the same name already exists!")
if message is not None:
event.Veto()
@@ -482,7 +497,7 @@
message = _("\"%s\" is not a valid identifier!") % value
elif value.upper() in IEC_KEYWORDS:
message = _("\"%s\" is a keyword. It can't be used!") % value
- elif value.upper() in [var["Name"].upper() for i ,var in enumerate(self.InstancesTable.data) if i!=row]:
+ elif value.upper() in [var["Name"].upper() for i, var in enumerate(self.InstancesTable.data) if i != row]:
message = _("An instance with the same name already exists!")
if message is not None:
event.Veto()
@@ -494,9 +509,9 @@
self.InstancesGrid.RefreshButtons()
event.Skip()
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def OnRefreshHighlightsTimer(self, event):
self.RefreshView()
--- a/editors/SFCViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/SFCViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -35,7 +35,7 @@
class SFC_Viewer(Viewer):
-
+
SFC_StandardRules = {
# The key of this dict is a block that user try to connect,
# and the value is a list of blocks, that can be connected with the current block
@@ -61,7 +61,7 @@
SELECTION_DIVERGENCE: [("SFC_Transition", SOUTH)],
SELECTION_CONVERGENCE: [("SFC_Step", SOUTH),
- ("SFC_Jump", SOUTH)],
+ ("SFC_Jump", SOUTH)],
SIMULTANEOUS_DIVERGENCE: [("SFC_Step", SOUTH)],
@@ -82,10 +82,10 @@
"LD_Coil": [("SFC_Transition", WEST)]
}
- def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
+ def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
Viewer.__init__(self, parent, tagname, window, controler, debug, instancepath)
self.CurrentLanguage = "SFC"
-
+
def ConnectConnectors(self, start, end):
startpoint = [start.GetPosition(False), start.GetDirection()]
endpoint = [end.GetPosition(False), end.GetDirection()]
@@ -96,8 +96,8 @@
wire.ConnectStartPoint(None, start)
wire.ConnectEndPoint(None, end)
return wire
-
- def CreateTransition(self, connector, next = None):
+
+ def CreateTransition(self, connector, next=None):
previous = connector.GetParentBlock()
id = self.GetNewId()
transition = SFC_Transition(self, "reference", "", 0, id)
@@ -124,7 +124,7 @@
next_block.RefreshPosition()
transition.RefreshOutputModel(True)
return transition
-
+
def RemoveTransition(self, transition):
connectors = transition.GetConnectors()
input_wires = connectors["input"].GetWires()
@@ -146,8 +146,8 @@
self.Controler.RemoveEditedElementInstance(self.TagName, transition.GetId())
wire = self.ConnectConnectors(next, previous)
return wire
-
- def CreateStep(self, name, connector, next = None):
+
+ def CreateStep(self, name, connector, next=None):
previous = connector.GetParentBlock()
id = self.GetNewId()
step = SFC_Step(self, name, False, id)
@@ -213,9 +213,9 @@
else:
return None
-#-------------------------------------------------------------------------------
-# Mouse event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Mouse event functions
+ # -------------------------------------------------------------------------------
def OnViewerLeftDown(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -289,7 +289,7 @@
self.SelectedElement.RefreshModel()
self.SelectedElement.SetSelected(True)
event.Skip()
-
+
def OnViewerRightUp(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.OnViewerRightUp(self, event)
@@ -307,7 +307,7 @@
self.SelectedElement.Refresh()
wx.CallAfter(self.SetCurrentCursor, 0)
event.Skip()
-
+
def OnViewerLeftDClick(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.OnViewerLeftDClick(self, event)
@@ -315,7 +315,7 @@
self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
self.Refresh(False)
event.Skip()
-
+
def OnViewerMotion(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.OnViewerMotion(self, event)
@@ -341,9 +341,9 @@
return blockName
# This method check the IEC 61131-3 compatibility between two SFC blocks
- def BlockCompatibility(self,startblock = None, endblock = None, direction = None):
- if startblock!= None and endblock != None and (isinstance(startblock,SFC_Objects)\
- or isinstance(endblock,SFC_Objects)):
+ def BlockCompatibility(self, startblock=None, endblock=None, direction=None):
+ if startblock is not None and endblock is not None and \
+ (isinstance(startblock, SFC_Objects) or isinstance(endblock, SFC_Objects)):
# Full "SFC_StandardRules" table would be symmetrical and
# to avoid duplicate records and minimize the table only upper part is defined.
if (direction == SOUTH or direction == EAST):
@@ -356,9 +356,9 @@
return False
return True
-#-------------------------------------------------------------------------------
-# Keyboard event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Keyboard event functions
+ # -------------------------------------------------------------------------------
def OnChar(self, event):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -424,13 +424,13 @@
self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(0, scaling[1])), False)
else:
event.Skip()
-
-#-------------------------------------------------------------------------------
-# Adding element functions
-#-------------------------------------------------------------------------------
+
+ # -------------------------------------------------------------------------------
+ # Adding element functions
+ # -------------------------------------------------------------------------------
def AddInitialStep(self, pos):
- dialog = SFCStepNameDialog(self.ParentWindow, _("Please enter step name"), _("Add a new initial step"), "", wx.OK|wx.CANCEL)
+ dialog = SFCStepNameDialog(self.ParentWindow, _("Please enter step name"), _("Add a new initial step"), "", wx.OK | wx.CANCEL)
dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)])
@@ -452,7 +452,7 @@
def AddStep(self):
if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, SFC_Step):
- dialog = SFCStepNameDialog(self.ParentWindow, _("Add a new step"), _("Please enter step name"), "", wx.OK|wx.CANCEL)
+ dialog = SFCStepNameDialog(self.ParentWindow, _("Add a new step"), _("Please enter step name"), "", wx.OK | wx.CANCEL)
dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step)])
@@ -503,7 +503,7 @@
self.RefreshScrollBars()
self.Refresh(False)
dialog.Destroy()
-
+
def AddStepAction(self):
if isinstance(self.SelectedElement, SFC_Step):
connectors = self.SelectedElement.GetConnectors()
@@ -532,9 +532,9 @@
self.RefreshScrollBars()
self.Refresh(False)
dialog.Destroy()
-
+
def AddDivergence(self):
- if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, Graphic_Group) or isinstance(self.SelectedElement, SFC_Step):
+ if self.SelectedElement in self.Wires or isinstance(self.SelectedElement, Graphic_Group) or isinstance(self.SelectedElement, SFC_Step):
dialog = SFCDivergenceDialog(self.ParentWindow)
dialog.SetPreviewFont(self.GetFont())
if dialog.ShowModal() == wx.ID_OK:
@@ -729,7 +729,7 @@
self.RefreshScrollBars()
self.Refresh(False)
dialog.Destroy()
-
+
def AddDivergenceBranch(self, divergence):
if isinstance(divergence, SFC_Divergence):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -750,7 +750,7 @@
self.RefreshBuffer()
self.RefreshScrollBars()
self.Refresh(False)
-
+
def RemoveDivergenceBranch(self, divergence):
if isinstance(divergence, SFC_Divergence):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -759,16 +759,18 @@
self.RefreshBuffer()
self.RefreshScrollBars()
self.Refresh(False)
-
+
def AddJump(self):
if isinstance(self.SelectedElement, SFC_Step) and not self.SelectedElement.Output:
choices = []
for block in self.Blocks:
if isinstance(block, SFC_Step):
choices.append(block.GetName())
- dialog = wx.SingleChoiceDialog(self.ParentWindow,
- _("Add a new jump"), _("Please choose a target"),
- choices, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(self.ParentWindow,
+ _("Add a new jump"),
+ _("Please choose a target"),
+ choices,
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetStringSelection()
self.SelectedElement.AddOutput()
@@ -796,7 +798,7 @@
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.EditStepContent(self, step)
else:
- dialog = SFCStepNameDialog(self.ParentWindow, _("Edit step name"), _("Please enter step name"), step.GetName(), wx.OK|wx.CANCEL)
+ dialog = SFCStepNameDialog(self.ParentWindow, _("Edit step name"), _("Please enter step name"), step.GetName(), wx.OK | wx.CANCEL)
dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, debug=self.Debug))
dialog.SetStepNames([block.GetName() for block in self.Blocks if isinstance(block, SFC_Step) and block.GetName() != step.GetName()])
@@ -812,9 +814,9 @@
self.Refresh(False)
dialog.Destroy()
-#-------------------------------------------------------------------------------
-# Delete element functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Delete element functions
+ # -------------------------------------------------------------------------------
def DeleteStep(self, step):
if self.GetDrawingMode() == FREEDRAWING_MODE:
@@ -884,7 +886,7 @@
self.DeleteDivergence(previous_block)
else:
self.RefreshDivergenceModel(previous_block)
-
+
def DeleteTransition(self, transition):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.DeleteTransition(self, transition)
@@ -919,7 +921,7 @@
self.DeleteDivergence(next_block)
else:
self.RefreshDivergenceModel(next_block)
-
+
def DeleteDivergence(self, divergence):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.DeleteDivergence(self, divergence)
@@ -979,8 +981,8 @@
next_pos = next.GetPosition(False)
wire_size = GetWireSize(previous_block)
previous_block.RefreshOutputPosition((0, previous_pos.y + wire_size - next_pos.y))
- wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
- wx.Point(previous_pos.x, previous_pos.y)])
+ wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
+ wx.Point(previous_pos.x, previous_pos.y)])
if isinstance(next_block, SFC_Divergence):
next_block.RefreshPosition()
previous_block.RefreshOutputModel(True)
@@ -1009,12 +1011,12 @@
next_pos = next.GetPosition(False)
wire_size = GetWireSize(previous_block)
previous_block.RefreshOutputPosition((previous_pos.x - next_pos.x, previous_pos.y + wire_size - next_pos.y))
- wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
- wx.Point(previous_pos.x, previous_pos.y)])
+ wire.SetPoints([wx.Point(previous_pos.x, previous_pos.y + wire_size),
+ wx.Point(previous_pos.x, previous_pos.y)])
if isinstance(next_block, SFC_Divergence):
next_block.RefreshPosition()
previous_block.RefreshOutputModel(True)
-
+
def DeleteJump(self, jump):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.DeleteJump(self, jump)
@@ -1049,7 +1051,7 @@
self.DeleteDivergence(previous_block)
else:
previous_block.RefreshModel()
-
+
def DeleteActionBlock(self, actionblock):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.DeleteActionBlock(self, actionblock)
@@ -1069,14 +1071,14 @@
self.RefreshStepModel(step)
step.RefreshOutputPosition()
step.RefreshOutputModel(True)
-
+
def DeleteWire(self, wire):
if self.GetDrawingMode() == FREEDRAWING_MODE:
Viewer.DeleteWire(self, wire)
-#-------------------------------------------------------------------------------
-# Model update functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Model update functions
+ # -------------------------------------------------------------------------------
def RefreshBlockModel(self, block):
blockid = block.GetId()
@@ -1087,4 +1089,3 @@
infos["width"], infos["height"] = block.GetSize()
infos["connectors"] = block.GetConnectors()
self.Controler.SetEditedElementBlockInfos(self.TagName, blockid, infos)
-
--- a/editors/TextViewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/TextViewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -33,9 +33,9 @@
from EditorPanel import EditorPanel
from controls.CustomStyledTextCtrl import CustomStyledTextCtrl, faces, GetCursorPos, NAVIGATION_KEYS
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Textual programs Viewer class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
NEWLINE = "\n"
@@ -51,15 +51,16 @@
STC_PLC_EMPTY] = range(11)
[SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA, DPRAGMA] = range(8)
-[ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL,
+[
+ ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL,
] = [wx.NewId() for _init_ctrls in range(2)]
re_texts = {}
re_texts["letter"] = "[A-Za-z]"
re_texts["digit"] = "[0-9]"
-re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts
+re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)" % re_texts
IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
-LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts)
+LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]" % re_texts)
EXTENSIBLE_PARAMETER = re.compile("IN[1-9][0-9]*$")
HIGHLIGHT_TYPES = {
@@ -67,15 +68,17 @@
SEARCH_RESULT_HIGHLIGHT: STC_PLC_SEARCH_RESULT,
}
+
def LineStartswith(line, symbols):
return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False)
+
class TextViewer(EditorPanel):
ID = ID_TEXTVIEWER
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
@@ -83,7 +86,7 @@
def _init_Editor(self, prnt):
self.Editor = CustomStyledTextCtrl(id=ID_TEXTVIEWERTEXTCTRL,
- parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0)
+ parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0)
self.Editor.ParentWindow = self
self.Editor.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
@@ -136,8 +139,8 @@
self.Editor.SetTabWidth(2)
self.Editor.SetUseTabs(0)
- self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|
- wx.stc.STC_MOD_BEFOREDELETE|
+ self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT |
+ wx.stc.STC_MOD_BEFOREDELETE |
wx.stc.STC_PERFORMED_USER)
self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWERTEXTCTRL)
@@ -149,7 +152,7 @@
self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWERTEXTCTRL)
self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWERTEXTCTRL)
- def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
+ def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
if tagname != "" and controler is not None:
self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1])
@@ -223,16 +226,16 @@
def OnModification(self, event):
if not self.DisableEvents:
mod_type = event.GetModificationType()
- if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
- if self.CurrentAction == None:
+ 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:
+ elif mod_type & wx.stc.STC_MOD_BEFOREDELETE:
+ if self.CurrentAction is None:
self.StartBuffering()
elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
self.Controler.EndBuffering()
@@ -244,7 +247,7 @@
def OnDoDrop(self, event):
try:
values = eval(event.GetDragText())
- except:
+ except Exception:
values = event.GetDragText()
if isinstance(values, tuple):
message = None
@@ -259,25 +262,25 @@
blockinputs = None
if values[1] != "function":
if blockname == "":
- dialog = wx.TextEntryDialog(self.ParentWindow, _("Block name"), _("Please enter a block name"), "", wx.OK|wx.CANCEL|wx.CENTRE)
+ dialog = wx.TextEntryDialog(self.ParentWindow, _("Block name"), _("Please enter a block name"), "", wx.OK | wx.CANCEL | wx.CENTRE)
if dialog.ShowModal() == wx.ID_OK:
blockname = dialog.GetValue()
else:
- event.SetDragText("")
+ event.SetDragText("")
return
dialog.Destroy()
if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
- message = _("\"%s\" pou already exists!")%blockname
+ message = _("\"%s\" pou already exists!") % blockname
elif blockname.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
- message = _("\"%s\" element for this pou already exists!")%blockname
+ message = _("\"%s\" element for this pou already exists!") % blockname
else:
self.Controler.AddEditedElementPouVar(self.TagName, values[0], blockname)
self.RefreshVariablePanel()
self.RefreshVariableTree()
blockinfo = self.Controler.GetBlockType(blocktype, blockinputs, self.Debug)
hint = ',\n '.join(
- [ " " + fctdecl[0]+" := (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["inputs"]] +
- [ " " + fctdecl[0]+" => (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["outputs"]])
+ [" " + fctdecl[0]+" := (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["inputs"]] +
+ [" " + fctdecl[0]+" => (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["outputs"]])
if values[1] == "function":
event.SetDragText(blocktype+"(\n "+hint+")")
else:
@@ -296,16 +299,18 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
elif var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
- message = _("\"%s\" element for this pou already exists!")%var_name
+ message = _("\"%s\" element for this pou already exists!") % var_name
else:
location = values[0]
if not location.startswith("%"):
- dialog = wx.SingleChoiceDialog(self.ParentWindow,
- _("Select a variable class:"), _("Variable class"),
- [_("Input"), _("Output"), _("Memory")],
- wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(
+ self.ParentWindow,
+ _("Select a variable class:"),
+ _("Variable class"),
+ [_("Input"), _("Output"), _("Memory")],
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetSelection()
else:
@@ -324,7 +329,8 @@
var_type = values[2]
else:
var_type = LOCATIONDATATYPES.get(location[2], ["BOOL"])[0]
- self.Controler.AddEditedElementPouVar(self.TagName,
+ self.Controler.AddEditedElementPouVar(
+ self.TagName,
var_type, var_name,
location=location, description=values[4])
self.RefreshVariablePanel()
@@ -347,7 +353,7 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
else:
var_type = values[2]
if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
@@ -370,7 +376,7 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
else:
if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
self.Controler.AddEditedElementPouExternalVar(self.TagName, values[2], var_name)
@@ -386,7 +392,7 @@
else:
message = _("Variable don't belong to this POU!")
if message is not None:
- dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ dialog = wx.MessageDialog(self, message, _("Error"), wx.OK | wx.ICON_ERROR)
dialog.ShowModal()
dialog.Destroy()
event.SetDragText("")
@@ -434,7 +440,7 @@
self.ParentWindow.RefreshEditMenu()
def ResetBuffer(self):
- if self.CurrentAction != None:
+ if self.CurrentAction is not None:
self.Controler.EndBuffering()
self.CurrentAction = None
@@ -473,7 +479,7 @@
self.SetText(new_text)
new_cursor_pos = GetCursorPos(old_text, new_text)
self.Editor.LineScroll(column, line)
- if new_cursor_pos != None:
+ if new_cursor_pos is not None:
self.Editor.GotoPos(new_cursor_pos)
else:
self.Editor.GotoPos(old_cursor_pos)
@@ -493,9 +499,9 @@
if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys():
interface = dict([(name, {}) for name, type, modifier in blocktype["inputs"] + blocktype["outputs"] if name != ''])
for param in ["EN", "ENO"]:
- if not interface.has_key(param):
+ if param not in interface:
interface[param] = {}
- if self.Functions.has_key(blockname):
+ if blockname in self.Functions:
self.Functions[blockname]["interface"].update(interface)
self.Functions[blockname]["extensible"] |= blocktype["extensible"]
else:
@@ -543,7 +549,7 @@
else:
level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK
if level != wx.stc.STC_FOLDLEVELBASE:
- level |= wx.stc.STC_FOLDLEVELWHITEFLAG
+ level |= wx.stc.STC_FOLDLEVELWHITEFLAG
elif LineStartswith(line, self.BlockStartKeywords):
level |= wx.stc.STC_FOLDLEVELHEADERFLAG
elif LineStartswith(line, self.BlockEndKeywords):
@@ -632,7 +638,7 @@
if len(self.CallStack) > 0:
current_call = self.CallStack.pop()
else:
- current_call = None
+ current_call = None
elif state == PRAGMA:
if line.endswith("}"):
self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY)
@@ -909,9 +915,9 @@
self.Editor.AutoCompCancel()
event.Skip()
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def OnRefreshHighlightsTimer(self, event):
self.RefreshView()
@@ -941,8 +947,8 @@
EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type)
highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
- if (infos[0] == "body" and highlight_type is not None and
- (infos[1], start, end, highlight_type) in self.Highlights):
+ if infos[0] == "body" and highlight_type is not None and \
+ (infos[1], start, end, highlight_type) in self.Highlights:
self.Highlights.remove((infos[1], start, end, highlight_type))
self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
@@ -961,4 +967,3 @@
self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type)
self.StartStyling(highlight_start_pos, 0x00)
self.SetStyling(len(self.Editor.GetText()) - highlight_end_pos, wx.stc.STC_STYLE_DEFAULT)
-
--- a/editors/Viewer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/editors/Viewer.py Mon Aug 21 23:22:58 2017 +0300
@@ -46,9 +46,10 @@
CURSORS = None
SFC_Objects = (SFC_Step, SFC_ActionBlock, SFC_Transition, SFC_Divergence, SFC_Jump)
+
def ResetCursors():
global CURSORS
- if CURSORS == None:
+ if CURSORS is None:
CURSORS = [wx.NullCursor,
wx.StockCursor(wx.CURSOR_HAND),
wx.StockCursor(wx.CURSOR_SIZENWSE),
@@ -56,26 +57,30 @@
wx.StockCursor(wx.CURSOR_SIZEWE),
wx.StockCursor(wx.CURSOR_SIZENS)]
+
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)
+
if wx.Platform == '__WXMSW__':
- faces = { 'times': 'Times New Roman',
- 'mono' : 'Courier New',
- 'helv' : 'Arial',
- 'other': 'Comic Sans MS',
- 'size' : 10,
- }
+ faces = {
+ 'times': 'Times New Roman',
+ 'mono': 'Courier New',
+ 'helv': 'Arial',
+ 'other': 'Comic Sans MS',
+ 'size': 10,
+ }
else:
- faces = { 'times': 'Times',
- 'mono' : 'Courier',
- 'helv' : 'Helvetica',
- 'other': 'new century schoolbook',
- 'size' : 12,
- }
+ faces = {
+ 'times': 'Times',
+ 'mono': 'Courier',
+ 'helv': 'Helvetica',
+ 'other': 'new century schoolbook',
+ 'size': 12,
+ }
if wx.Platform == '__WXMSW__':
MAX_ZOOMIN = 4
@@ -83,49 +88,67 @@
MAX_ZOOMIN = 7
ZOOM_FACTORS = [math.sqrt(2) ** x for x in xrange(-6, MAX_ZOOMIN)]
+
def GetVariableCreationFunction(variable_type):
def variableCreationFunction(viewer, id, specific_values):
- return FBD_Variable(viewer, variable_type,
- specific_values.name,
- specific_values.value_type,
- id,
- specific_values.execution_order)
+ return FBD_Variable(viewer,
+ variable_type,
+ specific_values.name,
+ specific_values.value_type,
+ id,
+ specific_values.execution_order)
return variableCreationFunction
+
def GetConnectorCreationFunction(connector_type):
def connectorCreationFunction(viewer, id, specific_values):
- return FBD_Connector(viewer, connector_type,
- specific_values.name, id)
+ return FBD_Connector(viewer,
+ connector_type,
+ specific_values.name,
+ id)
return connectorCreationFunction
+
def commentCreationFunction(viewer, id, specific_values):
return Comment(viewer, specific_values.content, id)
+
def GetPowerRailCreationFunction(powerrail_type):
def powerRailCreationFunction(viewer, id, specific_values):
- return LD_PowerRail(viewer, powerrail_type, id,
- specific_values.connectors)
+ return LD_PowerRail(viewer,
+ powerrail_type,
+ id,
+ specific_values.connectors)
return powerRailCreationFunction
-NEGATED_VALUE = lambda x: x if x is not None else False
-MODIFIER_VALUE = lambda x: x if x is not None else 'none'
+
+def NEGATED_VALUE(x):
+ return x if x is not None else False
+
+
+def MODIFIER_VALUE(x):
+ return x if x is not None else 'none'
+
CONTACT_TYPES = {(True, "none"): CONTACT_REVERSE,
(False, "rising"): CONTACT_RISING,
(False, "falling"): CONTACT_FALLING}
+
def contactCreationFunction(viewer, id, specific_values):
contact_type = CONTACT_TYPES.get((NEGATED_VALUE(specific_values.negated),
MODIFIER_VALUE(specific_values.edge)),
CONTACT_NORMAL)
return LD_Contact(viewer, contact_type, specific_values.name, id)
+
COIL_TYPES = {(True, "none", "none"): COIL_REVERSE,
(False, "none", "set"): COIL_SET,
(False, "none", "reset"): COIL_RESET,
(False, "rising", "none"): COIL_RISING,
(False, "falling", "none"): COIL_FALLING}
+
def coilCreationFunction(viewer, id, specific_values):
coil_type = COIL_TYPES.get((NEGATED_VALUE(specific_values.negated),
MODIFIER_VALUE(specific_values.edge),
@@ -133,36 +156,47 @@
COIL_NORMAL)
return LD_Coil(viewer, coil_type, specific_values.name, id)
+
def stepCreationFunction(viewer, id, specific_values):
- step = SFC_Step(viewer, specific_values.name,
- specific_values.initial, id)
+ step = SFC_Step(viewer,
+ specific_values.name,
+ specific_values.initial,
+ id)
if specific_values.action is not None:
step.AddAction()
connector = step.GetActionConnector()
connector.SetPosition(wx.Point(*specific_values.action.position))
return step
+
def transitionCreationFunction(viewer, id, specific_values):
- transition = SFC_Transition(viewer, specific_values.condition_type,
- specific_values.condition,
- specific_values.priority, id)
+ transition = SFC_Transition(viewer,
+ specific_values.condition_type,
+ specific_values.condition,
+ specific_values.priority,
+ id)
return transition
+
divergence_types = [SELECTION_DIVERGENCE,
SELECTION_CONVERGENCE, SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]
+
def GetDivergenceCreationFunction(divergence_type):
def divergenceCreationFunction(viewer, id, specific_values):
return SFC_Divergence(viewer, divergence_type,
- specific_values.connectors, id)
+ specific_values.connectors, id)
return divergenceCreationFunction
+
def jumpCreationFunction(viewer, id, specific_values):
return SFC_Jump(viewer, specific_values.target, id)
+
def actionBlockCreationFunction(viewer, id, specific_values):
return SFC_ActionBlock(viewer, specific_values.actions, id)
+
ElementCreationFunctions = {
"input": GetVariableCreationFunction(INPUT),
"output": GetVariableCreationFunction(OUTPUT),
@@ -184,6 +218,7 @@
"actionBlock": actionBlockCreationFunction,
}
+
def sort_blocks(block_infos1, block_infos2):
x1, y1 = block_infos1[0].GetPosition()
x2, y2 = block_infos2[0].GetPosition()
@@ -192,24 +227,27 @@
else:
return cmp(y1, y2)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Graphic elements Viewer base class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
# ID Constants for alignment menu items
-[ID_VIEWERALIGNMENTMENUITEMS0, ID_VIEWERALIGNMENTMENUITEMS1,
- ID_VIEWERALIGNMENTMENUITEMS2, ID_VIEWERALIGNMENTMENUITEMS4,
- ID_VIEWERALIGNMENTMENUITEMS5, ID_VIEWERALIGNMENTMENUITEMS6,
+[
+ ID_VIEWERALIGNMENTMENUITEMS0, ID_VIEWERALIGNMENTMENUITEMS1,
+ ID_VIEWERALIGNMENTMENUITEMS2, ID_VIEWERALIGNMENTMENUITEMS4,
+ ID_VIEWERALIGNMENTMENUITEMS5, ID_VIEWERALIGNMENTMENUITEMS6,
] = [wx.NewId() for _init_coll_AlignmentMenu_Items in range(6)]
# ID Constants for contextual menu items
-[ID_VIEWERCONTEXTUALMENUITEMS0, ID_VIEWERCONTEXTUALMENUITEMS1,
- ID_VIEWERCONTEXTUALMENUITEMS2, ID_VIEWERCONTEXTUALMENUITEMS3,
- ID_VIEWERCONTEXTUALMENUITEMS5, ID_VIEWERCONTEXTUALMENUITEMS6,
- ID_VIEWERCONTEXTUALMENUITEMS8, ID_VIEWERCONTEXTUALMENUITEMS9,
- ID_VIEWERCONTEXTUALMENUITEMS11, ID_VIEWERCONTEXTUALMENUITEMS12,
- ID_VIEWERCONTEXTUALMENUITEMS14, ID_VIEWERCONTEXTUALMENUITEMS16,
- ID_VIEWERCONTEXTUALMENUITEMS17,
+[
+ ID_VIEWERCONTEXTUALMENUITEMS0, ID_VIEWERCONTEXTUALMENUITEMS1,
+ ID_VIEWERCONTEXTUALMENUITEMS2, ID_VIEWERCONTEXTUALMENUITEMS3,
+ ID_VIEWERCONTEXTUALMENUITEMS5, ID_VIEWERCONTEXTUALMENUITEMS6,
+ ID_VIEWERCONTEXTUALMENUITEMS8, ID_VIEWERCONTEXTUALMENUITEMS9,
+ ID_VIEWERCONTEXTUALMENUITEMS11, ID_VIEWERCONTEXTUALMENUITEMS12,
+ ID_VIEWERCONTEXTUALMENUITEMS14, ID_VIEWERCONTEXTUALMENUITEMS16,
+ ID_VIEWERCONTEXTUALMENUITEMS17,
] = [wx.NewId() for _init_coll_ContextualMenu_Items in range(13)]
@@ -230,11 +268,11 @@
message = None
try:
values = eval(data)
- except:
- message = _("Invalid value \"%s\" for viewer block")%data
+ except Exception:
+ message = _("Invalid value \"%s\" for viewer block") % data
values = None
if not isinstance(values, TupleType):
- message = _("Invalid value \"%s\" for viewer block")%data
+ message = _("Invalid value \"%s\" for viewer block") % data
values = None
if values is not None:
if values[1] == "debug":
@@ -244,11 +282,11 @@
elif values[1] in ["function", "functionBlock"]:
words = tagname.split("::")
if pou_name == values[0]:
- message = _("\"%s\" can't use itself!")%pou_name
+ message = _("\"%s\" can't use itself!") % pou_name
elif pou_type == "function" and values[1] != "function":
message = _("Function Blocks can't be used in Functions!")
elif self.ParentWindow.Controler.PouIsUsedBy(pou_name, values[0], self.ParentWindow.Debug):
- message = _("\"{a1}\" is already used by \"{a2}\"!").format(a1 = pou_name, a2 = values[0])
+ message = _("\"{a1}\" is already used by \"{a2}\"!").format(a1=pou_name, a2=values[0])
else:
blockname = values[2]
if len(values) > 3:
@@ -258,12 +296,12 @@
if values[1] != "function" and blockname == "":
blockname = self.ParentWindow.GenerateNewName(blocktype=values[0])
if blockname.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]:
- message = _("\"%s\" pou already exists!")%blockname
+ message = _("\"%s\" pou already exists!") % blockname
elif blockname.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
- message = _("\"%s\" element for this pou already exists!")%blockname
+ message = _("\"%s\" element for this pou already exists!") % blockname
else:
id = self.ParentWindow.GetNewId()
- block = FBD_Block(self.ParentWindow, values[0], blockname, id, inputs = blockinputs)
+ block = FBD_Block(self.ParentWindow, values[0], blockname, id, inputs=blockinputs)
width, height = block.GetMinSize()
if scaling is not None:
x = round(float(x) / float(scaling[0])) * scaling[0]
@@ -285,10 +323,12 @@
if pou_type == "program":
location = values[0]
if not location.startswith("%"):
- dialog = wx.SingleChoiceDialog(self.ParentWindow.ParentWindow,
- _("Select a variable class:"), _("Variable class"),
- [_("Input"), _("Output"), _("Memory")],
- wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(
+ self.ParentWindow.ParentWindow,
+ _("Select a variable class:"),
+ _("Variable class"),
+ [_("Input"), _("Output"), _("Memory")],
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetSelection()
else:
@@ -313,7 +353,7 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
if location[1] == "Q":
var_class = OUTPUT
@@ -328,7 +368,7 @@
self.ParentWindow.ParentWindow.RefreshPouInstanceVariablesPanel()
self.ParentWindow.AddVariableBlock(x, y, scaling, var_class, var_name, var_type)
else:
- message = _("\"%s\" element for this pou already exists!")%var_name
+ message = _("\"%s\" element for this pou already exists!") % var_name
elif values[1] == "NamedConstant":
if pou_type == "program":
initval = values[0]
@@ -343,7 +383,7 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
var_class = INPUT
var_type = values[2]
@@ -352,7 +392,7 @@
self.ParentWindow.ParentWindow.RefreshPouInstanceVariablesPanel()
self.ParentWindow.AddVariableBlock(x, y, scaling, var_class, var_name, var_type)
else:
- message = _("\"%s\" element for this pou already exists!")%var_name
+ message = _("\"%s\" element for this pou already exists!") % var_name
elif values[1] == "Global":
var_name = values[0]
dlg = wx.TextEntryDialog(
@@ -365,14 +405,14 @@
if var_name is None:
return
elif var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetProjectPouNames(self.ParentWindow.Debug)]:
- message = _("\"%s\" pou already exists!")%var_name
+ message = _("\"%s\" pou already exists!") % var_name
elif not var_name.upper() in [name.upper() for name in self.ParentWindow.Controler.GetEditedElementVariables(tagname, self.ParentWindow.Debug)]:
self.ParentWindow.Controler.AddEditedElementPouExternalVar(tagname, values[2], var_name)
self.ParentWindow.RefreshVariablePanel()
self.ParentWindow.ParentWindow.RefreshPouInstanceVariablesPanel()
self.ParentWindow.AddVariableBlock(x, y, scaling, INPUT, var_name, values[2])
else:
- message = _("\"%s\" element for this pou already exists!")%var_name
+ message = _("\"%s\" element for this pou already exists!") % var_name
elif values[1] == "Constant":
self.ParentWindow.AddVariableBlock(x, y, scaling, INPUT, values[0], None)
elif values[3] == tagname:
@@ -421,15 +461,14 @@
return AddVariableFunction
def ShowMessage(self, message):
- message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
-
class DebugInstanceName(DebugDataConsumer):
VALUE_TRANSLATION = {True: _("Active"), False: _("Inactive")}
-
+
def __init__(self, parent):
DebugDataConsumer.__init__(self)
self.Parent = parent
@@ -437,7 +476,7 @@
self.ActionState = None
self.x_offset = 2
self.y_offset = 2
-
+
def SetValue(self, value):
self.ActionState = value
if self.ActionState != self.ActionLastState:
@@ -448,7 +487,7 @@
return _("Debug: %s") % self.Parent.InstancePath
def GetRedrawRect(self):
- x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset)
+ x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset)
dc = self.Parent.GetLogicalDC()
ipw, iph = dc.GetTextExtent(self.GetInstanceName())
vw, vh = 0, 0
@@ -462,13 +501,13 @@
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
x, y = self.Parent.CalcUnscrolledPosition(self.x_offset, self.y_offset)
-
+
text = self.GetInstanceName()
if self.ActionState is not None:
text += " ("
dc.DrawText(text, x, y)
- tw, th = dc.GetTextExtent(text)
+ tw, th = dc.GetTextExtent(text)
if self.ActionState is not None:
text = self.VALUE_TRANSLATION[self.ActionState]
@@ -478,20 +517,20 @@
if self.ActionState:
dc.SetTextForeground(wx.BLACK)
tw = tw + dc.GetTextExtent(text)[0]
-
- text = ")"
+
+ text = ")"
dc.DrawText(text, x + tw, y)
dc.SetUserScale(scalex, scaley)
-"""
-Class that implements a Viewer based on a wx.ScrolledWindow for drawing and
-manipulating graphic elements
-"""
class Viewer(EditorPanel, DebugViewer):
+ """
+ Class that implements a Viewer based on a wx.ScrolledWindow for drawing and
+ manipulating graphic elements
+ """
if wx.VERSION < (2, 6, 0):
- def Bind(self, event, function, id = None):
+ def Bind(self, event, function, id=None):
if id is not None:
event(self, id, function)
else:
@@ -535,8 +574,9 @@
# Add Alignment Menu items to the given menu
def AddAlignmentMenuItems(self, menu):
- [ID_ALIGN_LEFT, ID_ALIGN_CENTER, ID_ALIGN_RIGHT,
- ID_ALIGN_TOP, ID_ALIGN_MIDDLE, ID_ALIGN_BOTTOM,
+ [
+ ID_ALIGN_LEFT, ID_ALIGN_CENTER, ID_ALIGN_RIGHT,
+ ID_ALIGN_TOP, ID_ALIGN_MIDDLE, ID_ALIGN_BOTTOM,
] = [wx.NewId() for i in xrange(6)]
# Create menu items
@@ -587,7 +627,8 @@
None])
if self.CurrentLanguage != "FBD":
- [ID_ADD_POWER_RAIL, ID_ADD_CONTACT, ID_ADD_COIL,
+ [
+ ID_ADD_POWER_RAIL, ID_ADD_CONTACT, ID_ADD_COIL,
] = [wx.NewId() for i in xrange(3)]
# Create menu items
@@ -602,8 +643,9 @@
menu.AppendSeparator()
if self.CurrentLanguage == "SFC":
- [ID_ADD_INITIAL_STEP, ID_ADD_STEP, ID_ADD_TRANSITION,
- ID_ADD_ACTION_BLOCK, ID_ADD_DIVERGENCE, ID_ADD_JUMP,
+ [
+ ID_ADD_INITIAL_STEP, ID_ADD_STEP, ID_ADD_TRANSITION,
+ ID_ADD_ACTION_BLOCK, ID_ADD_DIVERGENCE, ID_ADD_JUMP,
] = [wx.NewId() for i in xrange(6)]
# Create menu items
@@ -662,12 +704,12 @@
def _init_Editor(self, prnt):
self.Editor = wx.ScrolledWindow(prnt, name="Viewer",
- pos=wx.Point(0, 0), size=wx.Size(0, 0),
- style=wx.HSCROLL | wx.VSCROLL)
+ pos=wx.Point(0, 0), size=wx.Size(0, 0),
+ style=wx.HSCROLL | wx.VSCROLL)
self.Editor.ParentWindow = self
# Create a new Viewer
- def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
+ def __init__(self, parent, tagname, window, controler, debug=False, instancepath=""):
self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1])
EditorPanel.__init__(self, parent, tagname, window, controler, debug)
@@ -675,7 +717,7 @@
# Adding a rubberband to Viewer
self.rubberBand = RubberBand(viewer=self)
- self.Editor.SetBackgroundColour(wx.Colour(255,255,255))
+ self.Editor.SetBackgroundColour(wx.Colour(255, 255, 255))
self.Editor.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
self.ResetView()
self.LastClientSize = None
@@ -722,17 +764,17 @@
self.ElementRefreshList_lock = Lock()
dc = wx.ClientDC(self.Editor)
- font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
+ font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName=faces["mono"])
dc.SetFont(font)
width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
while width > 260:
faces["size"] -= 1
- font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["mono"])
+ font = wx.Font(faces["size"], wx.SWISS, wx.NORMAL, wx.NORMAL, faceName=faces["mono"])
dc.SetFont(font)
width, height = dc.GetTextExtent("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
self.SetFont(font)
self.MiniTextDC = wx.MemoryDC()
- self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["helv"]))
+ self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName=faces["helv"]))
self.CurrentScale = None
self.SetScale(ZOOM_FACTORS.index(1.0), False)
@@ -776,7 +818,7 @@
def GetScrolledRect(self, rect):
rect.x, rect.y = self.Editor.CalcScrolledPosition(int(rect.x * self.ViewScale[0]),
- int(rect.y * self.ViewScale[1]))
+ int(rect.y * self.ViewScale[1]))
rect.width = int(rect.width * self.ViewScale[0]) + 2
rect.height = int(rect.height * self.ViewScale[1]) + 2
return rect
@@ -899,9 +941,9 @@
def GetMiniFont(self):
return self.MiniTextDC.GetFont()
-#-------------------------------------------------------------------------------
-# Element management functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Element management functions
+ # -------------------------------------------------------------------------------
def AddBlock(self, block):
self.Blocks[block.GetId()] = block
@@ -955,7 +997,7 @@
block.GetName() == name:
blocks.append(block)
return blocks
-
+
def GetConnectorByName(self, name):
for block in self.Blocks.itervalues():
if isinstance(block, FBD_Connector) and\
@@ -964,7 +1006,7 @@
return block
return None
- def RefreshVisibleElements(self, xp = None, yp = None):
+ def RefreshVisibleElements(self, xp=None, yp=None):
x, y = self.Editor.CalcUnscrolledPosition(0, 0)
if xp is not None:
x = xp * self.Editor.GetScrollPixelsPerUnit()[0]
@@ -991,14 +1033,14 @@
blockname = block.GetName()
connectorname = element.GetName()
if blockname != "":
- iec_path = "%s.%s.%s"%(instance_path, blockname, connectorname)
+ iec_path = "%s.%s.%s" % (instance_path, blockname, connectorname)
else:
if connectorname == "":
- iec_path = "%s.%s%d"%(instance_path, block.GetType(), block.GetId())
+ iec_path = "%s.%s%d" % (instance_path, block.GetType(), block.GetId())
else:
- iec_path = "%s.%s%d_%s"%(instance_path, block.GetType(), block.GetId(), connectorname)
+ iec_path = "%s.%s%d_%s" % (instance_path, block.GetType(), block.GetId(), connectorname)
elif isinstance(block, FBD_Variable):
- iec_path = "%s.%s"%(instance_path, block.GetName())
+ iec_path = "%s.%s" % (instance_path, block.GetName())
elif isinstance(block, FBD_Connector):
connection = self.GetConnectorByName(block.GetName())
if connection is not None:
@@ -1006,14 +1048,14 @@
if len(connector.Wires) == 1:
iec_path = self.GetElementIECPath(connector.Wires[0][0])
elif isinstance(element, LD_Contact):
- iec_path = "%s.%s"%(instance_path, element.GetName())
+ iec_path = "%s.%s" % (instance_path, element.GetName())
elif isinstance(element, SFC_Step):
- iec_path = "%s.%s.X"%(instance_path, element.GetName())
+ iec_path = "%s.%s.X" % (instance_path, element.GetName())
elif isinstance(element, SFC_Transition):
connectors = element.GetConnectors()
previous_steps = self.GetPreviousSteps(connectors["inputs"])
next_steps = self.GetNextSteps(connectors["outputs"])
- iec_path = "%s.%s->%s"%(instance_path, ",".join(previous_steps), ",".join(next_steps))
+ iec_path = "%s.%s->%s" % (instance_path, ",".join(previous_steps), ",".join(next_steps))
return iec_path
def GetWireModifier(self, wire):
@@ -1042,9 +1084,9 @@
element.SetSize(width, height)
element.RefreshModel()
-#-------------------------------------------------------------------------------
-# Reset functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Reset functions
+ # -------------------------------------------------------------------------------
# Resets Viewer lists
def ResetView(self):
@@ -1162,11 +1204,9 @@
self.RefreshVisibleElements()
self.Editor.Refresh(False)
-
-#-------------------------------------------------------------------------------
-# Refresh functions
-#-------------------------------------------------------------------------------
-
+ # -------------------------------------------------------------------------------
+ # Refresh functions
+ # -------------------------------------------------------------------------------
def ElementNeedRefresh(self, element):
self.ElementRefreshList_lock.acquire()
@@ -1208,13 +1248,12 @@
self.ResetBuffer()
instance = {}
# List of ids of already loaded blocks
- instances = self.Controler.GetEditedElementInstancesInfos(self.TagName, debug = self.Debug)
+ instances = self.Controler.GetEditedElementInstancesInfos(self.TagName, debug=self.Debug)
# Load Blocks until they are all loaded
while len(instances) > 0:
self.loadInstance(instances.popitem(0)[1], instances, selection)
- if (selection is not None and
- isinstance(self.SelectedElement, Graphic_Group)):
+ if selection is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.RefreshWireExclusion()
self.SelectedElement.RefreshBoundingBox()
@@ -1222,7 +1261,7 @@
if self.TagName.split("::")[0] == "A" and self.Debug:
self.AddDataConsumer("%s.Q" % self.InstancePath.upper(), self.InstanceName)
-
+
for wire in self.Wires:
if not wire.IsConnectedCompatible():
wire.SetValid(False)
@@ -1302,7 +1341,8 @@
maxy = max(maxy, extent.y + extent.height)
maxx = int(maxx * self.ViewScale[0])
maxy = int(maxy * self.ViewScale[1])
- self.Editor.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT,
+ self.Editor.SetScrollbars(
+ SCROLLBAR_UNIT, SCROLLBAR_UNIT,
round(maxx / SCROLLBAR_UNIT) + width_incr, round(maxy / SCROLLBAR_UNIT) + height_incr,
xstart, ystart, True)
@@ -1345,7 +1385,7 @@
def loadInstance(self, instance, remaining_instances, selection):
self.current_id = max(self.current_id, instance.id)
creation_function = ElementCreationFunctions.get(instance.type, None)
- connectors = {"inputs" : [], "outputs" : []}
+ connectors = {"inputs": [], "outputs": []}
specific_values = instance.specific_values
if creation_function is not None:
element = creation_function(self, instance.id, specific_values)
@@ -1384,10 +1424,11 @@
connectors["outputs"].pop(0)
executionControl = True
block_name = specific_values.name if specific_values.name is not None else ""
- element = FBD_Block(self, instance.type, block_name,
- instance.id, len(connectors["inputs"]),
- connectors=connectors, executionControl=executionControl,
- executionOrder=specific_values.execution_order)
+ element = FBD_Block(
+ self, instance.type, block_name,
+ instance.id, len(connectors["inputs"]),
+ connectors=connectors, executionControl=executionControl,
+ executionOrder=specific_values.execution_order)
if isinstance(element, Comment):
self.AddComment(element)
else:
@@ -1399,7 +1440,7 @@
connector_pos = wx.Point(*output_connector.position)
if isinstance(element, FBD_Block):
connector = element.GetConnector(connector_pos,
- output_name = output_connector.name)
+ output_name=output_connector.name)
elif i < len(connectors["outputs"]):
connector = connectors["outputs"][i]
else:
@@ -1415,7 +1456,7 @@
connector_pos = wx.Point(*input_connector.position)
if isinstance(element, FBD_Block):
connector = element.GetConnector(connector_pos,
- input_name = input_connector.name)
+ input_name=input_connector.name)
elif i < len(connectors["inputs"]):
connector = connectors["inputs"][i]
else:
@@ -1461,19 +1502,18 @@
wire = Wire(self)
wire.SetPoints(points)
else:
- wire = Wire(self,
- [wx.Point(*start_connector.GetPosition()),
- start_connector.GetDirection()],
- [wx.Point(*end_connector.GetPosition()),
- end_connector.GetDirection()])
+ wire = Wire(
+ self,
+ [wx.Point(*start_connector.GetPosition()), start_connector.GetDirection()],
+ [wx.Point(*end_connector.GetPosition()), end_connector.GetDirection()])
start_connector.Wires.append((wire, 0))
end_connector.Wires.append((wire, -1))
wire.StartConnected = start_connector
wire.EndConnected = end_connector
connected.RefreshConnectors()
self.AddWire(wire)
- if selection is not None and (\
- selection[1].get((id, refLocalId), False) or \
+ if selection is not None and (
+ selection[1].get((id, refLocalId), False) or
selection[1].get((refLocalId, id), False)):
self.SelectInGroup(wire)
else:
@@ -1487,12 +1527,12 @@
def IsEndType(self, type):
return self.Controler.IsEndType(type)
- def GetBlockType(self, type, inputs = None):
+ def GetBlockType(self, type, inputs=None):
return self.Controler.GetBlockType(type, inputs, self.Debug)
-#-------------------------------------------------------------------------------
-# Search Element functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Search Element functions
+ # -------------------------------------------------------------------------------
def FindBlock(self, event):
dc = self.GetLogicalDC()
@@ -1510,7 +1550,7 @@
return wire
return None
- def FindElement(self, event, exclude_group = False, connectors = True):
+ def FindElement(self, event, exclude_group=False, connectors=True):
dc = self.GetLogicalDC()
pos = event.GetLogicalPosition(dc)
if self.SelectedElement and not (exclude_group and isinstance(self.SelectedElement, Graphic_Group)):
@@ -1521,12 +1561,12 @@
return element
return None
- def FindBlockConnector(self, pos, direction = None, exclude = None):
+ def FindBlockConnector(self, pos, direction=None, exclude=None):
result, error = self.FindBlockConnectorWithError(pos, direction, exclude)
return result
- def FindBlockConnectorWithError(self, pos, direction = None, exclude = None):
- error = False
+ def FindBlockConnectorWithError(self, pos, direction=None, exclude=None):
+ error = False
startblock = None
for block in self.Blocks.itervalues():
connector = block.TestConnector(pos, direction, exclude)
@@ -1539,7 +1579,7 @@
error = True
return connector, error
return None, error
-
+
def FindElementById(self, id):
block = self.Blocks.get(id, None)
if block is not None:
@@ -1563,12 +1603,13 @@
self.SelectedElement.SetElements(self.GetElements())
self.SelectedElement.SetSelected(True)
-#-------------------------------------------------------------------------------
-# Popup menu functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Popup menu functions
+ # -------------------------------------------------------------------------------
def GetForceVariableMenuFunction(self, iec_path, element):
iec_type = self.GetDataType(iec_path)
+
def ForceVariableFunction(event):
if iec_type is not None:
dialog = ForceVariableDialog(self.ParentWindow, iec_type, str(element.GetValue()))
@@ -1611,7 +1652,7 @@
self.Editor.PopupMenu(menu)
menu.Destroy()
- def PopupBlockMenu(self, connector = None):
+ def PopupBlockMenu(self, connector=None):
menu = wx.Menu(title='')
if connector is not None and connector.IsCompatible("BOOL"):
self.AddBlockPinMenuItems(menu, connector)
@@ -1662,7 +1703,8 @@
if self.SelectedElement.GetStartConnected() in connected
else self.SelectedElement.GetStartConnected())
- self.AddWireMenuItems(menu, delete,
+ self.AddWireMenuItems(
+ menu, delete,
start_connector.GetDirection() == EAST and
not isinstance(start_connector.GetParentBlock(), SFC_Step))
@@ -1695,9 +1737,9 @@
self.Editor.PopupMenu(menu)
menu.Destroy()
-#-------------------------------------------------------------------------------
-# Menu items functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Menu items functions
+ # -------------------------------------------------------------------------------
def OnAlignLeftMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
@@ -1771,9 +1813,7 @@
def OnReplaceWireMenu(self, event):
# Check that selected element is a wire before applying replace
- if (self.SelectedElement is not None and
- self.IsWire(self.SelectedElement)):
-
+ if self.SelectedElement is not None and self.IsWire(self.SelectedElement):
# Get wire redraw bbox to erase it from screen
wire = self.SelectedElement
redraw_rect = wire.GetRedrawRect()
@@ -1844,8 +1884,8 @@
# Add Wire to Viewer and connect it to blocks
new_wire = Wire(self,
- [wx.Point(*start_point), connector.GetDirection()],
- [wx.Point(*end_point), end_connector.GetDirection()])
+ [wx.Point(*start_point), connector.GetDirection()],
+ [wx.Point(*end_point), end_connector.GetDirection()])
self.AddWire(new_wire)
connector.Connect((new_wire, 0), False)
end_connector.Connect((new_wire, -1), False)
@@ -1883,7 +1923,7 @@
def OnEditBlockMenu(self, event):
if self.SelectedElement is not None:
- self.ParentWindow.EditProjectElement(ITEM_POU, "P::%s"%self.SelectedElement.GetType())
+ self.ParentWindow.EditProjectElement(ITEM_POU, "P::%s" % self.SelectedElement.GetType())
def OnAdjustBlockSizeMenu(self, event):
if self.SelectedElement is not None:
@@ -1916,6 +1956,7 @@
def GetAddToWireMenuCallBack(self, func, *args):
args += (self.SelectedElement,)
+
def AddToWireMenuCallBack(event):
func(wx.Rect(0, 0, 0, 0), *args)
return AddToWireMenuCallBack
@@ -1925,16 +1966,16 @@
wx.CallAfter(func)
return ClipboardCallback
-#-------------------------------------------------------------------------------
-# Mouse event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Mouse event functions
+ # -------------------------------------------------------------------------------
def OnViewerMouseEvent(self, event):
self.ResetBuffer()
if event.Leaving() and self.ToolTipElement is not None:
self.ToolTipElement.DestroyToolTip()
elif (not event.Entering() and
- gettime() - self.LastToolTipCheckTime > REFRESH_PERIOD):
+ gettime() - self.LastToolTipCheckTime > REFRESH_PERIOD):
self.LastToolTipCheckTime = gettime()
element = None
if not event.Leaving() and not event.LeftUp() and not event.LeftDClick():
@@ -1991,7 +2032,7 @@
if element is None or element.TestHandle(event) == (0, 0):
connector = self.FindBlockConnector(pos, self.SelectedElement.GetConnectionDirection())
if connector is not None:
- event.Dragging = lambda : True
+ event.Dragging = lambda: True
self.SelectedElement.OnMotion(event, dc, self.Scaling)
if self.SelectedElement.EndConnected is not None:
self.SelectedElement.ResetPoints()
@@ -2130,8 +2171,8 @@
# Popup contextual menu
menu = wx.Menu()
self.AddMenuItems(menu,
- [(wx.NewId(), wx.ITEM_NORMAL, text, '', callback)
- for text, callback in items])
+ [(wx.NewId(), wx.ITEM_NORMAL, text, '', callback)
+ for text, callback in items])
self.PopupMenu(menu)
self.SelectedElement.StartConnected.HighlightParentBlock(False)
@@ -2237,16 +2278,18 @@
"functionBlock": ITEM_FUNCTIONBLOCK,
}.get(self.Controler.GetPouType(instance_type))
if pou_type is not None and instance_type in self.Controler.GetProjectPouNames(self.Debug):
- self.ParentWindow.OpenDebugViewer(pou_type,
- "%s.%s"%(self.GetInstancePath(True), self.SelectedElement.GetName()),
+ self.ParentWindow.OpenDebugViewer(
+ pou_type,
+ "%s.%s" % (self.GetInstancePath(True), self.SelectedElement.GetName()),
self.Controler.ComputePouName(instance_type))
else:
iec_path = self.GetElementIECPath(self.SelectedElement)
if iec_path is not None:
if isinstance(self.SelectedElement, Wire):
if self.SelectedElement.EndConnected is not None:
- self.ParentWindow.OpenDebugViewer(ITEM_VAR_LOCAL, iec_path,
- self.SelectedElement.EndConnected.GetType())
+ self.ParentWindow.OpenDebugViewer(
+ ITEM_VAR_LOCAL, iec_path,
+ self.SelectedElement.EndConnected.GetType())
else:
self.ParentWindow.OpenDebugViewer(ITEM_VAR_LOCAL, iec_path, "BOOL")
elif event.ControlDown() and not event.ShiftDown():
@@ -2256,8 +2299,9 @@
else:
instance_type = None
if instance_type in self.Controler.GetProjectPouNames(self.Debug):
- self.ParentWindow.EditProjectElement(ITEM_POU,
- self.Controler.ComputePouName(instance_type))
+ self.ParentWindow.EditProjectElement(
+ ITEM_POU,
+ self.Controler.ComputePouName(instance_type))
else:
self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
elif event.ControlDown() and event.ShiftDown():
@@ -2290,8 +2334,7 @@
self.RefreshScrollBars()
self.RefreshVisibleElements()
else:
- if (not event.Dragging() and
- gettime() - self.LastHighlightCheckTime > REFRESH_PERIOD):
+ if not event.Dragging() and (gettime() - self.LastHighlightCheckTime) > REFRESH_PERIOD:
self.LastHighlightCheckTime = gettime()
highlighted = self.FindElement(event, connectors=False)
if self.HighlightedElement is not None and self.HighlightedElement != highlighted:
@@ -2308,8 +2351,8 @@
elif not self.Debug and self.Mode == MODE_SELECTION and self.SelectedElement is not None:
if self.DrawingWire:
connector, errorHighlight = self.FindBlockConnectorWithError(pos, self.SelectedElement.GetConnectionDirection(), self.SelectedElement.EndConnected)
- self.SelectedElement.ErrHighlight = errorHighlight;
- if not connector or self.SelectedElement.EndConnected == None:
+ self.SelectedElement.ErrHighlight = errorHighlight
+ if not connector or self.SelectedElement.EndConnected is None:
self.SelectedElement.ResetPoints()
movex, movey = self.SelectedElement.OnMotion(event, dc, self.Scaling)
self.SelectedElement.GeneratePoints()
@@ -2371,11 +2414,11 @@
elif position.y > window_size[1] - SCROLL_ZONE:
move_window.y = 1
if move_window.x != 0 or move_window.y != 0:
- self.RefreshVisibleElements(xp = xstart + move_window.x, yp = ystart + move_window.y)
+ self.RefreshVisibleElements(xp=xstart + move_window.x, yp=ystart + move_window.y)
self.Scroll(xstart + move_window.x, ystart + move_window.y)
self.RefreshScrollBars(move_window.x, move_window.y)
- def BlockCompatibility(self, startblock=None, endblock=None, direction = None):
+ def BlockCompatibility(self, startblock=None, endblock=None, direction=None):
return True
def GetPopupMenuItems(self):
@@ -2423,9 +2466,9 @@
(_(u'Variable'), self.GetAddToWireMenuCallBack(self.AddNewVariable, True)))
return items
-#-------------------------------------------------------------------------------
-# Keyboard event functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Keyboard event functions
+ # -------------------------------------------------------------------------------
ARROW_KEY_MOVE = {
wx.WXK_LEFT: (-1, 0),
@@ -2453,7 +2496,7 @@
self.RefreshRect(self.GetScrolledRect(rect), False)
elif not self.Debug and keycode == wx.WXK_RETURN and self.SelectedElement is not None:
self.SelectedElement.OnLeftDClick(event, self.GetLogicalDC(), self.Scaling)
- elif self.ARROW_KEY_MOVE.has_key(keycode):
+ elif keycode in self.ARROW_KEY_MOVE:
move = self.ARROW_KEY_MOVE[keycode]
if event.ControlDown() and event.ShiftDown():
self.Scroll({-1: 0, 0: xpos, 1: xmax}[move[0]],
@@ -2501,9 +2544,9 @@
else:
event.Skip()
-#-------------------------------------------------------------------------------
-# Model adding functions from Drop Target
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Model adding functions from Drop Target
+ # -------------------------------------------------------------------------------
def AddVariableBlock(self, x, y, scaling, var_class, var_name, var_type):
id = self.GetNewId()
@@ -2524,9 +2567,9 @@
self.RefreshVisibleElements()
self.Editor.Refresh(False)
-#-------------------------------------------------------------------------------
-# Model adding functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Model adding functions
+ # -------------------------------------------------------------------------------
def GetScaledSize(self, width, height):
if self.Scaling is not None:
@@ -2571,10 +2614,11 @@
id = self.GetNewId()
values = dialog.GetValues()
values.setdefault("name", "")
- block = FBD_Block(self, values["type"], values["name"], id,
- values["extension"], values["inputs"],
- executionControl = values["executionControl"],
- executionOrder = values["executionOrder"])
+ block = FBD_Block(
+ self, values["type"], values["name"], id,
+ values["extension"], values["inputs"],
+ executionControl=values["executionControl"],
+ executionOrder=values["executionOrder"])
self.Controler.AddEditedElementBlock(self.TagName, id, values["type"], values.get("name", None))
connector = None
if wire is not None:
@@ -2585,7 +2629,7 @@
break
self.AddNewElement(block, bbox, wire, connector)
self.RefreshVariablePanel()
- self.ParentWindow.RefreshPouInstanceVariablesPanel()
+ self.ParentWindow.RefreshPouInstanceVariablesPanel()
dialog.Destroy()
def AddNewVariable(self, bbox, exclude_input=False, wire=None):
@@ -2625,7 +2669,7 @@
dialog = wx.TextEntryDialog(self.ParentWindow,
_("Edit comment"),
_("Please enter comment text"),
- "", wx.OK|wx.CANCEL|wx.TE_MULTILINE)
+ "", wx.OK | wx.CANCEL | wx.TE_MULTILINE)
dialog.SetClientSize(wx.Size(400, 200))
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
@@ -2633,7 +2677,7 @@
comment = Comment(self, value, id)
comment.SetPosition(bbox.x, bbox.y)
min_width, min_height = comment.GetMinSize()
- comment.SetSize(*self.GetScaledSize(max(min_width,bbox.width),max(min_height,bbox.height)))
+ comment.SetSize(*self.GetScaledSize(max(min_width, bbox.width), max(min_height, bbox.height)))
self.AddComment(comment)
self.Controler.AddEditedElementComment(self.TagName, id)
self.RefreshCommentModel(comment)
@@ -2689,11 +2733,11 @@
def AddNewStep(self, bbox, initial=False, wire=None):
if wire is not None:
values = {
- "name": self.Controler.GenerateNewName(
- self.TagName, None, "Step%d", 0),
- "input": True,
+ "name": self.Controler.GenerateNewName(self.TagName, None, "Step%d", 0),
+ "input": True,
"output": True,
- "action":False}
+ "action": False
+ }
else:
dialog = SFCStepDialog(self.ParentWindow, self.Controler, self.TagName, initial)
dialog.SetPreviewFont(self.GetFont())
@@ -2736,7 +2780,7 @@
connector = transition.GetConnectors()["inputs"][0]
self.AddNewElement(transition, bbox, wire, connector)
- def AddNewDivergence(self, bbox, poss_div_types = None, wire=None):
+ def AddNewDivergence(self, bbox, poss_div_types=None, wire=None):
dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler, self.TagName, poss_div_types)
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize((bbox.width, bbox.height))
@@ -2754,8 +2798,10 @@
if isinstance(block, SFC_Step):
choices.append(block.GetName())
dialog = wx.SingleChoiceDialog(self.ParentWindow,
- _("Add a new jump"), _("Please choose a target"),
- choices, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ _("Add a new jump"),
+ _("Please choose a target"),
+ choices,
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
id = self.GetNewId()
jump = SFC_Jump(self, dialog.GetStringSelection(), id)
@@ -2775,20 +2821,22 @@
self.AddNewElement(actionblock, bbox, wire)
dialog.Destroy()
-#-------------------------------------------------------------------------------
-# Edit element content functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Edit element content functions
+ # -------------------------------------------------------------------------------
def EditBlockContent(self, block):
dialog = FBDBlockDialog(self.ParentWindow, self.Controler, self.TagName)
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(block.GetSize())
- old_values = {"name" : block.GetName(),
- "type" : block.GetType(),
- "extension" : block.GetExtension(),
- "inputs" : block.GetInputTypes(),
- "executionControl" : block.GetExecutionControl(),
- "executionOrder" : block.GetExecutionOrder()}
+ old_values = {
+ "name": block.GetName(),
+ "type": block.GetType(),
+ "extension": block.GetExtension(),
+ "inputs": block.GetInputTypes(),
+ "executionControl": block.GetExecutionControl(),
+ "executionOrder": block.GetExecutionOrder()
+ }
dialog.SetValues(old_values)
if dialog.ShowModal() == wx.ID_OK:
new_values = dialog.GetValues()
@@ -2798,7 +2846,7 @@
else:
block.SetName("")
block.SetSize(*self.GetScaledSize(new_values["width"], new_values["height"]))
- block.SetType(new_values["type"], new_values["extension"], executionControl = new_values["executionControl"])
+ block.SetType(new_values["type"], new_values["extension"], executionControl=new_values["executionControl"])
block.SetExecutionOrder(new_values["executionOrder"])
rect = rect.Union(block.GetRedrawRect())
self.RefreshBlockModel(block)
@@ -2817,8 +2865,11 @@
dialog = FBDVariableDialog(self.ParentWindow, self.Controler, self.TagName)
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(variable.GetSize())
- old_values = {"expression" : variable.GetName(), "class" : variable.GetType(),
- "executionOrder" : variable.GetExecutionOrder()}
+ old_values = {
+ "expression": variable.GetName(),
+ "class": variable.GetType(),
+ "executionOrder": variable.GetExecutionOrder()
+ }
dialog.SetValues(old_values)
if dialog.ShowModal() == wx.ID_OK:
new_values = dialog.GetValues()
@@ -2846,7 +2897,7 @@
dialog = ConnectionDialog(self.ParentWindow, self.Controler, self.TagName, True)
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(connection.GetSize())
- values = {"name" : connection.GetName(), "type" : connection.GetType()}
+ values = {"name": connection.GetName(), "type": connection.GetType()}
dialog.SetValues(values)
result = dialog.ShowModal()
dialog.Destroy()
@@ -2878,8 +2929,8 @@
dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "contact")
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(contact.GetSize())
- dialog.SetValues({"variable" : contact.GetName(),
- "modifier" : contact.GetType()})
+ dialog.SetValues({"variable": contact.GetName(),
+ "modifier": contact.GetType()})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = contact.GetRedrawRect(1, 1)
@@ -2898,8 +2949,8 @@
dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "coil")
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(coil.GetSize())
- dialog.SetValues({"variable" : coil.GetName(),
- "modifier" : coil.GetType()})
+ dialog.SetValues({"variable": coil.GetName(),
+ "modifier": coil.GetType()})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = coil.GetRedrawRect(1, 1)
@@ -2946,10 +2997,10 @@
dialog.SetMinElementSize(step.GetSize())
connectors = step.GetConnectors()
dialog.SetValues({
- "name" : step.GetName(),
+ "name": step.GetName(),
"input": len(connectors["inputs"]) > 0,
"output": len(connectors["outputs"]) > 0,
- "action": step.GetActionConnector() != None})
+ "action": step.GetActionConnector() is not None})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = step.GetRedrawRect(1, 1)
@@ -2966,7 +3017,7 @@
rect = rect.Union(block.GetRedrawRect())
block.Refresh(rect)
step.SetName(new_name)
-
+
if values["input"]:
step.AddInput()
else:
@@ -2991,11 +3042,15 @@
dialog = SFCTransitionDialog(self.ParentWindow, self.Controler, self.TagName, self.GetDrawingMode() == FREEDRAWING_MODE)
dialog.SetPreviewFont(self.GetFont())
dialog.SetMinElementSize(transition.GetSize())
- dialog.SetValues({"type":transition.GetType(),"value":transition.GetCondition(), "priority":transition.GetPriority()})
+ dialog.SetValues({
+ "type": transition.GetType(),
+ "value": transition.GetCondition(),
+ "priority": transition.GetPriority()
+ })
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = transition.GetRedrawRect(1, 1)
- transition.SetType(values["type"],values["value"])
+ transition.SetType(values["type"], values["value"])
transition.SetPriority(values["priority"])
rect = rect.Union(transition.GetRedrawRect())
self.RefreshTransitionModel(transition)
@@ -3011,8 +3066,10 @@
if isinstance(block, SFC_Step):
choices.append(block.GetName())
dialog = wx.SingleChoiceDialog(self.ParentWindow,
- _("Edit jump target"), _("Please choose a target"),
- choices, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
+ _("Edit jump target"),
+ _("Please choose a target"),
+ choices,
+ wx.DEFAULT_DIALOG_STYLE | wx.OK | wx.CANCEL)
try:
indx = choices.index(jump.GetTarget())
dialog.SetSelection(indx)
@@ -3055,7 +3112,7 @@
_("Edit comment"),
_("Please enter comment text"),
comment.GetContent(),
- wx.OK|wx.CANCEL|wx.TE_MULTILINE)
+ wx.OK | wx.CANCEL | wx.TE_MULTILINE)
width, height = comment.GetSize()
dialogSize = wx.Size(max(width + 30, 400), max(height + 60, 200))
dialog.SetClientSize(dialogSize)
@@ -3072,9 +3129,9 @@
comment.Refresh(rect)
dialog.Destroy()
-#-------------------------------------------------------------------------------
-# Model update functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Model update functions
+ # -------------------------------------------------------------------------------
def RefreshBlockModel(self, block):
blockid = block.GetId()
@@ -3221,11 +3278,9 @@
infos["connector"] = actionblock.GetConnector()
self.Controler.SetEditedElementActionBlockInfos(self.TagName, actionblockid, infos)
-
-#-------------------------------------------------------------------------------
-# Model delete functions
-#-------------------------------------------------------------------------------
-
+ # -------------------------------------------------------------------------------
+ # Model delete functions
+ # -------------------------------------------------------------------------------
def DeleteBlock(self, block):
elements = []
@@ -3372,10 +3427,9 @@
self.RemoveBlock(actionblock)
self.Controler.RemoveEditedElementInstance(self.TagName, actionblock.GetId())
-
-#-------------------------------------------------------------------------------
-# Editing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Editing functions
+ # -------------------------------------------------------------------------------
def Cut(self):
if not self.Debug and (self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement) or isinstance(self.SelectedElement, Graphic_Group)):
@@ -3418,7 +3472,7 @@
self.RefreshVariablePanel()
self.ParentWindow.RefreshPouInstanceVariablesPanel()
else:
- message = wx.MessageDialog(self.Editor, result, "Error", wx.OK|wx.ICON_ERROR)
+ message = wx.MessageDialog(self.Editor, result, "Error", wx.OK | wx.ICON_ERROR)
message.ShowModal()
message.Destroy()
@@ -3506,9 +3560,9 @@
self.Controler.AddEditedElementActionBlock(self.TagName, block.GetId())
self.RefreshActionBlockModel(block)
-#-------------------------------------------------------------------------------
-# Find and Replace functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Find and Replace functions
+ # -------------------------------------------------------------------------------
def Find(self, direction, search_params):
if self.SearchParams != search_params:
@@ -3549,9 +3603,9 @@
self.RemoveHighlight(*self.CurrentFindHighlight)
self.CurrentFindHighlight = None
-#-------------------------------------------------------------------------------
-# Highlights showing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Highlights showing functions
+ # -------------------------------------------------------------------------------
def OnRefreshHighlightsTimer(self, event):
self.RefreshView()
@@ -3590,9 +3644,9 @@
if block is not None:
block.AddHighlight(infos[2:], start, end, highlight_type)
-#-------------------------------------------------------------------------------
-# Drawing functions
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Drawing functions
+ # -------------------------------------------------------------------------------
def OnScrollWindow(self, event):
if self.Editor.HasCapture() and self.StartMousePos is not None:
@@ -3602,9 +3656,9 @@
self.Editor.Freeze()
wx.CallAfter(self.Editor.Thaw)
elif event.GetOrientation() == wx.HORIZONTAL:
- self.RefreshVisibleElements(xp = event.GetPosition())
+ self.RefreshVisibleElements(xp=event.GetPosition())
else:
- self.RefreshVisibleElements(yp = event.GetPosition())
+ self.RefreshVisibleElements(yp=event.GetPosition())
# Handle scroll in debug to fully redraw area and ensuring
# instance path is fully draw without flickering
@@ -3627,16 +3681,16 @@
if event.ShiftDown():
x, y = self.GetViewStart()
xp = max(0, min(x - rotation * 3, self.Editor.GetVirtualSize()[0] / self.Editor.GetScrollPixelsPerUnit()[0]))
- self.RefreshVisibleElements(xp = xp)
+ self.RefreshVisibleElements(xp=xp)
self.Scroll(xp, y)
elif event.ControlDown():
dc = self.GetLogicalDC()
- self.SetScale(self.CurrentScale + rotation, mouse_event = event)
+ self.SetScale(self.CurrentScale + rotation, mouse_event=event)
self.ParentWindow.RefreshDisplayMenu()
else:
x, y = self.GetViewStart()
yp = max(0, min(y - rotation * 3, self.Editor.GetVirtualSize()[1] / self.Editor.GetScrollPixelsPerUnit()[1]))
- self.RefreshVisibleElements(yp = yp)
+ self.RefreshVisibleElements(yp=yp)
self.Scroll(x, yp)
def OnMoveWindow(self, event):
@@ -3647,7 +3701,7 @@
self.RefreshVisibleElements()
event.Skip()
- def DoDrawing(self, dc, printing = False):
+ def DoDrawing(self, dc, printing=False):
if printing:
if getattr(dc, "printing", False):
font = wx.Font(self.GetFont().GetPointSize(), wx.MODERN, wx.NORMAL, wx.NORMAL)
@@ -3684,11 +3738,11 @@
comment.Draw(dc)
for wire in self.Wires.iterkeys():
if wire != self.SelectedElement and (wire.IsVisible() or printing):
- if not self.Debug or wire.GetValue() != True:
+ if not self.Debug or not wire.GetValue():
wire.Draw(dc)
if self.Debug:
for wire in self.Wires.iterkeys():
- if wire != self.SelectedElement and (wire.IsVisible() or printing) and wire.GetValue() == True:
+ if wire != self.SelectedElement and (wire.IsVisible() or printing) and wire.GetValue():
wire.Draw(dc)
for block in self.Blocks.itervalues():
if block != self.SelectedElement and (block.IsVisible() or printing):
@@ -3711,5 +3765,3 @@
if self.Debug:
DebugViewer.RefreshNewData(self)
event.Skip()
-
-
--- a/graphics/DebugDataConsumer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/DebugDataConsumer.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,9 +24,10 @@
import datetime
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Date and Time conversion function
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
SECOND = 1000000 # Number of microseconds in one second
MINUTE = 60 * SECOND # Number of microseconds in one minute
@@ -36,6 +37,7 @@
# Date corresponding to Epoch (1970 January the first)
DATE_ORIGIN = datetime.datetime(1970, 1, 1)
+
def get_microseconds(value):
"""
Function converting time duration expressed in day, second and microseconds
@@ -43,10 +45,11 @@
@param value: Time duration to convert
@return: Time duration expressed in microsecond
"""
- return float(value.days * DAY + \
- value.seconds * SECOND + \
+ return float(value.days * DAY +
+ value.seconds * SECOND +
value.microseconds)
- return
+ return
+
def generate_time(value):
"""
@@ -56,40 +59,41 @@
@return: IEC 61131 TIME literal
"""
microseconds = get_microseconds(value)
-
+
# Get absolute microseconds value and save if it was negative
negative = microseconds < 0
microseconds = abs(microseconds)
-
+
# TIME literal prefix
data = "T#"
if negative:
data += "-"
-
+
# In TIME literal format, it isn't mandatory to indicate null values
# if no greater non-null values are available. This variable is used to
# inhibit formatting until a non-null value is found
not_null = False
-
+
for val, format in [
- (int(microseconds) / DAY, "%dd"), # Days
- ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours
- ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes
- ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds
-
- # Add value to TIME literal if value is non-null or another non-null
+ (int(microseconds) / DAY, "%dd"), # Days
+ ((int(microseconds) % DAY) / HOUR, "%dh"), # Hours
+ ((int(microseconds) % HOUR) / MINUTE, "%dm"), # Minutes
+ ((int(microseconds) % MINUTE) / SECOND, "%ds")]: # Seconds
+
+ # Add value to TIME literal if value is non-null or another non-null
# value have already be found
if val > 0 or not_null:
data += format % val
-
+
# Update non-null variable
not_null = True
-
- # In any case microseconds have to be added to TIME literal
+
+ # In any case microseconds have to be added to TIME literal
data += "%gms" % (microseconds % SECOND / 1000.)
-
+
return data
+
def generate_date(value):
"""
Function converting time duration expressed in day, second and microseconds
@@ -99,6 +103,7 @@
"""
return (DATE_ORIGIN + value).strftime("DATE#%Y-%m-%d")
+
def generate_datetime(value):
"""
Function converting time duration expressed in day, second and microseconds
@@ -108,6 +113,7 @@
"""
return (DATE_ORIGIN + value).strftime("DT#%Y-%m-%d-%H:%M:%S.%f")
+
def generate_timeofday(value):
"""
Function converting time duration expressed in day, second and microseconds
@@ -116,22 +122,23 @@
@return: IEC 61131 TIME_OF_DAY literal
"""
microseconds = get_microseconds(value)
-
+
# TIME_OF_DAY literal prefix
data = "TOD#"
-
+
for val, format in [
(int(microseconds) / HOUR, "%2.2d:"), # Hours
((int(microseconds) % HOUR) / MINUTE, "%2.2d:"), # Minutes
((int(microseconds) % MINUTE) / SECOND, "%2.2d."), # Seconds
(microseconds % SECOND, "%6.6d")]: # Microseconds
-
+
# Add value to TIME_OF_DAY literal
data += format % val
-
+
return data
-# Dictionary of translation functions from value send by debugger to IEC
+
+# Dictionary of translation functions from value send by debugger to IEC
# literal stored by type
TYPE_TRANSLATOR = {
"TIME": generate_time,
@@ -143,18 +150,19 @@
"REAL": lambda v: "%.6g" % v,
"LREAL": lambda v: "%.6g" % v}
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Debug Data Consumer Class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements an element that consumes debug values
-Value update can be inhibited during the time the associated Debug Viewer is
-refreshing
-"""
+# -------------------------------------------------------------------------------
+
class DebugDataConsumer:
-
+ """
+ Class that implements an element that consumes debug values
+ Value update can be inhibited during the time the associated Debug Viewer is
+ refreshing
+ """
+
def __init__(self):
"""
Constructor
@@ -162,17 +170,17 @@
# Debug value and forced flag
self.Value = None
self.Forced = False
-
+
# Store debug value and forced flag when value update is inhibited
self.LastValue = None
self.LastForced = False
-
+
# Value IEC data type
self.DataType = None
-
+
# Flag that value update is inhibited
self.Inhibited = False
-
+
def Inhibit(self, inhibit):
"""
Set flag to inhibit or activate value update
@@ -180,23 +188,23 @@
"""
# Save inhibit flag
self.Inhibited = inhibit
-
+
# When reactivated update value and forced flag with stored values
if not inhibit and self.LastValue is not None:
self.SetForced(self.LastForced)
self.SetValue(self.LastValue)
-
+
# Reset stored values
self.LastValue = None
self.LastForced = False
-
+
def SetDataType(self, data_type):
"""
Set value IEC data type
@param data_type: Value IEC data type
"""
self.DataType = data_type
-
+
def NewValues(self, tick, values, raw="BOOL"):
"""
Function called by debug thread when a new debug value is available
@@ -206,21 +214,21 @@
@param raw: Data type of values not translated (default: 'BOOL')
"""
value, forced = values
-
+
# Translate value to IEC literal
if self.DataType != raw:
value = TYPE_TRANSLATOR.get(self.DataType, str)(value)
-
+
# Store value and forced flag when value update is inhibited
if self.Inhibited:
self.LastValue = value
self.LastForced = forced
-
+
# Update value and forced flag in any other case
else:
self.SetForced(forced)
self.SetValue(value)
-
+
def SetValue(self, value):
"""
Update value.
@@ -228,14 +236,14 @@
@param value: New value
"""
self.Value = value
-
+
def GetValue(self):
"""
Return current value
@return: Current value
"""
return self.Value
-
+
def SetForced(self, forced):
"""
Update Forced flag.
@@ -243,7 +251,7 @@
@param forced: New forced flag
"""
self.Forced = forced
-
+
def IsForced(self):
"""
Indicate if current value is forced
--- a/graphics/FBD_Objects.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/FBD_Objects.py Mon Aug 21 23:22:58 2017 +0300
@@ -27,21 +27,23 @@
from graphics.GraphicCommons import *
from plcopen.structures import *
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Function Block Diagram Block
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a function block
-"""
+# -------------------------------------------------------------------------------
+
def TestConnectorName(name, block_type):
return name in ["OUT", "MN", "MX"] or name.startswith("IN") and (block_type, name) != ("EXPT", "IN2")
+
class FBD_Block(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of a function block
+ """
+
# Create a new block
- def __init__(self, parent, type, name, id = None, extension = 0, inputs = None, connectors = {}, executionControl = False, executionOrder = 0):
+ def __init__(self, parent, type, name, id=None, extension=0, inputs=None, connectors={}, executionControl=False, executionOrder=0):
Graphic_Element.__init__(self, parent)
self.Type = None
self.Description = None
@@ -56,9 +58,9 @@
self.Pen = MiterPen(wx.BLACK)
self.SetType(type, extension, inputs, connectors, executionControl)
self.Highlights = {}
-
+
# Make a clone of this FBD_Block
- def Clone(self, parent, id = None, name = "", pos = None):
+ def Clone(self, parent, id=None, name="", pos=None):
if self.Name != "" and name == "":
name = self.Name
block = FBD_Block(parent, self.Type, name, id, self.Extension)
@@ -70,10 +72,10 @@
block.Inputs = [input.Clone(block) for input in self.Inputs]
block.Outputs = [output.Clone(block) for output in self.Outputs]
return block
-
+
def GetConnectorTranslation(self, element):
return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs))
-
+
def Flush(self):
for input in self.Inputs:
input.Flush()
@@ -81,9 +83,9 @@
for output in self.Outputs:
output.Flush()
self.Outputs = []
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if movex != 0 or movey != 0:
for input in self.Inputs:
@@ -93,26 +95,26 @@
if output.IsConnected():
rect = rect.Union(output.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Delete this block by calling the appropriate method
def Delete(self):
self.Parent.DeleteBlock(self)
-
+
# Unconnect all inputs and outputs
def Clean(self):
for input in self.Inputs:
- input.UnConnect(delete = True)
+ input.UnConnect(delete=True)
for output in self.Outputs:
- output.UnConnect(delete = True)
-
+ output.UnConnect(delete=True)
+
# Refresh the size of text for name
def RefreshNameSize(self):
self.NameSize = self.Parent.GetTextExtent(self.Name)
-
+
# Refresh the size of text for execution order
def RefreshExecutionOrderSize(self):
self.ExecutionOrderSize = self.Parent.GetTextExtent(str(self.ExecutionOrder))
-
+
# Returns if the point given is in the bounding box
def HitTest(self, pt, connectors=True):
if self.Name != "":
@@ -121,7 +123,7 @@
test_text = False
test_block = self.GetBlockBoundingBox(connectors).InsideXY(pt.x, pt.y)
return test_text or test_block
-
+
# Returns the bounding box of the name outside the block
def GetTextBoundingBox(self):
# Calculate the size of the name outside the block
@@ -130,7 +132,7 @@
self.Pos.y - (text_height + 2),
text_width,
text_height)
-
+
# Returns the bounding box of function block without name outside
def GetBlockBoundingBox(self, connectors=True):
bbx_x, bbx_y = self.Pos.x, self.Pos.y
@@ -143,13 +145,13 @@
bbx_width = max(bbx_width, bbx_width + self.Pos.x + self.ExecutionOrderSize[0] - bbx_x - self.Size[0])
bbx_height = bbx_height + (self.ExecutionOrderSize[1] + 2)
return wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
-
+
# Refresh the block bounding box
def RefreshBoundingBox(self):
self.BoundingBox = self.GetBlockBoundingBox()
if self.Name != "":
self.BoundingBox.Union(self.GetTextBoundingBox())
-
+
# Refresh the positions of the block connectors
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -170,16 +172,16 @@
self.Outputs[i].SetPosition(wx.Point(self.Size[0], ypos))
position += linesize
self.RefreshConnected()
-
+
# Refresh the positions of wires connected to inputs and outputs
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
for input in self.Inputs:
input.MoveConnected(exclude)
for output in self.Outputs:
output.MoveConnected(exclude)
-
- # Returns the block connector that starts with the point given if it exists
- def GetConnector(self, position, output_name = None, input_name = None):
+
+ # Returns the block connector that starts with the point given if it exists
+ def GetConnector(self, position, output_name=None, input_name=None):
if input_name is not None:
# Test each input connector
for input in self.Inputs:
@@ -193,14 +195,14 @@
if input_name is None and output_name is None:
return self.FindNearestConnector(position, self.Inputs + self.Outputs)
return None
-
+
def GetInputTypes(self):
return tuple([input.GetType(True) for input in self.Inputs if input.GetName() != "EN"])
-
+
def SetOutputValues(self, values):
for output in self.Outputs:
output.SetValue(values.get(ouput.getName(), None))
-
+
def GetConnectionResultType(self, connector, connectortype):
if not TestConnectorName(connector.GetName(), self.Type):
return connectortype
@@ -216,13 +218,13 @@
if resulttype is None or outputtype is not None and self.IsOfType(outputtype, resulttype):
resulttype = outputtype
return resulttype
-
+
# Returns all the block connectors
def GetConnectors(self):
- return {"inputs" : self.Inputs, "outputs" : self.Outputs}
-
+ return {"inputs": self.Inputs, "outputs": self.Outputs}
+
# Test if point given is on one of the block connectors
- def TestConnector(self, pt, direction = None, exclude = True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test each input connector
for input in self.Inputs:
if input.TestPoint(pt, direction, exclude):
@@ -232,10 +234,10 @@
if output.TestPoint(pt, direction, exclude):
return output
return None
-
+
# Changes the block type
- def SetType(self, type, extension, inputs = None, connectors = {}, executionControl = False):
- if type != self.Type or self.Extension != extension or executionControl != self.ExecutionControl:
+ def SetType(self, type, extension, inputs=None, connectors={}, executionControl=False):
+ if type != self.Type or self.Extension != extension or executionControl != self.ExecutionControl:
if type != self.Type:
self.Type = type
self.TypeSize = self.Parent.GetTextExtent(self.Type)
@@ -252,7 +254,7 @@
start = int(inputs[-1][0].replace("IN", ""))
for i in xrange(self.Extension - len(blocktype["inputs"])):
start += 1
- inputs.append(("IN%d"%start, inputs[-1][1], inputs[-1][2]))
+ inputs.append(("IN%d" % start, inputs[-1][1], inputs[-1][2]))
comment = blocktype["comment"]
self.Description = _(comment) + blocktype.get("usage", "")
else:
@@ -261,14 +263,14 @@
outputs = connectors.get("outputs", [])
self.Description = None
if self.ExecutionControl:
- inputs.insert(0, ("EN","BOOL","none"))
- outputs.insert(0, ("ENO","BOOL","none"))
+ inputs.insert(0, ("EN", "BOOL", "none"))
+ outputs.insert(0, ("ENO", "BOOL", "none"))
self.Pen = MiterPen(self.Colour)
-
+
# Extract the inputs properties and create or modify the corresponding connector
input_connectors = []
for input_name, input_type, input_modifier in inputs:
- connector = Connector(self, input_name, input_type, wx.Point(0, 0), WEST, onlyone = True)
+ connector = Connector(self, input_name, input_type, wx.Point(0, 0), WEST, onlyone=True)
if input_modifier == "negated":
connector.SetNegated(True)
elif input_modifier != "none":
@@ -282,9 +284,9 @@
break
input_connectors.append(connector)
for input in self.Inputs:
- input.UnConnect(delete = True)
+ input.UnConnect(delete=True)
self.Inputs = input_connectors
-
+
# Extract the outputs properties and create or modify the corresponding connector
output_connectors = []
for output_name, output_type, output_modifier in outputs:
@@ -302,49 +304,49 @@
break
output_connectors.append(connector)
for output in self.Outputs:
- output.UnConnect(delete = True)
+ output.UnConnect(delete=True)
self.Outputs = output_connectors
-
+
self.RefreshMinSize()
self.RefreshConnectors()
for output in self.Outputs:
output.RefreshWires()
self.RefreshBoundingBox()
-
+
# Returns the block type
def GetType(self):
return self.Type
-
+
# Changes the block name
def SetName(self, name):
self.Name = name
self.RefreshNameSize()
-
+
# Returs the block name
def GetName(self):
return self.Name
-
+
# Changes the extension name
def SetExtension(self, extension):
self.Extension = extension
-
+
# Returs the extension name
def GetExtension(self):
return self.Extension
-
+
# Changes the execution order
def SetExecutionOrder(self, executionOrder):
self.ExecutionOrder = executionOrder
self.RefreshExecutionOrderSize()
-
+
# Returs the execution order
def GetExecutionOrder(self):
return self.ExecutionOrder
-
+
# Returs the execution order
def GetExecutionControl(self):
return self.ExecutionControl
-
+
# Refresh the block minimum size
def RefreshMinSize(self):
# Calculate the inputs maximum width
@@ -360,42 +362,42 @@
width = max(self.TypeSize[0] + 10, max_input + max_output + 15)
height = (max(len(self.Inputs), len(self.Outputs)) + 1) * BLOCK_LINE_SIZE
self.MinSize = width, height
-
+
# Returns the block minimum size
def GetMinSize(self):
return self.MinSize
-
+
# Changes the negated property of the connector handled
def SetConnectorNegated(self, negated):
handle_type, handle = self.Handle
if handle_type == HANDLE_CONNECTOR:
handle.SetNegated(negated)
self.RefreshModel(False)
-
+
# Changes the edge property of the connector handled
def SetConnectorEdge(self, edge):
handle_type, handle = self.Handle
if handle_type == HANDLE_CONNECTOR:
handle.SetEdge(edge)
self.RefreshModel(False)
-
-## # Method called when a Motion event have been generated
-## def OnMotion(self, event, dc, scaling):
-## if not event.Dragging():
-## pos = event.GetLogicalPosition(dc)
-## for input in self.Inputs:
-## rect = input.GetRedrawRect()
-## if rect.InsideXY(pos.x, pos.y):
-## print "Find input"
-## tip = wx.TipWindow(self.Parent, "Test")
-## tip.SetBoundingRect(rect)
-## return Graphic_Element.OnMotion(self, event, dc, scaling)
-
+
+# # Method called when a Motion event have been generated
+# def OnMotion(self, event, dc, scaling):
+# if not event.Dragging():
+# pos = event.GetLogicalPosition(dc)
+# for input in self.Inputs:
+# rect = input.GetRedrawRect()
+# if rect.InsideXY(pos.x, pos.y):
+# print "Find input"
+# tip = wx.TipWindow(self.Parent, "Test")
+# tip.SetBoundingRect(rect)
+# return Graphic_Element.OnMotion(self, event, dc, scaling)
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the block properties
self.Parent.EditBlockContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
@@ -406,7 +408,7 @@
self.Parent.PopupBlockMenu(connector)
else:
self.Parent.PopupBlockMenu()
-
+
# Refreshes the block model
def RefreshModel(self, move=True):
self.Parent.RefreshBlockModel(self)
@@ -414,12 +416,12 @@
if move:
for output in self.Outputs:
output.RefreshWires()
-
+
def GetToolTipValue(self):
return self.Description
-
+
# Adds an highlight to the block
- def AddHighlight(self, infos, start, end ,highlight_type):
+ def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] in ["type", "name"] and start[0] == 0 and end[0] == 0:
highlights = self.Highlights.setdefault(infos[0], [])
AddHighlight(highlights, (start, end, highlight_type))
@@ -427,7 +429,7 @@
self.Inputs[infos[1]].AddHighlight(infos[2:], start, end, highlight_type)
elif infos[0] == "output" and infos[1] < len(self.Outputs):
self.Outputs[infos[1]].AddHighlight(infos[2:], start, end, highlight_type)
-
+
# Removes an highlight from the block
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] in ["type", "name"]:
@@ -438,7 +440,7 @@
self.Inputs[infos[1]].RemoveHighlight(infos[2:], start, end, highlight_type)
elif infos[0] == "output" and infos[1] < len(self.Outputs):
self.Outputs[infos[1]].RemoveHighlight(infos[2:], start, end, highlight_type)
-
+
# Removes all the highlights of one particular type from the block
def ClearHighlight(self, highlight_type=None):
if highlight_type is None:
@@ -453,14 +455,14 @@
input.ClearHighlights(highlight_type)
for output in self.Outputs:
output.ClearHighlights(highlight_type)
-
+
# Draws block
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
dc.SetPen(self.Pen)
dc.SetBrush(wx.WHITE_BRUSH)
dc.SetTextForeground(self.Colour)
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
type_size = dc.GetTextExtent(self.Type)
@@ -469,7 +471,7 @@
name_size = self.NameSize
type_size = self.TypeSize
executionorder_size = self.ExecutionOrderSize
-
+
# Draw a rectangle with the block size
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
# Draw block name and block type
@@ -487,25 +489,25 @@
if self.ExecutionOrder != 0:
# Draw block execution order
dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
- self.Pos.y + self.Size[1] + 2)
-
+ self.Pos.y + self.Size[1] + 2)
+
if not getattr(dc, "printing", False):
DrawHighlightedText(dc, self.Name, self.Highlights.get("name", []), name_pos[0], name_pos[1])
DrawHighlightedText(dc, self.Type, self.Highlights.get("type", []), type_pos[0], type_pos[1])
-
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Function Block Diagram Variable
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a variable
-"""
+# -------------------------------------------------------------------------------
+
class FBD_Variable(Graphic_Element):
+ """
+ Class that implements the graphic representation of a variable
+ """
# Create a new variable
- def __init__(self, parent, type, name, value_type, id = None, executionOrder = 0):
+ def __init__(self, parent, type, name, value_type, id=None, executionOrder=0):
Graphic_Element.__init__(self, parent)
self.Type = None
self.ValueType = None
@@ -516,9 +518,9 @@
self.Output = None
self.SetType(type, value_type)
self.Highlights = []
-
+
# Make a clone of this FBD_Variable
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
variable = FBD_Variable(parent, self.Type, self.Name, self.ValueType, id)
variable.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -530,7 +532,7 @@
if self.Output:
variable.Output = self.Output.Clone(variable)
return variable
-
+
def GetConnectorTranslation(self, element):
connectors = {}
if self.Input is not None:
@@ -538,7 +540,7 @@
if self.Output is not None:
connectors[self.Output] = element.Output
return connectors
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
@@ -546,9 +548,9 @@
if self.Output is not None:
self.Output.Flush()
self.Output = None
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if movex != 0 or movey != 0:
if self.Input and self.Input.IsConnected():
@@ -556,26 +558,26 @@
if self.Output and self.Output.IsConnected():
rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Unconnect connector
def Clean(self):
if self.Input:
- self.Input.UnConnect(delete = True)
+ self.Input.UnConnect(delete=True)
if self.Output:
- self.Output.UnConnect(delete = True)
-
+ self.Output.UnConnect(delete=True)
+
# Delete this variable by calling the appropriate method
def Delete(self):
self.Parent.DeleteVariable(self)
-
+
# Refresh the size of text for name
def RefreshNameSize(self):
self.NameSize = self.Parent.GetTextExtent(self.Name)
-
+
# Refresh the size of text for execution order
def RefreshExecutionOrderSize(self):
self.ExecutionOrderSize = self.Parent.GetTextExtent(str(self.ExecutionOrder))
-
+
# Refresh the variable bounding box
def RefreshBoundingBox(self):
if self.Type in (OUTPUT, INOUT):
@@ -594,7 +596,7 @@
bbx_width = max(bbx_width, bbx_width + self.Pos.x + self.ExecutionOrderSize[0] - bbx_x - self.Size[0])
bbx_height = bbx_height + (self.ExecutionOrderSize[1] + 2)
self.BoundingBox = wx.Rect(bbx_x, self.Pos.y, bbx_width + 1, bbx_height + 1)
-
+
# Refresh the position of the variable connector
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -607,28 +609,28 @@
if self.Output:
self.Output.SetPosition(wx.Point(self.Size[0], position))
self.RefreshConnected()
-
+
# Refresh the position of wires connected to connector
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
if self.Input:
self.Input.MoveConnected(exclude)
if self.Output:
self.Output.MoveConnected(exclude)
-
+
# Test if point given is on the variable connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
if self.Input and self.Input.TestPoint(pt, direction, exclude):
return self.Input
if self.Output and self.Output.TestPoint(pt, direction, exclude):
return self.Output
return None
-
- # Returns the block connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the block connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test input and output connector if they exists
- #if self.Input and name == self.Input.GetName():
+ # if self.Input and name == self.Input.GetName():
# return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
@@ -640,8 +642,8 @@
if self.Output:
connectors.append(self.Output)
return self.FindNearestConnector(position, connectors)
-
- # Returns all the block connectors
+
+ # Returns all the block connectors
def GetConnectors(self):
connectors = {"inputs": [], "outputs": []}
if self.Input:
@@ -649,14 +651,14 @@
if self.Output:
connectors["outputs"].append(self.Output)
return connectors
-
+
# Changes the negated property of the variable connector if handled
def SetConnectorNegated(self, negated):
handle_type, handle = self.Handle
if handle_type == HANDLE_CONNECTOR:
handle.SetNegated(negated)
self.RefreshModel(False)
-
+
# Changes the variable type
def SetType(self, type, value_type):
if type != self.Type:
@@ -664,15 +666,15 @@
# Create an input or output connector according to variable type
if self.Type != INPUT:
if self.Input is None:
- self.Input = Connector(self, "", value_type, wx.Point(0, 0), WEST, onlyone = True)
+ self.Input = Connector(self, "", value_type, wx.Point(0, 0), WEST, onlyone=True)
elif self.Input:
- self.Input.UnConnect(delete = True)
+ self.Input.UnConnect(delete=True)
self.Input = None
if self.Type != OUTPUT:
if self.Output is None:
self.Output = Connector(self, "", value_type, wx.Point(0, 0), EAST)
elif self.Output:
- self.Output.UnConnect(delete = True)
+ self.Output.UnConnect(delete=True)
self.Output = None
self.RefreshConnectors()
self.RefreshBoundingBox()
@@ -680,38 +682,38 @@
if self.Input:
self.Input.SetType(value_type)
if self.Output:
- self.Output.SetType(value_type)
-
+ self.Output.SetType(value_type)
+
# Returns the variable type
def GetType(self):
return self.Type
-
+
# Returns the variable value type
def GetValueType(self):
return self.ValueType
-
+
# Changes the variable name
def SetName(self, name):
self.Name = name
self.RefreshNameSize()
-
+
# Returns the variable name
def GetName(self):
return self.Name
-
+
# Changes the execution order
def SetExecutionOrder(self, executionOrder):
self.ExecutionOrder = executionOrder
self.RefreshExecutionOrderSize()
-
+
# Returs the execution order
def GetExecutionOrder(self):
return self.ExecutionOrder
-
+
# Returns the variable minimum size
def GetMinSize(self):
return self.NameSize[0] + 10, self.NameSize[1] + 10
-
+
# Set size of the variable to the minimum size
def SetBestSize(self, scaling):
if self.Type == INPUT:
@@ -720,22 +722,22 @@
return Graphic_Element.SetBestSize(self, scaling, x_factor=0.)
else:
return Graphic_Element.SetBestSize(self, scaling)
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
if event.ControlDown():
- # Change variable type
+ # Change variable type
types = [INPUT, OUTPUT, INOUT]
- self.Parent.ChangeVariableType(self,
- types[(types.index(self.Type) + 1) % len(types)])
+ self.Parent.ChangeVariableType(
+ self, types[(types.index(self.Type) + 1) % len(types)])
else:
# Edit the variable properties
self.Parent.EditVariableContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
self.Parent.PopupVariableMenu()
-
+
# Refreshes the variable model
def RefreshModel(self, move=True):
self.Parent.RefreshVariableModel(self)
@@ -744,35 +746,35 @@
if move and self.Type != OUTPUT:
if self.Output:
self.Output.RefreshWires()
-
+
# Adds an highlight to the variable
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "expression" and start[0] == 0 and end[0] == 0:
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the variable
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] == "expression":
RemoveHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes all the highlights of one particular type from the variable
def ClearHighlight(self, highlight_type=None):
ClearHighlights(self.Highlights, highlight_type)
-
+
# Draws variable
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.WHITE_BRUSH)
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
executionorder_size = dc.GetTextExtent(str(self.ExecutionOrder))
else:
name_size = self.NameSize
executionorder_size = self.ExecutionOrderSize
-
- text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+
+ text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
self.Pos.y + (self.Size[1] - name_size[1]) / 2)
# Draw a rectangle with the variable size
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
@@ -781,27 +783,28 @@
# Draw connectors
if self.Input:
self.Input.Draw(dc)
- if self.Output:
+ if self.Output:
self.Output.Draw(dc)
if self.ExecutionOrder != 0:
# Draw variable execution order
dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
- self.Pos.y + self.Size[1] + 2)
+ self.Pos.y + self.Size[1] + 2)
if not getattr(dc, "printing", False):
DrawHighlightedText(dc, self.Name, self.Highlights, text_pos[0], text_pos[1])
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Function Block Diagram Connector
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a connection
-"""
+# -------------------------------------------------------------------------------
+
class FBD_Connector(Graphic_Element):
+ """
+ Class that implements the graphic representation of a connection
+ """
# Create a new connection
- def __init__(self, parent, type, name, id = None):
+ def __init__(self, parent, type, name, id=None):
Graphic_Element.__init__(self, parent)
self.Type = type
self.Id = id
@@ -811,27 +814,27 @@
self.Highlights = []
# Create an input or output connector according to connection type
if self.Type == CONNECTOR:
- self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), WEST, onlyone = True)
+ self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), WEST, onlyone=True)
else:
self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), EAST)
self.RefreshConnectors()
self.RefreshNameSize()
-
+
def Flush(self):
if self.Connector:
self.Connector.Flush()
self.Connector = None
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if movex != 0 or movey != 0:
if self.Connector and self.Connector.IsConnected():
rect = rect.Union(self.Connector.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Make a clone of this FBD_Connector
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
connection = FBD_Connector(parent, self.Type, self.Name, id)
connection.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -840,23 +843,23 @@
connection.SetPosition(self.Pos.x, self.Pos.y)
connection.Connector = self.Connector.Clone(connection)
return connection
-
+
def GetConnectorTranslation(self, element):
- return {self.Connector : element.Connector}
+ return {self.Connector: element.Connector}
# Unconnect connector
def Clean(self):
if self.Connector:
- self.Connector.UnConnect(delete = True)
-
+ self.Connector.UnConnect(delete=True)
+
# Delete this connection by calling the appropriate method
def Delete(self):
self.Parent.DeleteConnection(self)
-
+
# Refresh the size of text for name
def RefreshNameSize(self):
self.NameSize = self.Parent.GetTextExtent(self.Name)
-
+
# Refresh the connection bounding box
def RefreshBoundingBox(self):
if self.Type == CONNECTOR:
@@ -865,7 +868,7 @@
bbx_x = self.Pos.x
bbx_width = self.Size[0] + CONNECTOR_SIZE
self.BoundingBox = wx.Rect(bbx_x, self.Pos.y, bbx_width, self.Size[1])
-
+
# Refresh the position of the connection connector
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -878,23 +881,23 @@
else:
self.Connector.SetPosition(wx.Point(self.Size[0], position))
self.RefreshConnected()
-
+
# Refresh the position of wires connected to connector
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
if self.Connector:
self.Connector.MoveConnected(exclude)
-
+
# Test if point given is on the connection connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
if self.Connector and self.Connector.TestPoint(pt, direction, exclude):
return self.Connector
return None
-
+
# Returns the connection connector
- def GetConnector(self, position = None, name = None):
+ def GetConnector(self, position=None, name=None):
return self.Connector
-
- # Returns all the block connectors
+
+ # Returns all the block connectors
def GetConnectors(self):
connectors = {"inputs": [], "outputs": []}
if self.Type == CONNECTOR:
@@ -918,50 +921,50 @@
self.Clean()
# Create an input or output connector according to connection type
if self.Type == CONNECTOR:
- self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), WEST, onlyone = True)
+ self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), WEST, onlyone=True)
else:
self.Connector = Connector(self, "", "ANY", wx.Point(0, 0), EAST)
self.RefreshConnectors()
self.RefreshBoundingBox()
-
+
# Returns the connection type
def GetType(self):
return self.Type
-
+
def GetConnectionResultType(self, connector, connectortype):
if self.Type == CONTINUATION:
connector = self.Parent.GetConnectorByName(self.Name)
if connector is not None:
return connector.Connector.GetConnectedType()
return connectortype
-
+
# Changes the connection name
def SetName(self, name):
self.Name = name
self.RefreshNameSize()
-
+
# Returns the connection name
def GetName(self):
return self.Name
-
+
# Set size of the variable to the minimum size
def SetBestSize(self, scaling):
if self.Type == CONTINUATION:
return Graphic_Element.SetBestSize(self, scaling, x_factor=1.)
else:
return Graphic_Element.SetBestSize(self, scaling, x_factor=0.)
-
+
# Returns the connection minimum size
def GetMinSize(self):
text_width, text_height = self.NameSize
if text_height % 2 == 1:
text_height += 1
return text_width + text_height + 20, text_height + 10
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
if event.ControlDown():
- # Change connection type
+ # Change connection type
if self.Type == CONNECTOR:
self.Parent.ChangeConnectionType(self, CONTINUATION)
else:
@@ -969,12 +972,12 @@
else:
# Edit the connection properties
self.Parent.EditConnectionContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupConnectionMenu()
-
+
# Refreshes the connection model
def RefreshModel(self, move=True):
self.Parent.RefreshConnectionModel(self)
@@ -983,51 +986,50 @@
if move and self.Type == CONTINUATION:
if self.Connector:
self.Connector.RefreshWires()
-
+
# Adds an highlight to the connection
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "name" and start[0] == 0 and end[0] == 0:
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the connection
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] == "name":
RemoveHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes all the highlights of one particular type from the connection
def ClearHighlight(self, highlight_type=None):
ClearHighlights(self.Highlights, highlight_type)
-
+
# Draws connection
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.WHITE_BRUSH)
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
else:
name_size = self.NameSize
-
+
# Draw a rectangle with the connection size with arrows inside
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
arrowsize = min(self.Size[1] / 2, (self.Size[0] - name_size[0] - 10) / 2)
- dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize,
- self.Pos.y + self.Size[1] / 2)
- dc.DrawLine(self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2,
- self.Pos.x, self.Pos.y + self.Size[1])
- dc.DrawLine(self.Pos.x + self.Size[0] - arrowsize, self.Pos.y,
- self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2)
- dc.DrawLine(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2,
- self.Pos.x + self.Size[0] - arrowsize, self.Pos.y + self.Size[1])
+ dc.DrawLine(self.Pos.x, self.Pos.y, self.Pos.x + arrowsize,
+ self.Pos.y + self.Size[1] / 2)
+ dc.DrawLine(self.Pos.x + arrowsize, self.Pos.y + self.Size[1] / 2,
+ self.Pos.x, self.Pos.y + self.Size[1])
+ dc.DrawLine(self.Pos.x + self.Size[0] - arrowsize, self.Pos.y,
+ self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2)
+ dc.DrawLine(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1] / 2,
+ self.Pos.x + self.Size[0] - arrowsize, self.Pos.y + self.Size[1])
# Draw connection name
- text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+ text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
self.Pos.y + (self.Size[1] - name_size[1]) / 2)
dc.DrawText(self.Name, text_pos[0], text_pos[1])
# Draw connector
if self.Connector:
self.Connector.Draw(dc)
-
+
if not getattr(dc, "printing", False):
DrawHighlightedText(dc, self.Name, self.Highlights, text_pos[0], text_pos[1])
-
--- a/graphics/GraphicCommons.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/GraphicCommons.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,14 +26,14 @@
from math import *
from types import *
import datetime
-from threading import Lock,Timer
+from threading import Lock, Timer
from graphics.ToolTipProducer import ToolTipProducer
from graphics.DebugDataConsumer import DebugDataConsumer
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Common constants
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
"""
Definition of constants for dimensions of graphic elements
@@ -78,17 +78,17 @@
[HANDLE_MOVE, HANDLE_RESIZE, HANDLE_POINT, HANDLE_SEGMENT, HANDLE_CONNECTOR] = range(5)
# List of value for resize handle that are valid
-VALID_HANDLES = [(1,1), (1,2), (1,3), (2,3), (3,3), (3,2), (3,1), (2,1)]
+VALID_HANDLES = [(1, 1), (1, 2), (1, 3), (2, 3), (3, 3), (3, 2), (3, 1), (2, 1)]
# Contants for defining the direction of a connector
-[EAST, NORTH, WEST, SOUTH] = [(1,0), (0,-1), (-1,0), (0,1)]
-
-# Contants for defining which mode is selected for each view
-[MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT,
- MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP,
+[EAST, NORTH, WEST, SOUTH] = [(1, 0), (0, -1), (-1, 0), (0, 1)]
+
+# Contants for defining which mode is selected for each view
+[MODE_SELECTION, MODE_BLOCK, MODE_VARIABLE, MODE_CONNECTION, MODE_COMMENT,
+ MODE_COIL, MODE_CONTACT, MODE_POWERRAIL, MODE_INITIALSTEP, MODE_STEP,
MODE_TRANSITION, MODE_DIVERGENCE, MODE_JUMP, MODE_ACTION, MODE_MOTION] = range(15)
-# Contants for defining alignment types for graphic group
+# Contants for defining alignment types for graphic group
[ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM] = range(6)
# Contants for defining which drawing mode is selected for app
@@ -105,16 +105,17 @@
REFRESH_HIGHLIGHT_PERIOD = 0.1
HANDLE_CURSORS = {
- (1, 1) : 2,
- (3, 3) : 2,
- (1, 3) : 3,
- (3, 1) : 3,
- (1, 2) : 4,
- (3, 2) : 4,
- (2, 1) : 5,
- (2, 3) : 5
+ (1, 1): 2,
+ (3, 3): 2,
+ (1, 3): 3,
+ (3, 1): 3,
+ (1, 2): 4,
+ (3, 2): 4,
+ (2, 1): 5,
+ (2, 3): 5
}
+
def round_scaling(x, n, constraint=0):
fraction = float(x) / float(n)
if constraint == -1:
@@ -122,26 +123,36 @@
else:
xround = round(fraction)
if constraint == 1 and xround < fraction:
- xround += 1
+ xround += 1
return int(xround * n)
+
"""
Basic vector operations for calculate wire points
"""
-# Create a vector from two points and define if vector must be normal
-def vector(p1, p2, normal = True):
+
+def vector(p1, p2, normal=True):
+ """
+ Create a vector from two points and define if vector must be normal
+ """
vector = (p2.x - p1.x, p2.y - p1.y)
if normal:
return normalize(vector)
return vector
-# Calculate the norm of a given vector
+
def norm(v):
+ """
+ Calculate the norm of a given vector
+ """
return sqrt(v[0] * v[0] + v[1] * v[1])
-# Normalize a given vector
+
def normalize(v):
+ """
+ Normalize a given vector
+ """
v_norm = norm(v)
# Verifie if it is not a null vector
if v_norm > 0:
@@ -149,24 +160,32 @@
else:
return v
-# Calculate the scalar product of two vectors
+
def is_null_vector(v):
+ """
+ Calculate the scalar product of two vectors
+ """
return v == (0, 0)
-# Calculate the scalar product of two vectors
+
def add_vectors(v1, v2):
+ """
+ Calculate the scalar product of two vectors
+ """
return (v1[0] + v2[0], v1[1] + v2[1])
-# Calculate the scalar product of two vectors
+
def product(v1, v2):
+ """
+ Calculate the scalar product of two vectors
+ """
return v1[0] * v2[0] + v1[1] * v2[1]
-"""
-Function that calculates the nearest point of the grid defined by scaling for the given point
-"""
-
def GetScaledEventPosition(event, dc, scaling):
+ """
+ Function that calculates the nearest point of the grid defined by scaling for the given point
+ """
pos = event.GetLogicalPosition(dc)
if scaling:
pos.x = round(float(pos.x) / float(scaling[0])) * scaling[0]
@@ -174,11 +193,10 @@
return pos
-"""
-Function that choose a direction during the wire points generation
-"""
-
def DirectionChoice(v_base, v_target, dir_target):
+ """
+ Function that choose a direction during the wire points generation
+ """
dir_product = product(v_base, v_target)
if dir_product < 0:
return (-v_base[0], -v_base[1])
@@ -186,31 +204,37 @@
return dir_target
return v_base
+
def MiterPen(colour, width=1, style=wx.SOLID):
pen = wx.Pen(colour, width, style)
pen.SetJoin(wx.JOIN_MITER)
pen.SetCap(wx.CAP_PROJECTING)
return pen
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Helpers for highlighting text
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def AddHighlight(highlights, infos):
RemoveHighlight(highlights, infos)
highlights.append(infos)
+
def RemoveHighlight(highlights, infos):
if infos in highlights:
highlights.remove(infos)
return True
return False
+
def ClearHighlight(highlights, highlight_type=None):
if highlight_type is not None:
return [highlight for highlight in highlights if highlight[2] != highlight_type]
return []
+
def DrawHighlightedText(dc, text, highlights, x, y):
current_pen = dc.GetPen()
dc.SetPen(wx.TRANSPARENT_PEN)
@@ -224,26 +248,27 @@
dc.DrawText(part, x + offset_width, y)
dc.SetPen(current_pen)
dc.SetTextForeground(wx.BLACK)
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Graphic element base class
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a generic graphic element
-"""
+# -------------------------------------------------------------------------------
+
class Graphic_Element(ToolTipProducer):
-
+ """
+ Class that implements a generic graphic element
+ """
+
# Create a new graphic element
- def __init__(self, parent, id = None):
+ def __init__(self, parent, id=None):
ToolTipProducer.__init__(self, parent)
self.Parent = parent
self.Id = id
self.oldPos = None
self.StartPos = None
self.CurrentDrag = None
- self.Handle = (None,None)
+ self.Handle = (None, None)
self.Dragging = False
self.Selected = False
self.Highlighted = False
@@ -251,22 +276,22 @@
self.Size = wx.Size(0, 0)
self.BoundingBox = wx.Rect(0, 0, 0, 0)
self.Visible = False
-
+
def GetDefinition(self):
return [self.Id], []
-
+
def TestVisible(self, screen):
self.Visible = self.Selected or self.GetRedrawRect().Intersects(screen)
-
+
def IsVisible(self):
return self.Visible
-
+
def SpreadCurrent(self):
pass
-
+
def GetConnectorTranslation(self, element):
return {}
-
+
def FindNearestConnector(self, position, connectors):
distances = []
for connector in connectors:
@@ -278,20 +303,20 @@
if len(distances) > 0:
return distances[0][1]
return None
-
+
def IsOfType(self, type, reference):
return self.Parent.IsOfType(type, reference)
-
+
def IsEndType(self, type):
return self.Parent.IsEndType(type)
-
+
def GetDragging(self):
return self.Dragging
-
+
# Make a clone of this element
def Clone(self, parent):
return Graphic_Element(parent, self.Id)
-
+
# Changes the block position
def SetPosition(self, x, y):
self.Pos.x = x
@@ -302,7 +327,7 @@
# Returns the block position
def GetPosition(self):
return self.Pos.x, self.Pos.y
-
+
# Changes the element size
def SetSize(self, width, height):
self.Size.SetWidth(width)
@@ -313,11 +338,11 @@
# Returns the element size
def GetSize(self):
return self.Size.GetWidth(), self.Size.GetHeight()
-
+
# Returns the minimum element size
def GetMinSize(self):
return 0, 0
-
+
# Set size of the element to the minimum size
def SetBestSize(self, scaling, x_factor=0.5, y_factor=0.5):
width, height = self.GetSize()
@@ -336,31 +361,31 @@
height = round_scaling(height, scaling[1], 1)
self.SetSize(width, height)
return self.Pos.x - posx, self.Pos.y - posy
-
+
# Refresh the element Bounding Box
def RefreshBoundingBox(self):
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
-
+
# Refresh the element connectors position
def RefreshConnectors(self):
pass
-
+
# Refresh the position of wires connected to element inputs and outputs
def RefreshConnected(self):
pass
-
+
# Change the parent
def SetParent(self, parent):
self.Parent = parent
-
+
# Override this method for defining the method to call for deleting this element
def Delete(self):
pass
-
+
# Returns the Id
def GetId(self):
return self.Id
-
+
# Returns if the point given is in the bounding box
def HitTest(self, pt, connectors=True):
if connectors:
@@ -368,21 +393,21 @@
else:
rect = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0], self.Size[1])
return rect.InsideXY(pt.x, pt.y)
-
+
# Returns if the point given is in the bounding box
def IsInSelection(self, rect):
return rect.InsideXY(self.BoundingBox.x, self.BoundingBox.y) and rect.InsideXY(self.BoundingBox.x + self.BoundingBox.width, self.BoundingBox.y + self.BoundingBox.height)
-
+
# Override this method for refreshing the bounding box
def RefreshBoundingBox(self):
pass
-
+
# Returns the bounding box
def GetBoundingBox(self):
return self.BoundingBox
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
scalex, scaley = self.Parent.GetViewScale()
rect = wx.Rect()
rect.x = self.BoundingBox.x - int(HANDLE_SIZE / scalex) - 3 - abs(movex)
@@ -390,42 +415,42 @@
rect.width = self.BoundingBox.width + 2 * (int(HANDLE_SIZE / scalex) + abs(movex) + 1) + 4
rect.height = self.BoundingBox.height + 2 * (int(HANDLE_SIZE / scaley) + abs(movey) + 1) + 4
return rect
-
- def Refresh(self, rect = None):
+
+ def Refresh(self, rect=None):
if self.Visible:
if rect is not None:
self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False)
else:
self.Parent.RefreshRect(self.Parent.GetScrolledRect(self.GetRedrawRect()), False)
-
+
# Change the variable that indicates if this element is selected
def SetSelected(self, selected):
self.Selected = selected
self.Refresh()
-
+
# Change the variable that indicates if this element is highlighted
def SetHighlighted(self, highlighted):
self.Highlighted = highlighted
self.Refresh()
-
+
# Test if the point is on a handle of this element
def TestHandle(self, event):
dc = self.Parent.GetLogicalDC()
scalex, scaley = dc.GetUserScale()
pos = event.GetPosition()
pt = wx.Point(*self.Parent.CalcUnscrolledPosition(pos.x, pos.y))
-
+
left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE
center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2
right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex
-
+
top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE
middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2
bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley
-
+
extern_rect = wx.Rect(left, top, right + HANDLE_SIZE - left, bottom + HANDLE_SIZE - top)
intern_rect = wx.Rect(left + HANDLE_SIZE, top + HANDLE_SIZE, right - left - HANDLE_SIZE, bottom - top - HANDLE_SIZE)
-
+
# Verify that this element is selected
if self.Selected and extern_rect.InsideXY(pt.x, pt.y) and not intern_rect.InsideXY(pt.x, pt.y):
# Find if point is on a handle horizontally
@@ -450,7 +475,7 @@
if (handle_x, handle_y) in VALID_HANDLES:
return handle_x, handle_y
return 0, 0
-
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
pos = event.GetLogicalPosition(dc)
@@ -469,7 +494,7 @@
self.oldPos = GetScaledEventPosition(event, dc, scaling)
self.StartPos = wx.Point(self.Pos.x, self.Pos.y)
self.CurrentDrag = wx.Point(0, 0)
-
+
# Method called when a LeftUp event have been generated
def OnLeftUp(self, event, dc, scaling):
# If a dragging have been initiated
@@ -498,7 +523,7 @@
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
pass
-
+
# Method called when a Motion event have been generated
def OnMotion(self, event, dc, scaling):
# If the cursor is dragging and the element have been clicked
@@ -532,19 +557,19 @@
return 0, 0
# Moves the element
- def Move(self, dx, dy, exclude = []):
+ def Move(self, dx, dy, exclude=[]):
self.Pos.x += max(-self.BoundingBox.x, dx)
self.Pos.y += max(-self.BoundingBox.y, dy)
self.RefreshConnected(exclude)
self.RefreshBoundingBox()
-
+
# Resizes the element from position and size given
def Resize(self, x, y, width, height):
self.Move(x, y)
self.SetSize(width, height)
-
+
# Refreshes the element state according to move defined and handle selected
- def ProcessDragging(self, movex, movey, event, scaling, width_fac = 1, height_fac = 1):
+ def ProcessDragging(self, movex, movey, event, scaling, width_fac=1, height_fac=1):
handle_type, handle = self.Handle
# If it is a resize handle, calculate the values from resizing
if handle_type == HANDLE_RESIZE:
@@ -618,27 +643,27 @@
movey = self.StartPos.y - self.Pos.y
else:
movex = self.StartPos.x - self.Pos.x
- movey = self.StartPos.y + self.CurrentDrag.y - self.Pos.y
+ movey = self.StartPos.y + self.CurrentDrag.y - self.Pos.y
self.Move(movex, movey)
return movex, movey
return 0, 0
-
+
# Override this method for defining the method to call for adding an highlight to this element
def AddHighlight(self, infos, start, end, highlight_type):
pass
-
+
# Override this method for defining the method to call for removing an highlight from this element
def RemoveHighlight(self, infos, start, end, highlight_type):
pass
-
+
# Override this method for defining the method to call for removing all the highlights of one particular type from this element
def ClearHighlight(self, highlight_type=None):
pass
-
+
# Override this method for defining the method to call for refreshing the model of this element
def RefreshModel(self, move=True):
pass
-
+
# Draws the highlightment of this element if it is highlighted (can be overwritten)
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -646,13 +671,13 @@
dc.SetPen(MiterPen(HIGHLIGHTCOLOR))
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
dc.SetLogicalFunction(wx.AND)
- dc.DrawRectangle(int(round((self.Pos.x - 1) * scalex)) - 2,
- int(round((self.Pos.y - 1) * scaley)) - 2,
- int(round((self.Size.width + 3) * scalex)) + 5,
+ dc.DrawRectangle(int(round((self.Pos.x - 1) * scalex)) - 2,
+ int(round((self.Pos.y - 1) * scaley)) - 2,
+ int(round((self.Size.width + 3) * scalex)) + 5,
int(round((self.Size.height + 3) * scaley)) + 5)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Draws the handles of this element if it is selected
def Draw(self, dc):
if not getattr(dc, "printing", False):
@@ -663,55 +688,55 @@
dc.SetUserScale(1, 1)
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.BLACK_BRUSH)
-
+
left = (self.BoundingBox.x - 2) * scalex - HANDLE_SIZE
center = (self.BoundingBox.x + self.BoundingBox.width / 2) * scalex - HANDLE_SIZE / 2
right = (self.BoundingBox.x + self.BoundingBox.width + 2) * scalex
-
+
top = (self.BoundingBox.y - 2) * scaley - HANDLE_SIZE
middle = (self.BoundingBox.y + self.BoundingBox.height / 2) * scaley - HANDLE_SIZE / 2
bottom = (self.BoundingBox.y + self.BoundingBox.height + 2) * scaley
-
+
for x, y in [(left, top), (center, top), (right, top),
(left, middle), (right, middle),
(left, bottom), (center, bottom), (right, bottom)]:
dc.DrawRectangle(x, y, HANDLE_SIZE, HANDLE_SIZE)
-
+
dc.SetUserScale(scalex, scaley)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Group of graphic elements
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a group of graphic elements
-"""
+# -------------------------------------------------------------------------------
+
class Graphic_Group(Graphic_Element):
-
+ """
+ Class that implements a group of graphic elements
+ """
+
# Create a new group of graphic elements
def __init__(self, parent):
Graphic_Element.__init__(self, parent)
self.Elements = []
self.RefreshWireExclusion()
self.RefreshBoundingBox()
-
+
# Destructor
def __del__(self):
self.Elements = []
-
+
def GetDefinition(self):
- blocks = []
+ blocks = []
wires = []
for element in self.Elements:
block, wire = element.GetDefinition()
blocks.extend(block)
wires.extend(wire)
return blocks, wires
-
+
# Make a clone of this element
- def Clone(self, parent, pos = None):
+ def Clone(self, parent, pos=None):
group = Graphic_Group(parent)
connectors = {}
exclude_names = {}
@@ -729,9 +754,9 @@
if parent.IsNamedElement(element):
name = parent.GenerateNewName(element, exclude_names)
exclude_names[name.upper()] = True
- new_element = element.Clone(parent, newid, name, pos = new_pos)
+ new_element = element.Clone(parent, newid, name, pos=new_pos)
else:
- new_element = element.Clone(parent, newid, pos = new_pos)
+ new_element = element.Clone(parent, newid, pos=new_pos)
new_element.SetBestSize(parent.Scaling)
else:
new_element = element.Clone(parent)
@@ -751,20 +776,20 @@
if not isinstance(element, Wire):
parent.AddBlockInModel(element)
return group
-
+
def CanAddBlocks(self, parent):
valid = True
for element in self.Elements:
if not isinstance(element, Wire):
valid &= parent.CanAddElement(element)
return valid
-
+
def IsVisible(self):
for element in self.Elements:
if element.IsVisible():
return True
return False
-
+
# Refresh the list of wire excluded
def RefreshWireExclusion(self):
self.WireExcluded = []
@@ -774,9 +799,9 @@
endblock = element.EndConnected.GetParentBlock()
if startblock in self.Elements and endblock in self.Elements:
self.WireExcluded.append(element)
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = None
for element in self.Elements:
if rect is None:
@@ -784,41 +809,41 @@
else:
rect = rect.Union(element.GetRedrawRect(movex, movey))
return rect
-
+
# Clean this group of elements
def Clean(self):
# Clean all the elements of the group
for element in self.Elements:
element.Clean()
-
+
# Delete this group of elements
def Delete(self):
# Delete all the elements of the group
for element in self.Elements:
element.Delete()
self.WireExcluded = []
-
+
# Returns if the point given is in the bounding box of one of the elements of this group
def HitTest(self, pt, connectors=True):
result = False
for element in self.Elements:
result |= element.HitTest(pt, connectors)
return result
-
+
# Returns if the element given is in this group
def IsElementIn(self, element):
return element in self.Elements
-
+
# Change the elements of the group
def SetElements(self, elements):
self.Elements = elements
self.RefreshWireExclusion()
self.RefreshBoundingBox()
-
+
# Returns the elements of the group
def GetElements(self):
return self.Elements
-
+
# Align the group elements
def AlignElements(self, horizontally, vertically):
minx = self.BoundingBox.x + self.BoundingBox.width
@@ -854,11 +879,11 @@
element.Move(movex, movey)
element.RefreshModel()
self.RefreshBoundingBox()
-
+
# Add the given element to the group of elements
def AddElement(self, element):
self.Elements.append(element)
-
+
# Remove or select the given element if it is or not in the group
def SelectElement(self, element):
if element in self.Elements:
@@ -867,7 +892,7 @@
self.Elements.append(element)
self.RefreshWireExclusion()
self.RefreshBoundingBox()
-
+
# Move this group of elements
def Move(self, movex, movey):
movex = max(-self.BoundingBox.x, movex)
@@ -879,7 +904,7 @@
elif element in self.WireExcluded:
element.Move(movex, movey, True)
self.RefreshBoundingBox()
-
+
# Refreshes the bounding box of this group of elements
def RefreshBoundingBox(self):
if len(self.Elements) > 0:
@@ -902,7 +927,7 @@
# Forbids to change the group position
def SetPosition(x, y):
pass
-
+
# Returns the position of this group
def GetPosition(self, exclude_wires=False):
if exclude_wires:
@@ -919,15 +944,15 @@
return 0, 0
return posx, posy
return self.BoundingBox.x, self.BoundingBox.y
-
+
# Forbids to change the group size
def SetSize(width, height):
pass
-
+
# Returns the size of this group
def GetSize(self):
return self.BoundingBox.width, self.BoundingBox.height
-
+
# Set size of the group elements to their minimum size
def SetBestSize(self, scaling):
max_movex = max_movey = 0
@@ -936,7 +961,7 @@
max_movex = max(max_movex, movex)
max_movey = max(max_movey, movey)
return max_movex, max_movey
-
+
# Refreshes the group elements to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
handle_type, handle = self.Handle
@@ -960,17 +985,17 @@
self.Move(movex, movey)
return movex, movey
return 0, 0
-
+
# Change the variable that indicates if this element is highlighted
def SetHighlighted(self, highlighted):
for element in self.Elements:
element.SetHighlighted(highlighted)
-
+
def HighlightPoint(self, pos):
for element in self.Elements:
if isinstance(element, Wire):
element.HighlightPoint(pos)
-
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
Graphic_Element.OnLeftDown(self, event, dc, scaling)
@@ -998,18 +1023,19 @@
for element in self.Elements:
element.Draw(dc)
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Connector for all types of blocks
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a connector for any type of block
-"""
+# -------------------------------------------------------------------------------
+
class Connector(DebugDataConsumer, ToolTipProducer):
-
+ """
+ Class that implements a connector for any type of block
+ """
+
# Create a new connector
- def __init__(self, parent, name, type, position, direction, negated = False, edge = "none", onlyone = False):
+ def __init__(self, parent, name, type, position, direction, negated=False, edge="none", onlyone=False):
DebugDataConsumer.__init__(self)
ToolTipProducer.__init__(self, parent.Parent)
self.ParentBlock = parent
@@ -1033,15 +1059,15 @@
self.Selected = False
self.Highlights = []
self.RefreshNameSize()
-
+
def Flush(self):
self.ParentBlock = None
for wire, handle in self.Wires:
wire.Flush()
self.Wires = []
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
parent_pos = self.ParentBlock.GetPosition()
x = min(parent_pos[0] + self.Pos.x, parent_pos[0] + self.Pos.x + self.Direction[0] * CONNECTOR_SIZE)
y = min(parent_pos[1] + self.Pos.y, parent_pos[1] + self.Pos.y + self.Direction[1] * CONNECTOR_SIZE)
@@ -1060,43 +1086,44 @@
if self.Edge == "rising" and self.Direction[1] == 1:
y -= 5
height += 5
- rect = wx.Rect(x - abs(movex), y - abs(movey), width + 2 * abs(movex), height + 2 * abs(movey))
+ rect = wx.Rect(x - abs(movex), y - abs(movey), width + 2 * abs(movex), height + 2 * abs(movey))
if self.ValueSize is None and isinstance(self.ComputedValue, (StringType, UnicodeType)):
self.ValueSize = self.ParentBlock.Parent.GetMiniTextExtent(self.ComputedValue)
if self.ValueSize is not None:
width, height = self.ValueSize
- rect = rect.Union(wx.Rect(
- parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] + \
- width * (self.Direction[0] - 1) / 2,
- parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] + \
- height * (self.Direction[1] - 1),
+ rect = rect.Union(
+ wx.Rect(
+ parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] +
+ width * (self.Direction[0] - 1) / 2,
+ parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] +
+ height * (self.Direction[1] - 1),
width, height))
return rect
-
+
# Change the connector selection
def SetSelected(self, selected):
self.Selected = selected
-
+
# Make a clone of the connector
- def Clone(self, parent = None):
+ def Clone(self, parent=None):
if parent is None:
parent = self.ParentBlock
return Connector(parent, self.Name, self.Type, wx.Point(self.Pos[0], self.Pos[1]),
- self.Direction, self.Negated)
-
+ self.Direction, self.Negated)
+
# Returns the connector parent block
def GetParentBlock(self):
return self.ParentBlock
-
+
# Returns the connector type
- def GetType(self, raw = False):
+ def GetType(self, raw=False):
if self.ParentBlock.IsEndType(self.Type) or raw:
return self.Type
elif (self.Negated or self.Edge != "none") and self.ParentBlock.IsOfType("BOOL", self.Type):
return "BOOL"
else:
return self.ParentBlock.GetConnectionResultType(self, self.Type)
-
+
# Returns the connector type
def GetConnectedType(self):
if self.ParentBlock.IsEndType(self.Type):
@@ -1104,7 +1131,7 @@
elif len(self.Wires) == 1:
return self.Wires[0][0].GetOtherConnectedType(self.Wires[0][1])
return self.Type
-
+
# Returns the connector type
def GetConnectedRedrawRect(self, movex, movey):
rect = None
@@ -1114,22 +1141,22 @@
else:
rect = rect.Union(wire.GetRedrawRect())
return rect
-
+
# Returns if connector type is compatible with type given
def IsCompatible(self, type):
reference = self.GetType()
return self.ParentBlock.IsOfType(type, reference) or self.ParentBlock.IsOfType(reference, type)
-
+
# Changes the connector name
def SetType(self, type):
self.Type = type
for wire, handle in self.Wires:
wire.SetValid(wire.IsConnectedCompatible())
-
+
# Returns the connector name
def GetName(self):
return self.Name
-
+
# Changes the connector name
def SetName(self, name):
self.Name = name
@@ -1140,15 +1167,15 @@
self.Forced = forced
if self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
def GetComputedValue(self):
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType):
return self.Value
return None
-
+
def GetToolTipValue(self):
return self.GetComputedValue()
-
+
def SetValue(self, value):
if self.Value != value:
self.Value = value
@@ -1161,7 +1188,7 @@
self.ValueSize = None
if self.ParentBlock.Visible:
self.ParentBlock.Parent.ElementNeedRefresh(self)
-
+
def RefreshForced(self):
self.Forced = False
for wire, handle in self.Wires:
@@ -1169,12 +1196,12 @@
def RefreshValue(self):
self.Value = self.ReceivingCurrent()
-
+
def RefreshValid(self):
self.Valid = True
for wire, handle in self.Wires:
self.Valid &= wire.GetValid()
-
+
def ReceivingCurrent(self):
current = False
for wire, handle in self.Wires:
@@ -1184,36 +1211,36 @@
elif value == "undefined":
current = "undefined"
return current
-
+
def SpreadCurrent(self, spreading):
for wire, handle in self.Wires:
wire.SetValue(spreading)
-
+
# Changes the connector name size
def RefreshNameSize(self):
if self.Name != "":
self.NameSize = self.ParentBlock.Parent.GetTextExtent(self.Name)
else:
self.NameSize = 0, 0
-
+
# Returns the connector name size
def GetNameSize(self):
return self.NameSize
-
+
# Returns the wires connected to the connector
def GetWires(self):
return self.Wires
-
+
# Returns the parent block Id
def GetBlockId(self):
return self.ParentBlock.GetId()
-
+
# Returns the connector relative position
def GetRelPosition(self):
return self.Pos
-
+
# Returns the connector absolute position
- def GetPosition(self, size = True):
+ def GetPosition(self, size=True):
parent_pos = self.ParentBlock.GetPosition()
# If the position of the end of the connector is asked
if size:
@@ -1223,25 +1250,25 @@
x = parent_pos[0] + self.Pos.x
y = parent_pos[1] + self.Pos.y
return wx.Point(x, y)
-
+
# Change the connector relative position
def SetPosition(self, pos):
self.Pos = pos
-
+
# Returns the connector direction
def GetDirection(self):
return self.Direction
-
+
# Change the connector direction
def SetDirection(self, direction):
self.Direction = direction
-
+
# Connect a wire to this connector at the last place
- def Connect(self, wire, refresh = True):
+ def Connect(self, wire, refresh=True):
self.InsertConnect(len(self.Wires), wire, refresh)
-
+
# Connect a wire to this connector at the place given
- def InsertConnect(self, idx, wire, refresh = True):
+ def InsertConnect(self, idx, wire, refresh=True):
if wire not in self.Wires:
self.Wires.insert(idx, wire)
if wire[1] == 0:
@@ -1250,16 +1277,16 @@
wire[0].ConnectEndPoint(None, self)
if refresh:
self.ParentBlock.RefreshModel(False)
-
+
# Returns the index of the wire given in the list of connected
def GetWireIndex(self, wire):
for i, (tmp_wire, handle) in enumerate(self.Wires):
if tmp_wire == wire:
return i
return None
-
+
# Unconnect a wire or all wires connected to the connector
- def UnConnect(self, wire = None, unconnect = True, delete = False):
+ def UnConnect(self, wire=None, unconnect=True, delete=False):
i = 0
found = False
while i < len(self.Wires) and not found:
@@ -1281,13 +1308,13 @@
if not delete:
self.RefreshValid()
self.ParentBlock.RefreshModel(False)
-
+
# Returns if connector has one or more wire connected
def IsConnected(self):
return len(self.Wires) > 0
-
+
# Move the wires connected
- def MoveConnected(self, exclude = []):
+ def MoveConnected(self, exclude=[]):
if len(self.Wires) > 0:
# Calculate the new position of the end point
parent_pos = self.ParentBlock.GetPosition()
@@ -1300,21 +1327,21 @@
wire.MoveStartPoint(wx.Point(x, y))
else:
wire.MoveEndPoint(wx.Point(x, y))
-
+
# Refreshes the model of all the wires connected
def RefreshWires(self):
for wire in self.Wires:
wire[0].RefreshModel()
-
+
# Refreshes the parent block model
def RefreshParentBlock(self):
self.ParentBlock.RefreshModel(False)
-
+
# Highlight the parent block
def HighlightParentBlock(self, highlight):
self.ParentBlock.SetHighlighted(highlight)
self.ParentBlock.Refresh()
-
+
# Returns all the blocks connected to this connector
def GetConnectedBlocks(self):
blocks = []
@@ -1330,44 +1357,44 @@
if block not in blocks:
blocks.append(block)
return blocks
-
+
# Returns the connector negated property
def IsNegated(self):
return self.Negated
-
+
# Changes the connector negated property
def SetNegated(self, negated):
if self.ParentBlock.IsOfType("BOOL", self.Type):
self.Negated = negated
self.Edge = "none"
-
+
# Returns the connector edge property
def GetEdge(self):
return self.Edge
-
+
# Changes the connector edge property
def SetEdge(self, edge):
if self.ParentBlock.IsOfType("BOOL", self.Type):
- self.Edge = edge
+ self.Edge = edge
self.Negated = False
-
+
# assume that pointer is already inside of this connector
def ConnectionAvailable(self, direction=None, exclude=True):
wire_nums = len(self.Wires)
-
- connector_free = (wire_nums<= 0)
+
+ connector_free = (wire_nums <= 0)
connector_max_used = ((wire_nums > 0) and self.OneConnected)
if (self.Parent.CurrentLanguage in ["SFC", "LD"]) and (self.Type == "BOOL"):
- connector_max_used = False;
+ connector_max_used = False
# connector is available for new connection
- connect = connector_free or not connector_max_used
+ connect = connector_free or not connector_max_used
return connect, connector_max_used
-
+
# Tests if the point given is near from the end point of this connector
def TestPoint(self, pt, direction=None, exclude=True):
- inside = False;
- check_point = (not exclude) and (direction is None or self.Direction == direction);
+ inside = False
+ check_point = (not exclude) and (direction is None or self.Direction == direction)
if check_point:
# Calculate a square around the end point of this connector
@@ -1377,10 +1404,10 @@
width = ANCHOR_DISTANCE * 2 + abs(self.Direction[0]) * CONNECTOR_SIZE
height = ANCHOR_DISTANCE * 2 + abs(self.Direction[1]) * CONNECTOR_SIZE
rect = wx.Rect(x, y, width, height)
- inside = rect.InsideXY(pt.x, pt.y);
-
+ inside = rect.InsideXY(pt.x, pt.y)
+
return inside
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -1393,7 +1420,7 @@
parent_pos = self.ParentBlock.GetPosition()
posx = parent_pos[0] + self.Pos.x
posy = parent_pos[1] + self.Pos.y
- xstart = parent_pos[0] + self.Pos.x
+ xstart = parent_pos[0] + self.Pos.x
ystart = parent_pos[1] + self.Pos.y
if self.Direction[0] < 0:
xstart += 1
@@ -1401,18 +1428,18 @@
ystart += 1
xend = xstart + CONNECTOR_SIZE * self.Direction[0]
yend = ystart + CONNECTOR_SIZE * self.Direction[1]
- dc.DrawLine(round((xstart + self.Direction[0]) * scalex), round((ystart + self.Direction[1]) * scaley),
+ dc.DrawLine(round((xstart + self.Direction[0]) * scalex), round((ystart + self.Direction[1]) * scaley),
round(xend * scalex), round(yend * scaley))
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Adds an highlight to the connector
def AddHighlight(self, infos, start, end, highlight_type):
if highlight_type == ERROR_HIGHLIGHT:
for wire, handle in self.Wires:
wire.SetValid(False)
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the connector
def RemoveHighlight(self, infos, start, end, highlight_type):
error = False
@@ -1425,7 +1452,7 @@
if not error:
for wire, handle in self.Wires:
wire.SetValid(wire.IsConnectedCompatible())
-
+
# Removes all the highlights of one particular type from the connector
def ClearHighlight(self, highlight_type=None):
error = False
@@ -1441,13 +1468,13 @@
if not error:
for wire, handle in self.Wires:
wire.SetValid(wire.IsConnectedCompatible())
-
+
# Draws the connector
def Draw(self, dc):
if self.Selected:
dc.SetPen(MiterPen(wx.BLUE, 3))
dc.SetBrush(wx.WHITE_BRUSH)
- #elif len(self.Highlights) > 0:
+ # elif len(self.Highlights) > 0:
# dc.SetPen(MiterPen(self.Highlights[-1][1]))
# dc.SetBrush(wx.Brush(self.Highlights[-1][0]))
else:
@@ -1466,19 +1493,19 @@
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.WHITE_BRUSH)
parent_pos = self.ParentBlock.GetPosition()
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
else:
name_size = self.NameSize
-
+
if self.Negated:
# If connector is negated, draw a circle
xcenter = parent_pos[0] + self.Pos.x + (CONNECTOR_SIZE * self.Direction[0]) / 2
ycenter = parent_pos[1] + self.Pos.y + (CONNECTOR_SIZE * self.Direction[1]) / 2
dc.DrawCircle(xcenter, ycenter, CONNECTOR_SIZE / 2)
else:
- xstart = parent_pos[0] + self.Pos.x
+ xstart = parent_pos[0] + self.Pos.x
ystart = parent_pos[1] + self.Pos.y
if self.Edge == "rising":
# If connector has a rising edge, draw a right arrow
@@ -1524,26 +1551,27 @@
self.ValueSize = self.ParentBlock.Parent.GetMiniTextExtent(self.ComputedValue)
if self.ValueSize is not None:
width, height = self.ValueSize
- dc.DrawText(self.ComputedValue,
- parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] + \
- width * (self.Direction[0] - 1) / 2,
- parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] + \
- height * (self.Direction[1] - 1))
+ dc.DrawText(self.ComputedValue,
+ parent_pos[0] + self.Pos.x + CONNECTOR_SIZE * self.Direction[0] +
+ width * (self.Direction[0] - 1) / 2,
+ parent_pos[1] + self.Pos.y + CONNECTOR_SIZE * self.Direction[1] +
+ height * (self.Direction[1] - 1))
dc.SetFont(self.ParentBlock.Parent.GetFont())
dc.SetTextForeground(wx.BLACK)
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Common Wire Element
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements a wire for connecting two blocks
-"""
+# -------------------------------------------------------------------------------
+
class Wire(Graphic_Element, DebugDataConsumer):
-
+ """
+ Class that implements a wire for connecting two blocks
+ """
+
# Create a new wire
- def __init__(self, parent, start = None, end = None):
+ def __init__(self, parent, start=None, end=None):
Graphic_Element.__init__(self, parent)
DebugDataConsumer.__init__(self)
self.StartPoint = start
@@ -1568,20 +1596,20 @@
self.ComputingType = False
self.Font = parent.GetMiniFont()
self.ErrHighlight = False
-
+
def GetDefinition(self):
if self.StartConnected is not None and self.EndConnected is not None:
startblock = self.StartConnected.GetParentBlock()
endblock = self.EndConnected.GetParentBlock()
return [], [(startblock.GetId(), endblock.GetId())]
return [], []
-
+
def Flush(self):
self.StartConnected = None
self.EndConnected = None
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if self.StartConnected:
rect = rect.Union(self.StartConnected.GetRedrawRect(movex, movey))
@@ -1607,8 +1635,8 @@
y = self.Points[middle].y - height
rect = rect.Union(wx.Rect(x, y, width, height))
return rect
-
- def Clone(self, parent, connectors = {}, dx = 0, dy = 0):
+
+ def Clone(self, parent, connectors={}, dx=0, dy=0):
start_connector = connectors.get(self.StartConnected, None)
end_connector = connectors.get(self.EndConnected, None)
if start_connector is not None and end_connector is not None:
@@ -1620,18 +1648,18 @@
wire.ConnectEndPoint(end_connector.GetPosition(), end_connector)
return wire
return None
-
+
# Forbids to change the wire position
def SetPosition(x, y):
pass
-
+
# Forbids to change the wire size
def SetSize(width, height):
pass
-
+
# Forbids to et size of the group elements to their minimum size
pass
-
+
# Moves and Resizes the element for fitting scaling
def SetBestSize(self, scaling):
if scaling is not None:
@@ -1664,11 +1692,11 @@
point.y += movey
return movex_max, movey_max
return 0, 0
-
+
# Returns connector to which start point is connected
def GetStartConnected(self):
return self.StartConnected
-
+
# Returns connector to which start point is connected
def GetStartConnectedType(self):
if self.StartConnected and not self.ComputingType:
@@ -1677,11 +1705,11 @@
self.ComputingType = False
return computed_type
return None
-
+
# Returns connector to which end point is connected
def GetEndConnected(self):
return self.EndConnected
-
+
# Returns connector to which end point is connected
def GetEndConnectedType(self):
if self.EndConnected and not self.ComputingType:
@@ -1690,7 +1718,7 @@
self.ComputingType = False
return computed_type
return None
-
+
def GetConnectionDirection(self):
if self.StartConnected is None and self.EndConnected is None:
return None
@@ -1707,26 +1735,26 @@
else:
return (-self.StartPoint[1][0], -self.StartPoint[1][1])
return None
-
+
def GetOtherConnected(self, connector):
if self.StartConnected == connector:
return self.EndConnected
else:
return self.StartConnected
-
+
def GetOtherConnectedType(self, handle):
if handle == 0:
return self.GetEndConnectedType()
else:
return self.GetStartConnectedType()
-
+
def IsConnectedCompatible(self):
if self.StartConnected:
return self.StartConnected.IsCompatible(self.GetEndConnectedType())
elif self.EndConnected:
return True
return False
-
+
def SetForced(self, forced):
if self.Forced != forced:
self.Forced = forced
@@ -1741,7 +1769,7 @@
if self.Value is not None and self.Value != "undefined" and not isinstance(self.Value, BooleanType):
return self.Value
return None
-
+
def GetToolTipValue(self):
return self.GetComputedValue()
@@ -1773,25 +1801,25 @@
if isinstance(value, BooleanType) and self.StartConnected is not None:
block = self.StartConnected.GetParentBlock()
block.SpreadCurrent()
-
+
# Unconnect the start and end points
def Clean(self):
if self.StartConnected:
self.UnConnectStartPoint()
if self.EndConnected:
self.UnConnectEndPoint()
-
+
# Delete this wire by calling the corresponding method
def Delete(self):
self.Parent.DeleteWire(self)
-
+
# Select a segment and not the whole wire. It's useful for Ladder Diagram
def SetSelectedSegment(self, segment):
# The last segment is indicated
if segment == -1:
segment = len(self.Segments) - 1
# The selected segment is reinitialised
- if segment == None:
+ if segment is None:
if self.StartConnected:
self.StartConnected.SetSelected(False)
if self.EndConnected:
@@ -1814,17 +1842,17 @@
self.EndConnected.SetSelected(True)
self.SelectedSegment = segment
self.Refresh()
-
+
def SetValid(self, valid):
self.Valid = valid
if self.StartConnected:
self.StartConnected.RefreshValid()
if self.EndConnected:
self.EndConnected.RefreshValid()
-
+
def GetValid(self):
return self.Valid
-
+
# Reinitialize the wire points
def ResetPoints(self):
if self.StartPoint and self.EndPoint:
@@ -1833,7 +1861,7 @@
else:
self.Points = []
self.Segments = []
-
+
# Refresh the wire bounding box
def RefreshBoundingBox(self):
if len(self.Points) > 0:
@@ -1862,7 +1890,7 @@
self.Pos.x, self.Pos.y = minx, miny
self.Size = wx.Size(maxx - minx, maxy - miny)
self.BoundingBox = wx.Rect(minbbxx, minbbxy, maxbbxx - minbbxx + 1, maxbbxy - minbbxy + 1)
-
+
# Refresh the realpoints that permits to keep the proportionality in wire during resizing
def RefreshRealPoints(self):
if len(self.Points) > 0:
@@ -1870,8 +1898,8 @@
# Calculate float relative position of each point with the minimum point
for point in self.Points:
self.RealPoints.append([float(point.x - self.Pos.x), float(point.y - self.Pos.y)])
-
- # Returns the wire minimum size
+
+ # Returns the wire minimum size
def GetMinSize(self):
width = 1
height = 1
@@ -1893,7 +1921,7 @@
width = MIN_SEGMENT_SIZE
height = MIN_SEGMENT_SIZE
return width + 1, height + 1
-
+
# Returns if the point given is on one of the wire segments
def HitTest(self, pt, connectors=True):
test = False
@@ -1903,7 +1931,7 @@
x1 = self.Points[i].x - self.Segments[0][0] * CONNECTOR_SIZE
y1 = self.Points[i].y - self.Segments[0][1] * CONNECTOR_SIZE
else:
- x1, y1 = self.Points[i].x, self.Points[i].y
+ x1, y1 = self.Points[i].x, self.Points[i].y
if i == len(self.Points) - 2 and self.EndConnected is not None:
x2 = self.Points[i + 1].x + self.Segments[-1][0] * CONNECTOR_SIZE
y2 = self.Points[i + 1].y + self.Segments[-1][1] * CONNECTOR_SIZE
@@ -1911,25 +1939,25 @@
x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y
# Calculate a rectangle around the segment
rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE,
- abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE)
- test |= rect.InsideXY(pt.x, pt.y)
+ abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE)
+ test |= rect.InsideXY(pt.x, pt.y)
return test
-
- # Returns the wire start or end point if the point given is on one of them
+
+ # Returns the wire start or end point if the point given is on one of them
def TestPoint(self, pt):
# Test the wire start point
rect = wx.Rect(self.Points[0].x - ANCHOR_DISTANCE, self.Points[0].y - ANCHOR_DISTANCE,
- 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE)
+ 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE)
if rect.InsideXY(pt.x, pt.y):
return 0
# Test the wire end point
if len(self.Points) > 1:
rect = wx.Rect(self.Points[-1].x - ANCHOR_DISTANCE, self.Points[-1].y - ANCHOR_DISTANCE,
- 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE)
+ 2 * ANCHOR_DISTANCE, 2 * ANCHOR_DISTANCE)
if rect.InsideXY(pt.x, pt.y):
return -1
return None
-
+
# Returns the wire segment if the point given is on it
def TestSegment(self, pt, all=False):
for i in xrange(len(self.Segments)):
@@ -1939,11 +1967,11 @@
x2, y2 = self.Points[i + 1].x, self.Points[i + 1].y
# Calculate a rectangle around the segment
rect = wx.Rect(min(x1, x2) - ANCHOR_DISTANCE, min(y1, y2) - ANCHOR_DISTANCE,
- abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE)
+ abs(x1 - x2) + 2 * ANCHOR_DISTANCE, abs(y1 - y2) + 2 * ANCHOR_DISTANCE)
if rect.InsideXY(pt.x, pt.y):
return i, self.Segments[i]
return None
-
+
# Define the wire points
def SetPoints(self, points, verify=True):
if len(points) > 1:
@@ -1952,10 +1980,10 @@
self.StartPoint = [None, vector(self.Points[0], self.Points[1])]
self.EndPoint = [None, vector(self.Points[-1], self.Points[-2])]
# Calculate the start and end points
- self.StartPoint[0] = wx.Point(self.Points[0].x + CONNECTOR_SIZE * self.StartPoint[1][0],
- self.Points[0].y + CONNECTOR_SIZE * self.StartPoint[1][1])
- self.EndPoint[0] = wx.Point(self.Points[-1].x + CONNECTOR_SIZE * self.EndPoint[1][0],
- self.Points[-1].y + CONNECTOR_SIZE * self.EndPoint[1][1])
+ self.StartPoint[0] = wx.Point(self.Points[0].x + CONNECTOR_SIZE * self.StartPoint[1][0],
+ self.Points[0].y + CONNECTOR_SIZE * self.StartPoint[1][1])
+ self.EndPoint[0] = wx.Point(self.Points[-1].x + CONNECTOR_SIZE * self.EndPoint[1][0],
+ self.Points[-1].y + CONNECTOR_SIZE * self.EndPoint[1][1])
self.Points[0] = self.StartPoint[0]
self.Points[-1] = self.EndPoint[0]
# Calculate the segments directions
@@ -1979,37 +2007,37 @@
i += 1
self.RefreshBoundingBox()
self.RefreshRealPoints()
-
+
# Returns the position of the point indicated
def GetPoint(self, index):
if index < len(self.Points):
return self.Points[index].x, self.Points[index].y
return None
-
+
# Returns a list of the position of all wire points
- def GetPoints(self, invert = False):
+ def GetPoints(self, invert=False):
points = self.VerifyPoints()
- points[0] = wx.Point(points[0].x - CONNECTOR_SIZE * self.StartPoint[1][0],
- points[0].y - CONNECTOR_SIZE * self.StartPoint[1][1])
- points[-1] = wx.Point(points[-1].x - CONNECTOR_SIZE * self.EndPoint[1][0],
- points[-1].y - CONNECTOR_SIZE * self.EndPoint[1][1])
+ points[0] = wx.Point(points[0].x - CONNECTOR_SIZE * self.StartPoint[1][0],
+ points[0].y - CONNECTOR_SIZE * self.StartPoint[1][1])
+ points[-1] = wx.Point(points[-1].x - CONNECTOR_SIZE * self.EndPoint[1][0],
+ points[-1].y - CONNECTOR_SIZE * self.EndPoint[1][1])
# An inversion of the list is asked
if invert:
points.reverse()
return points
-
+
# Returns the position of the two selected segment points
def GetSelectedSegmentPoints(self):
- if self.SelectedSegment != None and len(self.Points) > 1:
+ if self.SelectedSegment is not None and len(self.Points) > 1:
return self.Points[self.SelectedSegment:self.SelectedSegment + 2]
return []
-
+
# Returns if the selected segment is the first and/or the last of the wire
def GetSelectedSegmentConnections(self):
- if self.SelectedSegment != None and len(self.Points) > 1:
+ if self.SelectedSegment is not None and len(self.Points) > 1:
return self.SelectedSegment == 0, self.SelectedSegment == len(self.Segments) - 1
return (True, True)
-
+
# Returns the connectors on which the wire is connected
def GetConnected(self):
connected = []
@@ -2018,7 +2046,7 @@
if self.EndConnected and self.EndPoint[1] == WEST:
connected.append(self.EndConnected)
return connected
-
+
# Returns the id of the block connected to the first or the last wire point
def GetConnectedInfos(self, index):
if index == 0 and self.StartConnected:
@@ -2026,15 +2054,15 @@
elif index == -1 and self.EndConnected:
return self.EndConnected.GetBlockId(), self.EndConnected.GetName()
return None
-
+
# Update the wire points position by keeping at most possible the current positions
- def GeneratePoints(self, realpoints = True):
+ def GeneratePoints(self, realpoints=True):
i = 0
# Calculate the start enad end points with the minimum segment size in the right direction
end = wx.Point(self.EndPoint[0].x + self.EndPoint[1][0] * MIN_SEGMENT_SIZE,
- self.EndPoint[0].y + self.EndPoint[1][1] * MIN_SEGMENT_SIZE)
- start = wx.Point(self.StartPoint[0].x + self.StartPoint[1][0] * MIN_SEGMENT_SIZE,
- self.StartPoint[0].y + self.StartPoint[1][1] * MIN_SEGMENT_SIZE)
+ self.EndPoint[0].y + self.EndPoint[1][1] * MIN_SEGMENT_SIZE)
+ start = wx.Point(self.StartPoint[0].x + self.StartPoint[1][0] * MIN_SEGMENT_SIZE,
+ self.StartPoint[0].y + self.StartPoint[1][1] * MIN_SEGMENT_SIZE)
# Evaluate the point till it's the last
while i < len(self.Points) - 1:
# The next point is the last
@@ -2046,15 +2074,17 @@
# If the end point is not in the start direction, a point is added
if v_end != self.Segments[0] or v_end == self.EndPoint[1]:
self.Points.insert(1, wx.Point(start.x, start.y))
- self.Segments.insert(1, DirectionChoice((self.Segments[0][1],
- self.Segments[0][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(1, DirectionChoice(
+ (self.Segments[0][1],
+ self.Segments[0][0]), v_end, self.EndPoint[1]))
# The current point is the second
elif i == 1:
# The previous direction and the target direction are mainly opposed, a point is added
if product(v_end, self.Segments[0]) < 0:
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y))
- self.Segments.insert(2, DirectionChoice((self.Segments[1][1],
- self.Segments[1][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(2, DirectionChoice(
+ (self.Segments[1][1],
+ self.Segments[1][0]), v_end, self.EndPoint[1]))
# The previous direction and the end direction are the same or they are
# perpendiculars and the end direction points towards current segment
elif product(self.Segments[0], self.EndPoint[1]) >= 0 and product(self.Segments[1], self.EndPoint[1]) <= 0:
@@ -2066,8 +2096,9 @@
# If the previous direction and the end direction are the same, a point is added
if product(self.Segments[0], self.EndPoint[1]) > 0:
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y))
- self.Segments.insert(2, DirectionChoice((self.Segments[1][1],
- self.Segments[1][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(2, DirectionChoice(
+ (self.Segments[1][1],
+ self.Segments[1][0]), v_end, self.EndPoint[1]))
else:
# Current point is positioned in the middle of start point
# and end point on the current direction and a point is added
@@ -2076,8 +2107,9 @@
if self.Segments[0][1] != 0:
self.Points[1].y = (end.y + start.y) / 2
self.Points.insert(2, wx.Point(self.Points[1].x, self.Points[1].y))
- self.Segments.insert(2, DirectionChoice((self.Segments[1][1],
- self.Segments[1][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(2, DirectionChoice(
+ (self.Segments[1][1],
+ self.Segments[1][0]), v_end, self.EndPoint[1]))
else:
# The previous direction and the end direction are perpendiculars
if product(self.Segments[i - 1], self.EndPoint[1]) == 0:
@@ -2093,7 +2125,7 @@
self.Segments[i - 1] = (-self.Segments[i - 1][0], -self.Segments[i - 1][1])
else:
test = True
- # If the current point is the third, test if the second
+ # If the current point is the third, test if the second
# point can be aligned with the end point
if i == 2:
test_point = wx.Point(self.Points[1].x, self.Points[1].y)
@@ -2119,8 +2151,12 @@
if self.Segments[1][1] != 0:
self.Points[2].y = (self.Points[1].y + end.y) / 2
self.Points.insert(3, wx.Point(self.Points[2].x, self.Points[2].y))
- self.Segments.insert(3, DirectionChoice((self.Segments[2][1],
- self.Segments[2][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(
+ 3,
+ DirectionChoice((self.Segments[2][1],
+ self.Segments[2][0]),
+ v_end,
+ self.EndPoint[1]))
else:
# Current point is aligned with end point
if self.Segments[i - 1][0] != 0:
@@ -2140,16 +2176,22 @@
self.Points[i].y = (end.y + self.Points[i - 1].y) / 2
# A point is added
self.Points.insert(i + 1, wx.Point(self.Points[i].x, self.Points[i].y))
- self.Segments.insert(i + 1, DirectionChoice((self.Segments[i][1],
- self.Segments[i][0]), v_end, self.EndPoint[1]))
+ self.Segments.insert(
+ i + 1,
+ DirectionChoice((self.Segments[i][1],
+ self.Segments[i][0]), v_end, self.EndPoint[1]))
else:
# Current point is the first, and second is not mainly in the first direction
if i == 0 and product(vector(start, self.Points[1]), self.Segments[0]) < 0:
- # If first and second directions aren't perpendiculars, a point is added
+ # If first and second directions aren't perpendiculars, a point is added
if product(self.Segments[0], self.Segments[1]) != 0:
self.Points.insert(1, wx.Point(start.x, start.y))
- self.Segments.insert(1, DirectionChoice((self.Segments[0][1],
- self.Segments[0][0]), vector(start, self.Points[1]), self.Segments[1]))
+ self.Segments.insert(
+ 1,
+ DirectionChoice((self.Segments[0][1],
+ self.Segments[0][0]),
+ vector(start, self.Points[1]),
+ self.Segments[1]))
else:
self.Points[1].x, self.Points[1].y = start.x, start.y
else:
@@ -2165,7 +2207,7 @@
self.RefreshBoundingBox()
if realpoints:
self.RefreshRealPoints()
-
+
# Verify that two consecutive points haven't the same position
def VerifyPoints(self):
points = [point for point in self.Points]
@@ -2185,9 +2227,9 @@
self.RefreshBoundingBox()
self.RefreshRealPoints()
return points
-
+
# Moves all the wire points except the first and the last if they are connected
- def Move(self, dx, dy, endpoints = False):
+ def Move(self, dx, dy, endpoints=False):
for i, point in enumerate(self.Points):
if endpoints or not (i == 0 and self.StartConnected) and not (i == len(self.Points) - 1 and self.EndConnected):
point.x += dx
@@ -2195,7 +2237,7 @@
self.StartPoint[0] = self.Points[0]
self.EndPoint[0] = self.Points[-1]
self.GeneratePoints()
-
+
# Resize the wire from position and size given
def Resize(self, x, y, width, height):
if len(self.Points) > 1:
@@ -2212,9 +2254,9 @@
else:
dir = (0, 0)
pointx = max(-dir[0] * MIN_SEGMENT_SIZE, min(int(round(point[0] * width / float(max(lastwidth, 1)))),
- width - dir[0] * MIN_SEGMENT_SIZE))
+ width - dir[0] * MIN_SEGMENT_SIZE))
pointy = max(-dir[1] * MIN_SEGMENT_SIZE, min(int(round(point[1] * height / float(max(lastheight, 1)))),
- height - dir[1] * MIN_SEGMENT_SIZE))
+ height - dir[1] * MIN_SEGMENT_SIZE))
self.Points[i] = wx.Point(minx + x + pointx, miny + y + pointy)
self.StartPoint[0] = self.Points[0]
self.EndPoint[0] = self.Points[-1]
@@ -2246,33 +2288,35 @@
dir = self.EndPoint[1]
else:
dir = (0, 0)
- realpointx = max(-dir[0] * MIN_SEGMENT_SIZE, min(int(round(point[0])),
- width - dir[0] * MIN_SEGMENT_SIZE))
- realpointy = max(-dir[1] * MIN_SEGMENT_SIZE, min(int(round(point[1])),
- height - dir[1] * MIN_SEGMENT_SIZE))
+ realpointx = max(-dir[0] * MIN_SEGMENT_SIZE,
+ min(int(round(point[0])),
+ width - dir[0] * MIN_SEGMENT_SIZE))
+ realpointy = max(-dir[1] * MIN_SEGMENT_SIZE,
+ min(int(round(point[1])),
+ height - dir[1] * MIN_SEGMENT_SIZE))
self.Points[i] = wx.Point(minx + x + realpointx, miny + y + realpointy)
self.StartPoint[0] = self.Points[0]
self.EndPoint[0] = self.Points[-1]
self.GeneratePoints(False)
-
+
# Moves the wire start point and update the wire points
def MoveStartPoint(self, point):
if len(self.Points) > 1:
self.StartPoint[0] = point
self.Points[0] = point
self.GeneratePoints()
-
+
# Changes the wire start direction and update the wire points
def SetStartPointDirection(self, dir):
if len(self.Points) > 1:
self.StartPoint[1] = dir
self.Segments[0] = dir
self.GeneratePoints()
-
+
# Rotates the wire start direction by an angle of 90 degrees anticlockwise
def RotateStartPoint(self):
self.SetStartPointDirection((self.StartPoint[1][1], -self.StartPoint[1][0]))
-
+
# Connects wire start point to the connector given and moves wire start point
# to given point
def ConnectStartPoint(self, point, connector):
@@ -2280,17 +2324,17 @@
self.MoveStartPoint(point)
self.StartConnected = connector
self.RefreshBoundingBox()
-
+
# Unconnects wire start point
- def UnConnectStartPoint(self, delete = False):
+ def UnConnectStartPoint(self, delete=False):
if delete:
self.StartConnected = None
self.Delete()
elif self.StartConnected:
- self.StartConnected.UnConnect(self, unconnect = False)
+ self.StartConnected.UnConnect(self, unconnect=False)
self.StartConnected = None
self.RefreshBoundingBox()
-
+
# Moves the wire end point and update the wire points
def MoveEndPoint(self, point):
if len(self.Points) > 1:
@@ -2303,7 +2347,7 @@
if len(self.Points) > 1:
self.EndPoint[1] = dir
self.GeneratePoints()
-
+
# Rotates the wire end direction by an angle of 90 degrees anticlockwise
def RotateEndPoint(self):
self.SetEndPointDirection((self.EndPoint[1][1], -self.EndPoint[1][0]))
@@ -2315,17 +2359,17 @@
self.MoveEndPoint(point)
self.EndConnected = connector
self.RefreshBoundingBox()
-
+
# Unconnects wire end point
- def UnConnectEndPoint(self, delete = False):
+ def UnConnectEndPoint(self, delete=False):
if delete:
self.EndConnected = None
self.Delete()
elif self.EndConnected:
- self.EndConnected.UnConnect(self, unconnect = False)
+ self.EndConnected.UnConnect(self, unconnect=False)
self.EndConnected = None
self.RefreshBoundingBox()
-
+
# Moves the wire segment given by its index
def MoveSegment(self, idx, movex, movey, scaling):
if 0 < idx < len(self.Segments) - 1:
@@ -2356,7 +2400,7 @@
if start_y != self.Points[idx].y:
return 0, self.Points[idx].y - start_y
return 0, 0
-
+
# Adds two points in the middle of the handled segment
def AddSegment(self):
handle_type, handle = self.Handle
@@ -2391,7 +2435,7 @@
self.Points.insert(segment + 4, wx.Point(p2x, p2y))
self.Segments.insert(segment + 4, dir)
self.GeneratePoints()
-
+
# Delete the handled segment by removing the two segment points
def DeleteSegment(self):
handle_type, handle = self.Handle
@@ -2402,19 +2446,19 @@
self.Segments.pop(segment)
self.GeneratePoints()
self.RefreshModel()
-
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
# Test if a point have been handled
- #result = self.TestPoint(pos)
- #if result != None:
+ # result = self.TestPoint(pos)
+ # if result != None:
# self.Handle = (HANDLE_POINT, result)
# wx.CallAfter(self.Parent.SetCurrentCursor, 1)
- #else:
+ # else:
# Test if a segment have been handled
result = self.TestSegment(pos)
- if result != None:
+ if result is not None:
if result[1] in (NORTH, SOUTH):
wx.CallAfter(self.Parent.SetCurrentCursor, 4)
elif result[1] in (EAST, WEST):
@@ -2424,20 +2468,20 @@
else:
Graphic_Element.OnLeftDown(self, event, dc, scaling)
self.oldPos = pos
-
+
# Method called when a RightUp event has been generated
def OnRightUp(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
# Test if a segment has been handled
result = self.TestSegment(pos, True)
- if result != None:
+ if result is not None:
self.Handle = (HANDLE_SEGMENT, result)
# Popup the menu with special items for a wire
self.Parent.PopupWireMenu(0 < result[0] < len(self.Segments) - 1)
else:
# Execute the default method for a graphic element
Graphic_Element.OnRightUp(self, event, dc, scaling)
-
+
# Method called when a LeftDClick event has been generated
def OnLeftDClick(self, event, dc, scaling):
rect = self.GetRedrawRect()
@@ -2492,7 +2536,7 @@
self.Parent.RefreshBuffer()
rect.Union(self.GetRedrawRect())
self.Parent.RefreshRect(self.Parent.GetScrolledRect(rect), False)
-
+
# Method called when a Motion event has been generated
def OnMotion(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
@@ -2511,7 +2555,7 @@
else:
# Execute the default method for a graphic element
return Graphic_Element.OnMotion(self, event, dc, scaling)
-
+
# Refreshes the wire state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
handle_type, handle = self.Handle
@@ -2572,14 +2616,14 @@
# Execute the default method for a graphic element
else:
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
-
+
# Refreshes the wire model
def RefreshModel(self, move=True):
if self.StartConnected and self.StartPoint[1] in [WEST, NORTH]:
self.StartConnected.RefreshParentBlock()
if self.EndConnected and self.EndPoint[1] in [WEST, NORTH]:
self.EndConnected.RefreshParentBlock()
-
+
# Change the variable that indicates if this element is highlighted
def SetHighlighted(self, highlighted):
self.Highlighted = highlighted
@@ -2587,7 +2631,7 @@
self.OverStart = False
self.OverEnd = False
self.Refresh()
-
+
def HighlightPoint(self, pos):
refresh = False
start, end = self.OverStart, self.OverEnd
@@ -2595,20 +2639,20 @@
self.OverEnd = False
# Test if a point has been handled
result = self.TestPoint(pos)
- if result != None:
+ if result is not None:
if result == 0 and self.StartConnected is not None:
self.OverStart = True
elif result != 0 and self.EndConnected is not None:
self.OverEnd = True
if start != self.OverStart or end != self.OverEnd:
self.Refresh()
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
# If user trying to connect wire with wrong input, highlight will become red.
- if self.ErrHighlight == True and not (self.EndConnected):
+ if self.ErrHighlight and not (self.EndConnected):
highlightcolor = wx.RED
else:
highlightcolor = HIGHLIGHTCOLOR
@@ -2617,31 +2661,31 @@
dc.SetLogicalFunction(wx.AND)
# Draw the start and end points if they are not connected or the mouse is over them
if len(self.Points) > 0 and (not self.StartConnected or self.OverStart):
- dc.DrawCircle(round(self.Points[0].x * scalex),
- round(self.Points[0].y * scaley),
+ dc.DrawCircle(round(self.Points[0].x * scalex),
+ round(self.Points[0].y * scaley),
(POINT_RADIUS + 1) * scalex + 2)
if len(self.Points) > 1 and (not self.EndConnected or self.OverEnd):
dc.DrawCircle(self.Points[-1].x * scalex, self.Points[-1].y * scaley, (POINT_RADIUS + 1) * scalex + 2)
# Draw the wire lines and the last point (it seems that DrawLines stop before the last point)
if len(self.Points) > 1:
- points = [wx.Point(round((self.Points[0].x - self.Segments[0][0]) * scalex),
+ points = [wx.Point(round((self.Points[0].x - self.Segments[0][0]) * scalex),
round((self.Points[0].y - self.Segments[0][1]) * scaley))]
points.extend([wx.Point(round(point.x * scalex), round(point.y * scaley)) for point in self.Points[1:-1]])
- points.append(wx.Point(round((self.Points[-1].x + self.Segments[-1][0]) * scalex),
+ points.append(wx.Point(round((self.Points[-1].x + self.Segments[-1][0]) * scalex),
round((self.Points[-1].y + self.Segments[-1][1]) * scaley)))
else:
points = []
dc.DrawLines(points)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
if self.StartConnected is not None:
self.StartConnected.DrawHighlightment(dc)
self.StartConnected.Draw(dc)
if self.EndConnected is not None:
self.EndConnected.DrawHighlightment(dc)
self.EndConnected.Draw(dc)
-
+
# Draws the wire lines and points
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -2712,9 +2756,10 @@
dc.SetTextForeground(wx.BLACK)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Graphic comment element
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def FilterHighlightsByRow(highlights, row, length):
_highlights = []
@@ -2727,6 +2772,7 @@
_highlights.append((start, end, highlight_type))
return _highlights
+
def FilterHighlightsByColumn(highlights, start_col, end_col):
_highlights = []
for start, end, highlight_type in highlights:
@@ -2736,41 +2782,41 @@
_highlights.append((start, end, highlight_type))
return _highlights
-"""
-Class that implements a comment
-"""
class Comment(Graphic_Element):
+ """
+ Class that implements a comment
+ """
# Create a new comment
- def __init__(self, parent, content, id = None):
+ def __init__(self, parent, content, id=None):
Graphic_Element.__init__(self, parent)
self.Id = id
self.Content = content
self.Pos = wx.Point(0, 0)
self.Size = wx.Size(0, 0)
self.Highlights = []
-
+
# Make a clone of this comment
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
comment = Comment(parent, self.Content, id)
if pos is not None:
comment.SetPosition(pos.x, pos.y)
comment.SetSize(self.Size[0], self.Size[1])
return comment
-
+
# Method for keeping compatibility with others
def Clean(self):
pass
-
+
# Delete this comment by calling the corresponding method
def Delete(self):
self.Parent.DeleteComment(self)
-
+
# Refresh the comment bounding box
def RefreshBoundingBox(self):
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
-
+
# Changes the comment size
def SetSize(self, width, height):
self.Size.SetWidth(width)
@@ -2780,7 +2826,7 @@
# Returns the comment size
def GetSize(self):
return self.Size.GetWidth(), self.Size.GetHeight()
-
+
# Returns the comment minimum size
def GetMinSize(self):
dc = wx.ClientDC(self.Parent)
@@ -2793,7 +2839,7 @@
min_width = max(min_width, wordwidth)
min_height = max(min_height, wordheight)
return min_width + 20, min_height + 20
-
+
# Changes the comment position
def SetPosition(self, x, y):
self.Pos.x = x
@@ -2815,51 +2861,51 @@
# Returns the comment position
def GetPosition(self):
return self.Pos.x, self.Pos.y
-
+
# Moves the comment
- def Move(self, dx, dy, connected = True):
+ def Move(self, dx, dy, connected=True):
self.Pos.x += dx
self.Pos.y += dy
self.RefreshBoundingBox()
-
+
# Resizes the comment with the position and the size given
def Resize(self, x, y, width, height):
self.Move(x, y)
self.SetSize(width, height)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the wire state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE and self.Parent.CurrentLanguage == "LD":
movex = movey = 0
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
-
+
# Refreshes the comment model
def RefreshModel(self, move=True):
self.Parent.RefreshCommentModel(self)
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the comment content
self.Parent.EditCommentContent(self)
-
+
# Adds an highlight to the comment
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "content":
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the comment
def RemoveHighlight(self, infos, start, end, highlight_type):
RemoveHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes all the highlights of one particular type from the comment
def ClearHighlight(self, highlight_type=None):
self.Highlights = ClearHighlights(self.Highlights, highlight_type)
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -2867,29 +2913,29 @@
dc.SetPen(MiterPen(HIGHLIGHTCOLOR))
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
dc.SetLogicalFunction(wx.AND)
-
+
left = (self.Pos.x - 1) * scalex - 2
right = (self.Pos.x + self.Size[0] + 1) * scalex + 2
top = (self.Pos.y - 1) * scaley - 2
bottom = (self.Pos.y + self.Size[1] + 1) * scaley + 2
angle_top = (self.Pos.x + self.Size[0] - 9) * scalex + 2
angle_right = (self.Pos.y + 9) * scaley - 2
-
+
polygon = [wx.Point(left, top), wx.Point(angle_top, top),
wx.Point(right, angle_right), wx.Point(right, bottom),
wx.Point(left, bottom)]
dc.DrawPolygon(polygon)
-
+
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Draws the comment and its content
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.WHITE_BRUSH)
# Draws the comment shape
- polygon = [wx.Point(self.Pos.x, self.Pos.y),
+ polygon = [wx.Point(self.Pos.x, self.Pos.y),
wx.Point(self.Pos.x + self.Size[0] - 10, self.Pos.y),
wx.Point(self.Pos.x + self.Size[0], self.Pos.y + 10),
wx.Point(self.Pos.x + self.Size[0], self.Pos.y + self.Size[1]),
@@ -2951,4 +2997,3 @@
y += wordheight + 5
if y + wordheight > self.Pos.y + self.Size[1] - 10:
break
-
--- a/graphics/LD_Objects.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/LD_Objects.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,16 +28,17 @@
from graphics.DebugDataConsumer import DebugDataConsumer
from plcopen.structures import *
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Ladder Diagram PowerRail
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a power rail
-"""
+# -------------------------------------------------------------------------------
+
class LD_PowerRail(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of a power rail
+ """
+
# Create a new power rail
def __init__(self, parent, type, id=None, connectors=1):
Graphic_Element.__init__(self, parent)
@@ -47,14 +48,14 @@
self.Id = id
self.Extensions = [LD_LINE_SIZE / 2, LD_LINE_SIZE / 2]
self.SetType(type, connectors)
-
+
def Flush(self):
for connector in self.Connectors:
connector.Flush()
self.Connectors = []
-
+
# Make a clone of this LD_PowerRail
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
powerrail = LD_PowerRail(parent, self.Type, id)
powerrail.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -65,13 +66,13 @@
for connector in self.Connectors:
powerrail.Connectors.append(connector.Clone(powerrail))
return powerrail
-
+
def GetConnectorTranslation(self, element):
return dict(zip([connector for connector in self.Connectors],
[connector for connector in element.Connectors]))
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
for connector in self.Connectors:
rect = rect.Union(connector.GetRedrawRect(movex, movey))
@@ -80,7 +81,7 @@
if connector.IsConnected():
rect = rect.Union(connector.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Forbids to change the power rail size
def SetSize(self, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -88,47 +89,47 @@
else:
Graphic_Element.SetSize(self, LD_POWERRAIL_WIDTH, height)
self.RefreshConnectors()
-
+
# Forbids to select a power rail
def HitTest(self, pt, connectors=True):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
- return Graphic_Element.HitTest(self, pt, connectors) or self.TestConnector(pt, exclude=False) != None
+ return Graphic_Element.HitTest(self, pt, connectors) or self.TestConnector(pt, exclude=False) is not None
return False
-
+
# Forbids to select a power rail
def IsInSelection(self, rect):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
return Graphic_Element.IsInSelection(self, rect)
return False
-
+
# Deletes this power rail by calling the appropriate method
def Delete(self):
self.Parent.DeletePowerRail(self)
-
+
# Unconnect all connectors
def Clean(self):
for connector in self.Connectors:
- connector.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ connector.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the power rail bounding box
def RefreshBoundingBox(self):
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
-
+
# Refresh the power rail size
def RefreshSize(self):
self.Size = wx.Size(LD_POWERRAIL_WIDTH, max(LD_LINE_SIZE * len(self.Connectors), self.Size[1]))
self.RefreshBoundingBox()
-
+
# Returns the block minimum size
def GetMinSize(self, default=False):
height = (LD_LINE_SIZE * (len(self.Connectors) - 1)
if default else 0)
return LD_POWERRAIL_WIDTH, height + self.Extensions[0] + self.Extensions[1]
-
+
# Add a connector or a blank to this power rail at the last place
def AddConnector(self):
self.InsertConnector(len(self.Connectors))
-
+
# Add a connector or a blank to this power rail at the place given
def InsertConnector(self, idx):
if self.Type == LEFTRAIL:
@@ -138,7 +139,7 @@
self.Connectors.insert(idx, connector)
self.RefreshSize()
self.RefreshConnectors()
-
+
# Moves the divergence connector given
def MoveConnector(self, connector, movey):
position = connector.GetRelPosition()
@@ -163,19 +164,19 @@
self.Size[1] = max(maxy + self.Extensions[1], self.Size[1])
connector.MoveConnected()
self.RefreshBoundingBox()
-
+
# Returns the index in connectors list for the connector given
def GetConnectorIndex(self, connector):
if connector in self.Connectors:
return self.Connectors.index(connector)
return None
-
+
# Delete the connector or blank from connectors list at the index given
def DeleteConnector(self, idx):
self.Connectors.pop(idx)
self.RefreshConnectors()
self.RefreshSize()
-
+
# Refresh the positions of the power rail connectors
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -193,14 +194,14 @@
elif self.Type == RIGHTRAIL:
connector.SetPosition(wx.Point(0, position))
self.RefreshConnected()
-
+
# Refresh the position of wires connected to power rail
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
for connector in self.Connectors:
connector.MoveConnected(exclude)
-
- # Returns the power rail connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the power rail connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test each connector if it exists
@@ -208,22 +209,22 @@
if name == connector.GetName():
return connector
return self.FindNearestConnector(position, [connector for connector in self.Connectors if connector is not None])
-
- # Returns all the power rail connectors
+
+ # Returns all the power rail connectors
def GetConnectors(self):
connectors = [connector for connector in self.Connectors if connector]
if self.Type == LEFTRAIL:
return {"inputs": [], "outputs": connectors}
else:
return {"inputs": connectors, "outputs": []}
-
+
# Test if point given is on one of the power rail connectors
- def TestConnector(self, pt, direction = None, exclude = True):
+ def TestConnector(self, pt, direction=None, exclude=True):
for connector in self.Connectors:
if connector.TestPoint(pt, direction, exclude):
return connector
return None
-
+
# Returns the power rail type
def SetType(self, type, connectors):
if type != self.Type or len(self.Connectors) != connectors:
@@ -235,11 +236,11 @@
for connector in xrange(connectors):
self.AddConnector()
self.RefreshSize()
-
+
# Returns the power rail type
def GetType(self):
return self.Type
-
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
self.RealConnectors = []
@@ -249,16 +250,16 @@
position = connector.GetRelPosition()
self.RealConnectors.append(max(0., min(float(position.y - self.Extensions[0]) / float(height), 1.)))
elif len(self.Connectors) > 1:
- self.RealConnectors = map(lambda x : x * 1 / (len(self.Connectors) - 1), xrange(len(self.Connectors)))
+ self.RealConnectors = map(lambda x: x * 1 / (len(self.Connectors) - 1), xrange(len(self.Connectors)))
else:
self.RealConnectors = [0.5]
Graphic_Element.OnLeftDown(self, event, dc, scaling)
-
+
# Method called when a LeftUp event have been generated
def OnLeftUp(self, event, dc, scaling):
Graphic_Element.OnLeftUp(self, event, dc, scaling)
self.RealConnectors = None
-
+
# Method called when a LeftDown event have been generated
def OnRightDown(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
@@ -272,12 +273,12 @@
self.oldPos = GetScaledEventPosition(event, dc, scaling)
else:
Graphic_Element.OnRightDown(self, event, dc, scaling)
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the powerrail properties
self.Parent.EditPowerRailContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
handle_type, handle = self.Handle
@@ -292,7 +293,7 @@
Graphic_Element.OnRightUp(self, event, dc, scaling)
else:
self.Parent.PopupDefaultMenu()
-
+
def Resize(self, x, y, width, height):
self.Move(x, y)
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
@@ -314,16 +315,16 @@
elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
return 0, 0
-
+
# Refreshes the power rail model
def RefreshModel(self, move=True):
self.Parent.RefreshPowerRailModel(self)
- # If power rail has moved and power rail is of type LEFT, refresh the model
+ # If power rail has moved and power rail is of type LEFT, refresh the model
# of wires connected to connectors
if move and self.Type == LEFTRAIL:
for connector in self.Connectors:
connector.RefreshWires()
-
+
# Draws power rail
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -337,20 +338,20 @@
# Draw connectors
for connector in self.Connectors:
connector.Draw(dc)
-
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Ladder Diagram Contact
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a contact
-"""
+# -------------------------------------------------------------------------------
+
class LD_Contact(Graphic_Element, DebugDataConsumer):
-
+ """
+ Class that implements the graphic representation of a contact
+ """
+
# Create a new contact
- def __init__(self, parent, type, name, id = None):
+ def __init__(self, parent, type, name, id=None):
Graphic_Element.__init__(self, parent)
DebugDataConsumer.__init__(self)
self.Type = type
@@ -365,7 +366,7 @@
self.PreviousSpreading = False
self.RefreshNameSize()
self.RefreshTypeSize()
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
@@ -373,13 +374,13 @@
if self.Output is not None:
self.Output.Flush()
self.Output = None
-
+
def SetForced(self, forced):
if self.Forced != forced:
self.Forced = forced
if self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
def SetValue(self, value):
if self.Type == CONTACT_RISING:
refresh = self.Value and not self.PreviousValue
@@ -393,7 +394,7 @@
if self.Visible:
self.Parent.ElementNeedRefresh(self)
self.SpreadCurrent()
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
if self.Value is None:
@@ -414,9 +415,9 @@
elif not spreading and self.PreviousSpreading:
self.Output.SpreadCurrent(False)
self.PreviousSpreading = spreading
-
+
# Make a clone of this LD_Contact
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
contact = LD_Contact(parent, self.Type, self.Name, id)
contact.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -426,12 +427,12 @@
contact.Input = self.Input.Clone(contact)
contact.Output = self.Output.Clone(contact)
return contact
-
+
def GetConnectorTranslation(self, element):
- return {self.Input : element.Input, self.Output : element.Output}
-
+ return {self.Input: element.Input, self.Output: element.Output}
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
@@ -445,30 +446,30 @@
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
movex = movey = 0
- return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2)
-
+ return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac=2)
+
# Forbids to change the contact size
def SetSize(self, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.SetSize(self, width, height)
self.RefreshConnectors()
-
+
# Delete this contact by calling the appropriate method
def Delete(self):
self.Parent.DeleteContact(self)
-
+
# Unconnect input and output
def Clean(self):
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
- self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the size of text for name
def RefreshNameSize(self):
if self.Name != "":
self.NameSize = self.Parent.GetTextExtent(self.Name)
else:
self.NameSize = 0, 0
-
+
# Refresh the size of text for type
def RefreshTypeSize(self):
typetext = ""
@@ -482,7 +483,7 @@
self.TypeSize = self.Parent.GetTextExtent(typetext)
else:
self.TypeSize = 0, 0
-
+
# Refresh the contact bounding box
def RefreshBoundingBox(self):
# Calculate the size of the name outside the contact
@@ -499,33 +500,33 @@
bbx_y = self.Pos.y
bbx_height = self.Size[1]
self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
-
+
# Returns the block minimum size
def GetMinSize(self):
return LD_ELEMENT_SIZE
-
+
# Refresh the position of wire connected to contact
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
self.Input.MoveConnected(exclude)
self.Output.MoveConnected(exclude)
-
- # Returns the contact connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the contact connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test input and output connector
- #if name == self.Input.GetName():
+ # if name == self.Input.GetName():
# return self.Input
if name == self.Output.GetName():
return self.Output
return self.FindNearestConnector(position, [self.Input, self.Output])
-
- # Returns input and output contact connectors
+
+ # Returns input and output contact connectors
def GetConnectors(self):
return {"inputs": [self.Input], "outputs": [self.Output]}
-
+
# Test if point given is on contact input or output connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
if self.Input.TestPoint(pt, direction, exclude):
return self.Input
@@ -561,24 +562,24 @@
# Returns the contact type
def GetType(self):
return self.Type
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the contact properties
self.Parent.EditContactContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the contact model
def RefreshModel(self, move=True):
self.Parent.RefreshContactModel(self)
# If contact has moved, refresh the model of wires connected to output
if move:
self.Output.RefreshWires()
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -592,12 +593,12 @@
top = (self.Pos.y - 1) * scaley - 2
width = 4 * scalex + 5
height = (self.Size[1] + 3) * scaley + 5
-
+
dc.DrawRectangle(left_left, top, width, height)
dc.DrawRectangle(right_left, top, width, height)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Adds an highlight to the connection
def AddHighlight(self, infos, start, end, highlight_type):
highlights = self.Highlights.setdefault(infos[0], [])
@@ -606,13 +607,13 @@
AddHighlight(highlights, (start, end, highlight_type))
else:
AddHighlight(highlights, ((0, 0), (0, 1), highlight_type))
-
+
# Removes an highlight from the connection
def RemoveHighlight(self, infos, start, end, highlight_type):
highlights = self.Highlights.get(infos[0], [])
if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0:
self.Highlights.pop(infos[0])
-
+
# Removes all the highlights of one particular type from the connection
def ClearHighlight(self, highlight_type=None):
if highlight_type is None:
@@ -623,11 +624,11 @@
highlights = ClearHighlights(highlight, highlight_type)
if len(highlights) == 0:
self.Highlights.pop(name)
-
+
# Draws contact
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
- if self.Value is not None:
+ if self.Value is not None:
if self.Type == CONTACT_NORMAL and self.Value or \
self.Type == CONTACT_REVERSE and not self.Value or \
self.Type == CONTACT_RISING and self.Value and not self.PreviousValue or \
@@ -643,7 +644,7 @@
else:
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.BLACK_BRUSH)
-
+
# Compiling contact type modifier symbol
typetext = ""
if self.Type == CONTACT_REVERSE:
@@ -652,7 +653,7 @@
typetext = "P"
elif self.Type == CONTACT_FALLING:
typetext = "N"
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
if typetext != "":
@@ -661,7 +662,7 @@
name_size = self.NameSize
if typetext != "":
type_size = self.TypeSize
-
+
# Draw two rectangles for representing the contact
dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1)
dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1)
@@ -677,7 +678,7 @@
# Draw input and output connectors
self.Input.Draw(dc)
self.Output.Draw(dc)
-
+
if not getattr(dc, "printing", False):
for name, highlights in self.Highlights.iteritems():
if name == "reference":
@@ -685,18 +686,19 @@
elif typetext != "":
DrawHighlightedText(dc, typetext, highlights, type_pos[0], type_pos[1])
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Ladder Diagram Coil
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a coil
-"""
+# -------------------------------------------------------------------------------
+
class LD_Coil(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of a coil
+ """
+
# Create a new coil
- def __init__(self, parent, type, name, id = None):
+ def __init__(self, parent, type, name, id=None):
Graphic_Element.__init__(self, parent)
self.Type = type
self.Name = name
@@ -710,7 +712,7 @@
self.PreviousValue = False
self.RefreshNameSize()
self.RefreshTypeSize()
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
@@ -718,7 +720,7 @@
if self.Output is not None:
self.Output.Flush()
self.Output = None
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
self.PreviousValue = self.Value
@@ -729,9 +731,9 @@
self.Output.SpreadCurrent(False)
if self.Value != self.PreviousValue and self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
# Make a clone of this LD_Coil
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
coil = LD_Coil(parent, self.Type, self.Name, id)
coil.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -741,12 +743,12 @@
coil.Input = self.Input.Clone(coil)
coil.Output = self.Output.Clone(coil)
return coil
-
+
def GetConnectorTranslation(self, element):
- return {self.Input : element.Input, self.Output : element.Output}
-
+ return {self.Input: element.Input, self.Output: element.Output}
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
rect = rect.Union(self.Output.GetRedrawRect(movex, movey))
@@ -756,34 +758,34 @@
if self.Output.IsConnected():
rect = rect.Union(self.Output.GetConnectedRedrawRect(movex, movey))
return rect
-
+
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
movex = movey = 0
- return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac = 2)
-
+ return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, height_fac=2)
+
# Forbids to change the Coil size
def SetSize(self, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.SetSize(self, width, height)
self.RefreshConnectors()
-
+
# Delete this coil by calling the appropriate method
def Delete(self):
self.Parent.DeleteCoil(self)
-
+
# Unconnect input and output
def Clean(self):
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
- self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the size of text for name
def RefreshNameSize(self):
if self.Name != "":
self.NameSize = self.Parent.GetTextExtent(self.Name)
else:
self.NameSize = 0, 0
-
+
# Refresh the size of text for type
def RefreshTypeSize(self):
typetext = ""
@@ -801,7 +803,7 @@
self.TypeSize = self.Parent.GetTextExtent(typetext)
else:
self.TypeSize = 0, 0
-
+
# Refresh the coil bounding box
def RefreshBoundingBox(self):
# Calculate the size of the name outside the coil
@@ -818,33 +820,33 @@
bbx_y = self.Pos.y
bbx_height = self.Size[1]
self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
-
+
# Returns the block minimum size
def GetMinSize(self):
return LD_ELEMENT_SIZE
-
+
# Refresh the position of wire connected to coil
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
self.Input.MoveConnected(exclude)
self.Output.MoveConnected(exclude)
-
- # Returns the coil connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the coil connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test input and output connector
- #if self.Input and name == self.Input.GetName():
+ # if self.Input and name == self.Input.GetName():
# return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
return self.FindNearestConnector(position, [self.Input, self.Output])
-
- # Returns input and output coil connectors
+
+ # Returns input and output coil connectors
def GetConnectors(self):
return {"inputs": [self.Input], "outputs": [self.Output]}
-
+
# Test if point given is on coil input or output connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
if self.Input.TestPoint(pt, direction, exclude):
return self.Input
@@ -852,7 +854,7 @@
if self.Output.TestPoint(pt, direction, exclude):
return self.Output
return None
-
+
# Refresh the positions of the block connectors
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -862,7 +864,7 @@
self.Input.SetPosition(wx.Point(0, position))
self.Output.SetPosition(wx.Point(self.Size[0], position))
self.RefreshConnected()
-
+
# Changes the coil name
def SetName(self, name):
self.Name = name
@@ -871,33 +873,33 @@
# Returns the coil name
def GetName(self):
return self.Name
-
+
# Changes the coil type
def SetType(self, type):
self.Type = type
self.RefreshTypeSize()
-
+
# Returns the coil type
def GetType(self):
return self.Type
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the coil properties
self.Parent.EditCoilContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the coil model
def RefreshModel(self, move=True):
self.Parent.RefreshCoilModel(self)
# If coil has moved, refresh the model of wires connected to output
if move:
self.Output.RefreshWires()
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -906,19 +908,19 @@
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetLogicalFunction(wx.AND)
# Draw a two circle arcs for representing the coil
- dc.DrawEllipticArc(round(self.Pos.x * scalex),
- round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley),
- round(self.Size[0] * scalex),
+ dc.DrawEllipticArc(round(self.Pos.x * scalex),
+ round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley),
+ round(self.Size[0] * scalex),
round((int(self.Size[1] * sqrt(2)) - 1) * scaley),
135, 225)
- dc.DrawEllipticArc(round(self.Pos.x * scalex),
- round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley),
- round(self.Size[0] * scalex),
+ dc.DrawEllipticArc(round(self.Pos.x * scalex),
+ round((self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1) * scaley),
+ round(self.Size[0] * scalex),
round((int(self.Size[1] * sqrt(2)) - 1) * scaley),
-45, 45)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Adds an highlight to the connection
def AddHighlight(self, infos, start, end, highlight_type):
highlights = self.Highlights.setdefault(infos[0], [])
@@ -927,13 +929,13 @@
AddHighlight(highlights, (start, end, highlight_type))
else:
AddHighlight(highlights, ((0, 0), (0, 1), highlight_type))
-
+
# Removes an highlight from the connection
def RemoveHighlight(self, infos, start, end, highlight_type):
highlights = self.Highlights.get(infos[0], [])
if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0:
self.Highlights.pop(infos[0])
-
+
# Removes all the highlights of one particular type from the connection
def ClearHighlight(self, highlight_type=None):
if highlight_type is None:
@@ -944,7 +946,7 @@
highlights = ClearHighlights(highlight, highlight_type)
if len(highlights) == 0:
self.Highlights.pop(name)
-
+
# Draws coil
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -953,8 +955,8 @@
else:
dc.SetPen(MiterPen(wx.BLACK, 2, wx.SOLID))
dc.SetBrush(wx.TRANSPARENT_BRUSH)
-
- # Compiling coil type modifier symbol
+
+ # Compiling coil type modifier symbol
typetext = ""
if self.Type == COIL_REVERSE:
typetext = "/"
@@ -966,7 +968,7 @@
typetext = "P"
elif self.Type == COIL_FALLING:
typetext = "N"
-
+
if getattr(dc, "printing", False) and not isinstance(dc, wx.PostScriptDC):
# Draw an clipped ellipse for representing the coil
clipping_box = dc.GetClippingBox()
@@ -992,7 +994,7 @@
name_size = self.NameSize
if typetext != "":
type_size = self.TypeSize
-
+
# Draw coil name
name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
self.Pos.y - (name_size[1] + 2))
@@ -1012,5 +1014,3 @@
DrawHighlightedText(dc, self.Name, highlights, name_pos[0], name_pos[1])
elif typetext != "":
DrawHighlightedText(dc, typetext, highlights, type_pos[0], type_pos[1])
-
-
--- a/graphics/RubberBand.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/RubberBand.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,28 +26,29 @@
from graphics.GraphicCommons import GetScaledEventPosition
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Viewer RubberBand
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements a rubberband for graphic Viewers
-"""
class RubberBand:
-
+ """
+ Class that implements a rubberband for graphic Viewers
+ """
+
def __init__(self, viewer):
"""
Constructor
@param viewer: Viewer on which rubberband must be drawn
"""
self.Viewer = viewer
-
+
# wx.Panel on which rubberband will be drawn
self.DrawingSurface = viewer.Editor
-
+
self.Reset()
-
+
def Reset(self):
"""
Initialize internal attributes of rubberband
@@ -55,14 +56,14 @@
self.StartPoint = None
self.CurrentBBox = None
self.LastBBox = None
-
+
def IsShown(self):
"""
Indicate if rubberband is drawn on viewer
@return: True if rubberband is drawn
"""
- return self.CurrentBBox != None
-
+ return self.CurrentBBox is not None
+
def GetCurrentExtent(self):
"""
Return the rubberband bounding box
@@ -73,7 +74,7 @@
if self.IsShown():
return self.CurrentBBox
return self.LastBBox
-
+
def OnLeftDown(self, event, dc, scaling):
"""
Called when left mouse is pressed on Viewer. Starts to edit a new
@@ -85,16 +86,16 @@
# Save the point where mouse was pressed in Viewer unit, position may
# be modified by scroll and zoom applied on viewer
self.StartPoint = GetScaledEventPosition(event, dc, scaling)
-
+
# Initialize rubberband bounding box
self.CurrentBBox = wx.Rect(self.StartPoint.x, self.StartPoint.y, 0, 0)
-
+
# Change viewer mouse cursor to reflect a rubberband bounding box is
# edited
self.DrawingSurface.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))
-
+
self.Redraw()
-
+
def OnMotion(self, event, dc, scaling):
"""
Called when mouse is dragging over Viewer. Update the current edited
@@ -106,19 +107,19 @@
# Get mouse position in Viewer unit, position may be modified by scroll
# and zoom applied on viewer
pos = GetScaledEventPosition(event, dc, scaling)
-
+
# Save the last bounding box drawn for erasing it later
self.LastBBox = wx.Rect(0, 0, 0, 0)
self.LastBBox.Union(self.CurrentBBox)
-
- # Calculate new position and size of the box
+
+ # Calculate new position and size of the box
self.CurrentBBox.x = min(pos.x, self.StartPoint.x)
self.CurrentBBox.y = min(pos.y, self.StartPoint.y)
self.CurrentBBox.width = abs(pos.x - self.StartPoint.x) + 1
self.CurrentBBox.height = abs(pos.y - self.StartPoint.y) + 1
-
+
self.Redraw()
-
+
def OnLeftUp(self, event, dc, scaling):
"""
Called when mouse is release from Viewer. Erase the current edited
@@ -129,16 +130,16 @@
"""
# Change viewer mouse cursor to default
self.DrawingSurface.SetCursor(wx.NullCursor)
-
+
# Save the last edited bounding box
self.LastBBox = self.CurrentBBox
self.CurrentBBox = None
-
+
self.Redraw()
-
+
def DrawBoundingBoxes(self, bboxes, dc=None):
"""
- Draw a list of bounding box on Viewer in the order given using XOR
+ Draw a list of bounding box on Viewer in the order given using XOR
logical function
@param bboxes: List of bounding boxes to draw on viewer
@param dc: Device Context of Viewer (default None)
@@ -146,38 +147,38 @@
# Get viewer Device Context if not given
if dc is None:
dc = self.Viewer.GetLogicalDC()
-
+
# Save current viewer scale factors before resetting them in order to
# avoid rubberband pen to be scaled
scalex, scaley = dc.GetUserScale()
dc.SetUserScale(1, 1)
-
+
# Set DC drawing style
dc.SetPen(wx.Pen(wx.WHITE, style=wx.DOT))
dc.SetBrush(wx.TRANSPARENT_BRUSH)
dc.SetLogicalFunction(wx.XOR)
-
+
# Draw the bounding boxes using viewer scale factor
for bbox in bboxes:
if bbox is not None:
dc.DrawRectangle(
- bbox.x * scalex, bbox.y * scaley,
+ bbox.x * scalex, bbox.y * scaley,
bbox.width * scalex, bbox.height * scaley)
-
+
dc.SetLogicalFunction(wx.COPY)
-
+
# Restore Viewer scale factor
dc.SetUserScale(scalex, scaley)
-
- def Redraw(self, dc = None):
+
+ def Redraw(self, dc=None):
"""
Redraw rubberband on Viewer
@param dc: Device Context of Viewer (default None)
"""
# Erase last bbox and draw current bbox
self.DrawBoundingBoxes([self.LastBBox, self.CurrentBBox], dc)
-
- def Erase(self, dc = None):
+
+ def Erase(self, dc=None):
"""
Erase rubberband from Viewer
@param dc: Device Context of Viewer (default None)
@@ -185,7 +186,7 @@
# Erase last bbox
self.DrawBoundingBoxes([self.LastBBox], dc)
- def Draw(self, dc = None):
+ def Draw(self, dc=None):
"""
Draw rubberband on Viewer
@param dc: Device Context of Viewer (default None)
--- a/graphics/SFC_Objects.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/SFC_Objects.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,24 +28,25 @@
from graphics.DebugDataConsumer import DebugDataConsumer
from plcopen.structures import *
+
def GetWireSize(block):
if isinstance(block, SFC_Step):
return SFC_WIRE_MIN_SIZE + block.GetActionExtraLineNumber() * SFC_ACTION_MIN_SIZE[1]
else:
return SFC_WIRE_MIN_SIZE
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Sequencial Function Chart Step
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a step
-"""
+# -------------------------------------------------------------------------------
+
class SFC_Step(Graphic_Element, DebugDataConsumer):
-
+ """
+ Class that implements the graphic representation of a step
+ """
+
# Create a new step
- def __init__(self, parent, name, initial = False, id = None):
+ def __init__(self, parent, name, initial=False, id=None):
Graphic_Element.__init__(self, parent)
DebugDataConsumer.__init__(self)
self.SetName(name)
@@ -62,7 +63,7 @@
self.Action = None
self.PreviousValue = None
self.PreviousSpreading = False
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
@@ -73,13 +74,13 @@
if self.Action is not None:
self.Action.Flush()
self.Action = None
-
+
def SetForced(self, forced):
if self.Forced != forced:
self.Forced = forced
if self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
def SetValue(self, value):
self.PreviousValue = self.Value
self.Value = value
@@ -87,7 +88,7 @@
if self.Visible:
self.Parent.ElementNeedRefresh(self)
self.SpreadCurrent()
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
spreading = self.Value
@@ -102,9 +103,9 @@
if self.Action is not None:
self.Action.SpreadCurrent(False)
self.PreviousSpreading = spreading
-
+
# Make a clone of this SFC_Step
- def Clone(self, parent, id = None, name = "Step", pos = None):
+ def Clone(self, parent, id=None, name="Step", pos=None):
step = SFC_Step(parent, name, self.Initial, id)
step.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -118,7 +119,7 @@
if self.Action:
step.Action = self.Action.Clone(step)
return step
-
+
def GetConnectorTranslation(self, element):
connectors = {}
if self.Input is not None:
@@ -128,9 +129,9 @@
if self.Action is not None:
connectors[self.Action] = element.Action
return connectors
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if self.Input:
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
@@ -146,63 +147,63 @@
if self.Action and self.Action.IsConnected():
rect = rect.Union(self.Action.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Delete this step by calling the appropriate method
def Delete(self):
self.Parent.DeleteStep(self)
-
+
# Unconnect input and output
def Clean(self):
if self.Input:
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
if self.Output:
- self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
if self.Action:
- self.Action.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Action.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the size of text for name
def RefreshNameSize(self):
self.NameSize = self.Parent.GetTextExtent(self.Name)
-
+
# Add output connector to step
def AddInput(self):
if not self.Input:
self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH)
self.RefreshBoundingBox()
-
+
# Remove output connector from step
def RemoveInput(self):
if self.Input:
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
self.Input = None
self.RefreshBoundingBox()
-
+
# Add output connector to step
def AddOutput(self):
if not self.Output:
- self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)
+ self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone=True)
self.RefreshBoundingBox()
-
+
# Remove output connector from step
def RemoveOutput(self):
if self.Output:
- self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
self.Output = None
self.RefreshBoundingBox()
-
+
# Add action connector to step
def AddAction(self):
if not self.Action:
- self.Action = Connector(self, "", None, wx.Point(self.Size[0], self.Size[1] / 2), EAST, onlyone = True)
+ self.Action = Connector(self, "", None, wx.Point(self.Size[0], self.Size[1] / 2), EAST, onlyone=True)
self.RefreshBoundingBox()
-
+
# Remove action connector from step
def RemoveAction(self):
if self.Action:
- self.Action.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Action.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
self.Action = None
self.RefreshBoundingBox()
-
+
# Refresh the step bounding box
def RefreshBoundingBox(self):
# Calculate the bounding box size
@@ -220,9 +221,9 @@
bbx_height = self.Size[1] + CONNECTOR_SIZE
if self.Output:
bbx_height += CONNECTOR_SIZE
- #self.BoundingBox = wx.Rect(self.Pos.x, bbx_y, bbx_width + 1, bbx_height + 1)
+ # self.BoundingBox = wx.Rect(self.Pos.x, bbx_y, bbx_width + 1, bbx_height + 1)
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
-
+
# Refresh the positions of the step connectors
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -241,22 +242,22 @@
if self.Action:
self.Action.SetPosition(wx.Point(self.Size[0], vertical_pos))
self.RefreshConnected()
-
+
# Refresh the position of wires connected to step
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
if self.Input:
self.Input.MoveConnected(exclude)
if self.Output:
self.Output.MoveConnected(exclude)
if self.Action:
self.Action.MoveConnected(exclude)
-
- # Returns the step connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the step connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test input, output and action connector if they exists
- #if self.Input and name == self.Input.GetName():
+ # if self.Input and name == self.Input.GetName():
# return self.Input
if self.Output and name == self.Output.GetName():
return self.Output
@@ -273,12 +274,12 @@
if self.Action:
connectors.append(self.Action)
return self.FindNearestConnector(position, connectors)
-
- # Returns action step connector
+
+ # Returns action step connector
def GetActionConnector(self):
return self.Action
-
- # Returns input and output step connectors
+
+ # Returns input and output step connectors
def GetConnectors(self):
connectors = {"inputs": [], "outputs": []}
if self.Input:
@@ -286,9 +287,9 @@
if self.Output:
connectors["outputs"].append(self.Output)
return connectors
-
+
# Test if point given is on step input or output connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector if it exists
if self.Input and self.Input.TestPoint(pt, direction, exclude):
return self.Input
@@ -312,7 +313,7 @@
# Returns the step initial property
def GetInitial(self):
return self.Initial
-
+
# Returns the connector connected to input
def GetPreviousConnector(self):
if self.Input:
@@ -320,7 +321,7 @@
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Input)
return None
-
+
# Returns the connector connected to output
def GetNextConnector(self):
if self.Output:
@@ -328,7 +329,7 @@
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Output)
return None
-
+
# Returns the connector connected to action
def GetActionConnected(self):
if self.Action:
@@ -336,7 +337,7 @@
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Action)
return None
-
+
# Returns the number of action line
def GetActionExtraLineNumber(self):
if self.Action:
@@ -346,7 +347,7 @@
action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock()
return max(0, action_block.GetLineNumber() - 1)
return 0
-
+
# Returns the step minimum size
def GetMinSize(self):
text_width, text_height = self.Parent.GetTextExtent(self.Name)
@@ -354,7 +355,7 @@
return text_width + 14, text_height + 14
else:
return text_width + 10, text_height + 10
-
+
# Updates the step size
def UpdateSize(self, width, height):
diffx = self.Size.GetWidth() / 2 - width / 2
@@ -365,7 +366,7 @@
self.RefreshConnected()
else:
self.RefreshOutputPosition((0, diffy))
-
+
# Align input element with this step
def RefreshInputPosition(self):
if self.Input:
@@ -382,9 +383,9 @@
input_block.MoveActionBlock((diffx, 0))
input_block.Move(diffx, 0)
input_block.RefreshInputPosition()
-
+
# Align output element with this step
- def RefreshOutputPosition(self, move = None):
+ def RefreshOutputPosition(self, move=None):
if self.Output:
wires = self.Output.GetWires()
if len(wires) != 1:
@@ -400,7 +401,7 @@
if isinstance(output_block, SFC_Step):
output_block.MoveActionBlock((diffx, diffy))
wires[0][0].SetPoints([wx.Point(current_pos.x, current_pos.y + wire_size),
- wx.Point(current_pos.x, current_pos.y)])
+ wx.Point(current_pos.x, current_pos.y)])
if not isinstance(output_block, SFC_Divergence) or output_block.GetConnectors()["inputs"].index(output) == 0:
output_block.Move(diffx, diffy, self.Parent.Wires)
output_block.RefreshOutputPosition((diffx, diffy))
@@ -422,7 +423,7 @@
output_block.MoveActionBlock((diffx, 0))
output_block.Move(diffx, 0)
output_block.RefreshOutputPosition()
-
+
# Refresh action element with this step
def MoveActionBlock(self, move):
if self.Action:
@@ -432,24 +433,24 @@
action_block = wires[0][0].GetOtherConnected(self.Action).GetParentBlock()
action_block.Move(move[0], move[1], self.Parent.Wires)
wires[0][0].Move(move[0], move[1], True)
-
+
# Resize the divergence from position and size given
def Resize(self, x, y, width, height):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
self.UpdateSize(width, height)
else:
Graphic_Element.Resize(self, x, y, width, height)
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the step properties
self.Parent.EditStepContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the menu with special items for a step
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the step state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
handle_type, handle = self.Handle
@@ -477,17 +478,17 @@
return movex, 0
else:
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
-
+
# Refresh input element model
def RefreshInputModel(self):
if self.Input:
input = self.GetPreviousConnector()
- if input:
+ if input:
input_block = input.GetParentBlock()
input_block.RefreshModel(False)
if not isinstance(input_block, SFC_Divergence):
input_block.RefreshInputModel()
-
+
# Refresh output element model
def RefreshOutputModel(self, move=False):
if self.Output:
@@ -497,7 +498,7 @@
output_block.RefreshModel(False)
if not isinstance(output_block, SFC_Divergence) or move:
output_block.RefreshOutputModel(move)
-
+
# Refreshes the step model
def RefreshModel(self, move=True):
self.Parent.RefreshStepModel(self)
@@ -513,21 +514,21 @@
self.RefreshOutputModel(self.Initial)
elif self.Output:
self.Output.RefreshWires()
-
+
# Adds an highlight to the connection
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "name" and start[0] == 0 and end[0] == 0:
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the connection
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] == "name":
RemoveHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes all the highlights of one particular type from the connection
def ClearHighlight(self, highlight_type=None):
ClearHighlights(self.Highlights, highlight_type)
-
+
# Draws step
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -541,12 +542,12 @@
else:
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.WHITE_BRUSH)
-
+
if getattr(dc, "printing", False):
name_size = dc.GetTextExtent(self.Name)
else:
name_size = self.NameSize
-
+
# Draw two rectangles for representing the step
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
if self.Initial:
@@ -562,23 +563,23 @@
self.Output.Draw(dc)
if self.Action:
self.Action.Draw(dc)
-
+
if not getattr(dc, "printing", False):
DrawHighlightedText(dc, self.Name, self.Highlights, name_pos[0], name_pos[1])
-
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Sequencial Function Chart Transition
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a transition
-"""
+# -------------------------------------------------------------------------------
+
class SFC_Transition(Graphic_Element, DebugDataConsumer):
-
+ """
+ Class that implements the graphic representation of a transition
+ """
+
# Create a new transition
- def __init__(self, parent, type = "reference", condition = None, priority = 0, id = None):
+ def __init__(self, parent, type="reference", condition=None, priority=0, id=None):
Graphic_Element.__init__(self, parent)
DebugDataConsumer.__init__(self)
self.Type = None
@@ -586,14 +587,14 @@
self.Priority = 0
self.Size = wx.Size(SFC_TRANSITION_SIZE[0], SFC_TRANSITION_SIZE[1])
# Create an input and output connector
- self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)
- self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)
+ self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone=True)
+ self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone=True)
self.SetType(type, condition)
self.SetPriority(priority)
self.Highlights = {}
self.PreviousValue = None
self.PreviousSpreading = False
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
@@ -604,13 +605,13 @@
if self.Type == "connection" and self.Condition is not None:
self.Condition.Flush()
self.Condition = None
-
+
def SetForced(self, forced):
if self.Forced != forced:
self.Forced = forced
if self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
def SetValue(self, value):
self.PreviousValue = self.Value
self.Value = value
@@ -618,7 +619,7 @@
if self.Visible:
self.Parent.ElementNeedRefresh(self)
self.SpreadCurrent()
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
if self.Value is None:
@@ -629,9 +630,9 @@
elif not spreading and self.PreviousSpreading:
self.Output.SpreadCurrent(False)
self.PreviousSpreading = spreading
-
+
# Make a clone of this SFC_Transition
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
transition = SFC_Transition(parent, self.Type, self.Condition, self.Priority, id)
transition.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -643,15 +644,15 @@
if self.Type == "connection":
transition.Condition = self.Condition.Clone(transition)
return transition
-
+
def GetConnectorTranslation(self, element):
- connectors = {self.Input : element.Input, self.Output : element.Output}
+ connectors = {self.Input: element.Input, self.Output: element.Output}
if self.Type == "connection" and self.Condition is not None:
connectors[self.Condition] = element.Condition
return connectors
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if self.Input:
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
@@ -665,17 +666,17 @@
if self.Type == "connection" and self.Condition.IsConnected():
rect = rect.Union(self.Condition.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Forbids to change the transition size
def SetSize(self, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.SetSize(self, width, height)
-
+
# Forbids to resize the transition
def Resize(self, x, y, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.Resize(self, x, y, width, height)
-
+
# Refresh the size of text for name
def RefreshConditionSize(self):
if self.Type != "connection":
@@ -683,7 +684,7 @@
self.ConditionSize = self.Parent.GetTextExtent(self.Condition)
else:
self.ConditionSize = self.Parent.GetTextExtent("Transition")
-
+
# Refresh the size of text for name
def RefreshPrioritySize(self):
if self.Priority != "":
@@ -694,14 +695,14 @@
# Delete this transition by calling the appropriate method
def Delete(self):
self.Parent.DeleteTransition(self)
-
+
# Unconnect input and output
def Clean(self):
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
- self.Output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
if self.Type == "connection":
- self.Condition.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Condition.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Returns if the point given is in the bounding box
def HitTest(self, pt, connectors=True):
if self.Type != "connection":
@@ -715,7 +716,7 @@
else:
test_text = False
return test_text or Graphic_Element.HitTest(self, pt, connectors)
-
+
# Refresh the transition bounding box
def RefreshBoundingBox(self):
bbx_x, bbx_y, bbx_width, bbx_height = self.Pos.x, self.Pos.y, self.Size[0], self.Size[1]
@@ -733,21 +734,21 @@
bbx_y = min(bbx_y, self.Pos.y - max(0, (text_height - self.Size[1]) / 2))
bbx_height = max(bbx_height, self.Pos.y - bbx_y + (self.Size[1] + text_height) / 2)
self.BoundingBox = wx.Rect(bbx_x, bbx_y, bbx_width + 1, bbx_height + 1)
-
+
# Returns the connector connected to input
def GetPreviousConnector(self):
wires = self.Input.GetWires()
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Input)
return None
-
+
# Returns the connector connected to output
def GetNextConnector(self):
wires = self.Output.GetWires()
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Output)
return None
-
+
# Refresh the positions of the transition connectors
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -763,20 +764,20 @@
if self.Type == "connection":
self.Condition.SetPosition(wx.Point(0, vertical_pos))
self.RefreshConnected()
-
+
# Refresh the position of the wires connected to transition
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
self.Input.MoveConnected(exclude)
self.Output.MoveConnected(exclude)
if self.Type == "connection":
self.Condition.MoveConnected(exclude)
-
- # Returns the transition connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the transition connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test input and output connector
- #if name == self.Input.GetName():
+ # if name == self.Input.GetName():
# return self.Input
if name == self.Output.GetName():
return self.Output
@@ -786,19 +787,19 @@
if self.Type == "connection":
connectors.append(self.Condition)
return self.FindNearestConnector(position, connectors)
-
+
# Returns the transition condition connector
def GetConditionConnector(self):
if self.Type == "connection":
return self.Condition
return None
-
+
# Returns input and output transition connectors
def GetConnectors(self):
return {"inputs": [self.Input], "outputs": [self.Output]}
-
+
# Test if point given is on transition input or output connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
if self.Input.TestPoint(pt, direction, exclude):
return self.Input
@@ -811,25 +812,25 @@
return None
# Changes the transition type
- def SetType(self, type, condition = None):
+ def SetType(self, type, condition=None):
if self.Type != type:
if self.Type == "connection":
- self.Condition.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ self.Condition.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
self.Type = type
if type == "connection":
self.Condition = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2), WEST)
else:
- if condition == None:
+ if condition is None:
condition = ""
self.Condition = condition
self.RefreshConditionSize()
elif self.Type != "connection":
- if condition == None:
+ if condition is None:
condition = ""
self.Condition = condition
self.RefreshConditionSize()
self.RefreshBoundingBox()
-
+
# Returns the transition type
def GetType(self):
return self.Type
@@ -839,7 +840,7 @@
self.Priority = priority
self.RefreshPrioritySize()
self.RefreshBoundingBox()
-
+
# Returns the transition type
def GetPriority(self):
return self.Priority
@@ -849,11 +850,11 @@
if self.Type != "connection":
return self.Condition
return None
-
+
# Returns the transition minimum size
def GetMinSize(self):
return SFC_TRANSITION_SIZE
-
+
# Align input element with this step
def RefreshInputPosition(self):
wires = self.Input.GetWires()
@@ -870,9 +871,9 @@
input_block.MoveActionBlock((diffx, 0))
input_block.Move(diffx, 0)
input_block.RefreshInputPosition()
-
+
# Align output element with this step
- def RefreshOutputPosition(self, move = None):
+ def RefreshOutputPosition(self, move=None):
wires = self.Output.GetWires()
if len(wires) != 1:
return
@@ -902,12 +903,12 @@
def OnLeftDClick(self, event, dc, scaling):
# Edit the transition properties
self.Parent.EditTransitionContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the menu with special items for a step
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the transition state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -919,8 +920,8 @@
self.RefreshOutputPosition()
return movex, 0
else:
- return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac = 2, height_fac = 2)
-
+ return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac=2, height_fac=2)
+
# Refresh input element model
def RefreshInputModel(self):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -930,7 +931,7 @@
input_block.RefreshModel(False)
if not isinstance(input_block, SFC_Divergence):
input_block.RefreshInputModel()
-
+
# Refresh output element model
def RefreshOutputModel(self, move=False):
output = self.GetNextConnector()
@@ -939,7 +940,7 @@
output_block.RefreshModel(False)
if not isinstance(output_block, SFC_Divergence) or move:
output_block.RefreshOutputModel(move)
-
+
# Refreshes the transition model
def RefreshModel(self, move=True):
self.Parent.RefreshTransitionModel(self)
@@ -950,20 +951,20 @@
self.RefreshOutputModel()
else:
self.Output.RefreshWires()
-
+
# Adds an highlight to the block
- def AddHighlight(self, infos, start, end ,highlight_type):
+ def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] in ["reference", "inline", "priority"] and start[0] == 0 and end[0] == 0:
highlights = self.Highlights.setdefault(infos[0], [])
AddHighlight(highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the block
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] in ["reference", "inline", "priority"]:
highlights = self.Highlights.get(infos[0], [])
if RemoveHighlight(highlights, (start, end, highlight_type)) and len(highlights) == 0:
self.Highlights.pop(infos[0])
-
+
# Removes all the highlights of one particular type from the block
def ClearHighlight(self, highlight_type=None):
if highlight_type is None:
@@ -974,7 +975,7 @@
highlights = ClearHighlights(highlight, highlight_type)
if len(highlights) == 0:
self.Highlights.pop(name)
-
+
# Draws transition
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -991,7 +992,7 @@
else:
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.BLACK_BRUSH)
-
+
if getattr(dc, "printing", False):
if self.Type != "connection":
condition_size = dc.GetTextExtent(self.Condition)
@@ -1002,14 +1003,14 @@
condition_size = self.ConditionSize
if self.Priority != 0:
priority_size = self.PrioritySize
-
+
# Draw plain rectangle for representing the transition
- dc.DrawRectangle(self.Pos.x,
- self.Pos.y + (self.Size[1] - SFC_TRANSITION_SIZE[1])/2,
+ dc.DrawRectangle(self.Pos.x,
+ self.Pos.y + (self.Size[1] - SFC_TRANSITION_SIZE[1])/2,
self.Size[0] + 1,
SFC_TRANSITION_SIZE[1] + 1)
vertical_line_x = self.Input.GetPosition()[0]
- dc.DrawLine(vertical_line_x, self.Pos.y, vertical_line_x, self.Pos.y + self.Size[1] + 1)
+ dc.DrawLine(vertical_line_x, self.Pos.y, vertical_line_x, self.Pos.y + self.Size[1] + 1)
# Draw transition condition
if self.Type != "connection":
if self.Condition != "":
@@ -1028,7 +1029,7 @@
self.Output.Draw(dc)
if self.Type == "connection":
self.Condition.Draw(dc)
-
+
if not getattr(dc, "printing", False):
for name, highlights in self.Highlights.iteritems():
if name == "priority":
@@ -1036,19 +1037,20 @@
else:
DrawHighlightedText(dc, condition, highlights, condition_pos[0], condition_pos[1])
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# Sequencial Function Chart Divergence and Convergence
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a divergence or convergence,
-selection or simultaneous
-"""
+# -------------------------------------------------------------------------------
+
class SFC_Divergence(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of a divergence or convergence,
+ selection or simultaneous
+ """
+
# Create a new divergence
- def __init__(self, parent, type, number = 2, id = None):
+ def __init__(self, parent, type, number=2, id=None):
Graphic_Element.__init__(self, parent)
self.Type = type
self.Id = id
@@ -1057,18 +1059,18 @@
self.Size = wx.Size((number - 1) * SFC_DEFAULT_SEQUENCE_INTERVAL, self.GetMinSize()[1])
# Create an input and output connector
if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
- self.Inputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)]
+ self.Inputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone=True)]
self.Outputs = []
for i in xrange(number):
- self.Outputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone = True))
+ self.Outputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone=True))
elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
self.Inputs = []
for i in xrange(number):
- self.Inputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone = True))
- self.Outputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)]
+ self.Inputs.append(Connector(self, "", None, wx.Point(i * SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone=True))
+ self.Outputs = [Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone=True)]
self.Value = None
self.PreviousValue = None
-
+
def Flush(self):
for input in self.Inputs:
input.Flush()
@@ -1076,7 +1078,7 @@
for output in self.Outputs:
output.Flush()
self.Outputs = []
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
self.PreviousValue = self.Value
@@ -1102,9 +1104,9 @@
self.Parent.ElementNeedRefresh(self)
for output in self.Outputs:
output.SpreadCurrent(False)
-
+
# Make a clone of this SFC_Divergence
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
divergence = SFC_Divergence(parent, self.Type, max(len(self.Inputs), len(self.Outputs)), id)
divergence.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -1114,12 +1116,12 @@
divergence.Inputs = [input.Clone(divergence) for input in self.Inputs]
divergence.Outputs = [output.Clone(divergence) for output in self.Outputs]
return divergence
-
+
def GetConnectorTranslation(self, element):
return dict(zip(self.Inputs + self.Outputs, element.Inputs + element.Outputs))
-
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if movex != 0 or movey != 0:
for input in self.Inputs:
@@ -1129,27 +1131,27 @@
if output.IsConnected():
rect = rect.Union(output.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Forbids to resize the divergence
def Resize(self, x, y, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.Resize(self, x, 0, width, self.GetMinSize()[1])
-
+
# Delete this divergence by calling the appropriate method
def Delete(self):
self.Parent.DeleteDivergence(self)
-
+
# Returns the divergence type
def GetType(self):
return self.Type
-
+
# Unconnect input and output
def Clean(self):
for input in self.Inputs:
- input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+ input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
for output in self.Outputs:
- output.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ output.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Add a branch to the divergence
def AddBranch(self):
if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
@@ -1157,7 +1159,7 @@
for output in self.Outputs:
pos = output.GetRelPosition()
maxx = max(maxx, pos.x)
- connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone = True)
+ connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, self.Size[1]), SOUTH, onlyone=True)
self.Outputs.append(connector)
self.MoveConnector(connector, 0)
elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
@@ -1165,10 +1167,10 @@
for input in self.Inputs:
pos = input.GetRelPosition()
maxx = max(maxx, pos.x)
- connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone = True)
+ connector = Connector(self, "", None, wx.Point(maxx + SFC_DEFAULT_SEQUENCE_INTERVAL, 0), NORTH, onlyone=True)
self.Inputs.append(connector)
self.MoveConnector(connector, SFC_DEFAULT_SEQUENCE_INTERVAL)
-
+
# Remove a branch from the divergence
def RemoveBranch(self, connector):
if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
@@ -1179,41 +1181,42 @@
if connector in self.Inputs and len(self.Inputs) > 2:
self.Inputs.remove(connector)
self.MoveConnector(self.Inputs[0], 0)
-
+
# Remove the handled branch from the divergence
def RemoveHandledBranch(self):
handle_type, handle = self.Handle
if handle_type == HANDLE_CONNECTOR:
handle.UnConnect(delete=True)
self.RemoveBranch(handle)
-
+
# Return the number of branches for the divergence
def GetBranchNumber(self):
if self.Type in [SELECTION_DIVERGENCE, SIMULTANEOUS_DIVERGENCE]:
return len(self.Outputs)
elif self.Type in [SELECTION_CONVERGENCE, SIMULTANEOUS_CONVERGENCE]:
return len(self.Inputs)
-
+
# Returns if the point given is in the bounding box
def HitTest(self, pt, connectors=True):
- return self.BoundingBox.InsideXY(pt.x, pt.y) or self.TestConnector(pt, exclude=False) != None
-
+ return self.BoundingBox.InsideXY(pt.x, pt.y) or self.TestConnector(pt, exclude=False) is not None
+
# Refresh the divergence bounding box
def RefreshBoundingBox(self):
if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
- self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y,
- self.Size[0] + 1, self.Size[1] + 1)
+ self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y,
+ self.Size[0] + 1, self.Size[1] + 1)
elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
- self.BoundingBox = wx.Rect(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y,
+ self.BoundingBox = wx.Rect(
+ self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y,
self.Size[0] + 2 * SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Size[1] + 1)
-
+
# Refresh the position of wires connected to divergence
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
for input in self.Inputs:
input.MoveConnected(exclude)
for output in self.Outputs:
output.MoveConnected(exclude)
-
+
# Moves the divergence connector given
def MoveConnector(self, connector, movex):
position = connector.GetRelPosition()
@@ -1241,26 +1244,26 @@
self.Size[0] = maxx - minx
connector.MoveConnected()
self.RefreshBoundingBox()
-
- # Returns the divergence connector that starts with the point given if it exists
- def GetConnector(self, position, name = None):
+
+ # Returns the divergence connector that starts with the point given if it exists
+ def GetConnector(self, position, name=None):
# if a name is given
if name is not None:
# Test each input and output connector
- #for input in self.Inputs:
+ # for input in self.Inputs:
# if name == input.GetName():
# return input
for output in self.Outputs:
if name == output.GetName():
return output
return self.FindNearestConnector(position, self.Inputs + self.Outputs)
-
- # Returns input and output divergence connectors
+
+ # Returns input and output divergence connectors
def GetConnectors(self):
return {"inputs": self.Inputs, "outputs": self.Outputs}
-
+
# Test if point given is on divergence input or output connector
- def TestConnector(self, pt, direction = None, exclude=True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
for input in self.Inputs:
if input.TestPoint(pt, direction, exclude):
@@ -1270,7 +1273,7 @@
if output.TestPoint(pt, direction, exclude):
return output
return None
-
+
# Changes the divergence size
def SetSize(self, width, height):
height = self.GetMinSize()[1]
@@ -1290,7 +1293,7 @@
output.MoveConnected()
self.Size = wx.Size(width, height)
self.RefreshBoundingBox()
-
+
# Returns the divergence minimum size
def GetMinSize(self, default=False):
width = 0
@@ -1304,7 +1307,7 @@
elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
return width, 3
return 0, 0
-
+
# Refresh the position of the block connected to connector
def RefreshConnectedPosition(self, connector):
wires = connector.GetWires()
@@ -1340,9 +1343,9 @@
self.RefreshOutputPosition((0, diffy))
for input in self.Inputs:
input.MoveConnected()
-
+
# Align output element with this divergence
- def RefreshOutputPosition(self, move = None):
+ def RefreshOutputPosition(self, move=None):
if move:
for output_connector in self.Outputs:
wires = output_connector.GetWires()
@@ -1359,10 +1362,10 @@
if not isinstance(output_block, SFC_Divergence) or output_block.GetConnectors()["inputs"].index(output) == 0:
output_block.Move(move[0], move[1], self.Parent.Wires)
output_block.RefreshOutputPosition(move)
-
+
# Method called when a LeftDown event have been generated
def OnLeftDown(self, event, dc, scaling):
- self.RealConnectors = {"Inputs":[],"Outputs":[]}
+ self.RealConnectors = {"Inputs": [], "Outputs": []}
for input in self.Inputs:
position = input.GetRelPosition()
self.RealConnectors["Inputs"].append(float(position.x)/float(self.Size[0]))
@@ -1370,12 +1373,12 @@
position = output.GetRelPosition()
self.RealConnectors["Outputs"].append(float(position.x)/float(self.Size[0]))
Graphic_Element.OnLeftDown(self, event, dc, scaling)
-
+
# Method called when a LeftUp event have been generated
def OnLeftUp(self, event, dc, scaling):
Graphic_Element.OnLeftUp(self, event, dc, scaling)
self.RealConnectors = None
-
+
# Method called when a RightDown event have been generated
def OnRightDown(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
@@ -1389,7 +1392,7 @@
self.oldPos = GetScaledEventPosition(event, dc, scaling)
else:
Graphic_Element.OnRightDown(self, event, dc, scaling)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
pos = GetScaledEventPosition(event, dc, scaling)
@@ -1414,7 +1417,7 @@
else:
# Popup the divergence menu without delete branch
self.Parent.PopupDivergenceMenu(False)
-
+
# Refreshes the divergence state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
handle_type, handle = self.Handle
@@ -1430,7 +1433,7 @@
elif self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
return 0, 0
-
+
# Refresh output element model
def RefreshOutputModel(self, move=False):
if move and self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -1442,7 +1445,7 @@
output_block.RefreshModel(False)
if not isinstance(output_block, SFC_Divergence) or move:
output_block.RefreshOutputModel(move)
-
+
# Refreshes the divergence model
def RefreshModel(self, move=True):
self.Parent.RefreshDivergenceModel(self)
@@ -1453,7 +1456,7 @@
else:
for output in self.Outputs:
output.RefreshWires()
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -1467,13 +1470,13 @@
if self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
posx -= SFC_SIMULTANEOUS_SEQUENCE_EXTRA
width += SFC_SIMULTANEOUS_SEQUENCE_EXTRA * 2
- dc.DrawRectangle(int(round((posx - 1) * scalex)) - 2,
- int(round((self.Pos.y - 1) * scaley)) - 2,
- int(round((width + 3) * scalex)) + 5,
+ dc.DrawRectangle(int(round((posx - 1) * scalex)) - 2,
+ int(round((self.Pos.y - 1) * scaley)) - 2,
+ int(round((width + 3) * scalex)) + 5,
int(round((self.Size.height + 3) * scaley)) + 5)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Draws divergence
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -1487,53 +1490,53 @@
if self.Type in [SELECTION_DIVERGENCE, SELECTION_CONVERGENCE]:
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
elif self.Type in [SIMULTANEOUS_DIVERGENCE, SIMULTANEOUS_CONVERGENCE]:
- dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y,
+ dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y,
self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y)
- dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + self.Size[1],
+ dc.DrawLine(self.Pos.x - SFC_SIMULTANEOUS_SEQUENCE_EXTRA, self.Pos.y + self.Size[1],
self.Pos.x + self.Size[0] + SFC_SIMULTANEOUS_SEQUENCE_EXTRA + 1, self.Pos.y + self.Size[1])
# Draw inputs and outputs connectors
for input in self.Inputs:
input.Draw(dc)
for output in self.Outputs:
output.Draw(dc)
-
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Sequencial Function Chart Jump to Step
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of a jump to step
-"""
+# -------------------------------------------------------------------------------
+
class SFC_Jump(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of a jump to step
+ """
+
# Create a new jump
- def __init__(self, parent, target, id = None):
+ def __init__(self, parent, target, id=None):
Graphic_Element.__init__(self, parent)
self.SetTarget(target)
self.Id = id
self.Size = wx.Size(SFC_JUMP_SIZE[0], SFC_JUMP_SIZE[1])
self.Highlights = []
# Create an input and output connector
- self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)
+ self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone=True)
self.Value = None
self.PreviousValue = None
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
self.Input = None
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
self.PreviousValue = self.Value
self.Value = self.Input.ReceivingCurrent()
if self.Value != self.PreviousValue and self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
# Make a clone of this SFC_Jump
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
jump = SFC_Jump(parent, self.Target, id)
jump.SetSize(self.Size[0], self.Size[1])
if pos is not None:
@@ -1542,12 +1545,12 @@
jump.SetPosition(self.Pos.x, self.Pos.y)
jump.Input = self.Input.Clone(jump)
return jump
-
+
def GetConnectorTranslation(self, element):
- return {self.Input : element.Input}
-
+ return {self.Input: element.Input}
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if self.Input:
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
@@ -1555,29 +1558,29 @@
if self.Input.IsConnected():
rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Forbids to change the jump size
def SetSize(self, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.SetSize(self, width, height)
-
+
# Forbids to resize jump
def Resize(self, x, y, width, height):
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
Graphic_Element.Resize(self, x, y, width, height)
-
+
# Delete this jump by calling the appropriate method
def Delete(self):
self.Parent.DeleteJump(self)
-
+
# Unconnect input
def Clean(self):
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the size of text for target
def RefreshTargetSize(self):
self.TargetSize = self.Parent.GetTextExtent(self.Target)
-
+
# Returns if the point given is in the bounding box
def HitTest(self, pt, connectors=True):
# Calculate the bounding box of the condition outside the transition
@@ -1587,22 +1590,22 @@
text_width,
text_height)
return text_bbx.InsideXY(pt.x, pt.y) or Graphic_Element.HitTest(self, pt, connectors)
-
+
# Refresh the jump bounding box
def RefreshBoundingBox(self):
text_width, text_height = self.Parent.GetTextExtent(self.Target)
# Calculate the bounding box size
bbx_width = self.Size[0] + 2 + text_width
- self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y - CONNECTOR_SIZE,
- bbx_width + 1, self.Size[1] + CONNECTOR_SIZE + 1)
-
+ self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y - CONNECTOR_SIZE,
+ bbx_width + 1, self.Size[1] + CONNECTOR_SIZE + 1)
+
# Returns the connector connected to input
def GetPreviousConnector(self):
wires = self.Input.GetWires()
if len(wires) == 1:
return wires[0][0].GetOtherConnected(self.Input)
return None
-
+
# Refresh the element connectors position
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -1611,41 +1614,41 @@
horizontal_pos = round(float(self.Pos.x + horizontal_pos) / float(scaling[0])) * scaling[0] - self.Pos.x
self.Input.SetPosition(wx.Point(horizontal_pos, 0))
self.RefreshConnected()
-
+
# Refresh the position of wires connected to jump
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
if self.Input:
self.Input.MoveConnected(exclude)
-
- # Returns input jump connector
- def GetConnector(self, position = None, name = None):
+
+ # Returns input jump connector
+ def GetConnector(self, position=None, name=None):
return self.Input
-
- # Returns all the jump connectors
+
+ # Returns all the jump connectors
def GetConnectors(self):
return {"inputs": [self.Input], "outputs": []}
-
+
# Test if point given is on jump input connector
- def TestConnector(self, pt, direction = None, exclude = True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
if self.Input and self.Input.TestPoint(pt, direction, exclude):
return self.Input
return None
-
+
# Changes the jump target
def SetTarget(self, target):
self.Target = target
self.RefreshTargetSize()
self.RefreshBoundingBox()
-
+
# Returns the jump target
def GetTarget(self):
return self.Target
-
+
# Returns the jump minimum size
def GetMinSize(self):
return SFC_JUMP_SIZE
-
+
# Align input element with this jump
def RefreshInputPosition(self):
if self.Input:
@@ -1662,21 +1665,21 @@
input_block.MoveActionBlock((diffx, 0))
input_block.Move(diffx, 0)
input_block.RefreshInputPosition()
-
+
# Can't align output element, because there is no output
- def RefreshOutputPosition(self, move = None):
+ def RefreshOutputPosition(self, move=None):
pass
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the jump properties
self.Parent.EditJumpContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the jump state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -1687,8 +1690,8 @@
self.RefreshInputPosition()
return movex, 0
else:
- return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac = 2)
-
+ return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling, width_fac=2)
+
# Refresh input element model
def RefreshInputModel(self):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -1698,32 +1701,32 @@
input_block.RefreshModel(False)
if not isinstance(input_block, SFC_Divergence):
input_block.RefreshInputModel()
-
+
# Refresh output element model
def RefreshOutputModel(self, move=False):
pass
-
+
# Refreshes the jump model
def RefreshModel(self, move=True):
self.Parent.RefreshJumpModel(self)
if move:
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
self.RefreshInputModel()
-
+
# Adds an highlight to the variable
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "target" and start[0] == 0 and end[0] == 0:
AddHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the variable
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] == "target":
RemoveHighlight(self.Highlights, (start, end, highlight_type))
-
+
# Removes all the highlights of one particular type from the variable
def ClearHighlight(self, highlight_type=None):
ClearHighlights(self.Highlights, highlight_type)
-
+
# Draws the highlightment of this element if it is highlighted
def DrawHighlightment(self, dc):
scalex, scaley = dc.GetUserScale()
@@ -1731,16 +1734,16 @@
dc.SetPen(MiterPen(HIGHLIGHTCOLOR))
dc.SetBrush(wx.Brush(HIGHLIGHTCOLOR))
dc.SetLogicalFunction(wx.AND)
- points = [wx.Point(int(round((self.Pos.x - 2) * scalex)) - 3,
+ points = [wx.Point(int(round((self.Pos.x - 2) * scalex)) - 3,
int(round((self.Pos.y - 2) * scaley)) - 2),
- wx.Point(int(round((self.Pos.x + self.Size[0] + 2) * scalex)) + 4,
+ wx.Point(int(round((self.Pos.x + self.Size[0] + 2) * scalex)) + 4,
int(round((self.Pos.y - 2) * scaley)) - 2),
- wx.Point(int(round((self.Pos.x + self.Size[0] / 2) * scalex)),
+ wx.Point(int(round((self.Pos.x + self.Size[0] / 2) * scalex)),
int(round((self.Pos.y + self.Size[1] + 3) * scaley)) + 4)]
dc.DrawPolygon(points)
dc.SetLogicalFunction(wx.COPY)
dc.SetUserScale(scalex, scaley)
-
+
# Draws divergence
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -1750,12 +1753,12 @@
else:
dc.SetPen(MiterPen(wx.BLACK))
dc.SetBrush(wx.BLACK_BRUSH)
-
+
if getattr(dc, "printing", False):
target_size = dc.GetTextExtent(self.Target)
else:
target_size = self.TargetSize
-
+
# Draw plain rectangle for representing the divergence
dc.DrawLine(self.Pos.x + self.Size[0] / 2, self.Pos.y, self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1])
points = [wx.Point(self.Pos.x, self.Pos.y),
@@ -1769,48 +1772,48 @@
# Draw input connector
if self.Input:
self.Input.Draw(dc)
-
+
if not getattr(dc, "printing", False):
DrawHighlightedText(dc, self.Target, self.Highlights, target_pos[0], target_pos[1])
-
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Sequencial Function Chart Action Block
-#-------------------------------------------------------------------------------
-
-"""
-Class that implements the graphic representation of an action block
-"""
+# -------------------------------------------------------------------------------
+
class SFC_ActionBlock(Graphic_Element):
-
+ """
+ Class that implements the graphic representation of an action block
+ """
+
# Create a new action block
- def __init__(self, parent, actions = [], id = None):
+ def __init__(self, parent, actions=[], id=None):
Graphic_Element.__init__(self, parent)
self.Id = id
self.Size = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
self.MinSize = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
self.Highlights = {}
# Create an input and output connector
- self.Input = Connector(self, "", None, wx.Point(0, SFC_ACTION_MIN_SIZE[1] / 2), WEST, onlyone = True)
+ self.Input = Connector(self, "", None, wx.Point(0, SFC_ACTION_MIN_SIZE[1] / 2), WEST, onlyone=True)
self.SetActions(actions)
self.Value = None
self.PreviousValue = None
-
+
def Flush(self):
if self.Input is not None:
self.Input.Flush()
self.Input = None
-
+
def SpreadCurrent(self):
if self.Parent.Debug:
self.PreviousValue = self.Value
self.Value = self.Input.ReceivingCurrent()
if self.Value != self.PreviousValue and self.Visible:
self.Parent.ElementNeedRefresh(self)
-
+
# Make a clone of this SFC_ActionBlock
- def Clone(self, parent, id = None, pos = None):
+ def Clone(self, parent, id=None, pos=None):
actions = [action.copy() for action in self.Actions]
action_block = SFC_ActionBlock(parent, actions, id)
action_block.SetSize(self.Size[0], self.Size[1])
@@ -1820,12 +1823,12 @@
action_block.SetPosition(self.Pos.x, self.Pos.y)
action_block.Input = self.Input.Clone(action_block)
return action_block
-
+
def GetConnectorTranslation(self, element):
- return {self.Input : element.Input}
-
+ return {self.Input: element.Input}
+
# Returns the RedrawRect
- def GetRedrawRect(self, movex = 0, movey = 0):
+ def GetRedrawRect(self, movex=0, movey=0):
rect = Graphic_Element.GetRedrawRect(self, movex, movey)
if self.Input:
rect = rect.Union(self.Input.GetRedrawRect(movex, movey))
@@ -1833,17 +1836,17 @@
if self.Input.IsConnected():
rect = rect.Union(self.Input.GetConnectedRedrawRect(movex, movey))
return rect
-
+
# Returns the number of action lines
def GetLineNumber(self):
return len(self.Actions)
-
+
def GetLineSize(self):
if len(self.Actions) > 0:
return self.Size[1] / len(self.Actions)
else:
return SFC_ACTION_MIN_SIZE[1]
-
+
# Forbids to resize the action block
def Resize(self, x, y, width, height):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -1851,38 +1854,38 @@
self.SetSize(width, self.Size[1])
else:
Graphic_Element.Resize(self, x, y, width, height)
-
+
# Delete this action block by calling the appropriate method
def Delete(self):
self.Parent.DeleteActionBlock(self)
-
+
# Unconnect input and output
def Clean(self):
- self.Input.UnConnect(delete = self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
-
+ self.Input.UnConnect(delete=self.Parent.GetDrawingMode() == FREEDRAWING_MODE)
+
# Refresh the action block bounding box
def RefreshBoundingBox(self):
self.BoundingBox = wx.Rect(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
-
+
# Refresh the position of wires connected to action block
- def RefreshConnected(self, exclude = []):
+ def RefreshConnected(self, exclude=[]):
self.Input.MoveConnected(exclude)
-
- # Returns input action block connector
- def GetConnector(self, position = None, name = None):
+
+ # Returns input action block connector
+ def GetConnector(self, position=None, name=None):
return self.Input
-
- # Returns all the action block connectors
+
+ # Returns all the action block connectors
def GetConnectors(self):
return {"inputs": [self.Input], "outputs": []}
-
+
# Test if point given is on action block input connector
- def TestConnector(self, pt, direction = None, exclude = True):
+ def TestConnector(self, pt, direction=None, exclude=True):
# Test input connector
if self.Input.TestPoint(pt, direction, exclude):
return self.Input
return None
-
+
# Refresh the element connectors position
def RefreshConnectors(self):
scaling = self.Parent.GetScaling()
@@ -1891,7 +1894,7 @@
vertical_pos = round(float(self.Pos.y + vertical_pos) / float(scaling[1])) * scaling[1] - self.Pos.y
self.Input.SetPosition(wx.Point(0, vertical_pos))
self.RefreshConnected()
-
+
# Changes the action block actions
def SetActions(self, actions):
self.Actions = actions
@@ -1917,13 +1920,14 @@
if self.Parent.GetDrawingMode() == FREEDRAWING_MODE:
self.Size = wx.Size(self.ColSize[0] + self.ColSize[1] + self.ColSize[2], max(min_height, SFC_ACTION_MIN_SIZE[1], self.Size[1]))
self.MinSize = max(self.ColSize[0] + self.ColSize[1] + self.ColSize[2],
- SFC_ACTION_MIN_SIZE[0]), max(SFC_ACTION_MIN_SIZE[1], min_height)
+ SFC_ACTION_MIN_SIZE[0]), max(SFC_ACTION_MIN_SIZE[1], min_height)
self.RefreshBoundingBox()
else:
self.Size = wx.Size(max(self.ColSize[0] + self.ColSize[1] + self.ColSize[2],
- SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1])
+ SFC_ACTION_MIN_SIZE[0]),
+ len(self.Actions) * SFC_ACTION_MIN_SIZE[1])
self.MinSize = max(self.ColSize[0] + self.ColSize[1] + self.ColSize[2],
- SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1]
+ SFC_ACTION_MIN_SIZE[0]), len(self.Actions) * SFC_ACTION_MIN_SIZE[1]
self.RefreshBoundingBox()
if self.Input is not None:
wires = self.Input.GetWires()
@@ -1931,25 +1935,25 @@
input_block = wires[0][0].GetOtherConnected(self.Input).GetParentBlock()
input_block.RefreshOutputPosition()
input_block.RefreshOutputModel(True)
-
+
# Returns the action block actions
def GetActions(self):
return self.Actions
-
+
# Returns the action block minimum size
def GetMinSize(self):
return self.MinSize
-
+
# Method called when a LeftDClick event have been generated
def OnLeftDClick(self, event, dc, scaling):
# Edit the action block properties
self.Parent.EditActionBlockContent(self)
-
+
# Method called when a RightUp event have been generated
def OnRightUp(self, event, dc, scaling):
# Popup the default menu
self.Parent.PopupDefaultMenu()
-
+
# Refreshes the action block state according to move defined and handle selected
def ProcessDragging(self, movex, movey, event, scaling):
if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
@@ -1970,18 +1974,17 @@
else:
return Graphic_Element.ProcessDragging(self, movex, movey, event, scaling)
-
# Refreshes the action block model
def RefreshModel(self, move=True):
self.Parent.RefreshActionBlockModel(self)
-
+
# Adds an highlight to the variable
def AddHighlight(self, infos, start, end, highlight_type):
if infos[0] == "action" and infos[1] < len(self.Actions):
action_highlights = self.Highlights.setdefault(infos[1], {})
attribute_highlights = action_highlights.setdefault(infos[2], [])
AddHighlight(attribute_highlights, (start, end, highlight_type))
-
+
# Removes an highlight from the block
def RemoveHighlight(self, infos, start, end, highlight_type):
if infos[0] == "action" and infos[1] < len(self.Actions):
@@ -1991,7 +1994,7 @@
action_highlights.pop(infos[2])
if len(action_highlights) == 0:
self.Highlights.pop(infos[1])
-
+
# Removes all the highlights of one particular type from the block
def ClearHighlight(self, highlight_type=None):
if highlight_type is None:
@@ -2006,7 +2009,7 @@
action_highlights.pop(name)
if len(action_highlights) == 0:
self.Highlights.pop(number)
-
+
# Draws divergence
def Draw(self, dc):
Graphic_Element.Draw(self, dc)
@@ -2018,15 +2021,15 @@
colsize = [self.ColSize[0], self.Size[0] - self.ColSize[0] - self.ColSize[2], self.ColSize[2]]
# Draw plain rectangle for representing the action block
dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
- dc.DrawLine(self.Pos.x + colsize[0], self.Pos.y,
- self.Pos.x + colsize[0], self.Pos.y + self.Size[1])
- dc.DrawLine(self.Pos.x + colsize[0] + colsize[1], self.Pos.y,
- self.Pos.x + colsize[0] + colsize[1], self.Pos.y + self.Size[1])
+ dc.DrawLine(self.Pos.x + colsize[0], self.Pos.y,
+ self.Pos.x + colsize[0], self.Pos.y + self.Size[1])
+ dc.DrawLine(self.Pos.x + colsize[0] + colsize[1], self.Pos.y,
+ self.Pos.x + colsize[0] + colsize[1], self.Pos.y + self.Size[1])
line_size = self.GetLineSize()
for i, action in enumerate(self.Actions):
if i != 0:
- dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size,
- self.Pos.x + self.Size[0], self.Pos.y + i * line_size)
+ dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size,
+ self.Pos.x + self.Size[0], self.Pos.y + i * line_size)
qualifier_size = dc.GetTextExtent(action.qualifier)
if action.duration != "":
qualifier_pos = (self.Pos.x + (colsize[0] - qualifier_size[0]) / 2,
@@ -2048,7 +2051,7 @@
indicator_pos = (self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - indicator_size[0]) / 2,
self.Pos.y + i * line_size + (line_size - indicator_size[1]) / 2)
dc.DrawText(action.indicator, indicator_pos[0], indicator_pos[1])
-
+
if not getattr(dc, "printing", False):
action_highlights = self.Highlights.get(i, {})
for name, attribute_highlights in action_highlights.iteritems():
@@ -2060,7 +2063,6 @@
DrawHighlightedText(dc, action.value, attribute_highlights, content_pos[0], content_pos[1])
elif name == "indicator":
DrawHighlightedText(dc, action.indicator, attribute_highlights, indicator_pos[0], indicator_pos[1])
-
+
# Draw input connector
self.Input.Draw(dc)
-
--- a/graphics/ToolTipProducer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/graphics/ToolTipProducer.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,39 +25,40 @@
import wx
from controls.CustomToolTip import CustomToolTip, TOOLTIP_WAIT_PERIOD
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Tool Tip Producer class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-"""
-Class that implements an element that generate Tool Tip
-"""
class ToolTipProducer:
-
+ """
+ Class that implements an element that generate Tool Tip
+ """
+
def __init__(self, parent):
"""
Constructor
@param parent: Parent Viewer
"""
self.Parent = parent
-
+
self.ToolTip = None
self.ToolTipPos = None
-
+
# Timer for firing Tool tip display
self.ToolTipTimer = wx.Timer(self.Parent, -1)
- self.Parent.Bind(wx.EVT_TIMER,
- self.OnToolTipTimer,
- self.ToolTipTimer)
-
+ self.Parent.Bind(wx.EVT_TIMER,
+ self.OnToolTipTimer,
+ self.ToolTipTimer)
+
def __del__(self):
"""
Destructor
"""
self.DestroyToolTip()
-
+
def OnToolTipTimer(self, event):
"""
Callback for Tool Tip firing timer Event
@@ -65,21 +66,21 @@
"""
# Get Tool Tip text
value = self.GetToolTipValue()
-
+
if value is not None and self.ToolTipPos is not None:
# Create Tool Tip
self.ToolTip = CustomToolTip(self.Parent, value)
self.ToolTip.SetToolTipPosition(self.ToolTipPos)
self.ToolTip.Show()
-
+
def GetToolTipValue(self):
"""
Return tool tip text
- Have to be overridden by inherited classes
- @return: Tool tip text (None if not overridden)
+ Have to be overridden by inherited classes
+ @return: Tool tip text (None if not overridden)
"""
return None
-
+
def DisplayToolTip(self, pos):
"""
Display Tool tip
@@ -87,14 +88,14 @@
"""
# Destroy current displayed Tool tip
self.DestroyToolTip()
-
+
# Save Tool Tip position
self.ToolTipPos = pos
# Start Tool tip firing timer
self.ToolTipTimer.Start(
- int(TOOLTIP_WAIT_PERIOD * 1000),
+ int(TOOLTIP_WAIT_PERIOD * 1000),
oneShot=True)
-
+
def SetToolTipText(self, text):
"""
Set current Tool tip text
@@ -102,7 +103,7 @@
"""
if self.ToolTip is not None:
self.ToolTip.SetTip(text)
-
+
def DestroyToolTip(self):
"""
Destroy current displayed Tool Tip
@@ -110,7 +111,7 @@
# Stop Tool tip firing timer
self.ToolTipTimer.Stop()
self.ToolTipPos = None
-
+
# Destroy Tool Tip
if self.ToolTip is not None:
self.ToolTip.Destroy()
--- a/i18n/mki18n.py Mon Aug 21 20:17:19 2017 +0000
+++ b/i18n/mki18n.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,503 +1,497 @@
-#! /usr/bin/env python
-# -*- coding: iso-8859-1 -*-
-#
-# PYTHON MODULE: MKI18N.PY
-# =========
-#
-# Abstract: Make Internationalization (i18n) files for an application.
-#
-# Copyright Pierre Rouleau. 2003. Released to public domain.
-#
-# Last update: Saturday, November 8, 2003. @ 15:55:18.
-#
-# File: ROUP2003N01::C:/dev/python/mki18n.py
-#
-# RCS $Header: //software/official/MKS/MKS_SI/TV_NT/dev/Python/rcs/mki18n.py 1.5 2003/11/05 19:40:04 PRouleau Exp $
-#
-# Update history:
-#
-# - File created: Saturday, June 7, 2003. by Pierre Rouleau
-# - 10/06/03 rcs : RCS Revision 1.1 2003/06/10 10:06:12 PRouleau
-# - 10/06/03 rcs : RCS Initial revision
-# - 23/08/03 rcs : RCS Revision 1.2 2003/06/10 10:54:27 PRouleau
-# - 23/08/03 P.R.: [code:fix] : The strings encoded in this file are encode in iso-8859-1 format. Added the encoding
-# notification to Python to comply with Python's 2.3 PEP 263.
-# - 23/08/03 P.R.: [feature:new] : Added the '-e' switch which is used to force the creation of the empty English .mo file.
-# - 22/10/03 P.R.: [code] : incorporated utility functions in here to make script self sufficient.
-# - 05/11/03 rcs : RCS Revision 1.4 2003/10/22 06:39:31 PRouleau
-# - 05/11/03 P.R.: [code:fix] : included the unixpath() in this file.
-# - 08/11/03 rcs : RCS Revision 1.5 2003/11/05 19:40:04 PRouleau
-#
-# RCS $Log: $
-#
-#
-# -----------------------------------------------------------------------------
-"""
-mki18n allows you to internationalize your software. You can use it to
-create the GNU .po files (Portable Object) and the compiled .mo files
-(Machine Object).
-
-mki18n module can be used from the command line or from within a script (see
-the Usage at the end of this page).
-
- Table of Contents
- -----------------
-
- makePO() -- Build the Portable Object file for the application --
- catPO() -- Concatenate one or several PO files with the application domain files. --
- makeMO() -- Compile the Portable Object files into the Machine Object stored in the right location. --
- printUsage -- Displays how to use this script from the command line --
-
- Scriptexecution -- Runs when invoked from the command line --
-
-
-NOTE: this module uses GNU gettext utilities.
-
-You can get the gettext tools from the following sites:
-
- - `GNU FTP site for gettetx`_ where several versions (0.10.40, 0.11.2, 0.11.5 and 0.12.1) are available.
- Note that you need to use `GNU libiconv`_ to use this. Get it from the `GNU
- libiconv ftp site`_ and get version 1.9.1 or later. Get the Windows .ZIP
- files and install the packages inside c:/gnu. All binaries will be stored
- inside c:/gnu/bin. Just put c:/gnu/bin inside your PATH. You will need
- the following files:
-
- - `gettext-runtime-0.12.1.bin.woe32.zip`_
- - `gettext-tools-0.12.1.bin.woe32.zip`_
- - `libiconv-1.9.1.bin.woe32.zip`_
-
-
-.. _GNU libiconv: http://www.gnu.org/software/libiconv/
-.. _GNU libiconv ftp site: http://www.ibiblio.org/pub/gnu/libiconv/
-.. _gettext-runtime-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-runtime-0.12.1.bin.woe32.zip
-.. _gettext-tools-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-tools-0.12.1.bin.woe32.zip
-.. _libiconv-1.9.1.bin.woe32.zip: http://www.ibiblio.org/pub/gnu/libiconv/libiconv-1.9.1.bin.woe32.zip
-
-"""
-# -----------------------------------------------------------------------------
-# Module Import
-# -------------
-#
-import os
-import sys
-import wx
-import re
-
-# -----------------------------------------------------------------------------
-# Global variables
-# ----------------
-#
-
-__author__ = "Pierre Rouleau"
-__version__= "$Revision: 1.5 $"
-
-# -----------------------------------------------------------------------------
-
-def getlanguageDict():
- languageDict = {}
-
- if wx.VERSION >= (3, 0, 0):
- app = wx.App()
- else:
- app = wx.PySimpleApp()
-
- for lang in [x for x in dir(wx) if x.startswith("LANGUAGE")]:
- i = wx.Locale(wx.LANGUAGE_DEFAULT).GetLanguageInfo(getattr(wx, lang))
- if i:
- languageDict[i.CanonicalName] = i.Description
-
- return languageDict
-
-
-
-def processCustomFiles(filein, fileout, regexp, prefix = ''):
- appfil_file = open(filein, 'r')
- messages_file = open(fileout, 'r')
- messages = messages_file.read()
- messages_file.close()
- messages_file = open(fileout, 'a')
- messages_file.write('\n')
- messages_file.write('#: %s\n' % prefix)
- messages_file.write('\n')
-
- words_found = {}
- for filepath in appfil_file.xreadlines():
- code_file = open(filepath.strip(), 'r')
- for match in regexp.finditer(code_file.read()):
- word = match.group(1)
- if not words_found.get(word, False) and messages.find("msgid \"%s\"\nmsgstr \"\"" % word) == -1:
- words_found[word] = True
- messages_file.write('\n')
- messages_file.write("msgid \"%s\"\n"%word)
- messages_file.write("msgstr \"\"\n")
- code_file.close()
-
- messages_file.close()
- appfil_file.close()
-
-
-# -----------------------------------------------------------------------------
-# m a k e P O ( ) -- Build the Portable Object file for the application --
-# ^^^^^^^^^^^^^^^
-#
-def makePO(applicationDirectoryPath, applicationDomain=None, verbose=0) :
- """Build the Portable Object Template file for the application.
-
- makePO builds the .pot file for the application stored inside
- a specified directory by running xgettext for all application source
- files. It finds the name of all files by looking for a file called 'app.fil'.
- If this file does not exists, makePo raises an IOError exception.
- By default the application domain (the application
- name) is the same as the directory name but it can be overridden by the
- 'applicationDomain' argument.
-
- makePO always creates a new file called messages.pot. If it finds files
- of the form app_xx.po where 'app' is the application name and 'xx' is one
- of the ISO 639 two-letter language codes, makePO resynchronizes those
- files with the latest extracted strings (now contained in messages.pot).
- This process updates all line location number in the language-specific
- .po files and may also create new entries for translation (or comment out
- some). The .po file is not changed, instead a new file is created with
- the .new extension appended to the name of the .po file.
-
- By default the function does not display what it is doing. Set the
- verbose argument to 1 to force it to print its commands.
- """
-
- if applicationDomain is None:
- applicationName = fileBaseOf(applicationDirectoryPath,withPath=0)
- else:
- applicationName = applicationDomain
- currentDir = os.getcwd()
- os.chdir(applicationDirectoryPath)
- filelist = 'app.fil'
- if not os.path.exists(filelist):
- raise IOError(2,'No module file: ' % filelist)
-
- fileout = 'messages.pot'
- # Steps:
- # Use xgettext to parse all application modules
- # The following switches are used:
- #
- # -s : sort output by string content (easier to use when we need to merge several .po files)
- # --files-from=app.fil : The list of files is taken from the file: app.fil
- # --output= : specifies the name of the output file (using a .pot extension)
- cmd = 'xgettext -s --no-wrap --language=Python --files-from=' + filelist + ' --output=' + fileout + ' --package-name ' + applicationName
- if verbose: print cmd
- os.system(cmd)
-
- XSD_STRING_MODEL = re.compile("<xsd\:(?:element|attribute) name=\"([^\"]*)\"[^\>]*\>")
- processCustomFiles(filelist, fileout, XSD_STRING_MODEL, 'Extra XSD strings')
-
- XML_TC6_STRING_MODEL = re.compile("<documentation>\s*<xhtml\:p><!\[CDATA\[([^\]]*)\]\]></xhtml\:p>\s*</documentation>", re.MULTILINE | re.DOTALL)
- processCustomFiles(filelist, fileout, XML_TC6_STRING_MODEL, 'Extra TC6 documentation strings')
-
- # generate messages.po
- cmd = 'msginit --no-wrap --no-translator -i %s -l en_US.UTF-8 -o messages.po' % (fileout)
- if verbose: print cmd
- os.system(cmd)
-
- languageDict = getlanguageDict()
-
- for langCode in languageDict.keys():
- if langCode == 'en':
- pass
- else:
- langPOfileName = "%s_%s.po" % (applicationName , langCode)
- if os.path.exists(langPOfileName):
- cmd = 'msgmerge -s --no-wrap "%s" %s > "%s.new"' % (langPOfileName, fileout, langPOfileName)
- if verbose: print cmd
- os.system(cmd)
- os.chdir(currentDir)
-
-# -----------------------------------------------------------------------------
-# c a t P O ( ) -- Concatenate one or several PO files with the application domain files. --
-# ^^^^^^^^^^^^^
-#
-def catPO(applicationDirectoryPath, listOf_extraPo, applicationDomain=None, targetDir=None, verbose=0) :
- """Concatenate one or several PO files with the application domain files.
- """
-
- if applicationDomain is None:
- applicationName = fileBaseOf(applicationDirectoryPath,withPath=0)
- else:
- applicationName = applicationDomain
- currentDir = os.getcwd()
- os.chdir(applicationDirectoryPath)
-
- languageDict = getlanguageDict()
-
- for langCode in languageDict.keys():
- if langCode == 'en':
- pass
- else:
- langPOfileName = "%s_%s.po" % (applicationName , langCode)
- if os.path.exists(langPOfileName):
- fileList = ''
- for fileName in listOf_extraPo:
- fileList += ("%s_%s.po " % (fileName,langCode))
- cmd = "msgcat -s --no-wrap %s %s > %s.cat" % (langPOfileName, fileList, langPOfileName)
- if verbose: print cmd
- os.system(cmd)
- if targetDir is None:
- pass
- else:
- mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir,langCode)
- cmd = "msgfmt --output-file=%s/%s.mo %s_%s.po.cat" % (mo_targetDir,applicationName,applicationName,langCode)
- if verbose: print cmd
- os.system(cmd)
- os.chdir(currentDir)
-
-# -----------------------------------------------------------------------------
-# m a k e M O ( ) -- Compile the Portable Object files into the Machine Object stored in the right location. --
-# ^^^^^^^^^^^^^^^
-#
-def makeMO(applicationDirectoryPath,targetDir='./locale',applicationDomain=None, verbose=0, forceEnglish=0) :
- """Compile the Portable Object files into the Machine Object stored in the right location.
-
- makeMO converts all translated language-specific PO files located inside
- the application directory into the binary .MO files stored inside the
- LC_MESSAGES sub-directory for the found locale files.
-
- makeMO searches for all files that have a name of the form 'app_xx.po'
- inside the application directory specified by the first argument. The
- 'app' is the application domain name (that can be specified by the
- applicationDomain argument or is taken from the directory name). The 'xx'
- corresponds to one of the ISO 639 two-letter language codes.
-
- makeMo stores the resulting files inside a sub-directory of `targetDir`
- called xx/LC_MESSAGES where 'xx' corresponds to the 2-letter language
- code.
- """
- if targetDir is None:
- targetDir = './locale'
- if verbose:
- print "Target directory for .mo files is: %s" % targetDir
-
- if applicationDomain is None:
- applicationName = fileBaseOf(applicationDirectoryPath,withPath=0)
- else:
- applicationName = applicationDomain
- currentDir = os.getcwd()
- os.chdir(applicationDirectoryPath)
-
- languageDict = getlanguageDict()
-
- for langCode in languageDict.keys():
- if (langCode == 'en') and (forceEnglish==0):
- pass
- else:
- langPOfileName = "%s_%s.po" % (applicationName , langCode)
- if os.path.exists(langPOfileName):
- mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir,langCode)
- if not os.path.exists(mo_targetDir):
- mkdir(mo_targetDir)
- cmd = 'msgfmt --output-file="%s/%s.mo" "%s_%s.po"' % (mo_targetDir,applicationName,applicationName,langCode)
- if verbose: print cmd
- os.system(cmd)
- os.chdir(currentDir)
-
-# -----------------------------------------------------------------------------
-# p r i n t U s a g e -- Displays how to use this script from the command line --
-# ^^^^^^^^^^^^^^^^^^^
-#
-def printUsage(errorMsg=None) :
- """Displays how to use this script from the command line."""
- print """
- ##################################################################################
- # mki18n : Make internationalization files. #
- # Uses the GNU gettext system to create PO (Portable Object) files #
- # from source code, coimpile PO into MO (Machine Object) files. #
- # Supports C,C++,Python source files. #
- # #
- # Usage: mki18n {OPTION} [appDirPath] #
- # #
- # Options: #
- # -e : When -m is used, forces English .mo file creation #
- # -h : prints this help #
- # -m : make MO from existing PO files #
- # -p : make PO, update PO files: Creates a new messages.pot #
- # file. Creates a dom_xx.po.new for every existing #
- # language specific .po file. ('xx' stands for the ISO639 #
- # two-letter language code and 'dom' stands for the #
- # application domain name). mki18n requires that you #
- # write a 'app.fil' file which contains the list of all #
- # source code to parse. #
- # -v : verbose (prints comments while running) #
- # --domain=appName : specifies the application domain name. By default #
- # the directory name is used. #
- # --moTarget=dir : specifies the directory where .mo files are stored. #
- # If not specified, the target is './locale' #
- # #
- # You must specify one of the -p or -m option to perform the work. You can #
- # specify the path of the target application. If you leave it out mki18n #
- # will use the current directory as the application main directory. #
- # #
- ##################################################################################"""
- if errorMsg:
- print "\n ERROR: %s" % errorMsg
-
-# -----------------------------------------------------------------------------
-# f i l e B a s e O f ( ) -- Return base name of filename --
-# ^^^^^^^^^^^^^^^^^^^^^^^
-#
-def fileBaseOf(filename,withPath=0) :
- """fileBaseOf(filename,withPath) ---> string
-
- Return base name of filename. The returned string never includes the extension.
- Use os.path.basename() to return the basename with the extension. The
- second argument is optional. If specified and if set to 'true' (non zero)
- the string returned contains the full path of the file name. Otherwise the
- path is excluded.
-
- [Example]
- >>> fn = 'd:/dev/telepath/tvapp/code/test.html'
- >>> fileBaseOf(fn)
- 'test'
- >>> fileBaseOf(fn)
- 'test'
- >>> fileBaseOf(fn,1)
- 'd:/dev/telepath/tvapp/code/test'
- >>> fileBaseOf(fn,0)
- 'test'
- >>> fn = 'abcdef'
- >>> fileBaseOf(fn)
- 'abcdef'
- >>> fileBaseOf(fn,1)
- 'abcdef'
- >>> fn = "abcdef."
- >>> fileBaseOf(fn)
- 'abcdef'
- >>> fileBaseOf(fn,1)
- 'abcdef'
- """
- pos = filename.rfind('.')
- if pos > 0:
- filename = filename[:pos]
- if withPath:
- return filename
- else:
- return os.path.basename(filename)
-# -----------------------------------------------------------------------------
-# m k d i r ( ) -- Create a directory (and possibly the entire tree) --
-# ^^^^^^^^^^^^^
-#
-def mkdir(directory) :
- """Create a directory (and possibly the entire tree).
-
- The os.mkdir() will fail to create a directory if one of the
- directory in the specified path does not exist. mkdir()
- solves this problem. It creates every intermediate directory
- required to create the final path. Under Unix, the function
- only supports forward slash separator, but under Windows and MacOS
- the function supports the forward slash and the OS separator (backslash
- under windows).
- """
-
- # translate the path separators
- directory = unixpath(directory)
- # build a list of all directory elements
- aList = filter(lambda x: len(x)>0, directory.split('/'))
- theLen = len(aList)
- # if the first element is a Windows-style disk drive
- # concatenate it with the first directory
- if aList[0].endswith(':'):
- if theLen > 1:
- aList[1] = aList[0] + '/' + aList[1]
- del aList[0]
- theLen -= 1
- # if the original directory starts at root,
- # make sure the first element of the list
- # starts at root too
- if directory[0] == '/':
- aList[0] = '/' + aList[0]
- # Now iterate through the list, check if the
- # directory exists and if not create it
- theDir = ''
- for i in range(theLen):
- theDir += aList[i]
- if not os.path.exists(theDir):
- os.mkdir(theDir)
- theDir += '/'
-
-# -----------------------------------------------------------------------------
-# u n i x p a t h ( ) -- Return a path name that contains Unix separator. --
-# ^^^^^^^^^^^^^^^^^^^
-#
-def unixpath(thePath) :
- r"""Return a path name that contains Unix separator.
-
- [Example]
- >>> unixpath(r"d:\test")
- 'd:/test'
- >>> unixpath("d:/test/file.txt")
- 'd:/test/file.txt'
- >>>
- """
- thePath = os.path.normpath(thePath)
- if os.sep == '/':
- return thePath
- else:
- return thePath.replace(os.sep,'/')
-
-# -----------------------------------------------------------------------------
-
-# S c r i p t e x e c u t i o n -- Runs when invoked from the command line --
-# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-#
-if __name__ == "__main__":
- import getopt # command line parsing
- argc = len(sys.argv)
- if argc == 1:
- printUsage('Missing argument: specify at least one of -m or -p (or both).')
- sys.exit(1)
- # If there is some arguments, parse the command line
- validOptions = "ehmpv"
- validLongOptions = ['domain=', 'moTarget=']
- option = {}
- option['forceEnglish'] = 0
- option['mo'] = 0
- option['po'] = 0
- option['verbose'] = 0
- option['domain'] = None
- option['moTarget'] = None
- try:
- optionList,pargs = getopt.getopt(sys.argv[1:],validOptions,validLongOptions)
- except getopt.GetoptError, e:
- printUsage(e[0])
- sys.exit(1)
- for (opt,val) in optionList:
- if (opt == '-h'):
- printUsage()
- sys.exit(0)
- elif (opt == '-e'): option['forceEnglish'] = 1
- elif (opt == '-m'): option['mo'] = 1
- elif (opt == '-p'): option['po'] = 1
- elif (opt == '-v'): option['verbose'] = 1
- elif (opt == '--domain'): option['domain'] = val
- elif (opt == '--moTarget'): option['moTarget'] = val
- if len(pargs) == 0:
- appDirPath = os.getcwd()
- if option['verbose']:
- print "No project directory given. Using current one: %s" % appDirPath
- elif len(pargs) == 1:
- appDirPath = pargs[0]
- else:
- printUsage('Too many arguments (%u). Use double quotes if you have space in directory name' % len(pargs))
- sys.exit(1)
- if option['domain'] is None:
- # If no domain specified, use the name of the target directory
- option['domain'] = fileBaseOf(appDirPath)
- if option['verbose']:
- print "Application domain used is: '%s'" % option['domain']
- if option['po']:
- try:
- makePO(appDirPath,option['domain'],option['verbose'])
- except IOError, e:
- printUsage(e[1] + '\n You must write a file app.fil that contains the list of all files to parse.')
- if option['mo']:
- makeMO(appDirPath,option['moTarget'],option['domain'],option['verbose'],option['forceEnglish'])
- sys.exit(1)
-
-
-# -----------------------------------------------------------------------------
+#! /usr/bin/env python
+# -*- coding: iso-8859-1 -*-
+#
+# PYTHON MODULE: MKI18N.PY
+# =========
+#
+# Abstract: Make Internationalization (i18n) files for an application.
+#
+# Copyright Pierre Rouleau. 2003. Released to public domain.
+#
+# Last update: Saturday, November 8, 2003. @ 15:55:18.
+#
+# File: ROUP2003N01::C:/dev/python/mki18n.py
+#
+# RCS $Header: //software/official/MKS/MKS_SI/TV_NT/dev/Python/rcs/mki18n.py 1.5 2003/11/05 19:40:04 PRouleau Exp $
+#
+# Update history:
+#
+# - File created: Saturday, June 7, 2003. by Pierre Rouleau
+# - 10/06/03 rcs : RCS Revision 1.1 2003/06/10 10:06:12 PRouleau
+# - 10/06/03 rcs : RCS Initial revision
+# - 23/08/03 rcs : RCS Revision 1.2 2003/06/10 10:54:27 PRouleau
+# - 23/08/03 P.R.: [code:fix] : The strings encoded in this file are encode in iso-8859-1 format. Added the encoding
+# notification to Python to comply with Python's 2.3 PEP 263.
+# - 23/08/03 P.R.: [feature:new] : Added the '-e' switch which is used to force the creation of the empty English .mo file.
+# - 22/10/03 P.R.: [code] : incorporated utility functions in here to make script self sufficient.
+# - 05/11/03 rcs : RCS Revision 1.4 2003/10/22 06:39:31 PRouleau
+# - 05/11/03 P.R.: [code:fix] : included the unixpath() in this file.
+# - 08/11/03 rcs : RCS Revision 1.5 2003/11/05 19:40:04 PRouleau
+#
+# RCS $Log: $
+#
+#
+# -----------------------------------------------------------------------------
+"""
+mki18n allows you to internationalize your software. You can use it to
+create the GNU .po files (Portable Object) and the compiled .mo files
+(Machine Object).
+
+mki18n module can be used from the command line or from within a script (see
+the Usage at the end of this page).
+
+ Table of Contents
+ -----------------
+
+ makePO() -- Build the Portable Object file for the application --
+ catPO() -- Concatenate one or several PO files with the application domain files. --
+ makeMO() -- Compile the Portable Object files into the Machine Object stored in the right location. --
+ printUsage -- Displays how to use this script from the command line --
+
+ Scriptexecution -- Runs when invoked from the command line --
+
+
+NOTE: this module uses GNU gettext utilities.
+
+You can get the gettext tools from the following sites:
+
+ - `GNU FTP site for gettetx`_ where several versions (0.10.40, 0.11.2, 0.11.5 and 0.12.1) are available.
+ Note that you need to use `GNU libiconv`_ to use this. Get it from the `GNU
+ libiconv ftp site`_ and get version 1.9.1 or later. Get the Windows .ZIP
+ files and install the packages inside c:/gnu. All binaries will be stored
+ inside c:/gnu/bin. Just put c:/gnu/bin inside your PATH. You will need
+ the following files:
+
+ - `gettext-runtime-0.12.1.bin.woe32.zip`_
+ - `gettext-tools-0.12.1.bin.woe32.zip`_
+ - `libiconv-1.9.1.bin.woe32.zip`_
+
+
+.. _GNU libiconv: http://www.gnu.org/software/libiconv/
+.. _GNU libiconv ftp site: http://www.ibiblio.org/pub/gnu/libiconv/
+.. _gettext-runtime-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-runtime-0.12.1.bin.woe32.zip
+.. _gettext-tools-0.12.1.bin.woe32.zip: ftp://ftp.gnu.org/gnu/gettext/gettext-tools-0.12.1.bin.woe32.zip
+.. _libiconv-1.9.1.bin.woe32.zip: http://www.ibiblio.org/pub/gnu/libiconv/libiconv-1.9.1.bin.woe32.zip
+
+"""
+# -----------------------------------------------------------------------------
+# Module Import
+# -------------
+#
+import os
+import sys
+import wx
+import re
+
+# -----------------------------------------------------------------------------
+# Global variables
+# ----------------
+#
+
+__author__ = "Pierre Rouleau"
+__version__ = "$Revision: 1.5 $"
+
+# -----------------------------------------------------------------------------
+
+
+def getlanguageDict():
+ languageDict = {}
+
+ if wx.VERSION >= (3, 0, 0):
+ app = wx.App()
+ else:
+ app = wx.PySimpleApp()
+
+ for lang in [x for x in dir(wx) if x.startswith("LANGUAGE")]:
+ i = wx.Locale(wx.LANGUAGE_DEFAULT).GetLanguageInfo(getattr(wx, lang))
+ if i:
+ languageDict[i.CanonicalName] = i.Description
+
+ return languageDict
+
+
+def verbosePrint(verbose, str):
+ if verbose:
+ print str
+
+
+def processCustomFiles(filein, fileout, regexp, prefix=''):
+ appfil_file = open(filein, 'r')
+ messages_file = open(fileout, 'r')
+ messages = messages_file.read()
+ messages_file.close()
+ messages_file = open(fileout, 'a')
+ messages_file.write('\n')
+ messages_file.write('#: %s\n' % prefix)
+ messages_file.write('\n')
+
+ words_found = {}
+ for filepath in appfil_file.xreadlines():
+ code_file = open(filepath.strip(), 'r')
+ for match in regexp.finditer(code_file.read()):
+ word = match.group(1)
+ if not words_found.get(word, False) and messages.find("msgid \"%s\"\nmsgstr \"\"" % word) == -1:
+ words_found[word] = True
+ messages_file.write('\n')
+ messages_file.write("msgid \"%s\"\n" % word)
+ messages_file.write("msgstr \"\"\n")
+ code_file.close()
+
+ messages_file.close()
+ appfil_file.close()
+
+
+# -----------------------------------------------------------------------------
+# m a k e P O ( ) -- Build the Portable Object file for the application --
+# ^^^^^^^^^^^^^^^
+#
+def makePO(applicationDirectoryPath, applicationDomain=None, verbose=0):
+ """Build the Portable Object Template file for the application.
+
+ makePO builds the .pot file for the application stored inside
+ a specified directory by running xgettext for all application source
+ files. It finds the name of all files by looking for a file called 'app.fil'.
+ If this file does not exists, makePo raises an IOError exception.
+ By default the application domain (the application
+ name) is the same as the directory name but it can be overridden by the
+ 'applicationDomain' argument.
+
+ makePO always creates a new file called messages.pot. If it finds files
+ of the form app_xx.po where 'app' is the application name and 'xx' is one
+ of the ISO 639 two-letter language codes, makePO resynchronizes those
+ files with the latest extracted strings (now contained in messages.pot).
+ This process updates all line location number in the language-specific
+ .po files and may also create new entries for translation (or comment out
+ some). The .po file is not changed, instead a new file is created with
+ the .new extension appended to the name of the .po file.
+
+ By default the function does not display what it is doing. Set the
+ verbose argument to 1 to force it to print its commands.
+ """
+
+ if applicationDomain is None:
+ applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
+ else:
+ applicationName = applicationDomain
+ currentDir = os.getcwd()
+ os.chdir(applicationDirectoryPath)
+ filelist = 'app.fil'
+ if not os.path.exists(filelist):
+ raise IOError(2, 'No module file: ' % filelist)
+
+ fileout = 'messages.pot'
+ # Steps:
+ # Use xgettext to parse all application modules
+ # The following switches are used:
+ #
+ # -s : sort output by string content (easier to use when we need to merge several .po files)
+ # --files-from=app.fil : The list of files is taken from the file: app.fil
+ # --output= : specifies the name of the output file (using a .pot extension)
+ cmd = 'xgettext -s --no-wrap --language=Python --files-from=' + filelist + ' --output=' + fileout + ' --package-name ' + applicationName
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+
+ XSD_STRING_MODEL = re.compile("<xsd\:(?:element|attribute) name=\"([^\"]*)\"[^\>]*\>")
+ processCustomFiles(filelist, fileout, XSD_STRING_MODEL, 'Extra XSD strings')
+
+ XML_TC6_STRING_MODEL = re.compile("<documentation>\s*<xhtml\:p><!\[CDATA\[([^\]]*)\]\]></xhtml\:p>\s*</documentation>", re.MULTILINE | re.DOTALL)
+ processCustomFiles(filelist, fileout, XML_TC6_STRING_MODEL, 'Extra TC6 documentation strings')
+
+ # generate messages.po
+ cmd = 'msginit --no-wrap --no-translator -i %s -l en_US.UTF-8 -o messages.po' % (fileout)
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+
+ languageDict = getlanguageDict()
+
+ for langCode in languageDict.keys():
+ if langCode == 'en':
+ pass
+ else:
+ langPOfileName = "%s_%s.po" % (applicationName, langCode)
+ if os.path.exists(langPOfileName):
+ cmd = 'msgmerge -s --no-wrap "%s" %s > "%s.new"' % (langPOfileName, fileout, langPOfileName)
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+ os.chdir(currentDir)
+
+
+def catPO(applicationDirectoryPath, listOf_extraPo, applicationDomain=None, targetDir=None, verbose=0):
+ """Concatenate one or several PO files with the application domain files.
+ """
+
+ if applicationDomain is None:
+ applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
+ else:
+ applicationName = applicationDomain
+ currentDir = os.getcwd()
+ os.chdir(applicationDirectoryPath)
+
+ languageDict = getlanguageDict()
+
+ for langCode in languageDict.keys():
+ if langCode == 'en':
+ pass
+ else:
+ langPOfileName = "%s_%s.po" % (applicationName, langCode)
+ if os.path.exists(langPOfileName):
+ fileList = ''
+ for fileName in listOf_extraPo:
+ fileList += ("%s_%s.po " % (fileName, langCode))
+ cmd = "msgcat -s --no-wrap %s %s > %s.cat" % (langPOfileName, fileList, langPOfileName)
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+ if targetDir is None:
+ pass
+ else:
+ mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir, langCode)
+ cmd = "msgfmt --output-file=%s/%s.mo %s_%s.po.cat" % (mo_targetDir, applicationName, applicationName, langCode)
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+ os.chdir(currentDir)
+
+
+def makeMO(applicationDirectoryPath, targetDir='./locale', applicationDomain=None, verbose=0, forceEnglish=0):
+ """Compile the Portable Object files into the Machine Object stored in the right location.
+
+ makeMO converts all translated language-specific PO files located inside
+ the application directory into the binary .MO files stored inside the
+ LC_MESSAGES sub-directory for the found locale files.
+
+ makeMO searches for all files that have a name of the form 'app_xx.po'
+ inside the application directory specified by the first argument. The
+ 'app' is the application domain name (that can be specified by the
+ applicationDomain argument or is taken from the directory name). The 'xx'
+ corresponds to one of the ISO 639 two-letter language codes.
+
+ makeMo stores the resulting files inside a sub-directory of `targetDir`
+ called xx/LC_MESSAGES where 'xx' corresponds to the 2-letter language
+ code.
+ """
+
+ if targetDir is None:
+ targetDir = './locale'
+
+ verbosePrint(verbose, "Target directory for .mo files is: %s" % targetDir)
+
+ if applicationDomain is None:
+ applicationName = fileBaseOf(applicationDirectoryPath, withPath=0)
+ else:
+ applicationName = applicationDomain
+ currentDir = os.getcwd()
+ os.chdir(applicationDirectoryPath)
+
+ languageDict = getlanguageDict()
+
+ for langCode in languageDict.keys():
+ if (langCode == 'en') and (forceEnglish == 0):
+ pass
+ else:
+ langPOfileName = "%s_%s.po" % (applicationName, langCode)
+ if os.path.exists(langPOfileName):
+ mo_targetDir = "%s/%s/LC_MESSAGES" % (targetDir, langCode)
+ if not os.path.exists(mo_targetDir):
+ mkdir(mo_targetDir)
+ cmd = 'msgfmt --output-file="%s/%s.mo" "%s_%s.po"' % (mo_targetDir, applicationName, applicationName, langCode)
+ verbosePrint(verbose, cmd)
+ os.system(cmd)
+ os.chdir(currentDir)
+
+
+def printUsage(errorMsg=None):
+ """Displays how to use this script from the command line."""
+ print """
+ ##################################################################################
+ # mki18n : Make internationalization files. #
+ # Uses the GNU gettext system to create PO (Portable Object) files #
+ # from source code, coimpile PO into MO (Machine Object) files. #
+ # Supports C,C++,Python source files. #
+ # #
+ # Usage: mki18n {OPTION} [appDirPath] #
+ # #
+ # Options: #
+ # -e : When -m is used, forces English .mo file creation #
+ # -h : prints this help #
+ # -m : make MO from existing PO files #
+ # -p : make PO, update PO files: Creates a new messages.pot #
+ # file. Creates a dom_xx.po.new for every existing #
+ # language specific .po file. ('xx' stands for the ISO639 #
+ # two-letter language code and 'dom' stands for the #
+ # application domain name). mki18n requires that you #
+ # write a 'app.fil' file which contains the list of all #
+ # source code to parse. #
+ # -v : verbose (prints comments while running) #
+ # --domain=appName : specifies the application domain name. By default #
+ # the directory name is used. #
+ # --moTarget=dir : specifies the directory where .mo files are stored. #
+ # If not specified, the target is './locale' #
+ # #
+ # You must specify one of the -p or -m option to perform the work. You can #
+ # specify the path of the target application. If you leave it out mki18n #
+ # will use the current directory as the application main directory. #
+ # #
+ ##################################################################################"""
+ if errorMsg:
+ print "\n ERROR: %s" % errorMsg
+
+
+def fileBaseOf(filename, withPath=0):
+ """fileBaseOf(filename,withPath) ---> string
+
+ Return base name of filename. The returned string never includes the extension.
+ Use os.path.basename() to return the basename with the extension. The
+ second argument is optional. If specified and if set to 'true' (non zero)
+ the string returned contains the full path of the file name. Otherwise the
+ path is excluded.
+
+ [Example]
+ >>> fn = 'd:/dev/telepath/tvapp/code/test.html'
+ >>> fileBaseOf(fn)
+ 'test'
+ >>> fileBaseOf(fn)
+ 'test'
+ >>> fileBaseOf(fn,1)
+ 'd:/dev/telepath/tvapp/code/test'
+ >>> fileBaseOf(fn,0)
+ 'test'
+ >>> fn = 'abcdef'
+ >>> fileBaseOf(fn)
+ 'abcdef'
+ >>> fileBaseOf(fn,1)
+ 'abcdef'
+ >>> fn = "abcdef."
+ >>> fileBaseOf(fn)
+ 'abcdef'
+ >>> fileBaseOf(fn,1)
+ 'abcdef'
+ """
+ pos = filename.rfind('.')
+ if pos > 0:
+ filename = filename[:pos]
+ if withPath:
+ return filename
+ else:
+ return os.path.basename(filename)
+
+
+def mkdir(directory):
+ """Create a directory (and possibly the entire tree).
+
+ The os.mkdir() will fail to create a directory if one of the
+ directory in the specified path does not exist. mkdir()
+ solves this problem. It creates every intermediate directory
+ required to create the final path. Under Unix, the function
+ only supports forward slash separator, but under Windows and MacOS
+ the function supports the forward slash and the OS separator (backslash
+ under windows).
+ """
+
+ # translate the path separators
+ directory = unixpath(directory)
+ # build a list of all directory elements
+ aList = filter(lambda x: len(x) > 0, directory.split('/'))
+ theLen = len(aList)
+ # if the first element is a Windows-style disk drive
+ # concatenate it with the first directory
+ if aList[0].endswith(':'):
+ if theLen > 1:
+ aList[1] = aList[0] + '/' + aList[1]
+ del aList[0]
+ theLen -= 1
+ # if the original directory starts at root,
+ # make sure the first element of the list
+ # starts at root too
+ if directory[0] == '/':
+ aList[0] = '/' + aList[0]
+ # Now iterate through the list, check if the
+ # directory exists and if not create it
+ theDir = ''
+ for i in range(theLen):
+ theDir += aList[i]
+ if not os.path.exists(theDir):
+ os.mkdir(theDir)
+ theDir += '/'
+
+
+def unixpath(thePath):
+ r"""Return a path name that contains Unix separator.
+
+ [Example]
+ >>> unixpath(r"d:\test")
+ 'd:/test'
+ >>> unixpath("d:/test/file.txt")
+ 'd:/test/file.txt'
+ >>>
+ """
+ thePath = os.path.normpath(thePath)
+ if os.sep == '/':
+ return thePath
+ else:
+ return thePath.replace(os.sep, '/')
+
+
+# -----------------------------------------------------------------------------
+
+# S c r i p t e x e c u t i o n -- Runs when invoked from the command line --
+# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+#
+if __name__ == "__main__":
+ import getopt # command line parsing
+ argc = len(sys.argv)
+ if argc == 1:
+ printUsage('Missing argument: specify at least one of -m or -p (or both).')
+ sys.exit(1)
+ # If there is some arguments, parse the command line
+ validOptions = "ehmpv"
+ validLongOptions = ['domain=', 'moTarget=']
+ option = {}
+ option['forceEnglish'] = 0
+ option['mo'] = 0
+ option['po'] = 0
+ option['verbose'] = 0
+ option['domain'] = None
+ option['moTarget'] = None
+ optionKey = {
+ '-e': 'forceEnglish',
+ '-m': 'mo',
+ '-p': 'po',
+ '-v': 'verbose',
+ '--domain': 'domain',
+ '--moTarget': 'moTarget',
+ }
+
+ try:
+ optionList, pargs = getopt.getopt(sys.argv[1:], validOptions, validLongOptions)
+ except getopt.GetoptError, e:
+ printUsage(e[0])
+ sys.exit(1)
+ for (opt, val) in optionList:
+ if (opt == '-h'):
+ printUsage()
+ sys.exit(0)
+ option[optionKey[opt]] = 1 if val == '' else val
+ if len(pargs) == 0:
+ appDirPath = os.getcwd()
+ if option['verbose']:
+ print "No project directory given. Using current one: %s" % appDirPath
+ elif len(pargs) == 1:
+ appDirPath = pargs[0]
+ else:
+ printUsage('Too many arguments (%u). Use double quotes if you have space in directory name' % len(pargs))
+ sys.exit(1)
+ if option['domain'] is None:
+ # If no domain specified, use the name of the target directory
+ option['domain'] = fileBaseOf(appDirPath)
+ if option['verbose']:
+ print "Application domain used is: '%s'" % option['domain']
+ if option['po']:
+ try:
+ makePO(appDirPath, option['domain'], option['verbose'])
+ except IOError, e:
+ printUsage(e[1] + '\n You must write a file app.fil that contains the list of all files to parse.')
+ if option['mo']:
+ makeMO(appDirPath, option['moTarget'], option['domain'], option['verbose'], option['forceEnglish'])
+ sys.exit(1)
+
+
+# -----------------------------------------------------------------------------
--- a/plcopen/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/plcopen/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,5 +28,3 @@
from plcopen import PLCOpenParser, LoadProject, SaveProject, LoadPou, \
LoadPouInstances, VarOrder, QualifierList, rect
-
-
--- a/plcopen/definitions.py Mon Aug 21 20:17:19 2017 +0000
+++ b/plcopen/definitions.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,29 +26,31 @@
from os.path import join, split, realpath
import util.paths as paths
+from util.TranslationCatalogs import NoTranslate
sd = paths.AbsDir(__file__)
# Override gettext _ in this module
# since we just want string to be added to dictionnary
# but translation should happen here
-_ = lambda x:x
+_ = NoTranslate
-LANGUAGES = ["IL","ST","FBD","LD","SFC"]
+LANGUAGES = ["IL", "ST", "FBD", "LD", "SFC"]
-LOCATIONDATATYPES = {"X" : ["BOOL"],
- "B" : ["SINT", "USINT", "BYTE", "STRING"],
- "W" : ["INT", "UINT", "WORD", "WSTRING"],
- "D" : ["DINT", "UDINT", "REAL", "DWORD"],
- "L" : ["LINT", "ULINT", "LREAL", "LWORD"]}
+LOCATIONDATATYPES = {"X": ["BOOL"],
+ "B": ["SINT", "USINT", "BYTE", "STRING"],
+ "W": ["INT", "UINT", "WORD", "WSTRING"],
+ "D": ["DINT", "UDINT", "REAL", "DWORD"],
+ "L": ["LINT", "ULINT", "LREAL", "LWORD"]}
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Function Block Types definitions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
-StdTC6Libs = [(_("Standard function blocks"), join(sd, "Standard_Function_Blocks.xml")),
- (_("Additional function blocks"),join(sd, "Additional_Function_Blocks.xml"))]
+StdTC6Libs = [(_("Standard function blocks"), join(sd, "Standard_Function_Blocks.xml")),
+ (_("Additional function blocks"), join(sd, "Additional_Function_Blocks.xml"))]
-StdFuncsCSV = join(sd,"iec_std.csv")
+StdFuncsCSV = join(sd, "iec_std.csv")
+
def GetBlockInfos(pou):
infos = pou.getblockInfos()
@@ -59,9 +61,10 @@
for var_name, var_type, var_modifier in infos["inputs"]]
return infos
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Data Types definitions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
"""
Ordored list of common data types defined in the IEC 61131-3
@@ -102,45 +105,45 @@
("WORD", "ANY_NBIT"),
("DWORD", "ANY_NBIT"),
("LWORD", "ANY_NBIT")
- #("WSTRING", "ANY_STRING") # TODO
+ # ("WSTRING", "ANY_STRING") # TODO
]
DefaultType = "DINT"
DataTypeRange_list = [
- ("SINT", (-2**7, 2**7 - 1)),
- ("INT", (-2**15, 2**15 - 1)),
- ("DINT", (-2**31, 2**31 - 1)),
- ("LINT", (-2**31, 2**31 - 1)),
- ("USINT", (0, 2**8 - 1)),
- ("UINT", (0, 2**16 - 1)),
- ("UDINT", (0, 2**31 - 1)),
- ("ULINT", (0, 2**31 - 1))
+ ("SINT", (-2**7, 2**7 - 1)),
+ ("INT", (-2**15, 2**15 - 1)),
+ ("DINT", (-2**31, 2**31 - 1)),
+ ("LINT", (-2**31, 2**31 - 1)),
+ ("USINT", (0, 2**8 - 1)),
+ ("UINT", (0, 2**16 - 1)),
+ ("UDINT", (0, 2**31 - 1)),
+ ("ULINT", (0, 2**31 - 1))
]
ANY_TO_ANY_FILTERS = {
- "ANY_TO_ANY":[
+ "ANY_TO_ANY": [
# simple type conv are let as C cast
- (("ANY_INT","ANY_BIT"),("ANY_NUM","ANY_BIT")),
- (("ANY_REAL",),("ANY_REAL",)),
+ (("ANY_INT", "ANY_BIT"), ("ANY_NUM", "ANY_BIT")),
+ (("ANY_REAL",), ("ANY_REAL",)),
# REAL_TO_INT
- (("ANY_REAL",),("ANY_SINT",)),
- (("ANY_REAL",),("ANY_UINT",)),
- (("ANY_REAL",),("ANY_BIT",)),
+ (("ANY_REAL",), ("ANY_SINT",)),
+ (("ANY_REAL",), ("ANY_UINT",)),
+ (("ANY_REAL",), ("ANY_BIT",)),
# TO_TIME
- (("ANY_INT","ANY_BIT"),("ANY_DATE","TIME")),
- (("ANY_REAL",),("ANY_DATE","TIME")),
- (("ANY_STRING",), ("ANY_DATE","TIME")),
+ (("ANY_INT", "ANY_BIT"), ("ANY_DATE", "TIME")),
+ (("ANY_REAL",), ("ANY_DATE", "TIME")),
+ (("ANY_STRING",), ("ANY_DATE", "TIME")),
# FROM_TIME
- (("ANY_DATE","TIME"), ("ANY_REAL",)),
- (("ANY_DATE","TIME"), ("ANY_INT","ANY_NBIT")),
+ (("ANY_DATE", "TIME"), ("ANY_REAL",)),
+ (("ANY_DATE", "TIME"), ("ANY_INT", "ANY_NBIT")),
(("TIME",), ("ANY_STRING",)),
(("DATE",), ("ANY_STRING",)),
- (("TOD",), ("ANY_STRING",)),
- (("DT",), ("ANY_STRING",)),
+ (("TOD",), ("ANY_STRING",)),
+ (("DT",), ("ANY_STRING",)),
# TO_STRING
- (("BOOL",), ("ANY_STRING",)),
- (("ANY_BIT",), ("ANY_STRING",)),
+ (("BOOL",), ("ANY_STRING",)),
+ (("ANY_BIT",), ("ANY_STRING",)),
(("ANY_REAL",), ("ANY_STRING",)),
(("ANY_SINT",), ("ANY_STRING",)),
(("ANY_UINT",), ("ANY_STRING",)),
@@ -149,17 +152,20 @@
(("ANY_STRING",), ("ANY_BIT",)),
(("ANY_STRING",), ("ANY_SINT",)),
(("ANY_STRING",), ("ANY_UINT",)),
- (("ANY_STRING",), ("ANY_REAL",))],
- "BCD_TO_ANY":[
- (("BYTE",),("USINT",)),
- (("WORD",),("UINT",)),
- (("DWORD",),("UDINT",)),
- (("LWORD",),("ULINT",))],
- "ANY_TO_BCD":[
- (("USINT",),("BYTE",)),
- (("UINT",),("WORD",)),
- (("UDINT",),("DWORD",)),
- (("ULINT",),("LWORD",))]
+ (("ANY_STRING",), ("ANY_REAL",))
+ ],
+ "BCD_TO_ANY": [
+ (("BYTE",), ("USINT",)),
+ (("WORD",), ("UINT",)),
+ (("DWORD",), ("UDINT",)),
+ (("LWORD",), ("ULINT",))
+ ],
+ "ANY_TO_BCD": [
+ (("USINT",), ("BYTE",)),
+ (("UINT",), ("WORD",)),
+ (("UDINT",), ("DWORD",)),
+ (("ULINT",), ("LWORD",))
+ ]
}
# remove gettext override
--- a/plcopen/plcopen.py Mon Aug 21 20:17:19 2017 +0000
+++ b/plcopen/plcopen.py Mon Aug 21 23:22:58 2017 +0300
@@ -25,7 +25,8 @@
from xmlclass import *
from types import *
-import os, re
+import os
+import re
from lxml import etree
from collections import OrderedDict
import util.paths as paths
@@ -33,30 +34,39 @@
"""
Dictionary that makes the relation between var names in plcopen and displayed values
"""
-VarTypes = {"Local" : "localVars", "Temp" : "tempVars", "Input" : "inputVars",
- "Output" : "outputVars", "InOut" : "inOutVars", "External" : "externalVars",
- "Global" : "globalVars", "Access" : "accessVars"}
+VarTypes = {
+ "Local": "localVars",
+ "Temp": "tempVars",
+ "Input": "inputVars",
+ "Output": "outputVars",
+ "InOut": "inOutVars",
+ "External": "externalVars",
+ "Global": "globalVars",
+ "Access": "accessVars"
+}
searchResultVarTypes = {
- "inputVars": "var_input",
+ "inputVars": "var_input",
"outputVars": "var_output",
- "inOutVars": "var_inout"
+ "inOutVars": "var_inout"
}
"""
Define in which order var types must be displayed
"""
-VarOrder = ["Local","Temp","Input","Output","InOut","External","Global","Access"]
+VarOrder = ["Local", "Temp", "Input", "Output", "InOut", "External", "Global", "Access"]
"""
-Define which action qualifier must be associated with a duration
+Define which action qualifier must be associated with a duration
"""
-QualifierList = OrderedDict([("N", False), ("R", False), ("S", False),
- ("L", True), ("D", True), ("P", False), ("P0", False),
+QualifierList = OrderedDict([
+ ("N", False), ("R", False), ("S", False),
+ ("L", True), ("D", True), ("P", False), ("P0", False),
("P1", False), ("SD", True), ("DS", True), ("SL", True)])
-FILTER_ADDRESS_MODEL = "(%%[IQM](?:[XBWDL])?)(%s)((?:\.[0-9]+)*)"
+FILTER_ADDRESS_MODEL = "(%%[IQM](?:[XBWDL])?)(%s)((?:\.[0-9]+)*)"
+
def update_address(address, address_model, new_leading):
result = address_model.match(address)
@@ -65,6 +75,7 @@
groups = result.groups()
return groups[0] + new_leading + groups[2]
+
def _init_and_compare(function, v1, v2):
if v1 is None:
return v2
@@ -72,11 +83,12 @@
return function(v1, v2)
return v1
-"""
-Helper class for bounding_box calculation
-"""
+
class rect:
-
+ """
+ Helper class for bounding_box calculation
+ """
+
def __init__(self, x=None, y=None, width=None, height=None):
self.x_min = x
self.x_max = None
@@ -86,19 +98,19 @@
self.x_max = x + width
if height is not None and y is not None:
self.y_max = y + height
-
+
def update(self, x, y):
self.x_min = _init_and_compare(min, self.x_min, x)
self.x_max = _init_and_compare(max, self.x_max, x)
self.y_min = _init_and_compare(min, self.y_min, y)
self.y_max = _init_and_compare(max, self.y_max, y)
-
+
def union(self, rect):
self.x_min = _init_and_compare(min, self.x_min, rect.x_min)
self.x_max = _init_and_compare(max, self.x_max, rect.x_max)
self.y_min = _init_and_compare(min, self.y_min, rect.y_min)
self.y_max = _init_and_compare(max, self.y_max, rect.y_max)
-
+
def bounding_box(self):
width = height = None
if self.x_min is not None and self.x_max is not None:
@@ -107,12 +119,14 @@
height = self.y_max - self.y_min
return self.x_min, self.y_min, width, height
+
def TextLenInRowColumn(text):
if text == "":
return (0, 0)
lines = text.split("\n")
return len(lines) - 1, len(lines[-1])
+
def CompilePattern(criteria):
flag = 0 if criteria["case_sensitive"] else re.IGNORECASE
find_pattern = criteria["find_pattern"]
@@ -120,32 +134,39 @@
find_pattern = re.escape(find_pattern)
criteria["pattern"] = re.compile(find_pattern, flag)
+
def TestTextElement(text, criteria):
lines = text.splitlines()
test_result = []
result = criteria["pattern"].search(text)
while result is not None:
- prev_pos=result.endpos
+ prev_pos = result.endpos
start = TextLenInRowColumn(text[:result.start()])
end = TextLenInRowColumn(text[:result.end() - 1])
test_result.append((start, end, "\n".join(lines[start[0]:end[0] + 1])))
result = criteria["pattern"].search(text, result.end())
- if result is not None and prev_pos==result.endpos:
+ if result is not None and prev_pos == result.endpos:
break
return test_result
+
def TextMatched(str1, str2):
return str1 and str2 and (str1.upper() == str2.upper())
+
PLCOpenParser = GenerateParserFromXSD(paths.AbsNeighbourFile(__file__, "tc6_xml_v201.xsd"))
-PLCOpen_XPath = lambda xpath: etree.XPath(xpath, namespaces=PLCOpenParser.NSMAP)
+
+
+def PLCOpen_XPath(xpath):
+ return etree.XPath(xpath, namespaces=PLCOpenParser.NSMAP)
+
LOAD_POU_PROJECT_TEMPLATE = """
-<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201"
- xmlns:xhtml="http://www.w3.org/1999/xhtml"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+<project xmlns:ns1="http://www.plcopen.org/xml/tc6_0201"
+ xmlns:xhtml="http://www.w3.org/1999/xhtml"
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://www.plcopen.org/xml/tc6_0201">
- <fileHeader companyName="" productName="" productVersion=""
+ <fileHeader companyName="" productName="" productVersion=""
creationDateTime="1970-01-01T00:00:00"/>
<contentHeader name="paste_project">
<coordinateInfo>
@@ -164,6 +185,7 @@
</project>
"""
+
def LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type):
return LOAD_POU_PROJECT_TEMPLATE % """
<pou name="paste_pou" pouType="program">
@@ -172,12 +194,13 @@
</body>
</pou>""" % locals()
+
PLCOpen_v1_file = open(paths.AbsNeighbourFile(__file__, "TC6_XML_V10_B.xsd"))
PLCOpen_v1_xml = PLCOpen_v1_file.read()
PLCOpen_v1_file.close()
PLCOpen_v1_xml = PLCOpen_v1_xml.replace(
- "http://www.plcopen.org/xml/tc6.xsd",
- "http://www.plcopen.org/xml/tc6_0201")
+ "http://www.plcopen.org/xml/tc6.xsd",
+ "http://www.plcopen.org/xml/tc6_0201")
PLCOpen_v1_xsd = etree.XMLSchema(etree.fromstring(PLCOpen_v1_xml))
# XPath for file compatibility process
@@ -188,23 +211,24 @@
ActionBlocksXPath = PLCOpen_XPath("ppx:types/ppx:pous/ppx:pou/ppx:body/*/ppx:actionBlock")
ActionBlocksConnectionPointOutXPath = PLCOpen_XPath("ppx:connectionPointOut")
+
def LoadProjectXML(project_xml):
project_xml = project_xml.replace(
- "http://www.plcopen.org/xml/tc6.xsd",
+ "http://www.plcopen.org/xml/tc6.xsd",
"http://www.plcopen.org/xml/tc6_0201")
for cre, repl in [
- (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
- (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
+ (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
+ (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
project_xml = cre.sub(repl, project_xml)
-
+
try:
tree, error = PLCOpenParser.LoadXMLString(project_xml)
if error is None:
return tree, None
-
+
if PLCOpen_v1_xsd.validate(tree):
# Make file compatible with PLCOpen v2
-
+
# Update resource interval value
for resource in ProjectResourcesXPath(tree):
for task in resource.gettask():
@@ -218,24 +242,24 @@
time_values.extend([int(seconds), int((seconds % 1) * 1000000)])
text = "T#"
if time_values[0] != 0:
- text += "%dh"%time_values[0]
+ text += "%dh" % time_values[0]
if time_values[1] != 0:
- text += "%dm"%time_values[1]
+ text += "%dm" % time_values[1]
if time_values[2] != 0:
- text += "%ds"%time_values[2]
+ text += "%ds" % time_values[2]
if time_values[3] != 0:
if time_values[3] % 1000 != 0:
- text += "%.3fms"%(float(time_values[3]) / 1000)
+ text += "%.3fms" % (float(time_values[3]) / 1000)
else:
- text += "%dms"%(time_values[3] / 1000)
+ text += "%dms" % (time_values[3] / 1000)
task.set("interval", text)
-
+
# Update resources pou instance attributes
for pouInstance in ResourceInstancesXpath(resource):
type_name = pouInstance.attrib.pop("type")
if type_name is not None:
pouInstance.set("typeName", type_name)
-
+
# Update transitions condition
for transition_condition in TransitionsConditionXPath(tree):
connections = ConditionConnectionsXPath(transition_condition)
@@ -245,55 +269,64 @@
connectionPointIn.setrelPositionXY(0, 0)
for connection in connections:
connectionPointIn.append(connection)
-
+
# Update actionBlocks
for actionBlock in ActionBlocksXPath(tree):
for connectionPointOut in ActionBlocksConnectionPointOutXPath(actionBlock):
actionBlock.remove(connectionPointOut)
-
+
for action in actionBlock.getaction():
action.set("localId", "0")
relPosition = PLCOpenParser.CreateElement("relPosition", "action")
relPosition.set("x", "0")
relPosition.set("y", "0")
action.setrelPosition(relPosition)
-
+
return tree, None
-
+
return tree, error
-
+
except Exception, e:
return None, e.message
+
def LoadProject(filepath):
project_file = open(filepath)
project_xml = project_file.read()
project_file.close()
return LoadProjectXML(project_xml)
+
project_pou_xpath = PLCOpen_XPath("/ppx:project/ppx:types/ppx:pous/ppx:pou")
+
+
def LoadPou(xml_string):
root, error = LoadProjectXML(LOAD_POU_PROJECT_TEMPLATE % xml_string)
return project_pou_xpath(root)[0], error
+
project_pou_instances_xpath = {
body_type: PLCOpen_XPath(
"/ppx:project/ppx:types/ppx:pous/ppx:pou[@name='paste_pou']/ppx:body/ppx:%s/*" % body_type)
for body_type in ["FBD", "LD", "SFC"]}
+
+
def LoadPouInstances(xml_string, body_type):
root, error = LoadProjectXML(
LOAD_POU_INSTANCES_PROJECT_TEMPLATE(body_type) % xml_string)
return project_pou_instances_xpath[body_type](root), error
+
def SaveProject(project, filepath):
project_file = open(filepath, 'w')
project_file.write(etree.tostring(
- project,
- pretty_print=True,
- xml_declaration=True,
+ project,
+ pretty_print=True,
+ xml_declaration=True,
encoding='utf-8'))
project_file.close()
+
cls = PLCOpenParser.GetElementClass("formattedText")
if cls:
def updateElementName(self, old_name, new_name):
@@ -302,7 +335,7 @@
text = pattern.sub(new_name, text)
self.setanyText(text)
setattr(cls, "updateElementName", updateElementName)
-
+
def updateElementAddress(self, address_model, new_leading):
text = self.getanyText()
startpos = 0
@@ -315,28 +348,28 @@
result = address_model.search(text, startpos)
self.setanyText(text)
setattr(cls, "updateElementAddress", updateElementAddress)
-
+
def hasblock(self, block_type):
- text = self.getanyText()
+ text = self.getanyText()
pattern = re.compile('\\b' + block_type + '\\b', re.IGNORECASE)
return pattern.search(text) is not None
setattr(cls, "hasblock", hasblock)
-
+
def Search(self, criteria, parent_infos):
return [(tuple(parent_infos),) + result for result in TestTextElement(self.getanyText(), criteria)]
setattr(cls, "Search", Search)
-
+
cls = PLCOpenParser.GetElementClass("project")
if cls:
-
+
def setname(self, name):
self.contentHeader.setname(name)
setattr(cls, "setname", setname)
-
+
def getname(self):
return self.contentHeader.getname()
setattr(cls, "getname", getname)
-
+
def getfileHeader(self):
fileheader_obj = self.fileHeader
return {
@@ -351,7 +384,7 @@
("contentDescription", fileheader_obj.getcontentDescription())]
}
setattr(cls, "getfileHeader", getfileHeader)
-
+
def setfileHeader(self, fileheader):
fileheader_obj = self.fileHeader
for attr in ["companyName", "companyURL", "productName",
@@ -361,7 +394,7 @@
if value is not None:
setattr(fileheader_obj, attr, value)
setattr(cls, "setfileHeader", setfileHeader)
-
+
def getcontentHeader(self):
contentheader_obj = self.contentHeader
contentheader = {
@@ -378,7 +411,7 @@
contentheader["scaling"] = self.contentHeader.getscaling()
return contentheader
setattr(cls, "getcontentHeader", getcontentHeader)
-
+
def setcontentHeader(self, contentheader):
contentheader_obj = self.contentHeader
for attr, value in contentheader.iteritems():
@@ -392,74 +425,78 @@
elif attr in ["modificationDateTime", "organization", "language"]:
setattr(contentheader_obj, attr, value)
setattr(cls, "setcontentHeader", setcontentHeader)
-
+
def gettypeElementFunc(element_type):
elements_xpath = PLCOpen_XPath(
"ppx:types/ppx:%(element_type)ss/ppx:%(element_type)s[@name=$name]" % locals())
+
def gettypeElement(self, name):
elements = elements_xpath(self, name=name)
if len(elements) == 1:
return elements[0]
return None
return gettypeElement
-
+
datatypes_xpath = PLCOpen_XPath("ppx:types/ppx:dataTypes/ppx:dataType")
filtered_datatypes_xpath = PLCOpen_XPath(
"ppx:types/ppx:dataTypes/ppx:dataType[@name!=$exclude]")
+
def getdataTypes(self, exclude=None):
if exclude is not None:
return filtered_datatypes_xpath(self, exclude=exclude)
return datatypes_xpath(self)
setattr(cls, "getdataTypes", getdataTypes)
-
+
setattr(cls, "getdataType", gettypeElementFunc("dataType"))
-
+
def appenddataType(self, name):
if self.getdataType(name) is not None:
- raise ValueError, "\"%s\" Data Type already exists !!!"%name
+ raise ValueError("\"%s\" Data Type already exists !!!" % name)
self.types.appenddataTypeElement(name)
setattr(cls, "appenddataType", appenddataType)
-
+
def insertdataType(self, index, datatype):
self.types.insertdataTypeElement(index, datatype)
setattr(cls, "insertdataType", insertdataType)
-
+
def removedataType(self, name):
self.types.removedataTypeElement(name)
setattr(cls, "removedataType", removedataType)
-
+
def getpous(self, exclude=None, filter=[]):
return self.xpath(
- "ppx:types/ppx:pous/ppx:pou%s%s" %
- (("[@name!='%s']" % exclude) if exclude is not None else '',
- ("[%s]" % " or ".join(
- map(lambda x: "@pouType='%s'" % x, filter)))
- if len(filter) > 0 else ""),
+ "ppx:types/ppx:pous/ppx:pou%s%s" %
+ (("[@name!='%s']" % exclude) if exclude is not None else '',
+ ("[%s]" % " or ".join(
+ map(lambda x: "@pouType='%s'" % x, filter)))
+ if len(filter) > 0 else ""),
namespaces=PLCOpenParser.NSMAP)
setattr(cls, "getpous", getpous)
-
+
setattr(cls, "getpou", gettypeElementFunc("pou"))
-
+
def appendpou(self, name, pou_type, body_type):
self.types.appendpouElement(name, pou_type, body_type)
setattr(cls, "appendpou", appendpou)
-
+
def insertpou(self, index, pou):
self.types.insertpouElement(index, pou)
setattr(cls, "insertpou", insertpou)
-
+
def removepou(self, name):
self.types.removepouElement(name)
setattr(cls, "removepou", removepou)
configurations_xpath = PLCOpen_XPath(
"ppx:instances/ppx:configurations/ppx:configuration")
+
def getconfigurations(self):
return configurations_xpath(self)
setattr(cls, "getconfigurations", getconfigurations)
configuration_xpath = PLCOpen_XPath(
"ppx:instances/ppx:configurations/ppx:configuration[@name=$name]")
+
def getconfiguration(self, name):
configurations = configuration_xpath(self, name=name)
if len(configurations) == 1:
@@ -469,21 +506,22 @@
def addconfiguration(self, name):
if self.getconfiguration(name) is not None:
- raise ValueError, _("\"%s\" configuration already exists !!!") % name
+ raise ValueError(_("\"%s\" configuration already exists !!!") % name)
new_configuration = PLCOpenParser.CreateElement("configuration", "configurations")
new_configuration.setname(name)
self.instances.configurations.appendconfiguration(new_configuration)
- setattr(cls, "addconfiguration", addconfiguration)
+ setattr(cls, "addconfiguration", addconfiguration)
def removeconfiguration(self, name):
configuration = self.getconfiguration(name)
if configuration is None:
- raise ValueError, ("\"%s\" configuration doesn't exist !!!") % name
+ raise ValueError(_("\"%s\" configuration doesn't exist !!!") % name)
self.instances.configurations.remove(configuration)
setattr(cls, "removeconfiguration", removeconfiguration)
-
+
resources_xpath = PLCOpen_XPath(
"ppx:instances/ppx:configurations/ppx:configuration[@name=$configname]/ppx:resource[@name=$name]")
+
def getconfigurationResource(self, config_name, name):
resources = resources_xpath(self, configname=config_name, name=name)
if len(resources) == 1:
@@ -493,8 +531,10 @@
def addconfigurationResource(self, config_name, name):
if self.getconfigurationResource(config_name, name) is not None:
- msg = _("\"{a1}\" resource already exists in \"{a2}\" configuration !!!").format(a1 = name, a2 = config_name)
- raise ValueError, msg
+ raise ValueError(
+ _("\"{a1}\" resource already exists in \"{a2}\" configuration !!!").
+ format(a1=name, a2=config_name))
+
configuration = self.getconfiguration(config_name)
if configuration is not None:
new_resource = PLCOpenParser.CreateElement("resource", "configuration")
@@ -511,8 +551,10 @@
configuration.remove(resource)
found = True
if not found:
- msg = _("\"{a1}\" resource doesn't exist in \"{a2}\" configuration !!!").format(a1 = name, a2 = config_name)
- raise ValueError, msg
+ raise ValueError(
+ _("\"{a1}\" resource doesn't exist in \"{a2}\" configuration !!!").
+ format(a1=name, a2=config_name))
+
setattr(cls, "removeconfigurationResource", removeconfigurationResource)
def updateElementName(self, old_name, new_name):
@@ -549,6 +591,7 @@
enumerated_values_xpath = PLCOpen_XPath(
"ppx:types/ppx:dataTypes/ppx:dataType/ppx:baseType/ppx:enum/ppx:values/ppx:value")
+
def GetEnumeratedDataTypeValues(self):
return [value.getname() for value in enumerated_values_xpath(self)]
setattr(cls, "GetEnumeratedDataTypeValues", GetEnumeratedDataTypeValues)
@@ -562,11 +605,11 @@
cls = PLCOpenParser.GetElementClass("contentHeader", "project")
if cls:
-
+
def setpageSize(self, width, height):
self.coordinateInfo.setpageSize(width, height)
setattr(cls, "setpageSize", setpageSize)
-
+
def getpageSize(self):
return self.coordinateInfo.getpageSize()
setattr(cls, "getpageSize", getpageSize)
@@ -575,7 +618,7 @@
for language, (x, y) in scaling.items():
self.coordinateInfo.setscaling(language, x, y)
setattr(cls, "setscaling", setscaling)
-
+
def getscaling(self):
scaling = {}
scaling["FBD"] = self.coordinateInfo.getscaling("FBD")
@@ -595,7 +638,7 @@
self.pageSize.setx(width)
self.pageSize.sety(height)
setattr(cls, "setpageSize", setpageSize)
-
+
def getpageSize(self):
if self.pageSize is not None:
return self.pageSize.getx(), self.pageSize.gety()
@@ -613,7 +656,7 @@
self.sfc.scaling.setx(x)
self.sfc.scaling.sety(y)
setattr(cls, "setscaling", setscaling)
-
+
def getscaling(self, language):
if language == "FBD":
return self.fbd.scaling.getx(), self.fbd.scaling.gety()
@@ -624,6 +667,7 @@
return 0, 0
setattr(cls, "getscaling", getscaling)
+
def _Search(attributes, criteria, parent_infos):
search_result = []
for attr, value in attributes:
@@ -631,6 +675,7 @@
search_result.extend([(tuple(parent_infos + [attr]),) + result for result in TestTextElement(value, criteria)])
return search_result
+
def _updateConfigurationResourceElementName(self, old_name, new_name):
for varlist in self.getglobalVars():
for var in varlist.getvariable():
@@ -641,6 +686,7 @@
if TextMatched(var.getname(), old_name):
var.setname(new_name)
+
def _updateConfigurationResourceElementAddress(self, address_model, new_leading):
for varlist in self.getglobalVars():
for var in varlist.getvariable():
@@ -648,6 +694,7 @@
if var_address is not None:
var.setaddress(update_address(var_address, address_model, new_leading))
+
def _removeConfigurationResourceVariableByAddress(self, address):
for varlist in self.getglobalVars():
variables = varlist.getvariable()
@@ -655,6 +702,7 @@
if variables[i].getaddress() == address:
variables.remove(variables[i])
+
def _removeConfigurationResourceVariableByFilter(self, address_model):
for varlist in self.getglobalVars():
variables = varlist.getvariable()
@@ -665,6 +713,7 @@
if result is not None:
variables.remove(variables[i])
+
def _SearchInConfigurationResource(self, criteria, parent_infos=[]):
search_result = _Search([("name", self.getname())], criteria, parent_infos)
var_number = 0
@@ -683,9 +732,10 @@
var_number += 1
return search_result
+
cls = PLCOpenParser.GetElementClass("configuration", "configurations")
if cls:
-
+
def addglobalVar(self, var_type, name, location="", description=""):
globalvars = self.getglobalVars()
if len(globalvars) == 0:
@@ -701,7 +751,7 @@
var.setdocumentation(ft)
globalvars[-1].appendvariable(var)
setattr(cls, "addglobalVar", addglobalVar)
-
+
def updateElementName(self, old_name, new_name):
_updateConfigurationResourceElementName(self, old_name, new_name)
for resource in self.getresource():
@@ -727,7 +777,7 @@
search_result.extend(resource.Search(criteria, parent_infos))
return search_result
setattr(cls, "Search", Search)
-
+
cls = PLCOpenParser.GetElementClass("resource", "configuration")
if cls:
def updateElementName(self, old_name, new_name):
@@ -788,7 +838,7 @@
setattr(cls, "updateElementAddress", updateElementAddress)
def Search(self, criteria, parent_infos=[]):
- return _Search([("single", self.getsingle()),
+ return _Search([("single", self.getsingle()),
("interval", self.getinterval()),
("priority", str(self.getpriority()))],
criteria, parent_infos)
@@ -802,7 +852,7 @@
setattr(cls, "updateElementName", updateElementName)
def Search(self, criteria, parent_infos=[]):
- return _Search([("name", self.getname()),
+ return _Search([("name", self.getname()),
("type", self.gettypeName())],
criteria, parent_infos)
setattr(cls, "Search", Search)
@@ -822,22 +872,22 @@
elif vartype_content_name == "array":
base_type = vartype_content.baseType.getcontent()
base_type_name = base_type.getLocalTag()
- # Array derived directly from a user defined type
+ # Array derived directly from a user defined type
if base_type_name == "derived":
basetype_name = base_type.getname()
- # Array derived directly from a string type
+ # Array derived directly from a string type
elif base_type_name in ["string", "wstring"]:
basetype_name = base_type_name.upper()
- # Array derived directly from an elementary type
+ # Array derived directly from an elementary type
else:
basetype_name = base_type_name
- return "ARRAY [%s] OF %s" % (",".join(map(lambda x : "%s..%s" % (x.getlower(), x.getupper()), vartype_content.getdimension())), basetype_name)
+ return "ARRAY [%s] OF %s" % (",".join(map(lambda x: "%s..%s" % (x.getlower(), x.getupper()), vartype_content.getdimension())), basetype_name)
# Variable type is an elementary type
return vartype_content_name
setattr(cls, "gettypeAsText", gettypeAsText)
-
+
def Search(self, criteria, parent_infos=[]):
- search_result = _Search([("name", self.getname()),
+ search_result = _Search([("name", self.getname()),
("type", self.gettypeAsText()),
("location", self.getaddress())],
criteria, parent_infos)
@@ -855,7 +905,7 @@
def getdataTypeElements(self):
return self.dataTypes.getdataType()
setattr(cls, "getdataTypeElements", getdataTypeElements)
-
+
def getdataTypeElement(self, name):
elements = self.dataTypes.getdataType()
for element in elements:
@@ -870,11 +920,11 @@
new_datatype.setname(name)
new_datatype.baseType.setcontent(PLCOpenParser.CreateElement("BOOL", "dataType"))
setattr(cls, "appenddataTypeElement", appenddataTypeElement)
-
+
def insertdataTypeElement(self, index, dataType):
self.dataTypes.insertdataType(index, dataType)
setattr(cls, "insertdataTypeElement", insertdataTypeElement)
-
+
def removedataTypeElement(self, name):
found = False
for element in self.dataTypes.getdataType():
@@ -883,13 +933,13 @@
found = True
break
if not found:
- raise ValueError, _("\"%s\" Data Type doesn't exist !!!")%name
+ raise ValueError(_("\"%s\" Data Type doesn't exist !!!") % name)
setattr(cls, "removedataTypeElement", removedataTypeElement)
-
+
def getpouElements(self):
return self.pous.getpou()
setattr(cls, "getpouElements", getpouElements)
-
+
def getpouElement(self, name):
elements = self.pous.getpou()
for element in elements:
@@ -901,7 +951,7 @@
def appendpouElement(self, name, pou_type, body_type):
for element in self.pous.getpou():
if TextMatched(element.getname(), name):
- raise ValueError, _("\"%s\" POU already exists !!!")%name
+ raise ValueError(_("\"%s\" POU already exists !!!") % name)
new_pou = PLCOpenParser.CreateElement("pou", "pous")
self.pous.appendpou(new_pou)
new_pou.setname(name)
@@ -909,11 +959,11 @@
new_pou.appendbody(PLCOpenParser.CreateElement("body", "pou"))
new_pou.setbodyType(body_type)
setattr(cls, "appendpouElement", appendpouElement)
-
+
def insertpouElement(self, index, pou):
self.pous.insertpou(index, pou)
setattr(cls, "insertpouElement", insertpouElement)
-
+
def removepouElement(self, name):
found = False
for element in self.pous.getpou():
@@ -922,7 +972,7 @@
found = True
break
if not found:
- raise ValueError, _("\"%s\" POU doesn't exist !!!")%name
+ raise ValueError(_("\"%s\" POU doesn't exist !!!") % name)
setattr(cls, "removepouElement", removepouElement)
def Search(self, criteria, parent_infos=[]):
@@ -935,13 +985,15 @@
return search_result
setattr(cls, "Search", Search)
+
def _updateBaseTypeElementName(self, old_name, new_name):
self.baseType.updateElementName(old_name, new_name)
+
cls = PLCOpenParser.GetElementClass("dataType", "dataTypes")
if cls:
setattr(cls, "updateElementName", _updateBaseTypeElementName)
-
+
def Search(self, criteria, parent_infos=[]):
search_result = []
filter = criteria["filter"]
@@ -956,7 +1008,7 @@
cls = PLCOpenParser.GetElementClass("dataType")
if cls:
-
+
def updateElementName(self, old_name, new_name):
content_name = self.content.getLocalTag()
if content_name in ["derived", "array", "subrangeSigned", "subrangeUnsigned"]:
@@ -987,7 +1039,7 @@
if TextMatched(self.name, old_name):
self.name = new_name
setattr(cls, "updateElementName", updateElementName)
-
+
def Search(self, criteria, parent_infos=[]):
return [(tuple(parent_infos),) + result for result in TestTextElement(self.name, criteria)]
setattr(cls, "Search", Search)
@@ -995,7 +1047,7 @@
cls = PLCOpenParser.GetElementClass("array", "dataType")
if cls:
setattr(cls, "updateElementName", _updateBaseTypeElementName)
-
+
def Search(self, criteria, parent_infos=[]):
search_result = self.baseType.Search(criteria, parent_infos)
for i, dimension in enumerate(self.getdimension()):
@@ -1005,6 +1057,7 @@
return search_result
setattr(cls, "Search", Search)
+
def _SearchInSubrange(self, criteria, parent_infos=[]):
search_result = self.baseType.Search(criteria, parent_infos)
search_result.extend(_Search([("lower", self.range.getlower()),
@@ -1012,6 +1065,7 @@
criteria, parent_infos))
return search_result
+
cls = PLCOpenParser.GetElementClass("subrangeSigned", "dataType")
if cls:
setattr(cls, "updateElementName", _updateBaseTypeElementName)
@@ -1024,12 +1078,13 @@
cls = PLCOpenParser.GetElementClass("enum", "dataType")
if cls:
-
+
def updateElementName(self, old_name, new_name):
pass
setattr(cls, "updateElementName", updateElementName)
-
+
enumerated_datatype_values_xpath = PLCOpen_XPath("ppx:values/ppx:value")
+
def Search(self, criteria, parent_infos=[]):
search_result = []
for i, value in enumerate(enumerated_datatype_values_xpath(self)):
@@ -1038,28 +1093,31 @@
return search_result
setattr(cls, "Search", Search)
+
def _getvariableTypeinfos(variable_type):
type_content = variable_type.getcontent()
type_content_type = type_content.getLocalTag()
if type_content_type == "derived":
return type_content.getname()
return type_content_type.upper()
-
+
+
cls = PLCOpenParser.GetElementClass("pou", "pous")
if cls:
-
+
block_inputs_xpath = PLCOpen_XPath(
"ppx:interface/*[self::ppx:inputVars or self::ppx:inOutVars]/ppx:variable")
block_outputs_xpath = PLCOpen_XPath(
"ppx:interface/*[self::ppx:outputVars or self::ppx:inOutVars]/ppx:variable")
- def getblockInfos(self):
+
+ def getblockInfos(self):
block_infos = {
- "name" : self.getname(),
- "type" : self.getpouType(),
- "extensible" : False,
- "inputs" : [],
- "outputs" : [],
- "comment" : self.getdescription()}
+ "name": self.getname(),
+ "type": self.getpouType(),
+ "extensible": False,
+ "inputs": [],
+ "outputs": [],
+ "comment": self.getdescription()}
if self.interface is not None:
return_type = self.interface.getreturnType()
if return_type is not None:
@@ -1071,15 +1129,15 @@
block_infos["outputs"].extend(
[(var.getname(), _getvariableTypeinfos(var.type), "none")
for var in block_outputs_xpath(self)])
-
- block_infos["usage"] = ("\n (%s) => (%s)" %
- (", ".join(["%s:%s" % (input[1], input[0])
- for input in block_infos["inputs"]]),
- ", ".join(["%s:%s" % (output[1], output[0])
- for output in block_infos["outputs"]])))
+
+ block_infos["usage"] = ("\n (%s) => (%s)" %
+ (", ".join(["%s:%s" % (input[1], input[0])
+ for input in block_infos["inputs"]]),
+ ", ".join(["%s:%s" % (output[1], output[0])
+ for output in block_infos["outputs"]])))
return block_infos
setattr(cls, "getblockInfos", getblockInfos)
-
+
def setdescription(self, description):
doc = self.getdocumentation()
if doc is None:
@@ -1087,81 +1145,81 @@
self.setdocumentation(doc)
doc.setanyText(description)
setattr(cls, "setdescription", setdescription)
-
+
def getdescription(self):
doc = self.getdocumentation()
if doc is not None:
return doc.getanyText()
return ""
setattr(cls, "getdescription", getdescription)
-
+
def setbodyType(self, body_type):
if len(self.body) > 0:
if body_type in ["IL", "ST", "LD", "FBD", "SFC"]:
self.body[0].setcontent(PLCOpenParser.CreateElement(body_type, "body"))
else:
- raise ValueError, "%s isn't a valid body type!"%type
+ raise ValueError("%s isn't a valid body type!" % type)
setattr(cls, "setbodyType", setbodyType)
-
+
def getbodyType(self):
if len(self.body) > 0:
return self.body[0].getcontent().getLocalTag()
setattr(cls, "getbodyType", getbodyType)
-
+
def resetexecutionOrder(self):
if len(self.body) > 0:
self.body[0].resetexecutionOrder()
setattr(cls, "resetexecutionOrder", resetexecutionOrder)
-
+
def compileexecutionOrder(self):
if len(self.body) > 0:
self.body[0].compileexecutionOrder()
setattr(cls, "compileexecutionOrder", compileexecutionOrder)
-
+
def setelementExecutionOrder(self, instance, new_executionOrder):
if len(self.body) > 0:
self.body[0].setelementExecutionOrder(instance, new_executionOrder)
setattr(cls, "setelementExecutionOrder", setelementExecutionOrder)
-
+
def addinstance(self, instance):
if len(self.body) > 0:
self.body[0].appendcontentInstance(instance)
setattr(cls, "addinstance", addinstance)
-
+
def getinstances(self):
if len(self.body) > 0:
return self.body[0].getcontentInstances()
return []
setattr(cls, "getinstances", getinstances)
-
+
def getinstance(self, id):
if len(self.body) > 0:
return self.body[0].getcontentInstance(id)
return None
setattr(cls, "getinstance", getinstance)
-
+
def getinstancesIds(self):
if len(self.body) > 0:
return self.body[0].getcontentInstancesIds()
return []
setattr(cls, "getinstancesIds", getinstancesIds)
-
+
def getinstanceByName(self, name):
if len(self.body) > 0:
return self.body[0].getcontentInstanceByName(name)
return None
setattr(cls, "getinstanceByName", getinstanceByName)
-
+
def removeinstance(self, id):
if len(self.body) > 0:
self.body[0].removecontentInstance(id)
setattr(cls, "removeinstance", removeinstance)
-
+
def settext(self, text):
if len(self.body) > 0:
self.body[0].settext(text)
setattr(cls, "settext", settext)
-
+
def gettext(self):
if len(self.body) > 0:
return self.body[0].gettext()
@@ -1178,17 +1236,17 @@
vars.append((reverse_types[varlist.getLocalTag()], varlist))
return vars
setattr(cls, "getvars", getvars)
-
+
def setvars(self, vars):
if self.interface is None:
self.interface = PLCOpenParser.CreateElement("interface", "pou")
self.interface.setcontent(vars)
setattr(cls, "setvars", setvars)
-
+
def addpouExternalVar(self, var_type, name):
self.addpouVar(var_type, name, "externalVars")
setattr(cls, "addpouExternalVar", addpouExternalVar)
-
+
def addpouVar(self, var_type, name, var_class="localVars", location="", description="", initval=""):
if self.interface is None:
self.interface = PLCOpenParser.CreateElement("interface", "pou")
@@ -1218,11 +1276,11 @@
el = PLCOpenParser.CreateElement("initialValue", "variable")
el.setvalue(initval)
var.setinitialValue(el)
-
+
varlist.appendvariable(var)
setattr(cls, "addpouVar", addpouVar)
setattr(cls, "addpouLocalVar", addpouVar)
-
+
def changepouVar(self, old_type, old_name, new_type, new_name):
if self.interface is not None:
content = self.interface.getcontent()
@@ -1236,7 +1294,7 @@
vartype_content.setname(new_type)
return
setattr(cls, "changepouVar", changepouVar)
-
+
def removepouVar(self, var_type, name):
if self.interface is not None:
content = self.interface.getcontent()
@@ -1255,15 +1313,16 @@
if self.getbodyType() in ["SFC"]:
for instance in self.getinstances():
if isinstance(instance, PLCOpenParser.GetElementClass("step", "sfcObjects")) and TextMatched(instance.getname(), name):
- return True
+ return True
return False
setattr(cls, "hasstep", hasstep)
-
+
def hasblock(self, name=None, block_type=None):
if self.getbodyType() in ["FBD", "LD", "SFC"]:
for instance in self.getinstances():
- if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and
- (TextMatched(instance.getinstanceName(), name) or TextMatched(instance.gettypeName(), block_type))):
+ if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) \
+ and (TextMatched(instance.getinstanceName(), name) or
+ TextMatched(instance.gettypeName(), block_type)):
return True
if self.transitions:
for transition in self.transitions.gettransition():
@@ -1279,7 +1338,7 @@
return self.body[0].hasblock(block_type)
return False
setattr(cls, "hasblock", hasblock)
-
+
def addtransition(self, name, body_type):
if self.transitions is None:
self.addtransitions()
@@ -1291,7 +1350,7 @@
if body_type == "ST":
transition.settext(":= ;")
setattr(cls, "addtransition", addtransition)
-
+
def gettransition(self, name):
if self.transitions is not None:
for transition in self.transitions.gettransition():
@@ -1299,13 +1358,13 @@
return transition
return None
setattr(cls, "gettransition", gettransition)
-
+
def gettransitionList(self):
if self.transitions is not None:
return self.transitions.gettransition()
return []
setattr(cls, "gettransitionList", gettransitionList)
-
+
def removetransition(self, name):
if self.transitions is not None:
removed = False
@@ -1314,13 +1373,13 @@
if transition.getbodyType() in ["FBD", "LD", "SFC"]:
for instance in transition.getinstances():
if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")):
- self.removepouVar(instance.gettypeName(),
+ self.removepouVar(instance.gettypeName(),
instance.getinstanceName())
self.transitions.remove(transition)
removed = True
break
if not removed:
- raise ValueError, _("Transition with name %s doesn't exist!")%name
+ raise ValueError(_("Transition with name %s doesn't exist!") % name)
setattr(cls, "removetransition", removetransition)
def addaction(self, name, body_type):
@@ -1332,7 +1391,7 @@
action.setname(name)
action.setbodyType(body_type)
setattr(cls, "addaction", addaction)
-
+
def getaction(self, name):
if self.actions is not None:
for action in self.actions.getaction():
@@ -1340,13 +1399,13 @@
return action
return None
setattr(cls, "getaction", getaction)
-
+
def getactionList(self):
if self.actions is not None:
return self.actions.getaction()
return []
setattr(cls, "getactionList", getactionList)
-
+
def removeaction(self, name):
if self.actions is not None:
removed = False
@@ -1355,13 +1414,13 @@
if action.getbodyType() in ["FBD", "LD", "SFC"]:
for instance in action.getinstances():
if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")):
- self.removepouVar(instance.gettypeName(),
+ self.removepouVar(instance.gettypeName(),
instance.getinstanceName())
self.actions.remove(action)
removed = True
break
if not removed:
- raise ValueError, _("Action with name %s doesn't exist!")%name
+ raise ValueError(_("Action with name %s doesn't exist!") % name)
setattr(cls, "removeaction", removeaction)
def updateElementName(self, old_name, new_name):
@@ -1417,7 +1476,7 @@
if result is not None:
content.remove(variable)
setattr(cls, "removeVariableByFilter", removeVariableByFilter)
-
+
def Search(self, criteria, parent_infos=[]):
search_result = []
filter = criteria["filter"]
@@ -1449,64 +1508,80 @@
return search_result
setattr(cls, "Search", Search)
+
def setbodyType(self, body_type):
if body_type in ["IL", "ST", "LD", "FBD", "SFC"]:
self.body.setcontent(PLCOpenParser.CreateElement(body_type, "body"))
else:
- raise ValueError, "%s isn't a valid body type!"%type
+ raise ValueError("%s isn't a valid body type!" % type)
+
def getbodyType(self):
return self.body.getcontent().getLocalTag()
+
def resetexecutionOrder(self):
self.body.resetexecutionOrder()
+
def compileexecutionOrder(self):
self.body.compileexecutionOrder()
+
def setelementExecutionOrder(self, instance, new_executionOrder):
self.body.setelementExecutionOrder(instance, new_executionOrder)
+
def addinstance(self, instance):
self.body.appendcontentInstance(instance)
+
def getinstances(self):
return self.body.getcontentInstances()
+
def getinstance(self, id):
return self.body.getcontentInstance(id)
+
def getrandomInstance(self, exclude):
return self.body.getcontentRandomInstance(exclude)
+
def getinstanceByName(self, name):
return self.body.getcontentInstanceByName(name)
+
def removeinstance(self, id):
self.body.removecontentInstance(id)
+
def settext(self, text):
self.body.settext(text)
+
def gettext(self):
return self.body.gettext()
+
def hasblock(self, name=None, block_type=None):
if self.getbodyType() in ["FBD", "LD", "SFC"]:
for instance in self.getinstances():
- if (isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and
- (TextMatched(instance.getinstanceName(), name) or TextMatched(instance.gettypeName(), block_type))):
+ if isinstance(instance, PLCOpenParser.GetElementClass("block", "fbdObjects")) and \
+ (TextMatched(instance.getinstanceName(), name) or TextMatched(instance.gettypeName(), block_type)):
return True
elif block_type is not None:
return self.body.hasblock(block_type)
return False
+
def updateElementName(self, old_name, new_name):
self.body.updateElementName(old_name, new_name)
+
def updateElementAddress(self, address_model, new_leading):
self.body.updateElementAddress(address_model, new_leading)
-
+
cls = PLCOpenParser.GetElementClass("transition", "transitions")
if cls:
@@ -1526,7 +1601,7 @@
setattr(cls, "hasblock", hasblock)
setattr(cls, "updateElementName", updateElementName)
setattr(cls, "updateElementAddress", updateElementAddress)
-
+
def Search(self, criteria, parent_infos):
search_result = []
parent_infos = parent_infos[:-1] + ["T::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
@@ -1554,7 +1629,7 @@
setattr(cls, "hasblock", hasblock)
setattr(cls, "updateElementName", updateElementName)
setattr(cls, "updateElementAddress", updateElementAddress)
-
+
def Search(self, criteria, parent_infos):
search_result = []
parent_infos = parent_infos[:-1] + ["A::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
@@ -1568,27 +1643,28 @@
if cls:
cls.currentExecutionOrderId = 0
cls.checkedBlocksDict = {}
+
def resetcurrentExecutionOrderId(self):
object.__setattr__(self, "currentExecutionOrderId", 0)
setattr(cls, "resetcurrentExecutionOrderId", resetcurrentExecutionOrderId)
-
+
def getnewExecutionOrderId(self):
object.__setattr__(self, "currentExecutionOrderId", self.currentExecutionOrderId + 1)
return self.currentExecutionOrderId
setattr(cls, "getnewExecutionOrderId", getnewExecutionOrderId)
-
+
def resetexecutionOrder(self):
if self.content.getLocalTag() == "FBD":
for element in self.content.getcontent():
- if not isinstance(element, (PLCOpenParser.GetElementClass("comment", "commonObjects"),
- PLCOpenParser.GetElementClass("connector", "commonObjects"),
+ if not isinstance(element, (PLCOpenParser.GetElementClass("comment", "commonObjects"),
+ PLCOpenParser.GetElementClass("connector", "commonObjects"),
PLCOpenParser.GetElementClass("continuation", "commonObjects"))):
element.setexecutionOrderId(0)
self.checkedBlocksDict.clear()
else:
- raise TypeError, _("Can only generate execution order on FBD networks!")
+ raise TypeError(_("Can only generate execution order on FBD networks!"))
setattr(cls, "resetexecutionOrder", resetexecutionOrder)
-
+
def compileexecutionOrder(self):
if self.content.getLocalTag() == "FBD":
self.resetexecutionOrder()
@@ -1600,9 +1676,9 @@
self.compileelementExecutionOrder(connections[0])
element.setexecutionOrderId(self.getnewExecutionOrderId())
else:
- raise TypeError, _("Can only generate execution order on FBD networks!")
+ raise TypeError(_("Can only generate execution order on FBD networks!"))
setattr(cls, "compileexecutionOrder", compileexecutionOrder)
-
+
def compileelementExecutionOrder(self, link):
if self.content.getLocalTag() == "FBD":
localid = link.getrefLocalId()
@@ -1612,21 +1688,22 @@
for variable in instance.inputVariables.getvariable():
connections = variable.connectionPointIn.getconnections()
if connections and len(connections) == 1:
- if (self.checkedBlocksDict.has_key(connections[0].getrefLocalId()) == False):
+ if not connections[0].getrefLocalId() in self.checkedBlocksDict:
self.compileelementExecutionOrder(connections[0])
if instance.getexecutionOrderId() == 0:
instance.setexecutionOrderId(self.getnewExecutionOrderId())
elif isinstance(instance, PLCOpenParser.GetElementClass("continuation", "commonObjects")) and instance.getexecutionOrderId() == 0:
for tmp_instance in self.getcontentInstances():
- if (isinstance(tmp_instance, PLCOpenParser.GetElementClass("connector", "commonObjects")) and
- TextMatched(tmp_instance.getname(), instance.getname()) and tmp_instance.getexecutionOrderId() == 0):
+ if isinstance(tmp_instance, PLCOpenParser.GetElementClass("connector", "commonObjects")) and \
+ TextMatched(tmp_instance.getname(), instance.getname()) and \
+ tmp_instance.getexecutionOrderId() == 0:
connections = tmp_instance.connectionPointIn.getconnections()
if connections and len(connections) == 1:
self.compileelementExecutionOrder(connections[0])
else:
- raise TypeError, _("Can only generate execution order on FBD networks!")
+ raise TypeError(_("Can only generate execution order on FBD networks!"))
setattr(cls, "compileelementExecutionOrder", compileelementExecutionOrder)
-
+
def setelementExecutionOrder(self, instance, new_executionOrder):
if self.content.getLocalTag() == "FBD":
old_executionOrder = instance.getexecutionOrderId()
@@ -1640,85 +1717,86 @@
element.setexecutionOrderId(element_executionOrder + 1)
instance.setexecutionOrderId(new_executionOrder)
else:
- raise TypeError, _("Can only generate execution order on FBD networks!")
+ raise TypeError(_("Can only generate execution order on FBD networks!"))
setattr(cls, "setelementExecutionOrder", setelementExecutionOrder)
-
+
def appendcontentInstance(self, instance):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
self.content.appendcontent(instance)
else:
- raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "appendcontentInstance", appendcontentInstance)
-
+
def getcontentInstances(self):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
return self.content.getcontent()
else:
- raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "getcontentInstances", getcontentInstances)
-
+
instance_by_id_xpath = PLCOpen_XPath("*[@localId=$localId]")
instance_by_name_xpath = PLCOpen_XPath("ppx:block[@instanceName=$name]")
+
def getcontentInstance(self, local_id):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
instance = instance_by_id_xpath(self.content, localId=local_id)
if len(instance) > 0:
return instance[0]
return None
else:
- raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "getcontentInstance", getcontentInstance)
-
+
def getcontentInstancesIds(self):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
return OrderedDict([(instance.getlocalId(), True)
for instance in self.content])
else:
- raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "getcontentInstancesIds", getcontentInstancesIds)
-
+
def getcontentInstanceByName(self, name):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
instance = instance_by_name_xpath(self.content)
if len(instance) > 0:
return instance[0]
return None
else:
- raise TypeError, _("%s body don't have instances!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "getcontentInstanceByName", getcontentInstanceByName)
-
+
def removecontentInstance(self, local_id):
- if self.content.getLocalTag() in ["LD","FBD","SFC"]:
+ if self.content.getLocalTag() in ["LD", "FBD", "SFC"]:
instance = instance_by_id_xpath(self.content, localId=local_id)
if len(instance) > 0:
self.content.remove(instance[0])
else:
- raise ValueError, _("Instance with id %d doesn't exist!")%id
+ raise ValueError(_("Instance with id %d doesn't exist!") % id)
else:
- raise TypeError, "%s body don't have instances!"%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have instances!") % self.content.getLocalTag())
setattr(cls, "removecontentInstance", removecontentInstance)
-
+
def settext(self, text):
- if self.content.getLocalTag() in ["IL","ST"]:
+ if self.content.getLocalTag() in ["IL", "ST"]:
self.content.setanyText(text)
else:
- raise TypeError, _("%s body don't have text!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have text!") % self.content.getLocalTag())
setattr(cls, "settext", settext)
def gettext(self):
- if self.content.getLocalTag() in ["IL","ST"]:
+ if self.content.getLocalTag() in ["IL", "ST"]:
return self.content.getanyText()
else:
- raise TypeError, _("%s body don't have text!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have text!") % self.content.getLocalTag())
setattr(cls, "gettext", gettext)
-
+
def hasblock(self, block_type):
- if self.content.getLocalTag() in ["IL","ST"]:
+ if self.content.getLocalTag() in ["IL", "ST"]:
return self.content.hasblock(block_type)
else:
- raise TypeError, _("%s body don't have text!")%self.content.getLocalTag()
+ raise TypeError(_("%s body don't have text!") % self.content.getLocalTag())
setattr(cls, "hasblock", hasblock)
-
+
def updateElementName(self, old_name, new_name):
if self.content.getLocalTag() in ["IL", "ST"]:
self.content.updateElementName(old_name, new_name)
@@ -1745,21 +1823,27 @@
return search_result
setattr(cls, "Search", Search)
+
def getx(self):
return self.position.getx()
+
def gety(self):
return self.position.gety()
+
def setx(self, x):
self.position.setx(x)
-
+
+
def sety(self, y):
self.position.sety(y)
+
def _getBoundingBox(self):
return rect(self.getx(), self.gety(), self.getwidth(), self.getheight())
+
def _getConnectionsBoundingBox(connectionPointIn):
bbox = rect()
connections = connectionPointIn.getconnections()
@@ -1769,39 +1853,46 @@
bbox.update(x, y)
return bbox
+
def _getBoundingBoxSingle(self):
bbox = _getBoundingBox(self)
if self.connectionPointIn is not None:
bbox.union(_getConnectionsBoundingBox(self.connectionPointIn))
return bbox
+
def _getBoundingBoxMultiple(self):
bbox = _getBoundingBox(self)
for connectionPointIn in self.getconnectionPointIn():
bbox.union(_getConnectionsBoundingBox(connectionPointIn))
return bbox
+
def _filterConnections(connectionPointIn, localId, connections):
in_connections = connectionPointIn.getconnections()
if in_connections is not None:
for connection in in_connections:
connected = connection.getrefLocalId()
- if not connections.has_key((localId, connected)) and \
- not connections.has_key((connected, localId)):
+ if not (localId, connected) in connections and \
+ not (connected, localId) in connections:
connectionPointIn.remove(connection)
+
def _filterConnectionsSingle(self, connections):
if self.connectionPointIn is not None:
_filterConnections(self.connectionPointIn, self.localId, connections)
+
def _filterConnectionsMultiple(self, connections):
for connectionPointIn in self.getconnectionPointIn():
_filterConnections(connectionPointIn, self.localId, connections)
+
def _getconnectionsdefinition(instance, connections_end):
local_id = instance.getlocalId()
return dict([((local_id, end), True) for end in connections_end])
+
def _updateConnectionsId(connectionPointIn, translation):
connections_end = []
connections = connectionPointIn.getconnections()
@@ -1813,22 +1904,26 @@
connections_end.append(new_reflocalId)
return connections_end
+
def _updateConnectionsIdSingle(self, translation):
connections_end = []
if self.connectionPointIn is not None:
connections_end = _updateConnectionsId(self.connectionPointIn, translation)
return _getconnectionsdefinition(self, connections_end)
+
def _updateConnectionsIdMultiple(self, translation):
connections_end = []
for connectionPointIn in self.getconnectionPointIn():
connections_end.extend(_updateConnectionsId(connectionPointIn, translation))
return _getconnectionsdefinition(self, connections_end)
+
def _translate(self, dx, dy):
self.setx(self.getx() + dx)
self.sety(self.gety() + dy)
-
+
+
def _translateConnections(connectionPointIn, dx, dy):
connections = connectionPointIn.getconnections()
if connections is not None:
@@ -1837,32 +1932,38 @@
position.setx(position.getx() + dx)
position.sety(position.gety() + dy)
+
def _translateSingle(self, dx, dy):
_translate(self, dx, dy)
if self.connectionPointIn is not None:
_translateConnections(self.connectionPointIn, dx, dy)
+
def _translateMultiple(self, dx, dy):
_translate(self, dx, dy)
for connectionPointIn in self.getconnectionPointIn():
_translateConnections(connectionPointIn, dx, dy)
+
def _updateElementName(self, old_name, new_name):
pass
+
def _updateElementAddress(self, address_model, new_leading):
pass
+
def _SearchInElement(self, criteria, parent_infos=[]):
return []
+
_connectionsFunctions = {
"bbox": {"none": _getBoundingBox,
"single": _getBoundingBoxSingle,
"multiple": _getBoundingBoxMultiple},
"translate": {"none": _translate,
- "single": _translateSingle,
- "multiple": _translateMultiple},
+ "single": _translateSingle,
+ "multiple": _translateMultiple},
"filter": {"none": lambda self, connections: None,
"single": _filterConnectionsSingle,
"multiple": _filterConnectionsMultiple},
@@ -1871,6 +1972,7 @@
"multiple": _updateConnectionsIdMultiple},
}
+
def _initElementClass(name, parent, connectionPointInType="none"):
cls = PLCOpenParser.GetElementClass(name, parent)
if cls:
@@ -1887,16 +1989,17 @@
setattr(cls, "Search", _SearchInElement)
return cls
+
cls = _initElementClass("comment", "commonObjects")
if cls:
def setcontentText(self, text):
self.content.setanyText(text)
setattr(cls, "setcontentText", setcontentText)
-
+
def getcontentText(self):
return self.content.getanyText()
setattr(cls, "getcontentText", getcontentText)
-
+
def updateElementName(self, old_name, new_name):
self.content.updateElementName(old_name, new_name)
setattr(cls, "updateElementName", updateElementName)
@@ -1958,18 +2061,22 @@
_initElementClass("leftPowerRail", "ldObjects")
_initElementClass("rightPowerRail", "ldObjects", "multiple")
+
def _UpdateLDElementName(self, old_name, new_name):
if TextMatched(self.variable, old_name):
self.variable = new_name
+
def _UpdateLDElementAddress(self, address_model, new_leading):
self.variable = update_address(self.variable, address_model, new_leading)
+
def _getSearchInLDElement(ld_element_type):
def SearchInLDElement(self, criteria, parent_infos=[]):
return _Search([("reference", self.variable)], criteria, parent_infos + [ld_element_type, self.getlocalId()])
return SearchInLDElement
+
cls = _initElementClass("contact", "ldObjects", "single")
if cls:
setattr(cls, "updateElementName", _UpdateLDElementName)
@@ -2004,11 +2111,11 @@
condition.setcontent(PLCOpenParser.CreateElement("ST", "inline"))
condition.settext(value)
setattr(cls, "setconditionContent", setconditionContent)
-
+
def getconditionContent(self):
if self.condition is not None:
content = self.condition.getcontent()
- values = {"type" : content.getLocalTag()}
+ values = {"type": content.getLocalTag()}
if values["type"] == "reference":
values["value"] = content.getname()
elif values["type"] == "inline":
@@ -2035,21 +2142,21 @@
bbox.union(_getConnectionsBoundingBox(condition_connection))
return bbox
setattr(cls, "getBoundingBox", getBoundingBox)
-
+
def translate(self, dx, dy):
_translateSingle(self, dx, dy)
condition_connection = self.getconditionConnection()
if condition_connection is not None:
_translateConnections(condition_connection, dx, dy)
setattr(cls, "translate", translate)
-
+
def filterConnections(self, connections):
_filterConnectionsSingle(self, connections)
condition_connection = self.getconditionConnection()
if condition_connection is not None:
_filterConnections(condition_connection, self.localId, connections)
setattr(cls, "filterConnections", filterConnections)
-
+
def updateConnectionsId(self, translation):
connections_end = []
if self.connectionPointIn is not None:
@@ -2087,7 +2194,7 @@
return condition_connection.getconnections()
return None
setattr(cls, "getconnections", getconnections)
-
+
def Search(self, criteria, parent_infos=[]):
parent_infos = parent_infos + ["transition", self.getlocalId()]
search_result = []
@@ -2104,7 +2211,7 @@
_initElementClass("selectionConvergence", "sfcObjects", "multiple")
_initElementClass("simultaneousDivergence", "sfcObjects", "single")
_initElementClass("simultaneousConvergence", "sfcObjects", "multiple")
-
+
cls = _initElementClass("jumpStep", "sfcObjects", "single")
if cls:
def Search(self, criteria, parent_infos):
@@ -2117,7 +2224,7 @@
if self.reference is not None:
self.reference.setname(name)
setattr(cls, "setreferenceName", setreferenceName)
-
+
def getreferenceName(self):
if self.reference is not None:
return self.reference.getname()
@@ -2129,7 +2236,7 @@
self.inline.setcontent(PLCOpenParser.CreateElement("ST", "inline"))
self.inline.settext(content)
setattr(cls, "setinlineContent", setinlineContent)
-
+
def getinlineContent(self):
if self.inline is not None:
return self.inline.gettext()
@@ -2155,7 +2262,7 @@
if qualifier is None:
qualifier = "N"
return _Search([("inline", self.getinlineContent()),
- ("reference", self.getreferenceName()),
+ ("reference", self.getreferenceName()),
("qualifier", qualifier),
("duration", self.getduration()),
("indicator", self.getindicator())],
@@ -2223,16 +2330,20 @@
return search_result
setattr(cls, "Search", Search)
+
def _SearchInIOVariable(self, criteria, parent_infos=[]):
return _Search([("expression", self.expression)], criteria, parent_infos + ["io_variable", self.getlocalId()])
+
def _UpdateIOElementName(self, old_name, new_name):
if TextMatched(self.expression, old_name):
self.expression = new_name
+
def _UpdateIOElementAddress(self, address_model, new_leading):
self.expression = update_address(self.expression, address_model, new_leading)
+
cls = _initElementClass("inVariable", "fbdObjects")
if cls:
setattr(cls, "updateElementName", _UpdateIOElementName)
@@ -2255,6 +2366,7 @@
def _SearchInConnector(self, criteria, parent_infos=[]):
return _Search([("name", self.getname())], criteria, parent_infos + ["connector", self.getlocalId()])
+
cls = _initElementClass("continuation", "commonObjects")
if cls:
setattr(cls, "Search", _SearchInConnector)
@@ -2288,7 +2400,7 @@
def getpoints(self):
points = []
for position in self.position:
- points.append((position.getx(),position.gety()))
+ points.append((position.getx(), position.gety()))
return points
setattr(cls, "getpoints", getpoints)
@@ -2318,33 +2430,34 @@
def removeconnections(self):
self.content = None
setattr(cls, "removeconnections", removeconnections)
-
+
connection_xpath = PLCOpen_XPath("ppx:connection")
connection_by_position_xpath = PLCOpen_XPath("ppx:connection[position()=$pos]")
+
def getconnections(self):
return connection_xpath(self)
setattr(cls, "getconnections", getconnections)
-
+
def getconnection(self, idx):
connection = connection_by_position_xpath(self, pos=idx+1)
if len(connection) > 0:
return connection[0]
return None
setattr(cls, "getconnection", getconnection)
-
+
def setconnectionId(self, idx, local_id):
connection = self.getconnection(idx)
if connection is not None:
connection.setrefLocalId(local_id)
setattr(cls, "setconnectionId", setconnectionId)
-
+
def getconnectionId(self, idx):
connection = self.getconnection(idx)
if connection is not None:
return connection.getrefLocalId()
return None
setattr(cls, "getconnectionId", getconnectionId)
-
+
def setconnectionPoints(self, idx, points):
connection = self.getconnection(idx)
if connection is not None:
@@ -2363,7 +2476,7 @@
if connection is not None:
connection.setformalParameter(parameter)
setattr(cls, "setconnectionParameter", setconnectionParameter)
-
+
def getconnectionParameter(self, idx):
connection = self.getconnection(idx)
if connection is not None:
@@ -2398,11 +2511,12 @@
content.setvalue(value)
self.setcontent(content)
setattr(cls, "setvalue", setvalue)
-
+
def getvalue(self):
return self.content.getvalue()
setattr(cls, "getvalue", getvalue)
+
def extractValues(values):
items = values.split(",")
i = 1
@@ -2414,13 +2528,14 @@
elif opened == closed:
i += 1
else:
- raise ValueError, _("\"%s\" is an invalid value!")%value
+ raise ValueError(_("\"%s\" is an invalid value!") % value)
return items
+
cls = PLCOpenParser.GetElementClass("arrayValue", "value")
if cls:
arrayValue_model = re.compile("([0-9]+)\((.*)\)$")
-
+
def setvalue(self, value):
elements = []
for item in extractValues(value[1:-1]):
@@ -2436,28 +2551,28 @@
elements.append(element)
self.value = elements
setattr(cls, "setvalue", setvalue)
-
+
def getvalue(self):
values = []
for element in self.value:
try:
repetition = int(element.getrepetitionValue())
- except:
+ except Exception:
repetition = 1
if repetition > 1:
value = element.getvalue()
if value is None:
value = ""
- values.append("%s(%s)"%(repetition, value))
+ values.append("%s(%s)" % (repetition, value))
else:
values.append(element.getvalue())
- return "[%s]"%", ".join(values)
+ return "[%s]" % ", ".join(values)
setattr(cls, "getvalue", getvalue)
cls = PLCOpenParser.GetElementClass("structValue", "value")
if cls:
structValue_model = re.compile("(.*):=(.*)")
-
+
def setvalue(self, value):
elements = []
for item in extractValues(value[1:-1]):
@@ -2470,11 +2585,10 @@
elements.append(element)
self.value = elements
setattr(cls, "setvalue", setvalue)
-
+
def getvalue(self):
values = []
for element in self.value:
- values.append("%s := %s"%(element.getmember(), element.getvalue()))
- return "(%s)"%", ".join(values)
+ values.append("%s := %s" % (element.getmember(), element.getvalue()))
+ return "(%s)" % ", ".join(values)
setattr(cls, "getvalue", getvalue)
-
--- a/plcopen/structures.py Mon Aug 21 20:17:19 2017 +0000
+++ b/plcopen/structures.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,17 +22,19 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import string, re
+import string
+import re
from plcopen import LoadProject
from collections import OrderedDict
from definitions import *
TypeHierarchy = dict(TypeHierarchy_list)
-"""
-returns true if the given data type is the same that "reference" meta-type or one of its types.
-"""
+
def IsOfType(type, reference):
+ """
+ Returns true if the given data type is the same that "reference" meta-type or one of its types.
+ """
if reference is None:
return True
elif type == reference:
@@ -43,12 +45,14 @@
return IsOfType(parent_type, reference)
return False
-"""
-returns list of all types that correspont to the ANY* meta type
-"""
+
def GetSubTypes(type):
+ """
+ Returns list of all types that correspont to the ANY* meta type
+ """
return [typename for typename, parenttype in TypeHierarchy.items() if not typename.startswith("ANY") and IsOfType(typename, type)]
+
DataTypeRange = dict(DataTypeRange_list)
"""
@@ -67,76 +71,82 @@
- The default modifier which can be "none", "negated", "rising" or "falling"
"""
-StdBlckLibs = {libname : LoadProject(tc6fname)[0]
- for libname, tc6fname in StdTC6Libs}
-StdBlckLst = [{"name" : libname, "list":
+StdBlckLibs = {libname: LoadProject(tc6fname)[0]
+ for libname, tc6fname in StdTC6Libs}
+StdBlckLst = [{"name": libname, "list":
[GetBlockInfos(pous) for pous in lib.getpous()]}
- for libname, lib in StdBlckLibs.iteritems()]
-
-#-------------------------------------------------------------------------------
+ for libname, lib in StdBlckLibs.iteritems()]
+
+# -------------------------------------------------------------------------------
# Test identifier
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
IDENTIFIER_MODEL = re.compile(
"(?:%(letter)s|_(?:%(letter)s|%(digit)s))(?:_?(?:%(letter)s|%(digit)s))*$" %
{"letter": "[a-zA-Z]", "digit": "[0-9]"})
-# Test if identifier is valid
+
def TestIdentifier(identifier):
- return IDENTIFIER_MODEL.match(identifier) is not None
-
-#-------------------------------------------------------------------------------
+ """
+ Test if identifier is valid
+ """
+ return IDENTIFIER_MODEL.match(identifier) is not None
+
+# -------------------------------------------------------------------------------
# Standard functions list generation
-#-------------------------------------------------------------------------------
-
-
-"""
-take a .csv file and translate it it a "csv_table"
-"""
+# -------------------------------------------------------------------------------
+
+
def csv_file_to_table(file):
- return [ map(string.strip,line.split(';')) for line in file.xreadlines()]
-
-"""
-seek into the csv table to a section ( section_name match 1st field )
-return the matching row without first field
-"""
+ """
+ take a .csv file and translate it it a "csv_table"
+ """
+ return [map(string.strip, line.split(';')) for line in file.xreadlines()]
+
+
def find_section(section_name, table):
+ """
+ seek into the csv table to a section ( section_name match 1st field )
+ return the matching row without first field
+ """
fields = [None]
while(fields[0] != section_name):
fields = table.pop(0)
return fields[1:]
-"""
-extract the standard functions standard parameter names and types...
-return a { ParameterName: Type, ...}
-"""
+
def get_standard_funtions_input_variables(table):
+ """
+ extract the standard functions standard parameter names and types...
+ return a { ParameterName: Type, ...}
+ """
variables = find_section("Standard_functions_variables_types", table)
standard_funtions_input_variables = {}
- fields = [True,True]
+ fields = [True, True]
while(fields[1]):
fields = table.pop(0)
- variable_from_csv = dict([(champ, val) for champ, val in zip(variables, fields[1:]) if champ!=''])
+ variable_from_csv = dict([(champ, val) for champ, val in zip(variables, fields[1:]) if champ != ''])
standard_funtions_input_variables[variable_from_csv['name']] = variable_from_csv['type']
return standard_funtions_input_variables
-
-"""
-translate .csv file input declaration into PLCOpenEditor interessting values
-in : "(ANY_NUM, ANY_NUM)" and { ParameterName: Type, ...}
-return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")]
-"""
+
+
def csv_input_translate(str_decl, variables, base):
- decl = str_decl.replace('(','').replace(')','').replace(' ','').split(',')
+ """
+ translate .csv file input declaration into PLCOpenEditor interessting values
+ in : "(ANY_NUM, ANY_NUM)" and { ParameterName: Type, ...}
+ return [("IN1","ANY_NUM","none"),("IN2","ANY_NUM","none")]
+ """
+ decl = str_decl.replace('(', '').replace(')', '').replace(' ', '').split(',')
params = []
-
+
len_of_not_predifined_variable = len([True for param_type in decl if param_type not in variables])
-
+
for param_type in decl:
if param_type in variables.keys():
param_name = param_type
param_type = variables[param_type]
elif len_of_not_predifined_variable > 1:
- param_name = "IN%d"%base
+ param_name = "IN%d" % base
base += 1
else:
param_name = "IN"
@@ -144,10 +154,11 @@
return params
-"""
-Returns this kind of declaration for all standard functions
-
- [{"name" : "Numerical", 'list': [ {
+def get_standard_funtions(table):
+ """
+ Returns this kind of declaration for all standard functions
+
+ [{"name" : "Numerical", 'list': [ {
'baseinputnumber': 1,
'comment': 'Addition',
'extensible': True,
@@ -156,21 +167,20 @@
'name': 'ADD',
'outputs': [('OUT', 'ANY_NUM', 'none')],
'type': 'function'}, ...... ] },.....]
-"""
-def get_standard_funtions(table):
-
+ """
+
variables = get_standard_funtions_input_variables(table)
-
- fonctions = find_section("Standard_functions_type",table)
+
+ fonctions = find_section("Standard_functions_type", table)
Standard_Functions_Decl = []
Current_section = None
-
+
translate = {
- "extensible" : lambda x: {"yes":True, "no":False}[x],
- "inputs" : lambda x:csv_input_translate(x,variables,baseinputnumber),
- "outputs":lambda x:[("OUT",x,"none")]}
-
+ "extensible": lambda x: {"yes": True, "no": False}[x],
+ "inputs": lambda x: csv_input_translate(x, variables, baseinputnumber),
+ "outputs": lambda x: [("OUT", x, "none")]}
+
for fields in table:
if fields[1]:
# If function section name given
@@ -180,82 +190,83 @@
section_name = words[1]
else:
section_name = fields[0]
- Current_section = {"name" : section_name, "list" : []}
+ Current_section = {"name": section_name, "list": []}
Standard_Functions_Decl.append(Current_section)
Function_decl_list = []
if Current_section:
Function_decl = dict([(champ, val) for champ, val in zip(fonctions, fields[1:]) if champ])
- baseinputnumber = int(Function_decl.get("baseinputnumber",1))
+ baseinputnumber = int(Function_decl.get("baseinputnumber", 1))
Function_decl["baseinputnumber"] = baseinputnumber
for param, value in Function_decl.iteritems():
if param in translate:
Function_decl[param] = translate[param](value)
Function_decl["type"] = "function"
-
- if Function_decl["name"].startswith('*') or Function_decl["name"].endswith('*') :
+
+ if Function_decl["name"].startswith('*') or Function_decl["name"].endswith('*'):
input_ovrloading_types = GetSubTypes(Function_decl["inputs"][0][1])
output_types = GetSubTypes(Function_decl["outputs"][0][1])
else:
input_ovrloading_types = [None]
output_types = [None]
-
+
funcdeclname_orig = Function_decl["name"]
funcdeclname = Function_decl["name"].strip('*_')
fdc = Function_decl["inputs"][:]
for intype in input_ovrloading_types:
- if intype != None:
+ if intype is not None:
Function_decl["inputs"] = []
for decl_tpl in fdc:
if IsOfType(intype, decl_tpl[1]):
Function_decl["inputs"] += [(decl_tpl[0], intype, decl_tpl[2])]
else:
Function_decl["inputs"] += [(decl_tpl)]
-
+
if funcdeclname_orig.startswith('*'):
- funcdeclin = intype + '_' + funcdeclname
+ funcdeclin = intype + '_' + funcdeclname
else:
funcdeclin = funcdeclname
else:
funcdeclin = funcdeclname
-
+
for outype in output_types:
- if outype != None:
+ if outype is not None:
decl_tpl = Function_decl["outputs"][0]
- Function_decl["outputs"] = [ (decl_tpl[0] , outype, decl_tpl[2])]
+ Function_decl["outputs"] = [(decl_tpl[0], outype, decl_tpl[2])]
if funcdeclname_orig.endswith('*'):
- funcdeclout = funcdeclin + '_' + outype
+ funcdeclout = funcdeclin + '_' + outype
else:
- funcdeclout = funcdeclin
+ funcdeclout = funcdeclin
else:
- funcdeclout = funcdeclin
+ funcdeclout = funcdeclin
Function_decl["name"] = funcdeclout
# apply filter given in "filter" column
filter_name = Function_decl["filter"]
store = True
- for (InTypes, OutTypes) in ANY_TO_ANY_FILTERS.get(filter_name,[]):
- outs = reduce(lambda a,b: a or b,
- map(lambda testtype : IsOfType(
- Function_decl["outputs"][0][1],
- testtype), OutTypes))
- inps = reduce(lambda a,b: a or b,
- map(lambda testtype : IsOfType(
- Function_decl["inputs"][0][1],
- testtype), InTypes))
+ for (InTypes, OutTypes) in ANY_TO_ANY_FILTERS.get(filter_name, []):
+ outs = reduce(lambda a, b: a or b,
+ map(lambda testtype: IsOfType(
+ Function_decl["outputs"][0][1],
+ testtype), OutTypes))
+ inps = reduce(lambda a, b: a or b,
+ map(lambda testtype: IsOfType(
+ Function_decl["inputs"][0][1],
+ testtype), InTypes))
if inps and outs and Function_decl["outputs"][0][1] != Function_decl["inputs"][0][1]:
store = True
break
else:
store = False
- if store :
+ if store:
# create the copy of decl dict to be appended to section
Function_decl_copy = Function_decl.copy()
Current_section["list"].append(Function_decl_copy)
else:
raise "First function must be in a category"
-
+
return Standard_Functions_Decl
+
StdBlckLst.extend(get_standard_funtions(csv_file_to_table(open(StdFuncsCSV))))
# Dictionary to speedup block type fetching by name
@@ -266,17 +277,17 @@
words = desc["comment"].split('"')
if len(words) > 1:
desc["comment"] = words[1]
- desc["usage"] = ("\n (%s) => (%s)" %
- (", ".join(["%s:%s" % (input[1], input[0])
- for input in desc["inputs"]]),
- ", ".join(["%s:%s" % (output[1], output[0])
- for output in desc["outputs"]])))
- BlkLst = StdBlckDct.setdefault(desc["name"],[])
+ desc["usage"] = ("\n (%s) => (%s)" %
+ (", ".join(["%s:%s" % (input[1], input[0])
+ for input in desc["inputs"]]),
+ ", ".join(["%s:%s" % (output[1], output[0])
+ for output in desc["outputs"]])))
+ BlkLst = StdBlckDct.setdefault(desc["name"], [])
BlkLst.append((section["name"], desc))
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Languages Keywords
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Keywords for Pou Declaration
POU_BLOCK_START_KEYWORDS = ["FUNCTION", "FUNCTION_BLOCK", "PROGRAM"]
@@ -313,16 +324,20 @@
# Keywords for Instruction List
-IL_KEYWORDS = ["TRUE", "FALSE", "LD", "LDN", "ST", "STN", "S", "R", "AND", "ANDN", "OR", "ORN",
- "XOR", "XORN", "NOT", "ADD", "SUB", "MUL", "DIV", "MOD", "GT", "GE", "EQ", "NE",
- "LE", "LT", "JMP", "JMPC", "JMPCN", "CAL", "CALC", "CALCN", "RET", "RETC", "RETCN"]
+IL_KEYWORDS = [
+ "TRUE", "FALSE", "LD", "LDN", "ST", "STN", "S", "R", "AND", "ANDN", "OR", "ORN",
+ "XOR", "XORN", "NOT", "ADD", "SUB", "MUL", "DIV", "MOD", "GT", "GE", "EQ", "NE",
+ "LE", "LT", "JMP", "JMPC", "JMPCN", "CAL", "CALC", "CALCN", "RET", "RETC", "RETCN"
+]
# Keywords for Structured Text
ST_BLOCK_START_KEYWORDS = ["IF", "ELSIF", "ELSE", "CASE", "FOR", "WHILE", "REPEAT"]
ST_BLOCK_END_KEYWORDS = ["END_IF", "END_CASE", "END_FOR", "END_WHILE", "END_REPEAT"]
-ST_KEYWORDS = ["TRUE", "FALSE", "THEN", "OF", "TO", "BY", "DO", "DO", "UNTIL", "EXIT",
- "RETURN", "NOT", "MOD", "AND", "XOR", "OR"] + ST_BLOCK_START_KEYWORDS + ST_BLOCK_END_KEYWORDS
+ST_KEYWORDS = [
+ "TRUE", "FALSE", "THEN", "OF", "TO", "BY", "DO", "DO", "UNTIL", "EXIT",
+ "RETURN", "NOT", "MOD", "AND", "XOR", "OR"
+] + ST_BLOCK_START_KEYWORDS + ST_BLOCK_END_KEYWORDS
# All the keywords of IEC
IEC_BLOCK_START_KEYWORDS = []
@@ -338,5 +353,3 @@
SFC_KEYWORDS, IL_KEYWORDS, ST_KEYWORDS])]:
for keywords in keywords_list:
all_keywords.extend([keyword for keyword in keywords if keyword not in all_keywords])
-
-
--- a/py_ext/PythonEditor.py Mon Aug 21 20:17:19 2017 +0000
+++ b/py_ext/PythonEditor.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,20 +28,21 @@
from controls.CustomStyledTextCtrl import faces
from editors.CodeFileEditor import CodeFileEditor, CodeEditor
+
class PythonCodeEditor(CodeEditor):
KEYWORDS = keyword.kwlist
COMMENT_HEADER = "#"
-
+
def SetCodeLexer(self):
self.SetLexer(stc.STC_LEX_PYTHON)
-
+
# Line numbers in margin
- self.StyleSetSpec(stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2,size:%(size)d' % faces)
+ self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, 'fore:#000000,back:#99A9C2,size:%(size)d' % faces)
# Highlighted brace
- self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00,size:%(size)d' % faces)
+ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, 'fore:#00009D,back:#FFFF00,size:%(size)d' % faces)
# Unmatched brace
- self.StyleSetSpec(stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000,size:%(size)d' % faces)
+ self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, 'fore:#00009D,back:#FF0000,size:%(size)d' % faces)
# Indentation guide
self.StyleSetSpec(stc.STC_STYLE_INDENTGUIDE, 'fore:#CDCDCD,size:%(size)d' % faces)
@@ -69,15 +70,14 @@
# Identifiers. I leave this as not bold because everything seems
# to be an identifier if it doesn't match the above criterae
self.StyleSetSpec(stc.STC_P_IDENTIFIER, 'fore:#000000,size:%(size)d' % faces)
-
-#-------------------------------------------------------------------------------
+
+# -------------------------------------------------------------------------------
# CFileEditor Main Frame Class
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class PythonEditor(CodeFileEditor):
-
+
CONFNODEEDITOR_TABS = [
(_("Python code"), "_create_CodePanel")]
CODE_EDITOR = PythonCodeEditor
-
--- a/py_ext/PythonFileCTNMixin.py Mon Aug 21 20:17:19 2017 +0000
+++ b/py_ext/PythonFileCTNMixin.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,7 +23,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, re
+import os
+import re
from lxml import etree
import util.paths as paths
@@ -32,6 +33,7 @@
from CodeFileTreeNode import CodeFile
from PythonEditor import PythonEditor
+
class PythonFileCTNMixin(CodeFile):
CODEFILE_NAME = "PyFile"
@@ -59,8 +61,8 @@
'xmlns="http://www.w3.org/2001/XMLSchema"',
'xmlns:xhtml="http://www.w3.org/1999/xhtml"')
for cre, repl in [
- (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
- (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
+ (re.compile("(?<!<xhtml:p>)(?:<!\[CDATA\[)"), "<xhtml:p><![CDATA["),
+ (re.compile("(?:]]>)(?!</xhtml:p>)"), "]]></xhtml:p>")]:
pythonfile_xml = cre.sub(repl, pythonfile_xml)
try:
@@ -85,34 +87,36 @@
PreSectionsTexts = {}
PostSectionsTexts = {}
- def GetSection(self,section):
- return self.PreSectionsTexts.get(section,"") + "\n" + \
+
+ def GetSection(self, section):
+ return self.PreSectionsTexts.get(section, "") + "\n" + \
getattr(self.CodeFile, section).getanyText() + "\n" + \
- self.PostSectionsTexts.get(section,"")
+ self.PostSectionsTexts.get(section, "")
def CTNGenerate_C(self, buildpath, locations):
# location string for that CTN
- location_str = "_".join(map(lambda x:str(x),
+ location_str = "_".join(map(lambda x: str(x),
self.GetCurrentLocation()))
configname = self.GetCTRoot().GetProjectConfigNames()[0]
pyextname = self.CTNName()
- varinfos = map(lambda variable : {
- "name": variable.getname(),
- "desc" : repr(variable.getdesc()),
- "onchangecode" : '"'+variable.getonchange()+\
- "('"+variable.getname()+"')\"" \
- if variable.getonchange() else '""',
- "onchange" : repr(variable.getonchange()) \
- if variable.getonchange() else None,
- "opts" : repr(variable.getopts()),
- "configname" : configname.upper(),
- "uppername" : variable.getname().upper(),
- "IECtype" : variable.gettype(),
- "pyextname" :pyextname},
- self.CodeFile.variables.variable)
+ varinfos = map(lambda variable: {
+ "name": variable.getname(),
+ "desc": repr(variable.getdesc()),
+ "onchangecode": '"' + variable.getonchange() +
+ "('" + variable.getname() + "')\""
+ if variable.getonchange() else '""',
+ "onchange": repr(variable.getonchange())
+ if variable.getonchange() else None,
+ "opts": repr(variable.getopts()),
+ "configname": configname.upper(),
+ "uppername": variable.getname().upper(),
+ "IECtype": variable.gettype(),
+ "pyextname": pyextname},
+ self.CodeFile.variables.variable)
# python side PLC global variables access stub
- globalstubs = "\n".join(["""\
+ globalstubs = "\n".join([
+ """\
_%(name)s_ctype, _%(name)s_unpack, _%(name)s_pack = \\
TypeTranslator["%(IECtype)s"]
_PySafeGetPLCGlob_%(name)s = PLCBinary.__SafeGetPLCGlob_%(name)s
@@ -127,8 +131,7 @@
%(desc)s,
%(onchange)s,
%(opts)s))
-""" % varinfo
- for varinfo in varinfos])
+""" % varinfo for varinfo in varinfos])
# Runtime calls (start, stop, init, and cleanup)
rtcalls = ""
@@ -170,7 +173,7 @@
# write generated content to python file
runtimefile_path = os.path.join(buildpath,
- "runtime_%s.py"%location_str)
+ "runtime_%s.py" % location_str)
runtimefile = open(runtimefile_path, 'w')
runtimefile.write(PyFileContent.encode('utf-8'))
runtimefile.close()
@@ -234,14 +237,14 @@
__SET_VAR(__%(name)s_notifier->,CODE,,__STRING_LITERAL(%(onchangelen)d,%(onchangecode)s));
"""
vardec = "\n".join([(vardecfmt + vardeconchangefmt
- if varinfo["onchange"] else vardecfmt)% varinfo
+ if varinfo["onchange"] else vardecfmt) % varinfo
for varinfo in varinfos])
varret = "\n".join([varretfmt % varinfo for varinfo in varinfos])
varpub = "\n".join([(varpubonchangefmt if varinfo["onchange"] else
varpubfmt) % varinfo
for varinfo in varinfos])
varinit = "\n".join([varinitonchangefmt % dict(
- onchangelen = len(varinfo["onchangecode"]),**varinfo)
+ onchangelen=len(varinfo["onchangecode"]), **varinfo)
for varinfo in varinfos if varinfo["onchange"]])
# TODO : use config name obtained from model instead of default
@@ -278,16 +281,15 @@
}
""" % locals()
- Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c"%location_str)
- pycfile = open(Gen_PyCfile_path,'w')
+ Gen_PyCfile_path = os.path.join(buildpath, "PyCFile_%s.c" % location_str)
+ pycfile = open(Gen_PyCfile_path, 'w')
pycfile.write(PyCFileContent)
pycfile.close()
- matiec_CFLAGS = '"-I%s"'%os.path.abspath(
+ matiec_CFLAGS = '"-I%s"' % os.path.abspath(
self.GetCTRoot().GetIECLibPath())
return ([(Gen_PyCfile_path, matiec_CFLAGS)],
"",
True,
- ("runtime_%s.py"%location_str, file(runtimefile_path,"rb")))
-
+ ("runtime_%s.py" % location_str, file(runtimefile_path, "rb")))
--- a/py_ext/py_ext.py Mon Aug 21 20:17:19 2017 +0000
+++ b/py_ext/py_ext.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,12 +28,13 @@
from PythonFileCTNMixin import PythonFileCTNMixin
import util.paths as paths
+
class PythonLibrary(POULibrary):
def GetLibraryPath(self):
- return paths.AbsNeighbourFile(__file__, "pous.xml")
+ return paths.AbsNeighbourFile(__file__, "pous.xml")
def Generate_C(self, buildpath, varlist, IECCFLAGS):
-
+
plc_python_filepath = paths.AbsNeighbourFile(__file__, "plc_python.c")
plc_python_file = open(plc_python_filepath, 'r')
plc_python_code = plc_python_file.read()
@@ -44,21 +45,20 @@
"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 }
-
+ "python_eval_fb_count": python_eval_fb_count}
+
Gen_Pythonfile_path = os.path.join(buildpath, "py_ext.c")
- pythonfile = open(Gen_Pythonfile_path,'w')
+ pythonfile = open(Gen_Pythonfile_path, 'w')
pythonfile.write(plc_python_code)
pythonfile.close()
-
+
return (["py_ext"], [(Gen_Pythonfile_path, IECCFLAGS)], True), ""
+
class PythonFile(PythonFileCTNMixin):
-
+
def GetIconName(self):
return "Pyfile"
-
-
--- a/runtime/NevowServer.py Mon Aug 21 20:17:19 2017 +0000
+++ b/runtime/NevowServer.py Mon Aug 21 23:22:58 2017 +0300
@@ -36,6 +36,7 @@
WorkingDir = None
+
class PLCHMI(athena.LiveElement):
initialised = False
@@ -46,21 +47,24 @@
def HMIinitialisation(self):
self.HMIinitialised(None)
+
class DefaultPLCStartedHMI(PLCHMI):
docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
tags.h1["PLC IS NOW STARTED"],
])
+
class PLCStoppedHMI(PLCHMI):
docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
tags.h1["PLC IS STOPPED"],
])
+
class MainPage(athena.LiveElement):
jsClass = u"WebInterface.PLC"
docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[
tags.div(id='content')[
- tags.div(render = tags.directive('PLCElement')),
+ tags.div(render=tags.directive('PLCElement')),
]])
def __init__(self, *a, **kw):
@@ -85,7 +89,7 @@
def HMIexec(self, function, *args, **kwargs):
if self.HMI is not None:
- getattr(self.HMI, function, lambda:None)(*args, **kwargs)
+ getattr(self.HMI, function, lambda: None)(*args, **kwargs)
athena.expose(HMIexec)
def resetHMI(self):
@@ -110,15 +114,16 @@
for child in self.liveFragmentChildren[:]:
child.detach()
+
class WebInterface(athena.LivePage):
docFactory = loaders.stan([tags.raw(xhtml_header),
- tags.html(xmlns="http://www.w3.org/1999/xhtml")[
- tags.head(render=tags.directive('liveglue')),
- tags.body[
- tags.div[
- tags.div( render = tags.directive( "MainPage" ))
- ]]]])
+ tags.html(xmlns="http://www.w3.org/1999/xhtml")[
+ tags.head(render=tags.directive('liveglue')),
+ tags.body[
+ tags.div[
+ tags.div(render=tags.directive("MainPage"))
+ ]]]])
MainPage = MainPage()
PLCHMI = PLCHMI
@@ -170,8 +175,9 @@
def disconnected(self, reason):
self.MainPage.resetHMI()
- #print reason
- #print "We will be called back when the client disconnects"
+ # print reason
+ # print "We will be called back when the client disconnects"
+
def RegisterWebsite(port):
website = WebInterface()
@@ -182,6 +188,7 @@
print _("HTTP interface port :"), port
return website
+
class statuslistener:
def __init__(self, site):
self.oldstate = None
@@ -191,8 +198,10 @@
if state != self.oldstate:
action = {'Started': self.site.PLCStarted,
'Stopped': self.site.PLCStopped}.get(state, None)
- if action is not None: action ()
+ if action is not None:
+ action()
self.oldstate = state
+
def website_statuslistener_factory(site):
return statuslistener(site).listen
--- a/runtime/PLCObject.py Mon Aug 21 20:17:19 2017 +0000
+++ b/runtime/PLCObject.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,7 +23,12 @@
import Pyro.core as pyro
from threading import Timer, Thread, Lock, Semaphore, Event
-import ctypes, os, commands, types, sys
+import ctypes
+import os
+import commands
+import types
+import sys
+import traceback
from targets.typemapping import LogLevelsDefault, LogLevelsCount, TypeTranslator, UnpackDebugBuffer
from time import time
@@ -34,26 +39,29 @@
elif os.name == "posix":
from _ctypes import dlopen, dlclose
-import traceback
+
def get_last_traceback(tb):
while tb.tb_next:
tb = tb.tb_next
return tb
-lib_ext ={
- "linux2":".so",
- "win32":".dll",
+
+lib_ext = {
+ "linux2": ".so",
+ "win32": ".dll",
}.get(sys.platform, "")
+
def PLCprint(message):
sys.stdout.write("PLCobject : "+message+"\n")
sys.stdout.flush()
+
class PLCObject(pyro.ObjBase):
def __init__(self, workingdir, daemon, argv, statuschange, evaluator, pyruntimevars):
pyro.ObjBase.__init__(self)
self.evaluator = evaluator
- self.argv = [workingdir] + argv # force argv[0] to be "path" to exec...
+ self.argv = [workingdir] + argv # force argv[0] to be "path" to exec...
self.workingdir = workingdir
self.PLCStatus = "Empty"
self.PLClibraryHandle = None
@@ -75,14 +83,14 @@
def AutoLoad(self):
# Get the last transfered PLC if connector must be restart
try:
- self.CurrentPLCFilename=open(
+ self.CurrentPLCFilename = open(
self._GetMD5FileName(),
"r").read().strip() + lib_ext
if self.LoadPLC():
self.PLCStatus = "Stopped"
except Exception, e:
self.PLCStatus = "Empty"
- self.CurrentPLCFilename=None
+ self.CurrentPLCFilename = None
def StatusChange(self):
if self.statuschange is not None:
@@ -102,9 +110,9 @@
self._ResetLogCount()
def GetLogCount(self, level):
- if self._GetLogCount is not None :
+ if self._GetLogCount is not None:
return int(self._GetLogCount(level))
- elif self._loading_error is not None and level==0:
+ elif self._loading_error is not None and level == 0:
return 1
def GetLogMessage(self, level, msgid):
@@ -114,23 +122,22 @@
if self._GetLogMessage is not None:
maxsz = len(self._log_read_buffer)-1
sz = self._GetLogMessage(level, msgid,
- self._log_read_buffer, maxsz,
- ctypes.byref(tick),
- ctypes.byref(tv_sec),
- ctypes.byref(tv_nsec))
+ self._log_read_buffer, maxsz,
+ ctypes.byref(tick),
+ ctypes.byref(tv_sec),
+ ctypes.byref(tv_nsec))
if sz and sz <= maxsz:
self._log_read_buffer[sz] = '\x00'
- return self._log_read_buffer.value,tick.value,tv_sec.value,tv_nsec.value
- elif self._loading_error is not None and level==0:
- return self._loading_error,0,0,0
+ return self._log_read_buffer.value, tick.value, tv_sec.value, tv_nsec.value
+ elif self._loading_error is not None and level == 0:
+ return self._loading_error, 0, 0, 0
return None
def _GetMD5FileName(self):
return os.path.join(self.workingdir, "lasttransferedPLC.md5")
def _GetLibFileName(self):
- return os.path.join(self.workingdir,self.CurrentPLCFilename)
-
+ return os.path.join(self.workingdir, self.CurrentPLCFilename)
def LoadPLC(self):
"""
@@ -143,8 +150,8 @@
self.PLClibraryHandle = ctypes.CDLL(self.CurrentPLCFilename, handle=self._PLClibraryHandle)
self.PLC_ID = ctypes.c_char_p.in_dll(self.PLClibraryHandle, "PLC_ID")
- if len(md5) == 32 :
- self.PLC_ID.value = md5
+ if len(md5) == 32:
+ self.PLC_ID.value = md5
self._startPLC = self.PLClibraryHandle.startPLC
self._startPLC.restype = ctypes.c_int
@@ -163,6 +170,7 @@
# If python confnode is not enabled, we reuse _PythonIterator
# as a call that block pythonthread until StopPLC
self.PlcStopping = Event()
+
def PythonIterator(res, blkid):
self.PlcStopping.clear()
self.PlcStopping.wait()
@@ -174,7 +182,6 @@
self.PlcStopping.set()
self._stopPLC = __StopPLC
-
self._ResetDebugVariables = self.PLClibraryHandle.ResetDebugVariables
self._ResetDebugVariables.restype = None
@@ -207,7 +214,7 @@
self._LogMessage.restype = ctypes.c_int
self._LogMessage.argtypes = [ctypes.c_uint8, ctypes.c_char_p, ctypes.c_uint32]
- self._log_read_buffer = ctypes.create_string_buffer(1<<14) #16K
+ self._log_read_buffer = ctypes.create_string_buffer(1 << 14) # 16K
self._GetLogMessage = self.PLClibraryHandle.GetLogMessage
self._GetLogMessage.restype = ctypes.c_uint32
self._GetLogMessage.argtypes = [ctypes.c_uint8, ctypes.c_uint32, ctypes.c_char_p, ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32), ctypes.POINTER(ctypes.c_uint32)]
@@ -217,7 +224,7 @@
self.PythonRuntimeInit()
return True
- except:
+ except Exception:
self._loading_error = traceback.format_exc()
PLCprint(self._loading_error)
return False
@@ -233,22 +240,22 @@
"""
self.PLClibraryLock.acquire()
# Forget all refs to library
- self._startPLC = lambda x,y:None
- self._stopPLC = lambda:None
- self._ResetDebugVariables = lambda:None
- self._RegisterDebugVariable = lambda x, y:None
- self._IterDebugData = lambda x,y:None
- self._FreeDebugData = lambda:None
- self._GetDebugData = lambda:-1
- self._suspendDebug = lambda x:-1
- self._resumeDebug = lambda:None
- self._PythonIterator = lambda:""
+ self._startPLC = lambda x, y: None
+ self._stopPLC = lambda: None
+ self._ResetDebugVariables = lambda: None
+ self._RegisterDebugVariable = lambda x, y: None
+ self._IterDebugData = lambda x, y: None
+ self._FreeDebugData = lambda: None
+ self._GetDebugData = lambda: -1
+ self._suspendDebug = lambda x: -1
+ self._resumeDebug = lambda: None
+ self._PythonIterator = lambda: ""
self._GetLogCount = None
- self._LogMessage = lambda l,m,s:PLCprint("OFF LOG :"+m)
+ self._LogMessage = lambda l, m, s: PLCprint("OFF LOG :"+m)
self._GetLogMessage = None
self.PLClibraryHandle = None
# Unload library explicitely
- if getattr(self,"_PLClibraryHandle",None) is not None:
+ if getattr(self, "_PLClibraryHandle", None) is not None:
dlclose(self._PLClibraryHandle)
self._PLClibraryHandle = None
@@ -260,10 +267,10 @@
Calls init, start, stop or cleanup method provided by
runtime python files, loaded when new PLC uploaded
"""
- for method in self.python_runtime_vars.get("_runtime_%s"%methodname, []):
- res,exp = self.evaluator(method)
+ for method in self.python_runtime_vars.get("_runtime_%s" % methodname, []):
+ res, exp = self.evaluator(method)
if exp is not None:
- self.LogMessage(0,'\n'.join(traceback.format_exception(*exp)))
+ self.LogMessage(0, '\n'.join(traceback.format_exception(*exp)))
def PythonRuntimeInit(self):
MethodNames = ["init", "start", "stop", "cleanup"]
@@ -272,30 +279,31 @@
class PLCSafeGlobals:
def __getattr__(_self, name):
- try :
+ try:
t = self.python_runtime_vars["_"+name+"_ctype"]
except KeyError:
- raise KeyError("Try to get unknown shared global variable : %s"%name)
+ raise KeyError("Try to get unknown shared global variable : %s" % name)
v = t()
r = self.python_runtime_vars["_PySafeGetPLCGlob_"+name](ctypes.byref(v))
return self.python_runtime_vars["_"+name+"_unpack"](v)
+
def __setattr__(_self, name, value):
- try :
+ try:
t = self.python_runtime_vars["_"+name+"_ctype"]
except KeyError:
- raise KeyError("Try to set unknown shared global variable : %s"%name)
- v = self.python_runtime_vars["_"+name+"_pack"](t,value)
+ raise KeyError("Try to set unknown shared global variable : %s" % name)
+ v = self.python_runtime_vars["_"+name+"_pack"](t, value)
self.python_runtime_vars["_PySafeSetPLCGlob_"+name](ctypes.byref(v))
self.python_runtime_vars.update({
- "PLCGlobals" : PLCSafeGlobals(),
- "WorkingDir" : self.workingdir,
- "PLCObject" : self,
- "PLCBinary" : self.PLClibraryHandle,
- "PLCGlobalsDesc" : []})
-
- for methodname in MethodNames :
- self.python_runtime_vars["_runtime_%s"%methodname] = []
+ "PLCGlobals": PLCSafeGlobals(),
+ "WorkingDir": self.workingdir,
+ "PLCObject": self,
+ "PLCBinary": self.PLClibraryHandle,
+ "PLCGlobalsDesc": []})
+
+ for methodname in MethodNames:
+ self.python_runtime_vars["_runtime_%s" % methodname] = []
try:
filenames = os.listdir(self.workingdir)
@@ -307,15 +315,13 @@
for methodname in MethodNames:
method = self.python_runtime_vars.get("_%s_%s" % (name, methodname), None)
if method is not None:
- self.python_runtime_vars["_runtime_%s"%methodname].append(method)
- except:
- self.LogMessage(0,traceback.format_exc())
+ self.python_runtime_vars["_runtime_%s" % methodname].append(method)
+ except Exception:
+ self.LogMessage(0, traceback.format_exc())
raise
self.PythonRuntimeCall("init")
-
-
def PythonRuntimeCleanup(self):
if self.python_runtime_vars is not None:
self.PythonRuntimeCall("cleanup")
@@ -324,49 +330,49 @@
def PythonThreadProc(self):
self.StartSem.release()
- res,cmd,blkid = "None","None",ctypes.c_void_p()
- compile_cache={}
+ res, cmd, blkid = "None", "None", ctypes.c_void_p()
+ compile_cache = {}
while True:
# print "_PythonIterator(", res, ")",
- cmd = self._PythonIterator(res,blkid)
+ cmd = self._PythonIterator(res, blkid)
FBID = blkid.value
# print " -> ", cmd, blkid
if cmd is None:
break
- try :
- self.python_runtime_vars["FBID"]=FBID
- ccmd,AST =compile_cache.get(FBID, (None,None))
- if ccmd is None or ccmd!=cmd:
+ try:
+ self.python_runtime_vars["FBID"] = FBID
+ ccmd, AST = compile_cache.get(FBID, (None, None))
+ if ccmd is None or ccmd != cmd:
AST = compile(cmd, '<plc>', 'eval')
- compile_cache[FBID]=(cmd,AST)
- result,exp = self.evaluator(eval,AST,self.python_runtime_vars)
+ compile_cache[FBID] = (cmd, AST)
+ result, exp = self.evaluator(eval, AST, self.python_runtime_vars)
if exp is not None:
res = "#EXCEPTION : "+str(exp[1])
- self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,
- '\n'.join(traceback.format_exception(*exp))))
+ self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (
+ FBID, cmd, '\n'.join(traceback.format_exception(*exp))))
else:
- res=str(result)
- self.python_runtime_vars["FBID"]=None
- except Exception,e:
+ res = str(result)
+ self.python_runtime_vars["FBID"] = None
+ except Exception, e:
res = "#EXCEPTION : "+str(e)
- self.LogMessage(1,('PyEval@0x%x(Code="%s") Exception "%s"')%(FBID,cmd,str(e)))
+ self.LogMessage(1, ('PyEval@0x%x(Code="%s") Exception "%s"') % (FBID, cmd, str(e)))
def StartPLC(self):
if self.CurrentPLCFilename is not None and self.PLCStatus == "Stopped":
c_argv = ctypes.c_char_p * len(self.argv)
error = None
- res = self._startPLC(len(self.argv),c_argv(*self.argv))
+ res = self._startPLC(len(self.argv), c_argv(*self.argv))
if res == 0:
self.PLCStatus = "Started"
self.StatusChange()
self.PythonRuntimeCall("start")
- self.StartSem=Semaphore(0)
+ self.StartSem = Semaphore(0)
self.PythonThread = Thread(target=self.PythonThreadProc)
self.PythonThread.start()
self.StartSem.acquire()
self.LogMessage("PLC started")
else:
- self.LogMessage(0,_("Problem starting PLC : error %d" % res))
+ self.LogMessage(0, _("Problem starting PLC : error %d" % res))
self.PLCStatus = "Broken"
self.StatusChange()
@@ -378,7 +384,7 @@
self.PLCStatus = "Stopped"
self.StatusChange()
self.PythonRuntimeCall("stop")
- if self.TraceThread is not None :
+ if self.TraceThread is not None:
self.TraceWakeup.set()
self.TraceThread.join()
self.TraceThread = None
@@ -388,26 +394,26 @@
def _Reload(self):
self.daemon.shutdown(True)
self.daemon.sock.close()
- os.execv(sys.executable,[sys.executable]+sys.argv[:])
+ os.execv(sys.executable, [sys.executable]+sys.argv[:])
# never reached
return 0
def ForceReload(self):
# respawn python interpreter
- Timer(0.1,self._Reload).start()
+ Timer(0.1, self._Reload).start()
return True
def GetPLCstatus(self):
- return self.PLCStatus, map(self.GetLogCount,xrange(LogLevelsCount))
+ return self.PLCStatus, map(self.GetLogCount, xrange(LogLevelsCount))
def NewPLC(self, md5sum, data, extrafiles):
if self.PLCStatus in ["Stopped", "Empty", "Broken"]:
NewFileName = md5sum + lib_ext
- extra_files_log = os.path.join(self.workingdir,"extra_files.txt")
+ extra_files_log = os.path.join(self.workingdir, "extra_files.txt")
self.UnLoadPLC()
- self.LogMessage("NewPLC (%s)"%md5sum)
+ self.LogMessage("NewPLC (%s)" % md5sum)
self.PLCStatus = "Empty"
try:
@@ -416,14 +422,14 @@
for filename in file(extra_files_log, "r").readlines() + [extra_files_log]:
try:
os.remove(os.path.join(self.workingdir, filename.strip()))
- except:
+ except Exception:
pass
- except:
+ except Exception:
pass
try:
# Create new PLC file
- open(os.path.join(self.workingdir,NewFileName),
+ open(os.path.join(self.workingdir, NewFileName),
'wb').write(data)
# Store new PLC filename based on md5 key
@@ -431,14 +437,14 @@
# Then write the files
log = file(extra_files_log, "w")
- for fname,fdata in extrafiles:
- fpath = os.path.join(self.workingdir,fname)
+ for fname, fdata in extrafiles:
+ fpath = os.path.join(self.workingdir, fname)
open(fpath, "wb").write(fdata)
log.write(fname+'\n')
# Store new PLC filename
self.CurrentPLCFilename = NewFileName
- except:
+ except Exception:
self.PLCStatus = "Broken"
self.StatusChange()
PLCprint(traceback.format_exc())
@@ -458,7 +464,7 @@
try:
last_md5 = open(self._GetMD5FileName(), "r").read()
return last_md5 == MD5
- except:
+ except Exception:
pass
return False
@@ -472,12 +478,12 @@
if self._suspendDebug(False) == 0:
# keep a copy of requested idx
self._ResetDebugVariables()
- for idx,iectype,force in idxs:
- if force !=None:
- c_type,unpack_func, pack_func = \
+ for idx, iectype, force in idxs:
+ if force is not None:
+ c_type, unpack_func, pack_func = \
TypeTranslator.get(iectype,
- (None,None,None))
- force = ctypes.byref(pack_func(c_type,force))
+ (None, None, None))
+ force = ctypes.byref(pack_func(c_type, force))
self._RegisterDebugVariable(idx, force)
self._TracesSwap()
self._resumeDebug()
@@ -487,7 +493,7 @@
def _TracesPush(self, trace):
self.TraceLock.acquire()
lT = len(self.Traces)
- if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024 :
+ if lT != 0 and lT * len(self.Traces[0]) > 1024 * 1024:
self.Traces.pop(0)
self.Traces.append(trace)
self.TraceLock.release()
@@ -511,10 +517,10 @@
self.TraceLock.acquire()
self.Traces = []
self.TraceLock.release()
- self._suspendDebug(True) # Disable debugger
+ self._suspendDebug(True) # Disable debugger
self.TraceWakeup.clear()
self.TraceWakeup.wait()
- self._resumeDebug() # Re-enable debugger
+ self._resumeDebug() # Re-enable debugger
def _TracesFlush(self):
self.TraceLock.acquire()
@@ -528,7 +534,7 @@
"""
Return a list of traces, corresponding to the list of required idx
"""
- while self.PLCStatus == "Started" :
+ while self.PLCStatus == "Started":
tick = ctypes.c_uint32()
size = ctypes.c_uint32()
buff = ctypes.c_void_p()
@@ -546,15 +552,12 @@
self._TracesAutoSuspend()
self._TracesFlush()
-
def RemoteExec(self, script, *kwargs):
try:
exec script in kwargs
- except:
+ except Exception:
e_type, e_value, e_traceback = sys.exc_info()
line_no = traceback.tb_lineno(get_last_traceback(e_traceback))
return (-1, "RemoteExec script failed!\n\nLine %d: %s\n\t%s" %
(line_no, e_value, script.splitlines()[line_no - 1]))
return (0, kwargs.get("returnVal", None))
-
-
--- a/runtime/ServicePublisher.py Mon Aug 21 20:17:19 2017 +0000
+++ b/runtime/ServicePublisher.py Mon Aug 21 23:22:58 2017 +0300
@@ -21,33 +21,35 @@
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-import socket, threading
+import socket
+import threading
from util import Zeroconf
service_type = '_PYRO._tcp.local.'
+
class ServicePublisher():
def __init__(self):
# type: fully qualified service type name
- self.serviceproperties = {'description':'Beremiz remote PLC'}
-
+ self.serviceproperties = {'description': 'Beremiz remote PLC'}
+
self.name = None
self.ip_32b = None
self.port = None
self.server = None
self.service_name = None
self.retrytimer = None
-
+
def RegisterService(self, name, ip, port):
try:
self._RegisterService(name, ip, port)
- except Exception,e:
- self.retrytimer = threading.Timer(2,self.RegisterService,[name, ip, port])
- self.retrytimer.start()
+ except Exception, e:
+ self.retrytimer = threading.Timer(2, self.RegisterService, [name, ip, port])
+ self.retrytimer.start()
def _RegisterService(self, name, ip, port):
# name: fully qualified service name
- self.service_name = 'Beremiz_%s.%s'%(name,service_type)
+ self.service_name = 'Beremiz_%s.%s' % (name, service_type)
self.name = name
self.port = port
@@ -64,23 +66,23 @@
self.service_name,
self.ip_32b,
self.port,
- properties = self.serviceproperties))
- self.retrytimer=None
-
+ properties=self.serviceproperties))
+ self.retrytimer = None
+
def UnRegisterService(self):
if self.retrytimer is not None:
self.retrytimer.cancel()
self.server.unregisterService(
- Zeroconf.ServiceInfo(service_type,
- self.service_name,
- self.ip_32b,
- self.port,
- properties = self.serviceproperties))
+ Zeroconf.ServiceInfo(service_type,
+ self.service_name,
+ self.ip_32b,
+ self.port,
+ properties=self.serviceproperties))
self.server.close()
self.server = None
-
- def gethostaddr(self, dst = '224.0.1.41'):
+
+ def gethostaddr(self, dst='224.0.1.41'):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
s.connect((dst, 7))
@@ -88,6 +90,6 @@
s.close()
if host != '0.0.0.0':
return host
- except Exception,e:
+ except Exception, e:
pass
return socket.gethostbyname(socket.gethostname())
--- a/runtime/WampClient.py Mon Aug 21 20:17:19 2017 +0000
+++ b/runtime/WampClient.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,7 +22,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import sys
-#from twisted.python import log
from autobahn.twisted import wamp
from autobahn.twisted.websocket import WampWebSocketClientFactory, connectWS
from twisted.internet.defer import inlineCallbacks
@@ -51,14 +50,17 @@
DoOnJoin = []
+
def GetCallee(name):
""" Get Callee or Subscriber corresponding to '.' spearated object path """
global _PySrv
names = name.split('.')
obj = _PySrv.plcobj
- while names: obj = getattr(obj, names.pop(0))
+ while names:
+ obj = getattr(obj, names.pop(0))
return obj
+
class WampSession(wamp.ApplicationSession):
@inlineCallbacks
@@ -68,7 +70,7 @@
ID = self.config.extra["ID"]
print 'WAMP session joined by :', ID
for name in ExposedCalls:
- reg = yield self.register(GetCallee(name), '.'.join((ID,name)))
+ reg = yield self.register(GetCallee(name), '.'.join((ID, name)))
for name in SubscribedEvents:
reg = yield self.subscribe(GetCallee(name), name)
@@ -81,52 +83,57 @@
_WampSession = None
print 'WAMP session left'
+
class ReconnectingWampWebSocketClientFactory(WampWebSocketClientFactory, ReconnectingClientFactory):
def clientConnectionFailed(self, connector, reason):
print("WAMP Client connection failed .. retrying ..")
self.retry(connector)
+
def clientConnectionLost(self, connector, reason):
print("WAMP Client connection lost .. retrying ..")
self.retry(connector)
+
def LoadWampClientConf(wampconf):
WSClientConf = json.load(open(wampconf))
return WSClientConf
+
def RegisterWampClient(wampconf):
WSClientConf = LoadWampClientConf(wampconf)
- ## start logging to console
+ # start logging to console
# log.startLogging(sys.stdout)
# create a WAMP application session factory
component_config = types.ComponentConfig(
- realm = WSClientConf["realm"],
- extra = {"ID":WSClientConf["ID"]})
+ realm=WSClientConf["realm"],
+ extra={"ID": WSClientConf["ID"]})
session_factory = wamp.ApplicationSessionFactory(
- config = component_config)
+ config=component_config)
session_factory.session = WampSession
# create a WAMP-over-WebSocket transport client factory
transport_factory = ReconnectingWampWebSocketClientFactory(
session_factory,
- url = WSClientConf["url"],
- serializers = [MsgPackSerializer()],
- debug = False,
- debug_wamp = False)
+ url=WSClientConf["url"],
+ serializers=[MsgPackSerializer()],
+ debug=False,
+ debug_wamp=False)
# start the client from a Twisted endpoint
conn = connectWS(transport_factory)
- print "WAMP client connecting to :",WSClientConf["url"]
+ print "WAMP client connecting to :", WSClientConf["url"]
return conn
+
def GetSession():
global _WampSession
return _WampSession
+
def SetServer(pysrv):
global _PySrv
_PySrv = pysrv
-
--- a/svgui/pyjs/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,2 +1,1 @@
from pyjs import *
-
--- a/svgui/pyjs/build.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/build.py Mon Aug 21 23:22:58 2017 +0300
@@ -7,11 +7,12 @@
from os.path import join, dirname, basename, abspath, split, isfile, isdir
from optparse import OptionParser
import pyjs
+import time
from cStringIO import StringIO
try:
# Python 2.5 and above
from hashlib import md5
-except:
+except Exception:
import md5
import re
@@ -45,7 +46,7 @@
# .cache.html files produces look like this
-CACHE_HTML_PAT=re.compile('^[a-z]*.[0-9a-f]{32}\.cache\.html$')
+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.)
@@ -63,6 +64,7 @@
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)
@@ -76,7 +78,7 @@
names = os.listdir(src)
try:
os.mkdir(dst)
- except:
+ except Exception:
pass
errors = []
@@ -103,6 +105,7 @@
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.
@@ -136,19 +139,17 @@
</html>
"""
- filename = os.path.split ( source_file )[1]
- mod_name = os.path.splitext ( filename )[0]
- file_name = os.path.join ( dest_path, mod_name + '.html' )
+ 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 ):
+ if os.path.exists(file_name):
return 0
- if os.path.exists (
- os.path.join ( dest_path, mod_name + '.css' ) ) :
+ if os.path.exists(os.path.join(dest_path, mod_name + '.css')):
css = "<link rel='stylesheet' href='" + mod_name + ".css'>"
- elif os.path.exists (
- os.path.join ( dest_path, 'pyjamas_default.css' ) ) :
+ elif os.path.exists(os.path.join(dest_path, 'pyjamas_default.css')):
css = "<link rel='stylesheet' href='pyjamas_default.css'>"
else:
@@ -158,9 +159,9 @@
base_html = base_html % {'modulename': mod_name, 'title': title, 'css': css}
- fh = open (file_name, 'w')
- fh.write (base_html)
- fh.close ()
+ fh = open(file_name, 'w')
+ fh.write(base_html)
+ fh.close()
return 1
@@ -187,14 +188,14 @@
except StandardError, e:
print >>sys.stderr, "Exception creating output directory %s: %s" % (output, e)
- ## public dir
+ # 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
+ # 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):
@@ -203,7 +204,7 @@
os.path.getmtime(html_output_filename):
try:
shutil.copy(html_input_filename, html_output_filename)
- except:
+ except Exception:
print >>sys.stderr, "Warning: Missing module HTML file %s" % html_input_filename
print "Copying: %(html_input_filename)s" % locals()
@@ -211,7 +212,7 @@
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
+ # pygwt.js
print "Copying: pygwt.js"
@@ -222,7 +223,7 @@
pygwt_js_output.close()
- ## Images
+ # Images
print "Copying: Images and History"
copy_boilerplate(data_dir, "corner_dialog_topleft_black.png", output)
@@ -240,12 +241,11 @@
copy_boilerplate(data_dir, "tree_white.gif", output)
copy_boilerplate(data_dir, "history.html", output)
-
- ## all.cache.html
+ # all.cache.html
app_files = generateAppFiles(data_dir, js_includes, app_name, debug,
output, dynamic, cache_buster, optimize)
- ## AppName.nocache.html
+ # AppName.nocache.html
print "Creating: %(app_name)s.nocache.html" % locals()
@@ -261,8 +261,8 @@
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(),
+ app_name=app_name,
+ script_selectors=script_selectors.getvalue(),
)
home_nocache_html_output.close()
@@ -287,8 +287,8 @@
tmpl = read_boilerplate(data_dir, "all.cache.html")
parser = pyjs.PlatformParser("platform")
app_headers = ''
- scripts = ['<script type="text/javascript" src="%s"></script>'%script \
- for script in js_includes]
+ scripts = ['<script type="text/javascript" src="%s"></script>' %
+ script for script in js_includes]
app_body = '\n'.join(scripts)
mod_code = {}
@@ -306,7 +306,7 @@
# Second, (dynamic only), post-analyse the places where modules
# haven't changed
# Third, write everything out.
-
+
for platform in app_platforms:
mod_code[platform] = {}
@@ -324,24 +324,24 @@
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'])
+ 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
+ # 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
+ # modules_to_do = [app_name] + app_translator.library_modules
+ modules_to_do = [app_name] + app_translator.library_modules
dependencies = {}
@@ -350,13 +350,13 @@
sublist = add_subdeps(dependencies, d)
modules_to_do += sublist
deps = uniquify(deps)
- #dependencies[app_name] = deps
+ # dependencies[app_name] = deps
modules[platform] = modules_done + modules_to_do
while modules_to_do:
- #print "modules to do", modules_to_do
+ # print "modules to do", modules_to_do
mn = modules_to_do.pop()
mod_name = pyjs.strip_py(mn)
@@ -371,9 +371,9 @@
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)
+ 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, {})
@@ -390,22 +390,22 @@
while mod_name in deps:
deps.remove(mod_name)
- #print
- #print
- #print "modname preadd:", mod_name, deps
- #print
- #print
+ # 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
+ # print "modname:", mod_name, deps
deps = uniquify(deps)
- #print "modname:", mod_name, 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
@@ -415,7 +415,7 @@
early_app_libs_ = early_app_libs[platform]
app_libs_ = app_libs[platform]
app_code_ = app_code[platform]
- #modules_ = filter_mods(app_name, modules[platform])
+ # modules_ = filter_mods(app_name, modules[platform])
mods = flattenlist(mod_levels[platform])
mods.reverse()
modules_ = filter_mods(None, mods)
@@ -427,7 +427,7 @@
mod_name = pyjs.strip_py(mod_name)
override_name = "%s.%s" % (platform.lower(), mod_name)
- if pover[platform].has_key(override_name):
+ if override_name in pover[platform]:
mod_cache_name = "%s.cache.js" % (override_name)
else:
mod_cache_name = "%s.cache.js" % (mod_name)
@@ -457,13 +457,13 @@
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_,
+ 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:
@@ -473,7 +473,7 @@
app_libs_ += mod_cache_html_output.read()
# write out the dependency ordering of the modules
-
+
app_modnames = []
for md in mod_levels[platform]:
@@ -489,30 +489,30 @@
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
+ # 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
+ 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"
+ file_name += ".cache.html"
out_path = join(output, file_name)
out_file = open(out_path, 'w')
out_file.write(file_contents)
@@ -523,49 +523,56 @@
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):
+ """
+ creates sub-dependencies e.g. pyjamas.ui.Widget
+ creates pyjamas.ui.Widget, pyjamas.ui and pyjamas.
+ """
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
+ # 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
+ k = deps.get(child, [])
+ k.append(parent)
+ deps[child] = k
if parent not in res:
res.append(parent)
- #print deps
+ # print deps
return res
-# makes unique and preserves list order
+
def uniquify(md):
+ """
+ makes unique and preserves list order
+ """
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')
@@ -578,6 +585,7 @@
return uniquify(md)
+
def filter_deps(app_name, deps):
res = {}
@@ -588,18 +596,20 @@
res[k] = mods
return res
+
def has_nodeps(mod, deps):
- if not deps.has_key(mod) or not deps[mod]:
+ if mod not in deps 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
@@ -616,26 +626,26 @@
if not mod_list:
return []
- #print mod_list
- #print deps
+ # print mod_list
+ # print deps
ordered_deps = []
last_len = -1
while deps:
l_deps = len(deps)
- #print l_deps
- if l_deps==last_len:
+ # 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)
+ # raise Exception('Could not calculate dependencies: \n%s' % deps)
break
last_len = l_deps
- #print "modlist", mod_list
+ # print "modlist", mod_list
nodeps = nodeps_list(mod_list, deps)
- #print "nodeps", nodeps
+ # print "nodeps", nodeps
mod_list = filter(lambda x: x not in nodeps, mod_list)
newdeps = {}
for k in deps.keys():
@@ -643,45 +653,86 @@
depslist = filter(lambda x: x not in nodeps, depslist)
if depslist:
newdeps[k] = depslist
- #print "newdeps", newdeps
+ # print "newdeps", newdeps
deps = newdeps
ordered_deps.append(nodeps)
- #time.sleep(0)
+ # time.sleep(0)
if mod_list:
- ordered_deps.append(mod_list) # last dependencies - usually the app(s)
+ 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=[],
+ 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,
@@ -710,7 +761,7 @@
pyjs.path.append(abspath(d))
if options.platforms:
- app_platforms = options.platforms.split(',')
+ app_platforms = options.platforms.split(',')
# this is mostly for getting boilerplate stuff
data_dir = os.path.abspath(options.data_dir)
@@ -719,6 +770,6 @@
options.debug, options.dynamic and 1 or 0, data_dir,
options.cache_buster, options.optimize)
+
if __name__ == "__main__":
main()
-
--- a/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/jsonrpc/django/jsonrpc.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,9 +1,15 @@
# jsonrpc.py
# original code: http://trac.pyworks.org/pyjamas/wiki/DjangoWithPyJamas
# also from: http://www.pimentech.fr/technologies/outils
+from datetime import date
+import datetime
+import sys
+
from django.utils import simplejson
from django.http import HttpResponse
-import sys
+from django import forms
+from django.core.serializers import serialize
+
from pyjs.jsonrpc import JSONRPCServiceBase
# JSONRPCService and jsonremote are used in combination to drastically
@@ -18,14 +24,16 @@
# 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()
@@ -38,7 +46,7 @@
service.add_method(func.__name__, func)
else:
emsg = 'Service "%s" not found' % str(service.__name__)
- raise NotImplementedError, emsg
+ raise NotImplementedError(emsg)
return func
return remotify
@@ -62,7 +70,6 @@
# part of the app:
# (r'^formsservice/$', 'djangoapp.views.processor'),
-from django import forms
def builderrors(form):
d = {}
@@ -83,7 +90,7 @@
'DateField': ['input_formats'],
'DateTimeField': ['input_formats'],
'TimeField': ['input_formats'],
- 'RegexField': ['max_length', 'min_length'], # sadly we can't get the expr
+ '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'],
@@ -91,6 +98,7 @@
'IPAddressField': ['max_length', 'min_length'],
}
+
def describe_field_errors(field):
res = {}
field_type = field.__class__.__name__
@@ -102,6 +110,7 @@
res['fields'] = map(describe_field, field.fields)
return res
+
def describe_fields_errors(fields, field_names):
res = {}
if not field_names:
@@ -111,16 +120,18 @@
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']:
+ 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:
@@ -130,13 +141,14 @@
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])
+ s = FormProcessor({}, forms[k])
self.add_method(k, s.__process)
else:
JSONRPCService.__init__(self, forms)
@@ -146,33 +158,30 @@
f = self.formcls(params)
- if command is None: # just validate
+ 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'):
+ return {'success': False, 'errors': builderrors(f)}
+ return {'success': True}
+
+ elif 'describe_errors' in command:
field_names = command['describe_errors']
return describe_fields_errors(f.fields, field_names)
- elif command.has_key('describe'):
+ elif 'describe' in command:
field_names = command['describe']
return describe_fields(f.fields, field_names)
- elif command.has_key('save'):
+ elif 'save' in command:
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': False, 'errors': builderrors(f)}
+ instance = f.save() # XXX: if you want more, over-ride save.
+ return {'success': True, 'instance': json_convert(instance)}
+
+ elif 'html' in command:
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,
@@ -202,9 +211,6 @@
# 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 = {}
@@ -218,9 +224,9 @@
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
-
--- a/svgui/pyjs/jsonrpc/jsonrpc.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/jsonrpc/jsonrpc.py Mon Aug 21 23:22:58 2017 +0300
@@ -2,22 +2,24 @@
import types
import sys
+
class JSONRPCServiceBase:
def __init__(self):
- self.methods={}
+ self.methods = {}
def response(self, id, result):
- return simplejson.dumps({'version': '1.1', 'id':id,
- 'result':result, 'error':None})
+ 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
- }
- })
+ 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
@@ -27,17 +29,16 @@
id, method, params = data["id"], data["method"], data["params"]
if method in self.methods:
try:
- result =self.methods[method](*params)
+ 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:
+ return self.error(id, 100, '%s: %s' % (etype.__name__, eval))
+ except Exception:
etype, eval, etb = sys.exc_info()
- return self.error(id, 100, 'Exception %s: %s' %(etype, eval))
+ 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()
-
+ return self.methods.keys()
--- a/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/jsonrpc/web2py/jsonrpc.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,11 +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
+ def __call__(self, func):
+ self.methods[func.__name__] = func
return func
-
--- a/svgui/pyjs/lib/pyjslib.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/lib/pyjslib.py Mon Aug 21 23:22:58 2017 +0300
@@ -19,8 +19,9 @@
# must declare import _before_ importing sys
+
def import_module(path, parent_module, module_name, dynamic=1, async=False):
- """
+ """
"""
JS("""
@@ -38,7 +39,7 @@
}
var override_name = sys.platform + "." + module_name;
- if (((sys.overrides != null) &&
+ if (((sys.overrides != null) &&
(sys.overrides.has_key(override_name))))
{
cache_file = sys.overrides.__getitem__(override_name) ;
@@ -67,7 +68,7 @@
module_load_request[module_name] = 1;
}
- /* following a load, this first executes the script
+ /* following a load, this first executes the script
* "preparation" function MODULENAME_loaded_fn()
* and then sets up the loaded module in the namespace
* of the parent.
@@ -105,6 +106,7 @@
""")
+
JS("""
function import_wait(proceed_fn, parent_mod, dynamic) {
@@ -184,11 +186,14 @@
}
""")
+
class Object:
pass
+
object = Object
+
class Modload:
def __init__(self, path, app_modlist, app_imported_fn, dynamic,
@@ -196,15 +201,15 @@
self.app_modlist = app_modlist
self.app_imported_fn = app_imported_fn
self.path = path
- self.idx = 0;
+ 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);
+ import_module(self.path, self.parent_mod, app, self.dynamic, True)
self.idx += 1
if self.idx >= len(self.app_modlist):
@@ -212,18 +217,24 @@
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
+
+# as comment on line 20 says
+# import sys should be below
+import sys # noqa
+
class BaseException:
@@ -242,32 +253,37 @@
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();
@@ -407,6 +423,7 @@
""")
+
class Class:
def __init__(self, name):
self.name = name
@@ -414,7 +431,8 @@
def __str___(self):
return self.name
-def eq(a,b):
+
+def eq(a, b):
JS("""
if (pyjslib.hasattr(a, "__cmp__")) {
return a.__cmp__(b) == 0;
@@ -424,7 +442,8 @@
return a == b;
""")
-def cmp(a,b):
+
+def cmp(a, b):
if hasattr(a, "__cmp__"):
return a.__cmp__(b)
elif hasattr(b, "__cmp__"):
@@ -436,6 +455,7 @@
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
@@ -456,6 +476,7 @@
return Boolean(v);
""")
+
class List:
def __init__(self, data=None):
JS("""
@@ -511,7 +532,7 @@
def insert(self, index, value):
JS(""" var a = this.l; this.l=a.slice(0, index).concat(value, a.slice(index));""")
- def pop(self, index = -1):
+ def pop(self, index=-1):
JS("""
if (index<0) index = this.l.length + index;
var a = this.l[index];
@@ -580,15 +601,15 @@
global cmp
compareFunc = cmp
if keyFunc and reverse:
- def thisSort1(a,b):
+ def thisSort1(a, b):
return -compareFunc(keyFunc(a), keyFunc(b))
self.l.sort(thisSort1)
elif keyFunc:
- def thisSort2(a,b):
+ def thisSort2(a, b):
return compareFunc(keyFunc(a), keyFunc(b))
self.l.sort(thisSort2)
elif reverse:
- def thisSort3(a,b):
+ def thisSort3(a, b):
return -compareFunc(a, b)
self.l.sort(thisSort3)
else:
@@ -603,8 +624,10 @@
def __str__(self):
return repr(self)
+
list = List
+
class Tuple:
def __init__(self, data=None):
JS("""
@@ -660,7 +683,7 @@
def insert(self, index, value):
JS(""" var a = this.l; this.l=a.slice(0, index).concat(value, a.slice(index));""")
- def pop(self, index = -1):
+ def pop(self, index=-1):
JS("""
if (index<0) index = this.l.length + index;
var a = this.l[index];
@@ -729,15 +752,15 @@
global cmp
compareFunc = cmp
if keyFunc and reverse:
- def thisSort1(a,b):
+ def thisSort1(a, b):
return -compareFunc(keyFunc(a), keyFunc(b))
self.l.sort(thisSort1)
elif keyFunc:
- def thisSort2(a,b):
+ def thisSort2(a, b):
return compareFunc(keyFunc(a), keyFunc(b))
self.l.sort(thisSort2)
elif reverse:
- def thisSort3(a,b):
+ def thisSort3(a, b):
return -compareFunc(a, b)
self.l.sort(thisSort3)
else:
@@ -752,6 +775,7 @@
def __str__(self):
return repr(self)
+
tuple = Tuple
@@ -866,22 +890,22 @@
return self.__iter__()
def itervalues(self):
- return self.values().__iter__();
+ return self.values().__iter__()
def iteritems(self):
- return self.items().__iter__();
+ return self.items().__iter__()
def setdefault(self, key, default_value):
- if not self.has_key(key):
+ if key not in self:
self[key] = default_value
def get(self, key, default_=None):
- if not self.has_key(key):
+ if key not in self:
return default_
return self[key]
def update(self, d):
- for k,v in d.iteritems():
+ for k, v in d.iteritems():
self[k] = v
def getObject(self):
@@ -897,9 +921,12 @@
def __str__(self):
return repr(self)
+
dict = Dict
# taken from mochikit: range( [start,] stop[, step] )
+
+
def range():
JS("""
var start = 0;
@@ -930,6 +957,7 @@
}
""")
+
def slice(object, lower, upper):
JS("""
if (pyjslib.isString(object)) {
@@ -948,6 +976,7 @@
return null;
""")
+
def str(text):
JS("""
if (pyjslib.hasattr(text,"__str__")) {
@@ -956,6 +985,7 @@
return String(text);
""")
+
def ord(x):
if(isString(x) and len(x) is 1):
JS("""
@@ -967,11 +997,13 @@
""")
return None
+
def chr(x):
JS("""
return String.fromCharCode(x)
""")
+
def is_basetype(x):
JS("""
var t = typeof(x);
@@ -983,6 +1015,7 @@
;
""")
+
def get_pyjs_classtype(x):
JS("""
if (pyjslib.hasattr(x, "__class__"))
@@ -992,6 +1025,7 @@
return null;
""")
+
def repr(x):
""" Return the string representation of 'x'.
"""
@@ -1088,16 +1122,19 @@
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;
@@ -1105,11 +1142,12 @@
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:
@@ -1119,6 +1157,7 @@
else:
return _isinstance(object_, classinfo)
+
def _isinstance(object_, classinfo):
if not pyjslib.isObject(object_):
return False
@@ -1130,6 +1169,7 @@
return false;
""")
+
def getattr(obj, name, default_):
JS("""
if ((!pyjslib.isObject(obj))||(pyjslib.isUndefined(obj[name]))){
@@ -1151,6 +1191,7 @@
return fnwrap;
""")
+
def setattr(obj, name, value):
JS("""
if (!pyjslib.isObject(obj)) return null;
@@ -1159,6 +1200,7 @@
""")
+
def hasattr(obj, name):
JS("""
if (!pyjslib.isObject(obj)) return false;
@@ -1167,6 +1209,7 @@
return true;
""")
+
def dir(obj):
JS("""
var properties=new pyjslib.List();
@@ -1174,6 +1217,7 @@
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
@@ -1240,6 +1284,7 @@
next_hash_id = 0
+
def hash(obj):
JS("""
if (obj == null) return null;
@@ -1259,41 +1304,49 @@
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
@@ -1337,6 +1390,7 @@
""")
return x
+
def printFunc(objs):
JS("""
if ($wnd.console==undefined) return;
@@ -1348,6 +1402,7 @@
console.debug(s)
""")
+
def type(clsname, bases=None, methods=None):
""" creates a class, derived from bases, with methods and variables
"""
@@ -1362,4 +1417,3 @@
if bases:
JS("bss = bases.l;")
JS(" return pyjs_type(clsname, bss, mths); ")
-
--- a/svgui/pyjs/lib/sys.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/lib/sys.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,32 +1,37 @@
# the platform name (PyV8, smjs, Mozilla, IE6, Opera, Safari etc.)
-platform = '' # to be updated by app, on compile
+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
+overrides = None # to be updated by app, on compile
# the remote path for loading modules
-loadpath = None
+loadpath = None
-stacktrace = None
+stacktrace = None
-appname = None
+appname = None
+
def setloadpath(lp):
global loadpath
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))) {
@@ -34,11 +39,14 @@
}
sys.stacktrace.append(linedebug);
""")
+
+
def popstack():
JS("""
sys.stacktrace.pop()
""")
+
def printstack():
JS("""
var res = '';
--- a/svgui/pyjs/pyjs.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/pyjs/pyjs.py Mon Aug 21 23:22:58 2017 +0300
@@ -20,6 +20,7 @@
from compiler import ast
import os
import copy
+import cStringIO
# the standard location for builtins (e.g. pyjslib) can be
# over-ridden by changing this. it defaults to sys.prefix
@@ -31,7 +32,7 @@
prefix = sys.prefix
-if os.environ.has_key('PYJSPREFIX'):
+if 'PYJSPREFIX' in os.environ:
prefix = os.environ['PYJSPREFIX']
# pyjs.path is the list of paths, just like sys.path, from which
@@ -41,7 +42,7 @@
path = [os.path.abspath('')]
-if os.environ.has_key('PYJSPATH'):
+if 'PYJSPATH' in os.environ:
for p in os.environ['PYJSPATH'].split(os.pathsep):
p = os.path.abspath(p)
if os.path.isdir(p):
@@ -52,43 +53,43 @@
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",
- )
+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!
@@ -102,10 +103,11 @@
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")
+PYJS_GLOBAL_VARS = ("console")
# This is taken from the django project.
# Escape every ASCII character with a value less than 32.
@@ -119,17 +121,20 @@
(';', 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 = {}
@@ -154,9 +159,11 @@
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
@@ -174,12 +181,14 @@
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);
+ # 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)
+ mod_var_name_decl(importName)
+
class Translator:
@@ -228,7 +237,6 @@
if decl:
print >>self.output, decl
-
if self.debug:
haltException = self.module_prefix + "HaltException"
print >>self.output, haltException + ' = function () {'
@@ -273,14 +281,14 @@
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
+ 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)
+ self.imported_js.add(importName)
else:
- self.add_imported_module(strip_py(importName))
+ 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
+ if child.modname == '__pyjamas__': # special module to help make pyjamas modules loadable in the python interpreter
pass
else:
self.add_imported_module(child.modname)
@@ -302,9 +310,9 @@
elif isinstance(child, ast.Global):
self._global(child, None)
elif isinstance(child, ast.Printnl):
- self._print(child, None)
+ self._print(child, None)
elif isinstance(child, ast.Print):
- self._print(child, None)
+ self._print(child, None)
elif isinstance(child, ast.TryExcept):
self._tryExcept(child, None)
elif isinstance(child, ast.Raise):
@@ -315,14 +323,14 @@
raise TranslationError("unsupported type (in __init__)", child)
# Initialize all classes for this module
- #print >> self.output, "__"+self.modpfx()+\
+ # print >> self.output, "__"+self.modpfx()+\
# "classes_initialize = function() {\n"
- #for className in self.top_level_classes:
+ # for className in self.top_level_classes:
# print >> self.output, "\t"+UU+self.modpfx()+"__"+className+"_initialize();"
- #print >> self.output, "};\n"
+ # print >> self.output, "};\n"
print >> self.output, "return this;\n"
- print >> self.output, "}; /* end %s */ \n" % module_name
+ print >> self.output, "}; /* end %s */ \n" % module_name
def module_imports(self):
return self.imported_modules + self.imported_modules_as
@@ -345,7 +353,7 @@
# added to the dependencies, and it's half way up the
# module import directory structure!
child_name = name[-1]
- self.imported_modules_as.append(child_name)
+ self.imported_modules_as.append(child_name)
print >> self.output, gen_mod_import(self.raw_module_name,
strip_py(importName),
self.dynamic)
@@ -396,12 +404,13 @@
# 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)
+ 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)"]
+ # 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)
@@ -418,16 +427,19 @@
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()
+ 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)
+ 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
+ local_arg_names = normal_arg_names + declared_arg_names
if node.varargs:
self._varargs_handler(node, varargname, declared_arg_names, None)
@@ -451,25 +463,20 @@
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):
@@ -477,7 +484,7 @@
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):
+ elif v.node.name in self.imported_classes:
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
@@ -535,18 +542,15 @@
if kwargs or star_arg_name:
if not star_arg_name:
star_arg_name = 'null'
- try: call_this, method_name = call_name.rsplit(".", 1)
+ 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+"]"
- + ")" )
+ + star_arg_name + ", ["+fn_args+"]" + ")")
else:
return ("pyjs_kwargs_method_call("+call_this+", '"+method_name+"', "
- + star_arg_name
- + ", ["+fn_args+"]"
- + ")")
+ + star_arg_name + ", ["+fn_args+"]" + ")")
else:
return call_name + "(" + ", ".join(call_args) + ")"
@@ -581,19 +585,19 @@
self._stmt(stmt, current_klass)
print >> self.output, " } catch(%s) {" % errName
if expr:
- l = []
+ k = []
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)
+ k.append("(%(err)s.__name__ == %(expr)s.__name__)" % dict(err=errName, expr=self.expr(x, current_klass)))
+ else:
+ k = [" (%(err)s.__name__ == %(expr)s.__name__) " % dict(err=errName, expr=self.expr(expr, current_klass))]
+ print >> self.output, " if(%s) {" % '||\n\t\t'.join(k)
for stmt in node.handlers[0][2]:
self._stmt(stmt, current_klass)
if expr:
- #print >> self.output, "} else { throw(%s); } " % errName
+ # print >> self.output, "} else { throw(%s); } " % errName
print >> self.output, "}"
- if node.else_ != None:
+ if node.else_ is not None:
print >>self.output, " } finally {"
for stmt in node.else_:
self._stmt(stmt, current_klass)
@@ -605,13 +609,13 @@
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():
+ if obj is 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':
+ # if v.expr.name == 'sys':
return v.expr.name+'.'+attr_name
- #return v.expr.name+'.__'+attr_name+'.prototype.__class__'
+ # return v.expr.name+'.__'+attr_name+'.prototype.__class__'
if not use_getattr or attr_name == '__class__' or \
attr_name == '__name__':
return obj + "." + attr_name
@@ -625,12 +629,11 @@
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):
+ return_none_for_module=False):
if v.name == 'ilikesillynamesfornicedebugcode':
print top_level, current_klass, repr(v)
@@ -662,14 +665,14 @@
return UU+self.modpfx() + v.name
elif v.name in local_var_names:
return v.name
- elif self.imported_classes.has_key(v.name):
+ elif v.name in self.imported_classes:
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 )
+ 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 \
@@ -681,9 +684,8 @@
cls_name_ = cls_name.name_
cls_name = cls_name.name
else:
- cls_name_ = current_klass + "_" # XXX ???
- name = UU+cls_name_ + ".prototype.__class__." \
- + v.name
+ cls_name_ = current_klass + "_" # XXX ???
+ name = UU+cls_name_ + ".prototype.__class__." + v.name
if v.name == 'listener':
name = 'listener+' + name
return name
@@ -695,33 +697,31 @@
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__":
+ elif obj in self.imported_classes:
+ # 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
+ 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
+ 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.
@@ -761,12 +761,11 @@
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):
+ if node.bases[0].name in self.imported_classes:
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:
@@ -777,8 +776,9 @@
# 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
+ base_class = \
+ self._name(node.bases[0].expr, None) + \
+ "." + node.bases[0].attrname
else:
raise TranslationError("unsupported type (in _class)", node.bases[0])
@@ -788,28 +788,28 @@
print >>self.output, UU+class_name_ + " = function () {"
# call superconstructor
- #if base_class:
+ # 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)
+ # 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;"
+ 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)
@@ -847,7 +847,6 @@
print >> self.output, class_name_+".__initialize__();"
-
def classattr(self, node, current_klass):
self._assign(node, current_klass, True)
@@ -876,22 +875,25 @@
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;";
+ 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":
+ # 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()
+ 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)
+ if node.kwargs:
+ declared_arg_names.append(kwargname)
function_args = "(" + ", ".join(declared_arg_names) + ")"
@@ -904,13 +906,12 @@
# default arguments
self._default_args_handler(node, normal_arg_names, current_klass)
- local_arg_names = normal_arg_names + declared_arg_names
+ local_arg_names = normal_arg_names + declared_arg_names
if node.varargs:
self._varargs_handler(node, varargname, declared_arg_names, current_klass)
local_arg_names.append(varargname)
-
# stack of local variable names for this function call
self.local_arg_stack.append(local_arg_names)
@@ -944,7 +945,7 @@
print >>self.output, " "+altexpr+".__name__ = '%s';" % node.name
print >>self.output, UU + class_name_ + ".prototype.%s.__name__ = '%s';" % \
- (node.name, node.name)
+ (node.name, node.name)
if node.kwargs or len(node.defaults):
print >>self.output, " "+altexpr + ".parse_kwargs = " + fexpr + ".parse_kwargs;"
@@ -992,9 +993,9 @@
elif isinstance(node, ast.Function):
self._function(node, True)
elif isinstance(node, ast.Printnl):
- self._print(node, current_klass)
+ self._print(node, current_klass)
elif isinstance(node, ast.Print):
- self._print(node, current_klass)
+ self._print(node, current_klass)
elif isinstance(node, ast.TryExcept):
self._tryExcept(node, current_klass)
elif isinstance(node, ast.Raise):
@@ -1009,30 +1010,28 @@
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, ' }'
-
+ out = (
+ ' } catch (__err) {',
+ ' if (' + isHaltFunction + '(__err.name)) {',
+ ' throw __err;',
+ ' } else {',
+ ' st = sys.printstack() + ' + '"%s"' % lt + "+ '\\n' ;"
+ ' alert("' + 'Error in ' + lt + '"'
+ + '+"\\n"+__err.name+": "+__err.message'
+ + '+"\\n\\nStack trace:\\n"' + '+st' + ');',
+ ' debugger;',
+ ' throw new ' + self.module_prefix + 'HaltException();',
+ ' }',
+ ' }'
+ )
+ for s in out:
+ print >>self.output, s
def get_line_trace(self, node):
lineNum = "Unknown"
srcLine = ""
if hasattr(node, "lineno"):
- if node.lineno != None:
+ if node.lineno is not None:
lineNum = node.lineno
srcLine = self.src[min(lineNum, len(self.src))-1]
srcLine = srcLine.replace('\\', '\\\\')
@@ -1040,9 +1039,9 @@
srcLine = srcLine.replace("'", "\\'")
return self.raw_module_name + ".py, line " \
- + str(lineNum) + ":"\
- + "\\n" \
- + " " + srcLine
+ + str(lineNum) + ":"\
+ + "\\n" \
+ + " " + srcLine
def _augassign(self, node, current_klass):
v = node.node
@@ -1056,15 +1055,14 @@
rhs = self.expr(node.expr, current_klass)
print >>self.output, " " + lhs + " " + op + " " + rhs + ";"
-
- def _assign(self, node, current_klass, top_level = False):
+ 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)
+ tnode2 = ast.Assign([v], ast.Name(tempvar, node.lineno), node.lineno)
+ self._assign(tnode2, current_klass, top_level)
return
local_var_names = None
@@ -1093,7 +1091,7 @@
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:
+ self.method_imported_globals:
lhs = "var " + vname
else:
lhs = UU + vname
@@ -1140,7 +1138,7 @@
tempName = "__tupleassign" + str(uniqueID) + "__"
print >>self.output, " var " + tempName + " = " + \
self.expr(node.expr, current_klass) + ";"
- for index,child in enumerate(v.getChildNodes()):
+ for index, child in enumerate(v.getChildNodes()):
rhs = tempName + ".__getitem__(" + str(index) + ")"
if isinstance(child, ast.AssAttr):
@@ -1156,7 +1154,7 @@
idx = self.expr(child.subs[0], current_klass)
value = self.expr(node.expr, current_klass)
print >>self.output, " " + obj + ".__setitem__(" \
- + idx + ", " + rhs + ");"
+ + idx + ", " + rhs + ");"
continue
print >>self.output, " " + lhs + " = " + rhs + ";"
return
@@ -1168,14 +1166,13 @@
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
+ debugStmt = False
if debugStmt:
st = self.get_line_trace(node)
print >>self.output, "sys.addstack('%s');\n" % st
@@ -1194,12 +1191,11 @@
print >>self.output, "sys.popstack();\n"
elif isinstance(node.expr, ast.Const):
- if node.expr.value is not None: # Empty statements generate ignore None
+ 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]
@@ -1217,7 +1213,6 @@
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)
@@ -1234,7 +1229,6 @@
print >>self.output, " }"
-
def _from(self, node):
for name in node.names:
# look up "hack" in AppTranslator as to how findFile gets here
@@ -1248,7 +1242,6 @@
else:
self.imported_classes[name[0]] = node.modname
-
def _compare(self, node, current_klass):
lhs = self.expr(node.expr, current_klass)
@@ -1272,7 +1265,6 @@
return "(" + lhs + " " + op + " " + rhs + ")"
-
def _not(self, node, current_klass):
expr = self.expr(node.expr, current_klass)
@@ -1341,7 +1333,6 @@
}
""" % locals()
-
def _while(self, node, current_klass):
test = self.expr(node.test, current_klass)
print >>self.output, " while (pyjslib.bool(" + test + ")) {"
@@ -1352,7 +1343,6 @@
raise TranslationError("unsupported type (in _while)", node.body)
print >>self.output, " }"
-
def _const(self, node):
if isinstance(node.value, int):
return str(node.value)
@@ -1362,7 +1352,7 @@
v = node.value
if isinstance(node.value, unicode):
v = v.encode('utf-8')
- return "String('%s')" % escapejs(v)
+ return "String('%s')" % escapejs(v)
elif node.value is None:
return "null"
else:
@@ -1388,8 +1378,8 @@
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)+")"
+ 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):
@@ -1404,7 +1394,7 @@
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):
+ def _bitxor(self, node, current_klass):
return " ^ ".join([self.expr(child, current_klass) for child in node.nodes])
def _bitor(self, node, current_klass):
@@ -1459,11 +1449,11 @@
if node.flags == "OP_APPLY":
lower = "null"
upper = "null"
- if node.lower != None:
+ if node.lower is not None:
lower = self.expr(node.lower, current_klass)
- if node.upper != None:
+ if node.upper is not None:
upper = self.expr(node.upper, current_klass)
- return "pyjslib.slice(" + self.expr(node.expr, current_klass) + ", " + lower + ", " + upper + ")"
+ return "pyjslib.slice(" + self.expr(node.expr, current_klass) + ", " + lower + ", " + upper + ")"
else:
raise TranslationError("unsupported flag (in _slice)", node)
@@ -1499,7 +1489,7 @@
return self._invert(node, current_klass)
elif isinstance(node, ast.Bitand):
return "("+self._bitand(node, current_klass)+")"
- elif isinstance(node,ast.LeftShift):
+ elif isinstance(node, ast.LeftShift):
return self._bitshiftleft(node, current_klass)
elif isinstance(node, ast.RightShift):
return self._bitshiftright(node, current_klass)
@@ -1531,9 +1521,6 @@
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()
@@ -1545,7 +1532,7 @@
class PlatformParser:
- def __init__(self, platform_dir = "", verbose=True):
+ def __init__(self, platform_dir="", verbose=True):
self.platform_dir = platform_dir
self.parse_cache = {}
self.platform = ""
@@ -1557,7 +1544,7 @@
def parseModule(self, module_name, file_name):
importing = False
- if not self.parse_cache.has_key(file_name):
+ if file_name not in self.parse_cache:
importing = True
mod = compiler.parseFile(file_name)
self.parse_cache[file_name] = mod
@@ -1631,12 +1618,14 @@
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
+ 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,
@@ -1693,7 +1682,7 @@
mod, override = self.parser.parseModule(module_name, file_name)
if override:
override_name = "%s.%s" % (self.parser.platform.lower(),
- module_name)
+ module_name)
self.overrides[override_name] = override_name
if is_app:
mn = '__main__'
@@ -1709,13 +1698,12 @@
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(
+ # 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()
@@ -1742,24 +1730,26 @@
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
+ 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:
+ if len(sys.argv) < 2:
print >> sys.stderr, usage % sys.argv[0]
sys.exit(1)
file_name = os.path.abspath(sys.argv[1])
@@ -1772,6 +1762,6 @@
module_name = None
print translate(file_name, module_name),
+
if __name__ == "__main__":
main()
-
--- a/svgui/svgui.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/svgui.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,7 +24,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import wx
-import os, sys, shutil
+import os
+import sys
+import shutil
from pyjs import translate
@@ -33,21 +35,27 @@
from docutil import open_svg
from py_ext import PythonFileCTNMixin
+
class SVGUILibrary(POULibrary):
def GetLibraryPath(self):
- return paths.AbsNeighbourFile(__file__, "pous.xml")
+ return paths.AbsNeighbourFile(__file__, "pous.xml")
+
class SVGUI(PythonFileCTNMixin):
ConfNodeMethods = [
- {"bitmap" : "ImportSVG",
- "name" : _("Import SVG"),
- "tooltip" : _("Import SVG"),
- "method" : "_ImportSVG"},
- {"bitmap" : "ImportSVG", # should be something different
- "name" : _("Inkscape"),
- "tooltip" : _("Create HMI"),
- "method" : "_StartInkscape"},
+ {
+ "bitmap": "ImportSVG",
+ "name": _("Import SVG"),
+ "tooltip": _("Import SVG"),
+ "method": "_ImportSVG"
+ },
+ {
+ "bitmap": "ImportSVG", # should be something different
+ "name": _("Inkscape"),
+ "tooltip": _("Create HMI"),
+ "method": "_StartInkscape"
+ },
]
def ConfNodePath(self):
@@ -70,21 +78,21 @@
def CTNGenerate_C(self, buildpath, locations):
"""
- Return C code generated by iec2c compiler
+ Return C code generated by iec2c compiler
when _generate_softPLC have been called
@param locations: ignored
@return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
"""
-
+
current_location = self.GetCurrentLocation()
# define a unique name for the generated C file
- location_str = "_".join(map(lambda x:str(x), current_location))
-
+ location_str = "_".join(map(lambda x: str(x), current_location))
+
res = ([], "", False)
-
- svgfile=self._getSVGpath()
+
+ svgfile = self._getSVGpath()
if os.path.exists(svgfile):
- res += (("gui.svg", file(svgfile,"rb")),)
+ res += (("gui.svg", file(svgfile, "rb")),)
svguiserverfile = open(self._getSVGUIserverpath(), 'r')
svguiservercode = svguiserverfile.read()
@@ -92,7 +100,7 @@
svguilibpath = os.path.join(self._getBuildPath(), "svguilib.js")
svguilibfile = open(svguilibpath, 'w')
- fpath=paths.AbsDir(__file__)
+ fpath = paths.AbsDir(__file__)
svguilibfile.write(translate(os.path.join(fpath, "pyjs", "lib", "sys.py"), "sys"))
svguilibfile.write(open(os.path.join(fpath, "pyjs", "lib", "_pyjs.js"), 'r').read())
svguilibfile.write(translate(os.path.join(fpath, "pyjs", "lib", "pyjslib.py"), "pyjslib"))
@@ -102,26 +110,25 @@
svguilibfile.write(open(os.path.join(fpath, "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)
+ 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(svguiservercode % {"svgfile": "gui.svg"})
runtimefile.write("""
def _runtime_%(location)s_start():
website.LoadHMI(%(svgui_class)s, %(jsmodules)s)
-
+
def _runtime_%(location)s_stop():
website.UnLoadHMI()
-
-""" % {"location": location_str,
- "svgui_class": "SVGUI_HMI",
- "jsmodules" : str(jsmodules),
- })
+
+ """ % {"location": location_str,
+ "svgui_class": "SVGUI_HMI",
+ "jsmodules": str(jsmodules)})
runtimefile.close()
-
- res += (("runtime_%s.py"%location_str, file(runtimefile_path,"rb")),)
-
+
+ res += (("runtime_%s.py" % location_str, file(runtimefile_path, "rb")),)
+
return res
def _ImportSVG(self):
@@ -131,8 +138,8 @@
if os.path.isfile(svgpath):
shutil.copy(svgpath, self._getSVGpath())
else:
- self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n")%svgpath)
- dialog.Destroy()
+ self.GetCTRoot().logger.write_error(_("No such SVG file: %s\n") % svgpath)
+ dialog.Destroy()
def _StartInkscape(self):
svgfile = self._getSVGpath()
@@ -141,7 +148,7 @@
dialog = wx.MessageDialog(self.GetCTRoot().AppFrame,
_("You don't have write permissions.\nOpen Inkscape anyway ?"),
_("Open Inkscape"),
- wx.YES_NO|wx.ICON_QUESTION)
+ wx.YES_NO | wx.ICON_QUESTION)
open_inkscape = dialog.ShowModal() == wx.ID_YES
dialog.Destroy()
if open_inkscape:
--- a/svgui/svgui_server.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/svgui_server.py Mon Aug 21 23:22:58 2017 +0300
@@ -32,13 +32,16 @@
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
@@ -50,9 +53,9 @@
def setinput(self, attrname, value):
self.inputs[attrname] = value
-
+
def getinput(self, attrname, default=None):
- if not self.inputs.has_key(attrname):
+ if attrname not in self.inputs:
self.inputs[attrname] = default
return self.inputs[attrname]
@@ -61,14 +64,14 @@
self.outputs[attrname] = value
self.changed = True
self.RefreshInterface()
-
+
def updateoutputs(self, **kwargs):
for attrname, value in kwargs.iteritems():
if self.outputs.get(attrname) != value:
self.outputs[attrname] = value
self.changed = True
self.RefreshInterface()
-
+
def RefreshInterface(self):
interface = website.getHMI()
if isinstance(interface, SVGUI_HMI) and self.changed and not self.inhibit:
@@ -77,52 +80,58 @@
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),
- }
+ 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),
- }
+ 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'))[
+
+ 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):
+
+ def sendData(self, data):
if self.initialised:
- return self.callRemote('receiveData',unicode(json.dumps(data, default=get_object_current_state, indent=2), 'ascii'))
+ 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)
@@ -133,19 +142,21 @@
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
-
--- a/svgui/svguilib.py Mon Aug 21 20:17:19 2017 +0000
+++ b/svgui/svguilib.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,8 +22,9 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
class button:
-
+
def __init__(self, parent, id, args):
self.parent = parent
self.id = id
@@ -40,19 +41,19 @@
self.up = not self.state
else:
self.up = True
-
+
# Add event on each element of the button
if self.active:
self.back_elt.addEventListener("mouseup", self, False)
self.back_elt.addEventListener("mousedown", self, False)
self.back_elt.addEventListener("mouseover", self, False)
self.back_elt.addEventListener("mouseout", self, False)
-
+
self.sele_elt.addEventListener("mouseup", self, False)
self.sele_elt.addEventListener("mousedown", self, False)
self.sele_elt.addEventListener("mouseover", self, False)
self.sele_elt.addEventListener("mouseout", self, False)
-
+
blockSVGElementDrag(self.back_elt)
blockSVGElementDrag(self.sele_elt)
@@ -66,7 +67,7 @@
else:
self.sele_elt.removeAttribute("display")
self.back_elt.setAttribute("display", "none")
-
+
def updateValues(self, values):
if values.state != self.state:
self.state = values.state
@@ -80,9 +81,9 @@
if evt.type == "mousedown":
evt.stopPropagation()
setCurrentObject(self)
-
+
self.dragging = True
-
+
if self.toggle:
self.up = self.state
else:
@@ -90,18 +91,18 @@
self.state = True
updateAttr(self.id, 'state', self.state)
self.updateElements()
-
+
if isCurrentObject(self) and self.dragging:
# Quand le bouton est survole
if evt.type == "mouseover" and self.toggle:
self.up = self.state
self.updateElements()
-
+
# Quand le curseur quitte la zone du bouton
- elif evt.type == "mouseout" and self.toggle:
+ elif evt.type == "mouseout" and self.toggle:
self.up = not self.state
self.updateElements()
-
+
# Quand le bouton de la souris est relache
elif evt.type == "mouseup":
evt.stopPropagation()
@@ -115,8 +116,9 @@
self.updateElements()
self.dragging = False
+
class textControl:
-
+
def __init__(self, parent, id, args):
self.parent = parent
self.id = id
@@ -126,17 +128,15 @@
else:
self.text = ""
self.updateElements()
-
+
def updateValues(self, values):
if values.text != self.value:
self.text = values.text
updateAttr(self.id, 'text', self.text)
self.updateElements()
-
+
def updateElements(self):
self.back_elt.firstChild.firstChild.textContent = self.text
-
+
def handleEvent(self, evt):
pass
-
-
--- a/targets/Generic/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/Generic/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,5 +24,6 @@
from ..toolchain_makefile import toolchain_makefile
+
class Generic_target(toolchain_makefile):
pass
--- a/targets/Linux/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/Linux/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,10 +24,13 @@
from ..toolchain_gcc import toolchain_gcc
+
class Linux_target(toolchain_gcc):
dlopen_prefix = "./"
extension = ".so"
+
def getBuilderCFLAGS(self):
return toolchain_gcc.getBuilderCFLAGS(self) + ["-fPIC"]
+
def getBuilderLDFLAGS(self):
return toolchain_gcc.getBuilderLDFLAGS(self) + ["-shared", "-lrt"]
--- a/targets/Win32/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/Win32/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,8 +24,10 @@
from ..toolchain_gcc import toolchain_gcc
+
class Win32_target(toolchain_gcc):
dlopen_prefix = ""
extension = ".dll"
+
def getBuilderLDFLAGS(self):
return toolchain_gcc.getBuilderLDFLAGS(self) + ["-shared", "-lwinmm"]
--- a/targets/Xenomai/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/Xenomai/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,22 +24,24 @@
from ..toolchain_gcc import toolchain_gcc
+
class Xenomai_target(toolchain_gcc):
dlopen_prefix = "./"
extension = ".so"
+
def getXenoConfig(self, flagsname):
""" Get xeno-config from target parameters """
- xeno_config=self.CTRInstance.GetTarget().getcontent().getXenoConfig()
+ xeno_config = self.CTRInstance.GetTarget().getcontent().getXenoConfig()
if xeno_config:
from util.ProcessLogger import ProcessLogger
status, result, err_result = ProcessLogger(self.CTRInstance.logger,
xeno_config + " --skin=native --"+flagsname,
no_stdout=True).spin()
if status:
- self.CTRInstance.logger.write_error(_("Unable to get Xenomai's %s \n")%flagsname)
+ self.CTRInstance.logger.write_error(_("Unable to get Xenomai's %s \n") % flagsname)
return [result.strip()]
return []
-
+
def getBuilderLDFLAGS(self):
xeno_ldflags = self.getXenoConfig("ldflags")
return toolchain_gcc.getBuilderLDFLAGS(self) + xeno_ldflags + ["-shared"]
@@ -47,4 +49,3 @@
def getBuilderCFLAGS(self):
xeno_cflags = self.getXenoConfig("cflags")
return toolchain_gcc.getBuilderCFLAGS(self) + xeno_cflags + ["-fPIC"]
-
--- a/targets/__init__.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/__init__.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,89 +1,95 @@
-#!/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
-# Copyright (C) 2017: Andrey Skvortsov
-#
-# See COPYING file for copyrights details.
-#
-# This program 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
-# of the License, or (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-# Package initialisation
-#import targets
-
-"""
-Beremiz Targets
-
-- Target are python packages, containing at least one "XSD" file
-- Target class may inherit from a toolchain_(toolchainname)
-- The target folder's name must match to name define in the XSD for TargetType
-"""
-
-from os import listdir, path
-import util.paths as paths
-
-_base_path = paths.AbsDir(__file__)
-def _GetLocalTargetClassFactory(name):
- return lambda:getattr(__import__(name,globals(),locals()), name+"_target")
-
-targets = dict([(name, {"xsd":path.join(_base_path, name, "XSD"),
- "class":_GetLocalTargetClassFactory(name),
- "code": { fname: path.join(_base_path, name, fname)
- for fname in listdir(path.join(_base_path, name))
- if fname.startswith("plc_%s_main"%name) and
- fname.endswith(".c")}})
- for name in listdir(_base_path)
- if path.isdir(path.join(_base_path, name))
- and not name.startswith("__")])
-
-toolchains = {"gcc": path.join(_base_path, "XSD_toolchain_gcc"),
- "makefile": path.join(_base_path, "XSD_toolchain_makefile")}
-
-def GetBuilder(targetname):
- return targets[targetname]["class"]()
-
-def GetTargetChoices():
- DictXSD_toolchain = {}
- targetchoices = ""
-
- # Get all xsd toolchains
- for toolchainname,xsdfilename in toolchains.iteritems() :
- if path.isfile(xsdfilename):
- DictXSD_toolchain["toolchain_"+toolchainname] = \
- open(xsdfilename).read()
-
- # Get all xsd targets
- for targetname,nfo in targets.iteritems():
- xsd_string = open(nfo["xsd"]).read()
- targetchoices += xsd_string%DictXSD_toolchain
-
- return targetchoices
-
-def GetTargetCode(targetname):
- codedesc = targets[targetname]["code"]
- code = "\n".join([open(fpath).read() for fname, fpath in sorted(codedesc.items())])
- return code
-
-def GetHeader():
- filename = paths.AbsNeighbourFile(__file__,"beremiz.h")
- return open(filename).read()
-
-def GetCode(name):
- filename = paths.AbsNeighbourFile(__file__,name)
- return open(filename).read()
-
+#!/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
+# Copyright (C) 2017: Andrey Skvortsov
+#
+# See COPYING file for copyrights details.
+#
+# This program 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Package initialisation
+
+
+"""
+Beremiz Targets
+
+- Target are python packages, containing at least one "XSD" file
+- Target class may inherit from a toolchain_(toolchainname)
+- The target folder's name must match to name define in the XSD for TargetType
+"""
+
+from os import listdir, path
+import util.paths as paths
+
+_base_path = paths.AbsDir(__file__)
+
+
+def _GetLocalTargetClassFactory(name):
+ return lambda: getattr(__import__(name, globals(), locals()), name+"_target")
+
+
+targets = dict([(name, {"xsd": path.join(_base_path, name, "XSD"),
+ "class": _GetLocalTargetClassFactory(name),
+ "code": {fname: path.join(_base_path, name, fname)
+ for fname in listdir(path.join(_base_path, name))
+ if (fname.startswith("plc_%s_main" % name) and
+ fname.endswith(".c"))}})
+ for name in listdir(_base_path)
+ if (path.isdir(path.join(_base_path, name))
+ and not name.startswith("__"))])
+
+toolchains = {"gcc": path.join(_base_path, "XSD_toolchain_gcc"),
+ "makefile": path.join(_base_path, "XSD_toolchain_makefile")}
+
+
+def GetBuilder(targetname):
+ return targets[targetname]["class"]()
+
+
+def GetTargetChoices():
+ DictXSD_toolchain = {}
+ targetchoices = ""
+
+ # Get all xsd toolchains
+ for toolchainname, xsdfilename in toolchains.iteritems():
+ if path.isfile(xsdfilename):
+ DictXSD_toolchain["toolchain_"+toolchainname] = open(xsdfilename).read()
+
+ # Get all xsd targets
+ for targetname, nfo in targets.iteritems():
+ xsd_string = open(nfo["xsd"]).read()
+ targetchoices += xsd_string % DictXSD_toolchain
+
+ return targetchoices
+
+
+def GetTargetCode(targetname):
+ codedesc = targets[targetname]["code"]
+ code = "\n".join([open(fpath).read() for fname, fpath in sorted(codedesc.items())])
+ return code
+
+
+def GetHeader():
+ filename = paths.AbsNeighbourFile(__file__, "beremiz.h")
+ return open(filename).read()
+
+
+def GetCode(name):
+ filename = paths.AbsNeighbourFile(__file__, name)
+ return open(filename).read()
--- a/targets/toolchain_gcc.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/toolchain_gcc.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,237 +1,239 @@
-#!/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
-# Copyright (C) 2017: Paul Beltyukov
-#
-# See COPYING file for copyrights details.
-#
-# This program 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
-# of the License, or (at your option) any later version.
-#
-# This program 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 program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-
-import os, re, operator
-from util.ProcessLogger import ProcessLogger
-import hashlib
-
-includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
-
-class toolchain_gcc():
- """
- This abstract class contains GCC specific code.
- 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, CTRInstance):
- self.CTRInstance = CTRInstance
- self.buildpath = None
- self.SetBuildPath(self.CTRInstance._getBuildPath())
-
- def getBuilderCFLAGS(self):
- """
- Returns list of builder specific CFLAGS
- """
- return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()]
-
- def getBuilderLDFLAGS(self):
- """
- Returns list of builder specific LDFLAGS
- """
- return self.CTRInstance.LDFLAGS + \
- [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()]
-
- def getCompiler(self):
- """
- Returns compiler
- """
- return self.CTRInstance.GetTarget().getcontent().getCompiler()
-
- def getLinker(self):
- """
- Returns linker
- """
- return self.CTRInstance.GetTarget().getcontent().getLinker()
-
- def GetBinaryCode(self):
- try:
- return open(self.exe_path, "rb").read()
- except Exception, e:
- return None
-
- def _GetMD5FileName(self):
- return os.path.join(self.buildpath, "lastbuildPLC.md5")
-
- def ResetBinaryCodeMD5(self):
- self.md5key = None
- try:
- os.remove(self._GetMD5FileName())
- except Exception, e:
- pass
-
- def GetBinaryCodeMD5(self):
- if self.md5key is not None:
- return self.md5key
- else:
- try:
- return open(self._GetMD5FileName(), "r").read()
- except Exception, e:
- return None
-
- def SetBuildPath(self, buildpath):
- if self.buildpath != buildpath:
- self.buildpath = buildpath
- self.exe = self.CTRInstance.GetProjectName() + self.extension
- self.exe_path = os.path.join(self.buildpath, self.exe)
- self.md5key = None
- self.srcmd5 = {}
-
- def append_cfile_deps(self, src, deps):
- for l in src.splitlines():
- res = includes_re.match(l)
- if res is not None:
- depfn = res.groups()[0]
- if os.path.exists(os.path.join(self.buildpath, depfn)):
- deps.append(depfn)
-
- def concat_deps(self, bn):
- # read source
- src = open(os.path.join(self.buildpath, bn),"r").read()
- # update direct dependencies
- deps = []
- self.append_cfile_deps(src, deps)
- # recurse through deps
- # TODO detect cicular deps.
- return reduce(operator.concat, map(self.concat_deps, deps), src)
-
- def check_and_update_hash_and_deps(self, bn):
- # Get latest computed hash and deps
- oldhash, deps = self.srcmd5.get(bn,(None,[]))
- # read source
- src = open(os.path.join(self.buildpath, bn)).read()
- # compute new hash
- newhash = hashlib.md5(src).hexdigest()
- # compare
- match = (oldhash == newhash)
- if not match:
- # file have changed
- # update direct dependencies
- deps = []
- self.append_cfile_deps(src, deps)
- # store that hashand deps
- self.srcmd5[bn] = (newhash, deps)
- # recurse through deps
- # TODO detect cicular deps.
- return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match)
-
- def calc_source_md5(self):
- wholesrcdata = ""
- for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
- # Get CFiles list to give it to makefile
- for CFile, CFLAGS in CFilesAndCFLAGS:
- CFileName = os.path.basename(CFile)
- wholesrcdata += self.concat_deps(CFileName)
- return hashlib.md5(wholesrcdata).hexdigest()
-
- def calc_md5(self):
- return hashlib.md5(self.GetBinaryCode()).hexdigest()
-
- def build(self):
- # Retrieve compiler and linker
- self.compiler = self.getCompiler()
- self.linker = self.getLinker()
-
- Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS())
-
- ######### GENERATE OBJECT FILES ########################################
- obns = []
- objs = []
- relink = self.GetBinaryCode() is None
- for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
- if CFilesAndCFLAGS:
- if Location :
- self.CTRInstance.logger.write(".".join(map(str,Location))+" :\n")
- else:
- self.CTRInstance.logger.write(_("PLC :\n"))
-
- for CFile, CFLAGS in CFilesAndCFLAGS:
- if CFile.endswith(".c"):
- bn = os.path.basename(CFile)
- obn = os.path.splitext(bn)[0]+".o"
- objectfilename = os.path.splitext(CFile)[0]+".o"
-
- match = self.check_and_update_hash_and_deps(bn)
-
- if match:
- self.CTRInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n")
- else:
- relink = True
-
- self.CTRInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n")
-
- status, result, err_result = ProcessLogger(
- self.CTRInstance.logger,
- "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
- (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)
- ).spin()
-
- if status :
- self.srcmd5.pop(bn)
- self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n")%bn)
- return False
- obns.append(obn)
- objs.append(objectfilename)
- elif CFile.endswith(".o"):
- obns.append(os.path.basename(CFile))
- objs.append(CFile)
-
- ######### GENERATE OUTPUT FILE ########################################
- # Link all the object files into one binary file
- self.CTRInstance.logger.write(_("Linking :\n"))
- if relink:
- objstring = []
-
- # Generate list .o files
- listobjstring = '"' + '" "'.join(objs) + '"'
-
- ALLldflags = ' '.join(self.getBuilderLDFLAGS())
-
- self.CTRInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n")
-
- status, result, err_result = ProcessLogger(
- self.CTRInstance.logger,
- "\"%s\" %s -o \"%s\" %s"%
- (self.linker,
- listobjstring,
- self.exe_path,
- ALLldflags)
- ).spin()
-
- if status :
- return False
-
- else:
- self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n")
-
- # Calculate md5 key and get data for the new created PLC
- self.md5key = self.calc_md5()
-
- # Store new PLC filename based on md5 key
- f = open(self._GetMD5FileName(), "w")
- f.write(self.md5key)
- f.close()
-
- return True
-
+#!/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
+# Copyright (C) 2017: Paul Beltyukov
+#
+# See COPYING file for copyrights details.
+#
+# This program 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
+# of the License, or (at your option) any later version.
+#
+# This program 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 program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+import os
+import re
+import operator
+from util.ProcessLogger import ProcessLogger
+import hashlib
+
+includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
+
+
+class toolchain_gcc():
+ """
+ This abstract class contains GCC specific code.
+ 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, CTRInstance):
+ self.CTRInstance = CTRInstance
+ self.buildpath = None
+ self.SetBuildPath(self.CTRInstance._getBuildPath())
+
+ def getBuilderCFLAGS(self):
+ """
+ Returns list of builder specific CFLAGS
+ """
+ return [self.CTRInstance.GetTarget().getcontent().getCFLAGS()]
+
+ def getBuilderLDFLAGS(self):
+ """
+ Returns list of builder specific LDFLAGS
+ """
+ return self.CTRInstance.LDFLAGS + \
+ [self.CTRInstance.GetTarget().getcontent().getLDFLAGS()]
+
+ def getCompiler(self):
+ """
+ Returns compiler
+ """
+ return self.CTRInstance.GetTarget().getcontent().getCompiler()
+
+ def getLinker(self):
+ """
+ Returns linker
+ """
+ return self.CTRInstance.GetTarget().getcontent().getLinker()
+
+ def GetBinaryCode(self):
+ try:
+ return open(self.exe_path, "rb").read()
+ except Exception, e:
+ return None
+
+ def _GetMD5FileName(self):
+ return os.path.join(self.buildpath, "lastbuildPLC.md5")
+
+ def ResetBinaryCodeMD5(self):
+ self.md5key = None
+ try:
+ os.remove(self._GetMD5FileName())
+ except Exception, e:
+ pass
+
+ def GetBinaryCodeMD5(self):
+ if self.md5key is not None:
+ return self.md5key
+ else:
+ try:
+ return open(self._GetMD5FileName(), "r").read()
+ except Exception, e:
+ return None
+
+ def SetBuildPath(self, buildpath):
+ if self.buildpath != buildpath:
+ self.buildpath = buildpath
+ self.exe = self.CTRInstance.GetProjectName() + self.extension
+ self.exe_path = os.path.join(self.buildpath, self.exe)
+ self.md5key = None
+ self.srcmd5 = {}
+
+ def append_cfile_deps(self, src, deps):
+ for l in src.splitlines():
+ res = includes_re.match(l)
+ if res is not None:
+ depfn = res.groups()[0]
+ if os.path.exists(os.path.join(self.buildpath, depfn)):
+ deps.append(depfn)
+
+ def concat_deps(self, bn):
+ # read source
+ src = open(os.path.join(self.buildpath, bn), "r").read()
+ # update direct dependencies
+ deps = []
+ self.append_cfile_deps(src, deps)
+ # recurse through deps
+ # TODO detect cicular deps.
+ return reduce(operator.concat, map(self.concat_deps, deps), src)
+
+ def check_and_update_hash_and_deps(self, bn):
+ # Get latest computed hash and deps
+ oldhash, deps = self.srcmd5.get(bn, (None, []))
+ # read source
+ src = open(os.path.join(self.buildpath, bn)).read()
+ # compute new hash
+ newhash = hashlib.md5(src).hexdigest()
+ # compare
+ match = (oldhash == newhash)
+ if not match:
+ # file have changed
+ # update direct dependencies
+ deps = []
+ self.append_cfile_deps(src, deps)
+ # store that hashand deps
+ self.srcmd5[bn] = (newhash, deps)
+ # recurse through deps
+ # TODO detect cicular deps.
+ return reduce(operator.and_, map(self.check_and_update_hash_and_deps, deps), match)
+
+ def calc_source_md5(self):
+ wholesrcdata = ""
+ for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
+ # Get CFiles list to give it to makefile
+ for CFile, CFLAGS in CFilesAndCFLAGS:
+ CFileName = os.path.basename(CFile)
+ wholesrcdata += self.concat_deps(CFileName)
+ return hashlib.md5(wholesrcdata).hexdigest()
+
+ def calc_md5(self):
+ return hashlib.md5(self.GetBinaryCode()).hexdigest()
+
+ def build(self):
+ # Retrieve compiler and linker
+ self.compiler = self.getCompiler()
+ self.linker = self.getLinker()
+
+ Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS())
+
+ # ----------------- GENERATE OBJECT FILES ------------------------
+ obns = []
+ objs = []
+ relink = self.GetBinaryCode() is None
+ for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
+ if CFilesAndCFLAGS:
+ if Location:
+ self.CTRInstance.logger.write(".".join(map(str, Location))+" :\n")
+ else:
+ self.CTRInstance.logger.write(_("PLC :\n"))
+
+ for CFile, CFLAGS in CFilesAndCFLAGS:
+ if CFile.endswith(".c"):
+ bn = os.path.basename(CFile)
+ obn = os.path.splitext(bn)[0]+".o"
+ objectfilename = os.path.splitext(CFile)[0]+".o"
+
+ match = self.check_and_update_hash_and_deps(bn)
+
+ if match:
+ self.CTRInstance.logger.write(" [pass] "+bn+" -> "+obn+"\n")
+ else:
+ relink = True
+
+ self.CTRInstance.logger.write(" [CC] "+bn+" -> "+obn+"\n")
+
+ status, result, err_result = ProcessLogger(
+ self.CTRInstance.logger,
+ "\"%s\" -c \"%s\" -o \"%s\" %s %s" %
+ (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)
+ ).spin()
+
+ if status:
+ self.srcmd5.pop(bn)
+ self.CTRInstance.logger.write_error(_("C compilation of %s failed.\n") % bn)
+ return False
+ obns.append(obn)
+ objs.append(objectfilename)
+ elif CFile.endswith(".o"):
+ obns.append(os.path.basename(CFile))
+ objs.append(CFile)
+
+ # ---------------- GENERATE OUTPUT FILE --------------------------
+ # Link all the object files into one binary file
+ self.CTRInstance.logger.write(_("Linking :\n"))
+ if relink:
+ objstring = []
+
+ # Generate list .o files
+ listobjstring = '"' + '" "'.join(objs) + '"'
+
+ ALLldflags = ' '.join(self.getBuilderLDFLAGS())
+
+ self.CTRInstance.logger.write(" [CC] " + ' '.join(obns)+" -> " + self.exe + "\n")
+
+ status, result, err_result = ProcessLogger(
+ self.CTRInstance.logger,
+ "\"%s\" %s -o \"%s\" %s" %
+ (self.linker,
+ listobjstring,
+ self.exe_path,
+ ALLldflags)
+ ).spin()
+
+ if status:
+ return False
+
+ else:
+ self.CTRInstance.logger.write(" [pass] " + ' '.join(obns)+" -> " + self.exe + "\n")
+
+ # Calculate md5 key and get data for the new created PLC
+ self.md5key = self.calc_md5()
+
+ # Store new PLC filename based on md5 key
+ f = open(self._GetMD5FileName(), "w")
+ f.write(self.md5key)
+ f.close()
+
+ return True
--- a/targets/toolchain_makefile.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/toolchain_makefile.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,18 +22,21 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, re, operator
+import os
+import re
+import operator
from util.ProcessLogger import ProcessLogger
import hashlib
import time
-includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
+includes_re = re.compile('\s*#include\s*["<]([^">]*)[">].*')
+
class toolchain_makefile():
def __init__(self, CTRInstance):
self.CTRInstance = CTRInstance
- self.md5key = None
+ self.md5key = None
self.buildpath = None
self.SetBuildPath(self.CTRInstance._getBuildPath())
@@ -66,7 +69,7 @@
def concat_deps(self, bn):
# read source
- src = open(os.path.join(self.buildpath, bn),"r").read()
+ src = open(os.path.join(self.buildpath, bn), "r").read()
# update direct dependencies
deps = []
for l in src.splitlines():
@@ -74,16 +77,16 @@
if res is not None:
depfn = res.groups()[0]
if os.path.exists(os.path.join(self.buildpath, depfn)):
- #print bn + " depends on "+depfn
+ # print bn + " depends on "+depfn
deps.append(depfn)
# recurse through deps
# TODO detect cicular deps.
return reduce(operator.concat, map(self.concat_deps, deps), src)
def build(self):
- srcfiles= []
+ srcfiles = []
cflags = []
- wholesrcdata = ""
+ wholesrcdata = ""
for Location, CFilesAndCFLAGS, DoCalls in self.CTRInstance.LocationCFilesAndCFLAGS:
# Get CFiles list to give it to makefile
for CFile, CFLAGS in CFilesAndCFLAGS:
@@ -92,7 +95,7 @@
srcfiles.append(CFileName)
if CFLAGS not in cflags:
cflags.append(CFLAGS)
-
+
oldmd5 = self.md5key
self.md5key = hashlib.md5(wholesrcdata).hexdigest()
@@ -101,28 +104,26 @@
f.write(self.md5key)
f.close()
- if oldmd5 != self.md5key :
+ if oldmd5 != self.md5key:
target = self.CTRInstance.GetTarget().getcontent()
beremizcommand = {"src": ' '.join(srcfiles),
"cflags": ' '.join(cflags),
"md5": self.md5key,
- "buildpath": self.buildpath
- }
-
- # clean sequence of multiple whitespaces
+ "buildpath": self.buildpath}
+
+ # clean sequence of multiple whitespaces
cmd = re.sub(r"[ ]+", " ", target.getCommand().strip())
- command = [ token % beremizcommand for token in cmd.split(' ')]
+ command = [token % beremizcommand for token in cmd.split(' ')]
# Call Makefile to build PLC code and link it with target specific code
status, result, err_result = ProcessLogger(self.CTRInstance.logger,
command).spin()
- if status :
+ if status:
self.md5key = None
self.CTRInstance.logger.write_error(_("C compilation failed.\n"))
return False
return True
- else :
+ else:
self.CTRInstance.logger.write(_("Source didn't change, no build.\n"))
return True
-
--- a/targets/typemapping.py Mon Aug 21 20:17:19 2017 +0000
+++ b/targets/typemapping.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,13 +23,13 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import ctypes
+from ctypes import *
+from datetime import timedelta as td
+
ctypes.pythonapi.PyString_AsString.argtypes = (ctypes.c_void_p,)
ctypes.pythonapi.PyString_AsString.restype = ctypes.POINTER(ctypes.c_char)
-from ctypes import *
-from datetime import timedelta as td
-
class IEC_STRING(Structure):
"""
Must be changed according to changes in iec_types.h
@@ -37,68 +37,73 @@
_fields_ = [("len", c_uint8),
("body", c_char * 126)]
+
class IEC_TIME(Structure):
"""
Must be changed according to changes in iec_types.h
"""
- _fields_ = [("s", c_long), #tv_sec
- ("ns", c_long)] #tv_nsec
+ _fields_ = [("s", c_long), # tv_sec
+ ("ns", c_long)] # tv_nsec
-def _t(t, u=lambda x:x.value, p=lambda t,x:t(x)): return (t, u, p)
+
+def _t(t, u=lambda x: x.value, p=lambda t, x: t(x)): return (t, u, p)
+
+
def _ttime(): return (IEC_TIME,
- lambda x:td(0, x.s, x.ns/1000),
- lambda t,x:t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
+ lambda x: td(0, x.s, x.ns/1000),
+ lambda t, x: t(x.days * 24 * 3600 + x.seconds, x.microseconds*1000))
+
SameEndianessTypeTranslator = {
- "BOOL" : _t(c_uint8, lambda x:x.value!=0),
- "STEP" : _t(c_uint8),
- "TRANSITION" : _t(c_uint8),
- "ACTION" : _t(c_uint8),
- "SINT" : _t(c_int8),
- "USINT" : _t(c_uint8),
- "BYTE" : _t(c_uint8),
- "STRING" : (IEC_STRING,
- lambda x:x.body[:x.len],
- lambda t,x:t(len(x),x)),
- "INT" : _t(c_int16),
- "UINT" : _t(c_uint16),
- "WORD" : _t(c_uint16),
- "DINT" : _t(c_int32),
- "UDINT" : _t(c_uint32),
- "DWORD" : _t(c_uint32),
- "LINT" : _t(c_int64),
- "ULINT" : _t(c_uint64),
- "LWORD" : _t(c_uint64),
- "REAL" : _t(c_float),
- "LREAL" : _t(c_double),
- "TIME" : _ttime(),
- "TOD" : _ttime(),
- "DATE" : _ttime(),
- "DT" : _ttime(),
+ "BOOL": _t(c_uint8, lambda x: x.value != 0),
+ "STEP": _t(c_uint8),
+ "TRANSITION": _t(c_uint8),
+ "ACTION": _t(c_uint8),
+ "SINT": _t(c_int8),
+ "USINT": _t(c_uint8),
+ "BYTE": _t(c_uint8),
+ "STRING": (IEC_STRING,
+ lambda x: x.body[:x.len],
+ lambda t, x: t(len(x), x)),
+ "INT": _t(c_int16),
+ "UINT": _t(c_uint16),
+ "WORD": _t(c_uint16),
+ "DINT": _t(c_int32),
+ "UDINT": _t(c_uint32),
+ "DWORD": _t(c_uint32),
+ "LINT": _t(c_int64),
+ "ULINT": _t(c_uint64),
+ "LWORD": _t(c_uint64),
+ "REAL": _t(c_float),
+ "LREAL": _t(c_double),
+ "TIME": _ttime(),
+ "TOD": _ttime(),
+ "DATE": _ttime(),
+ "DT": _ttime(),
}
SwapedEndianessTypeTranslator = {
- #TODO
+ # TODO
}
-TypeTranslator=SameEndianessTypeTranslator
+TypeTranslator = SameEndianessTypeTranslator
# Construct debugger natively supported types
-DebugTypesSize = dict([(key,sizeof(t)) for key,(t,p,u) in SameEndianessTypeTranslator.iteritems() if t is not None])
+DebugTypesSize = dict([(key, sizeof(t)) for key, (t, p, u) in SameEndianessTypeTranslator.iteritems() if t is not None])
+
def UnpackDebugBuffer(buff, indexes):
- res = []
+ res = []
buffoffset = 0
buffsize = len(buff)
- buffptr = cast(ctypes.pythonapi.PyString_AsString(id(buff)),c_void_p).value
+ buffptr = cast(ctypes.pythonapi.PyString_AsString(id(buff)), c_void_p).value
for iectype in indexes:
- c_type,unpack_func, pack_func = \
- TypeTranslator.get(iectype,
- (None,None,None))
+ c_type, unpack_func, pack_func = \
+ TypeTranslator.get(iectype, (None, None, None))
if c_type is not None and buffoffset < buffsize:
- cursor = c_void_p( buffptr + buffoffset)
- value = unpack_func( cast(cursor,
- POINTER(c_type)).contents)
+ cursor = c_void_p(buffptr + buffoffset)
+ value = unpack_func(cast(cursor,
+ POINTER(c_type)).contents)
buffoffset += sizeof(c_type) if iectype != "STRING" else len(value)+1
res.append(value)
else:
@@ -108,9 +113,7 @@
return None
-
-LogLevels = ["CRITICAL","WARNING","INFO","DEBUG"]
+LogLevels = ["CRITICAL", "WARNING", "INFO", "DEBUG"]
LogLevelsCount = len(LogLevels)
-LogLevelsDict = dict(zip(LogLevels,range(LogLevelsCount)))
+LogLevelsDict = dict(zip(LogLevels, range(LogLevelsCount)))
LogLevelsDefault = LogLevelsDict["DEBUG"]
-
--- a/util/BitmapLibrary.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/BitmapLibrary.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,45 +26,48 @@
import wx
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Library Structures
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
BitmapLibrary = {}
BitmapFolders = []
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Library Helpers
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
def AddBitmapFolder(path):
if os.path.exists(path) and os.path.isdir(path) and path not in BitmapFolders:
BitmapFolders.append(path)
+
def SearchBitmap(bmp_name):
for folder in BitmapFolders:
bmp_path = os.path.join(folder, bmp_name + ".png")
if os.path.isfile(bmp_path):
return wx.Bitmap(bmp_path)
return None
-
+
+
def GetBitmap(bmp_name1, bmp_name2=None, size=None):
bmp = BitmapLibrary.get((bmp_name1, bmp_name2, size))
if bmp is not None:
return bmp
-
+
if bmp_name2 is None:
bmp = SearchBitmap(bmp_name1)
else:
# Bitmap with two icon
bmp1 = SearchBitmap(bmp_name1)
bmp2 = SearchBitmap(bmp_name2)
-
+
if bmp1 is not None and bmp2 is not None:
# Calculate bitmap size
width = bmp1.GetWidth() + bmp2.GetWidth() - 1
height = max(bmp1.GetHeight(), bmp2.GetHeight())
-
+
# Create bitmap with both icons
bmp = wx.EmptyBitmap(width, height)
dc = wx.MemoryDC()
@@ -73,13 +76,13 @@
dc.DrawBitmap(bmp1, 0, 0)
dc.DrawBitmap(bmp2, bmp1.GetWidth() - 1, 0)
dc.Destroy()
-
+
elif bmp1 is not None:
bmp = bmp1
elif bmp2 is not None:
bmp = bmp2
-
+
if bmp is not None:
BitmapLibrary[(bmp_name1, bmp_name2, size)] = bmp
-
+
return bmp
--- a/util/MiniTextControler.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/MiniTextControler.py Mon Aug 21 23:22:58 2017 +0300
@@ -28,49 +28,50 @@
import os
+
class MiniTextControler:
-
+
def __init__(self, filepath, controller):
self.FilePath = filepath
self.BaseController = controller
-
+
def __del__(self):
self.BaseController = None
-
+
def CTNFullName(self):
return ""
-
+
def SetEditedElementText(self, tagname, text):
file = open(self.FilePath, "w")
file.write(text)
file.close()
-
- def GetEditedElementText(self, tagname, debug = False):
+
+ 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, tree=False, debug = False):
+
+ def GetEditedElementInterfaceVars(self, tagname, tree=False, debug=False):
return []
-
- def GetEditedElementType(self, tagname, debug = False):
+
+ def GetEditedElementType(self, tagname, debug=False):
return "program"
-
- def GetBlockType(self, type, inputs = None, debug = False):
+
+ def GetBlockType(self, type, inputs=None, debug=False):
return self.BaseController.GetBlockType(type, inputs, debug)
-
- def GetBlockTypes(self, tagname = "", debug = False):
+
+ def GetBlockTypes(self, tagname="", debug=False):
return self.BaseController.GetBlockTypes(tagname, debug)
-
- def GetDataTypes(self, tagname = "", basetypes = True, only_locatables = False, debug = False):
+
+ def GetDataTypes(self, tagname="", basetypes=True, only_locatables=False, debug=False):
return self.BaseController.GetDataTypes(tagname, basetypes, only_locatables, debug)
-
- def GetEnumeratedDataValues(self, debug = False):
+
+ def GetEnumeratedDataValues(self, debug=False):
return self.BaseController.GetEnumeratedDataValues(debug)
-
+
def StartBuffering(self):
pass
@@ -79,4 +80,3 @@
def BufferProject(self):
pass
-
--- a/util/ProcessLogger.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/ProcessLogger.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,11 +22,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+import os
+import sys
import time
import wx
-import subprocess, ctypes
+import subprocess
+import ctypes
from threading import Timer, Lock, Thread, Semaphore
-import os, sys
if os.name == 'posix':
from signal import SIGTERM, SIGKILL
@@ -48,36 +50,39 @@
def run(self):
outchunk = None
self.retval = None
- while self.retval is None and not self.killed :
+ while self.retval is None and not self.killed:
if self.endcallback:
self.retval = self.Proc.poll()
else:
self.retval = self.Proc.returncode
-
+
outchunk = self.fd.readline()
- if self.callback : self.callback(outchunk)
- while outchunk != '' and not self.killed :
+ if self.callback:
+ self.callback(outchunk)
+ while outchunk != '' and not self.killed:
outchunk = self.fd.readline()
- if self.callback : self.callback(outchunk)
+ if self.callback:
+ self.callback(outchunk)
if self.endcallback:
try:
err = self.Proc.wait()
- except:
+ except Exception:
err = self.retval
self.finished = True
self.endcallback(self.Proc.pid, err)
+
class ProcessLogger:
- def __init__(self, logger, Command, finish_callback = None,
- no_stdout = False, no_stderr = False, no_gui = True,
- timeout = None, outlimit = None, errlimit = None,
- endlog = None, keyword = None, kill_it = False, cwd = None,
- encoding = None):
+ def __init__(self, logger, Command, finish_callback=None,
+ no_stdout=False, no_stderr=False, no_gui=True,
+ timeout=None, outlimit=None, errlimit=None,
+ endlog=None, keyword=None, kill_it=False, cwd=None,
+ encoding=None):
self.logger = logger
if not isinstance(Command, list):
self.Command_str = Command
self.Command = []
- for i,word in enumerate(Command.replace("'",'"').split('"')):
+ for i, word in enumerate(Command.replace("'", '"').split('"')):
if i % 2 == 0:
word = word.strip()
if len(word) > 0:
@@ -108,17 +113,18 @@
self.errdata = []
self.keyword = keyword
self.kill_it = kill_it
- self.startsem = Semaphore(0)
+ self.startsem = Semaphore(0)
self.finishsem = Semaphore(0)
self.endlock = Lock()
- popenargs= {
- "cwd":os.getcwd() if cwd is None else cwd,
- "stdin":subprocess.PIPE,
- "stdout":subprocess.PIPE,
- "stderr":subprocess.PIPE}
-
- if no_gui == True and wx.Platform == '__WXMSW__':
+ popenargs = {
+ "cwd": os.getcwd() if cwd is None else cwd,
+ "stdin": subprocess.PIPE,
+ "stdout": subprocess.PIPE,
+ "stderr": subprocess.PIPE
+ }
+
+ if no_gui and wx.Platform == '__WXMSW__':
self.startupinfo = subprocess.STARTUPINFO()
self.startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
popenargs["startupinfo"] = self.startupinfo
@@ -126,12 +132,12 @@
popenargs["shell"] = False
if timeout:
- self.timeout = Timer(timeout,self.endlog)
+ self.timeout = Timer(timeout, self.endlog)
self.timeout.start()
else:
self.timeout = None
-
- self.Proc = subprocess.Popen( self.Command, **popenargs )
+
+ self.Proc = subprocess.Popen(self.Command, **popenargs)
self.outt = outputThread(
self.Proc,
@@ -147,16 +153,15 @@
self.errt.start()
self.startsem.release()
-
- def output(self,v):
+ def output(self, v):
self.outdata.append(v)
self.outlen += 1
if not self.no_stdout:
self.logger.write(v)
- if (self.keyword and v.find(self.keyword)!=-1) or (self.outlimit and self.outlen > self.outlimit):
+ if (self.keyword and v.find(self.keyword) != -1) or (self.outlimit and self.outlen > self.outlimit):
self.endlog()
- def errors(self,v):
+ def errors(self, v):
self.errdata.append(v)
self.errlen += 1
if not self.no_stderr:
@@ -164,28 +169,28 @@
if self.errlimit and self.errlen > self.errlimit:
self.endlog()
- def log_the_end(self,ecode,pid):
+ def log_the_end(self, ecode, pid):
self.logger.write(self.Command_str + "\n")
- self.logger.write_warning(_("exited with status {a1} (pid {a2})\n").format(a1 = str(ecode), a2 = str(pid)))
-
- def finish(self, pid,ecode):
- # avoid running function before start is finished
+ self.logger.write_warning(_("exited with status {a1} (pid {a2})\n").format(a1=str(ecode), a2=str(pid)))
+
+ def finish(self, pid, ecode):
+ # avoid running function before start is finished
self.startsem.acquire()
if self.timeout:
self.timeout.cancel()
self.exitcode = ecode
if self.exitcode != 0:
- self.log_the_end(ecode,pid)
+ self.log_the_end(ecode, pid)
if self.finish_callback is not None:
- self.finish_callback(self,ecode,pid)
+ self.finish_callback(self, ecode, pid)
self.errt.join()
self.finishsem.release()
- def kill(self,gently=True):
+ def kill(self, gently=True):
# avoid running kill before start is finished
self.startsem.acquire()
self.startsem.release()
-
+
self.outt.killed = True
self.errt.killed = True
if wx.Platform == '__WXMSW__':
@@ -195,12 +200,12 @@
ctypes.windll.kernel32.CloseHandle(handle)
else:
if gently:
- sig=SIGTERM
+ sig = SIGTERM
else:
- sig=SIGKILL
+ sig = SIGKILL
try:
os.kill(self.Proc.pid, sig)
- except:
+ except Exception:
pass
self.outt.join()
self.errt.join()
@@ -208,11 +213,9 @@
def endlog(self):
if self.endlock.acquire(False):
if not self.outt.finished and self.kill_it:
- self.kill()
+ self.kill()
self.finishsem.release()
-
def spin(self):
self.finishsem.acquire()
return [self.exitcode, "".join(self.outdata), "".join(self.errdata)]
-
--- a/util/TranslationCatalogs.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/TranslationCatalogs.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,7 +22,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os
+import os
import wx
@@ -32,6 +32,7 @@
# Define locale for wx
locale = wx.Locale(langid)
+
def GetDomain(path):
for name in os.listdir(path):
filepath = os.path.join(path, name)
@@ -44,9 +45,14 @@
return basename
return None
+
def AddCatalog(locale_dir):
if os.path.exists(locale_dir) and os.path.isdir(locale_dir):
domain = GetDomain(locale_dir)
if domain is not None:
locale.AddCatalogLookupPathPrefix(locale_dir)
locale.AddCatalog(domain)
+
+
+def NoTranslate(x):
+ return x
--- a/util/Zeroconf.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/Zeroconf.py Mon Aug 21 23:22:58 2017 +0300
@@ -1,82 +1,78 @@
-""" Multicast DNS Service Discovery for Python, v0.12
- Copyright (C) 2003, Paul Scott-Murphy
-
- This module provides a framework for the use of DNS Service Discovery
- using IP multicast. It has been tested against the JRendezvous
- implementation from <a href="http://strangeberry.com">StrangeBerry</a>,
- and against the mDNSResponder from Mac OS X 10.3.8.
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-"""
-
-"""0.12 update - allow selection of binding interface
- typo fix - Thanks A. M. Kuchlingi
- removed all use of word 'Rendezvous' - this is an API change"""
-
-"""0.11 update - correction to comments for addListener method
- support for new record types seen from OS X
- - IPv6 address
- - hostinfo
- ignore unknown DNS record types
- fixes to name decoding
- works alongside other processes using port 5353 (e.g. on Mac OS X)
- tested against Mac OS X 10.3.2's mDNSResponder
- corrections to removal of list entries for service browser"""
-
-"""0.10 update - Jonathon Paisley contributed these corrections:
- always multicast replies, even when query is unicast
- correct a pointer encoding problem
- can now write records in any order
- traceback shown on failure
- better TXT record parsing
- server is now separate from name
- can cancel a service browser
-
- modified some unit tests to accommodate these changes"""
-
-"""0.09 update - remove all records on service unregistration
- fix DOS security problem with readName"""
-
-"""0.08 update - changed licensing to LGPL"""
-
-"""0.07 update - faster shutdown on engine
- pointer encoding of outgoing names
- ServiceBrowser now works
- new unit tests"""
-
-"""0.06 update - small improvements with unit tests
- added defined exception types
- new style objects
- fixed hostname/interface problem
- fixed socket timeout problem
- fixed addServiceListener() typo bug
- using select() for socket reads
- tested on Debian unstable with Python 2.2.2"""
-
-"""0.05 update - ensure case insensitivty on domain names
- support for unicast DNS queries"""
-
-"""0.04 update - added some unit tests
- added __ne__ adjuncts where required
- ensure names end in '.local.'
- timeout on receiving socket for clean shutdown"""
-
-__author__ = "Paul Scott-Murphy"
-__email__ = "paul at scott dash murphy dot com"
-__version__ = "0.12"
+# Multicast DNS Service Discovery for Python, v0.12
+# Copyright (C) 2003, Paul Scott-Murphy
+#
+# This module provides a framework for the use of DNS Service Discovery
+# using IP multicast. It has been tested against the JRendezvous
+# implementation from <a href="http://strangeberry.com">StrangeBerry</a>,
+# and against the mDNSResponder from Mac OS X 10.3.8.
+
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+#
+#
+# 0.12 update - allow selection of binding interface
+# typo fix - Thanks A. M. Kuchlingi
+# removed all use of word 'Rendezvous' - this is an API change
+#
+# 0.11 update - correction to comments for addListener method
+# support for new record types seen from OS X
+# - IPv6 address
+# - hostinfo
+# ignore unknown DNS record types
+# fixes to name decoding
+# works alongside other processes using port 5353 (e.g. on Mac OS X)
+# tested against Mac OS X 10.3.2's mDNSResponder
+# corrections to removal of list entries for service browser
+#
+# 0.10 update - Jonathon Paisley contributed these corrections:
+# always multicast replies, even when query is unicast
+# correct a pointer encoding problem
+# can now write records in any order
+# traceback shown on failure
+# better TXT record parsing
+# server is now separate from name
+# can cancel a service browser
+#
+# modified some unit tests to accommodate these changes
+#
+# 0.09 update - remove all records on service unregistration
+# fix DOS security problem with readName
+#
+# 0.08 update - changed licensing to LGPL
+#
+# 0.07 update - faster shutdown on engine
+# pointer encoding of outgoing names
+# ServiceBrowser now works
+# new unit tests
+#
+# 0.06 update - small improvements with unit tests
+# added defined exception types
+# new style objects
+# fixed hostname/interface problem
+# fixed socket timeout problem
+# fixed addServiceListener() typo bug
+# using select() for socket reads
+# tested on Debian unstable with Python 2.2.2
+#
+# 0.05 update - ensure case insensitivty on domain names
+# support for unicast DNS queries
+#
+# 0.04 update - added some unit tests
+# added __ne__ adjuncts where required
+# ensure names end in '.local.'
+# timeout on receiving socket for clean shutdown
import string
import time
@@ -86,6 +82,12 @@
import select
import traceback
+
+__author__ = "Paul Scott-Murphy"
+__email__ = "paul at scott dash murphy dot com"
+__version__ = "0.12"
+
+
__all__ = ["Zeroconf", "ServiceInfo", "ServiceBrowser"]
# hook for threads
@@ -101,27 +103,27 @@
_BROWSER_TIME = 500
# Some DNS constants
-
+
_MDNS_ADDR = '224.0.0.251'
-_MDNS_PORT = 5353;
-_DNS_PORT = 53;
-_DNS_TTL = 60 * 60; # one hour default TTL
-
-_MAX_MSG_TYPICAL = 1460 # unused
+_MDNS_PORT = 5353
+_DNS_PORT = 53
+_DNS_TTL = 60 * 60 # one hour default TTL
+
+_MAX_MSG_TYPICAL = 1460 # unused
_MAX_MSG_ABSOLUTE = 8972
-_FLAGS_QR_MASK = 0x8000 # query response mask
-_FLAGS_QR_QUERY = 0x0000 # query
-_FLAGS_QR_RESPONSE = 0x8000 # response
-
-_FLAGS_AA = 0x0400 # Authorative answer
-_FLAGS_TC = 0x0200 # Truncated
-_FLAGS_RD = 0x0100 # Recursion desired
-_FLAGS_RA = 0x8000 # Recursion available
-
-_FLAGS_Z = 0x0040 # Zero
-_FLAGS_AD = 0x0020 # Authentic data
-_FLAGS_CD = 0x0010 # Checking disabled
+_FLAGS_QR_MASK = 0x8000 # query response mask
+_FLAGS_QR_QUERY = 0x0000 # query
+_FLAGS_QR_RESPONSE = 0x8000 # response
+
+_FLAGS_AA = 0x0400 # Authorative answer
+_FLAGS_TC = 0x0200 # Truncated
+_FLAGS_RD = 0x0100 # Recursion desired
+_FLAGS_RA = 0x8000 # Recursion available
+
+_FLAGS_Z = 0x0040 # Zero
+_FLAGS_AD = 0x0020 # Authentic data
+_FLAGS_CD = 0x0010 # Checking disabled
_CLASS_IN = 1
_CLASS_CS = 2
@@ -150,65 +152,76 @@
_TYPE_TXT = 16
_TYPE_AAAA = 28
_TYPE_SRV = 33
-_TYPE_ANY = 255
+_TYPE_ANY = 255
# Mapping constants to names
-_CLASSES = { _CLASS_IN : "in",
- _CLASS_CS : "cs",
- _CLASS_CH : "ch",
- _CLASS_HS : "hs",
- _CLASS_NONE : "none",
- _CLASS_ANY : "any" }
-
-_TYPES = { _TYPE_A : "a",
- _TYPE_NS : "ns",
- _TYPE_MD : "md",
- _TYPE_MF : "mf",
- _TYPE_CNAME : "cname",
- _TYPE_SOA : "soa",
- _TYPE_MB : "mb",
- _TYPE_MG : "mg",
- _TYPE_MR : "mr",
- _TYPE_NULL : "null",
- _TYPE_WKS : "wks",
- _TYPE_PTR : "ptr",
- _TYPE_HINFO : "hinfo",
- _TYPE_MINFO : "minfo",
- _TYPE_MX : "mx",
- _TYPE_TXT : "txt",
- _TYPE_AAAA : "quada",
- _TYPE_SRV : "srv",
- _TYPE_ANY : "any" }
+_CLASSES = {
+ _CLASS_IN: "in",
+ _CLASS_CS: "cs",
+ _CLASS_CH: "ch",
+ _CLASS_HS: "hs",
+ _CLASS_NONE: "none",
+ _CLASS_ANY: "any"
+}
+
+_TYPES = {
+ _TYPE_A: "a",
+ _TYPE_NS: "ns",
+ _TYPE_MD: "md",
+ _TYPE_MF: "mf",
+ _TYPE_CNAME: "cname",
+ _TYPE_SOA: "soa",
+ _TYPE_MB: "mb",
+ _TYPE_MG: "mg",
+ _TYPE_MR: "mr",
+ _TYPE_NULL: "null",
+ _TYPE_WKS: "wks",
+ _TYPE_PTR: "ptr",
+ _TYPE_HINFO: "hinfo",
+ _TYPE_MINFO: "minfo",
+ _TYPE_MX: "mx",
+ _TYPE_TXT: "txt",
+ _TYPE_AAAA: "quada",
+ _TYPE_SRV: "srv",
+ _TYPE_ANY: "any"
+}
# utility functions
+
def currentTimeMillis():
"""Current system time in milliseconds"""
return time.time() * 1000
# Exceptions
+
class NonLocalNameException(Exception):
pass
+
class NonUniqueNameException(Exception):
pass
+
class NamePartTooLongException(Exception):
pass
+
class AbstractMethodException(Exception):
pass
+
class BadTypeInNameException(Exception):
pass
# implementation classes
+
class DNSEntry(object):
"""A DNS entry"""
-
+
def __init__(self, name, type, clazz):
self.key = string.lower(name)
self.name = name
@@ -230,14 +243,14 @@
"""Class accessor"""
try:
return _CLASSES[clazz]
- except:
+ except Exception:
return "?(%s)" % (clazz)
def getType(self, type):
"""Type accessor"""
try:
return _TYPES[type]
- except:
+ except Exception:
return "?(%s)" % (type)
def toString(self, hdr, other):
@@ -254,9 +267,10 @@
result += "]"
return result
+
class DNSQuestion(DNSEntry):
"""A DNS question entry"""
-
+
def __init__(self, name, type, clazz):
if not name.endswith(".local."):
raise NonLocalNameException
@@ -273,7 +287,7 @@
class DNSRecord(DNSEntry):
"""A DNS record - like a DNS entry, but has a TTL"""
-
+
def __init__(self, name, type, clazz, ttl):
DNSEntry.__init__(self, name, type, clazz)
self.ttl = ttl
@@ -332,9 +346,10 @@
arg = "%s/%s,%s" % (self.ttl, self.getRemainingTTL(currentTimeMillis()), other)
return DNSEntry.toString(self, "record", arg)
+
class DNSAddress(DNSRecord):
"""A DNS address record"""
-
+
def __init__(self, name, type, clazz, ttl, address):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.address = address
@@ -353,9 +368,10 @@
"""String representation"""
try:
return socket.inet_ntoa(self.address)
- except:
+ except Exception:
return self.address
+
class DNSHinfo(DNSRecord):
"""A DNS host information record"""
@@ -378,10 +394,11 @@
def __repr__(self):
"""String representation"""
return self.cpu + " " + self.os
-
+
+
class DNSPointer(DNSRecord):
"""A DNS pointer record"""
-
+
def __init__(self, name, type, clazz, ttl, alias):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.alias = alias
@@ -400,9 +417,10 @@
"""String representation"""
return self.toString(self.alias)
+
class DNSText(DNSRecord):
"""A DNS text record"""
-
+
def __init__(self, name, type, clazz, ttl, text):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.text = text
@@ -424,9 +442,10 @@
else:
return self.toString(self.text)
+
class DNSService(DNSRecord):
"""A DNS service record"""
-
+
def __init__(self, name, type, clazz, ttl, priority, weight, port, server):
DNSRecord.__init__(self, name, type, clazz, ttl)
self.priority = priority
@@ -451,9 +470,10 @@
"""String representation"""
return self.toString("%s:%s" % (self.server, self.port))
+
class DNSIncoming(object):
"""Object representation of an incoming DNS packet"""
-
+
def __init__(self, data):
"""Constructor from string holding bytes of packet"""
self.offset = 0
@@ -464,7 +484,7 @@
self.numAnswers = 0
self.numAuthorities = 0
self.numAdditionals = 0
-
+
self.readHeader()
self.readQuestions()
self.readOthers()
@@ -491,7 +511,7 @@
name = self.readName()
info = struct.unpack(format, self.data[self.offset:self.offset+length])
self.offset += length
-
+
question = DNSQuestion(name, info[0], info[1])
self.questions.append(question)
@@ -512,7 +532,7 @@
def readString(self, len):
"""Reads a string of a given length from the packet"""
format = '!' + str(len) + 's'
- length = struct.calcsize(format)
+ length = struct.calcsize(format)
info = struct.unpack(format, self.data[self.offset:self.offset+length])
self.offset += length
return info[0]
@@ -555,13 +575,13 @@
# so this is left for debugging. New types
# encountered need to be parsed properly.
#
- #print "UNKNOWN TYPE = " + str(info[0])
- #raise BadTypeInNameException
+ # print "UNKNOWN TYPE = " + str(info[0])
+ # raise BadTypeInNameException
pass
if rec is not None:
self.answers.append(rec)
-
+
def isQuery(self):
"""Returns true if this is a query"""
return (self.flags & _FLAGS_QR_MASK) == _FLAGS_QR_QUERY
@@ -574,7 +594,7 @@
"""Reads a UTF-8 string of a given length from the packet"""
result = self.data[offset:offset+len].decode('utf-8')
return result
-
+
def readName(self):
"""Reads a domain name from the packet"""
result = ''
@@ -607,12 +627,12 @@
self.offset = off
return result
-
-
+
+
class DNSOutgoing(object):
"""Object representation of an outgoing packet"""
-
- def __init__(self, flags, multicast = 1):
+
+ def __init__(self, flags, multicast=1):
self.finished = 0
self.id = 0
self.multicast = multicast
@@ -620,7 +640,7 @@
self.names = {}
self.data = []
self.size = 12
-
+
self.questions = []
self.answers = []
self.authorities = []
@@ -660,7 +680,7 @@
format = '!H'
self.data.insert(index, struct.pack(format, value))
self.size += 2
-
+
def writeShort(self, value):
"""Writes an unsigned short to the packet"""
format = '!H'
@@ -739,9 +759,9 @@
self.size += 2
record.write(self)
self.size -= 2
-
+
length = len(''.join(self.data[index:]))
- self.insertShort(index, length) # Here is the short we adjusted for
+ self.insertShort(index, length) # Here is the short we adjusted for
def packet(self):
"""Returns a string containing the packet's bytes
@@ -758,7 +778,7 @@
self.writeRecord(authority, 0)
for additional in self.additionals:
self.writeRecord(additional, 0)
-
+
self.insertShort(0, len(self.additionals))
self.insertShort(0, len(self.authorities))
self.insertShort(0, len(self.answers))
@@ -773,7 +793,7 @@
class DNSCache(object):
"""A cache of DNS entries"""
-
+
def __init__(self):
self.cache = {}
@@ -781,7 +801,7 @@
"""Adds an entry"""
try:
list = self.cache[entry.key]
- except:
+ except Exception:
list = self.cache[entry.key] = []
list.append(entry)
@@ -790,7 +810,7 @@
try:
list = self.cache[entry.key]
list.remove(entry)
- except:
+ except Exception:
pass
def get(self, entry):
@@ -799,7 +819,7 @@
try:
list = self.cache[entry.key]
return list[list.index(entry)]
- except:
+ except Exception:
return None
def getByDetails(self, name, type, clazz):
@@ -812,7 +832,7 @@
"""Returns a list of entries whose key matches the name."""
try:
return self.cache[name]
- except:
+ except Exception:
return []
def entries(self):
@@ -820,7 +840,7 @@
def add(x, y): return x+y
try:
return reduce(add, self.cache.values())
- except:
+ except Exception:
return []
@@ -839,7 +859,7 @@
def __init__(self, zeroconf):
threading.Thread.__init__(self)
self.zeroconf = zeroconf
- self.readers = {} # maps socket to reader
+ self.readers = {} # maps socket to reader
self.timeout = 5
self.condition = threading.Condition()
self.start()
@@ -860,10 +880,10 @@
for socket in rr:
try:
self.readers[socket].handle_read()
- except:
+ except Exception:
# Ignore errors that occur on shutdown
pass
- except:
+ except Exception:
pass
def getReaders(self):
@@ -872,7 +892,7 @@
result = self.readers.keys()
self.condition.release()
return result
-
+
def addReader(self, reader, socket):
self.condition.acquire()
self.readers[socket] = reader
@@ -890,6 +910,7 @@
self.condition.notify()
self.condition.release()
+
class Listener(object):
"""A Listener is used by this module to listen on the multicast
group to which DNS messages are sent, allowing the implementation
@@ -897,7 +918,7 @@
It requires registration with an Engine object in order to have
the read() method called when a socket is availble for reading."""
-
+
def __init__(self, zeroconf):
self.zeroconf = zeroconf
self.zeroconf.engine.addReader(self, self.zeroconf.socket)
@@ -924,7 +945,7 @@
class Reaper(threading.Thread):
"""A Reaper is used by this module to remove cache entries that
have expired."""
-
+
def __init__(self, zeroconf):
threading.Thread.__init__(self)
self.zeroconf = zeroconf
@@ -948,7 +969,7 @@
The listener object will have its addService() and
removeService() methods called when this browser
discovers changes in the services availability."""
-
+
def __init__(self, zeroconf, type, listener):
"""Creates a browser for a specific type"""
threading.Thread.__init__(self)
@@ -959,7 +980,7 @@
self.nextTime = currentTimeMillis()
self.delay = _BROWSER_TIME
self.list = []
-
+
self.done = 0
self.zeroconf.addListener(self, DNSQuestion(self.type, _TYPE_PTR, _CLASS_IN))
@@ -976,14 +997,16 @@
if not expired:
oldrecord.resetTTL(record)
else:
+ def callback(x):
+ return self.listener.removeService(x, self.type, record.alias)
del(self.services[record.alias.lower()])
- callback = lambda x: self.listener.removeService(x, self.type, record.alias)
self.list.append(callback)
return
- except:
+ except Exception:
if not expired:
+ def callback(x):
+ return self.listener.addService(x, self.type, record.alias)
self.services[record.alias.lower()] = record
- callback = lambda x: self.listener.addService(x, self.type, record.alias)
self.list.append(callback)
expires = record.getExpirationTime(75)
@@ -1019,11 +1042,11 @@
if event is not None:
event(self.zeroconf)
-
+
class ServiceInfo(object):
"""Service information"""
-
+
def __init__(self, type, name, address=None, port=None, weight=0, priority=0, properties=None, server=None):
"""Create a service description.
@@ -1089,7 +1112,7 @@
index += 1
strs.append(text[index:index+length])
index += length
-
+
for s in strs:
eindex = s.find('=')
if eindex == -1:
@@ -1105,14 +1128,14 @@
value = 0
# Only update non-existent properties
- if key and result.get(key) == None:
+ if key and result.get(key) is None:
result[key] = value
self.properties = result
- except:
+ except Exception:
traceback.print_exc()
self.properties = None
-
+
def getType(self):
"""Type accessor"""
return self.type
@@ -1200,7 +1223,7 @@
result = 1
finally:
zeroconf.removeListener(self)
-
+
return result
def __eq__(self, other):
@@ -1225,7 +1248,7 @@
result += self.text[:17] + "..."
result += "]"
return result
-
+
class Zeroconf(object):
"""Implementation of Zeroconf Multicast DNS Service Discovery
@@ -1242,7 +1265,7 @@
try:
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
- except:
+ except Exception:
# SO_REUSEADDR should be equivalent to SO_REUSEPORT for
# multicast UDP sockets (p 731, "TCP/IP Illustrated,
# Volume 2"), but some BSD-derived systems require
@@ -1257,7 +1280,7 @@
self.socket.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
try:
self.socket.bind(self.group)
- except:
+ except Exception:
# Some versions of linux raise an exception even though
# the SO_REUSE* options have been set, so ignore it
#
@@ -1274,7 +1297,7 @@
self.cache = DNSCache()
self.condition = threading.Condition()
-
+
self.engine = Engine(self)
self.listener = Listener(self)
self.reaper = Reaper(self)
@@ -1354,7 +1377,7 @@
"""Unregister a service."""
try:
del(self.services[info.name.lower()])
- except:
+ except Exception:
pass
now = currentTimeMillis()
nextTime = now
@@ -1439,7 +1462,7 @@
try:
self.listeners.remove(listener)
self.notifyAll()
- except:
+ except Exception:
pass
def updateRecord(self, now, rec):
@@ -1465,7 +1488,7 @@
record = entry
else:
self.cache.add(record)
-
+
self.updateRecord(now, record)
def handleQuery(self, msg, addr, port):
@@ -1479,7 +1502,7 @@
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA, 0)
for question in msg.questions:
out.addQuestion(question)
-
+
for question in msg.questions:
if question.type == _TYPE_PTR:
for service in self.services.values():
@@ -1491,36 +1514,37 @@
try:
if out is None:
out = DNSOutgoing(_FLAGS_QR_RESPONSE | _FLAGS_AA)
-
+
# Answer A record queries for any service addresses we know
if question.type == _TYPE_A or question.type == _TYPE_ANY:
for service in self.services.values():
if service.server == question.name.lower():
out.addAnswer(msg, DNSAddress(question.name, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
-
+
service = self.services.get(question.name.lower(), None)
- if not service: continue
-
+ if not service:
+ continue
+
if question.type == _TYPE_SRV or question.type == _TYPE_ANY:
out.addAnswer(msg, DNSService(question.name, _TYPE_SRV, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.priority, service.weight, service.port, service.server))
if question.type == _TYPE_TXT or question.type == _TYPE_ANY:
out.addAnswer(msg, DNSText(question.name, _TYPE_TXT, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.text))
if question.type == _TYPE_SRV:
out.addAdditionalAnswer(DNSAddress(service.server, _TYPE_A, _CLASS_IN | _CLASS_UNIQUE, _DNS_TTL, service.address))
- except:
+ except Exception:
traceback.print_exc()
-
+
if out is not None and out.answers:
out.id = msg.id
self.send(out, addr, port)
- def send(self, out, addr = _MDNS_ADDR, port = _MDNS_PORT):
+ def send(self, out, addr=_MDNS_ADDR, port=_MDNS_PORT):
"""Sends an outgoing packet."""
# This is a quick test to see if we can parse the packets we generate
- #temp = DNSIncoming(out.packet())
+ # temp = DNSIncoming(out.packet())
try:
bytes_sent = self.socket.sendto(out.packet(), 0, (addr, port))
- except:
+ except Exception:
# Ignore this, it may be a temporary loss of network connection
pass
@@ -1534,15 +1558,16 @@
self.unregisterAllServices()
self.socket.setsockopt(socket.SOL_IP, socket.IP_DROP_MEMBERSHIP, socket.inet_aton(_MDNS_ADDR) + socket.inet_aton('0.0.0.0'))
self.socket.close()
-
+
# Test a few module features, including service registration, service
# query (for Zoe), and service unregistration.
-if __name__ == '__main__':
+
+if __name__ == '__main__':
print "Multicast DNS Service Discovery for Python, version", __version__
r = Zeroconf()
print "1. Testing registration of a service..."
- desc = {'version':'0.10','a':'test value', 'b':'another value'}
+ desc = {'version': '0.10', 'a': 'test value', 'b': 'another value'}
info = ServiceInfo("_http._tcp.local.", "My Service Name._http._tcp.local.", socket.inet_aton("127.0.0.1"), 1234, 0, 0, desc)
print " Registering service..."
r.registerService(info)
--- a/util/misc.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/misc.py Mon Aug 21 23:22:58 2017 +0300
@@ -26,10 +26,12 @@
Misc definitions
"""
-import os,sys
+import os
+import sys
-# helper func to check path write permission
+
def CheckPathPerm(path):
+ """ Helper func to check path write permission """
if path is None or not os.path.isdir(path):
return False
for root, dirs, files in os.walk(path):
@@ -40,15 +42,17 @@
return False
return True
+
def GetClassImporter(classpath):
- if type(classpath)==str:
+ if type(classpath) == str:
def fac():
- mod=__import__(classpath.rsplit('.',1)[0])
+ mod = __import__(classpath.rsplit('.', 1)[0])
return reduce(getattr, classpath.split('.')[1:], mod)
return fac
else:
return classpath
+
def InstallLocalRessources(CWD):
from BitmapLibrary import AddBitmapFolder
from TranslationCatalogs import AddCatalog
@@ -61,6 +65,5 @@
AddCatalog(os.path.join(CWD, "locale"))
import gettext
import __builtin__
-
+
__builtin__.__dict__['_'] = wx.GetTranslation
-
--- a/util/paths.py Mon Aug 21 20:17:19 2017 +0000
+++ b/util/paths.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,22 +22,26 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys
+import os
+import sys
+
def AbsFile(file):
if isinstance(file, str):
- file = unicode(file,sys.getfilesystemencoding())
+ file = unicode(file, sys.getfilesystemencoding())
return file
+
def AbsDir(file):
file = AbsFile(file)
return os.path.dirname(os.path.realpath(file))
+
def AbsNeighbourFile(file, *args):
return os.path.join(AbsDir(file), *args)
-def AbsParentDir(file, level = 1):
+def AbsParentDir(file, level=1):
path = AbsDir(file)
for i in range(0, level):
path = os.path.dirname(path)
--- a/version.py Mon Aug 21 20:17:19 2017 +0000
+++ b/version.py Mon Aug 21 23:22:58 2017 +0300
@@ -23,105 +23,114 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import subprocess, os
+import subprocess
+import os
+
import util.paths as paths
+
def GetCommunityHelpMsg():
- return _("The best place to ask questions about Beremiz/PLCOpenEditor\n"
- "is project's mailing list: beremiz-devel@lists.sourceforge.net\n"
- "\n"
- "This is the main community support channel.\n"
- "For posting it is required to be subscribed to the mailing list.\n"
- "\n"
- "You can subscribe to the list here:\n"
- "https://lists.sourceforge.net/lists/listinfo/beremiz-devel")
+ return _(
+ "The best place to ask questions about Beremiz/PLCOpenEditor\n"
+ "is project's mailing list: beremiz-devel@lists.sourceforge.net\n"
+ "\n"
+ "This is the main community support channel.\n"
+ "For posting it is required to be subscribed to the mailing list.\n"
+ "\n"
+ "You can subscribe to the list here:\n"
+ "https://lists.sourceforge.net/lists/listinfo/beremiz-devel"
+ )
+
def GetAppRevision():
rev = None
- app_dir=paths.AbsDir(__file__)
+ app_dir = paths.AbsDir(__file__)
try:
pipe = subprocess.Popen(
["hg", "id", "-i"],
- stdout = subprocess.PIPE,
- cwd = app_dir
+ stdout=subprocess.PIPE,
+ cwd=app_dir
)
rev = pipe.communicate()[0]
if pipe.returncode != 0:
rev = None
- except:
+ except Exception:
pass
-
+
# if this is not mercurial repository
# try to read revision from file
if rev is None:
try:
- f = open(os.path.join(app_dir,"revision"))
+ f = open(os.path.join(app_dir, "revision"))
rev = f.readline()
- except:
+ except Exception:
pass
return rev
+
def GetAboutDialogInfo():
import wx
info = wx.AboutDialogInfo()
info.Name = "Beremiz"
info.Version = app_version
-
- info.Copyright = "(C) 2016 Andrey Skvortsov\n"
+
+ info.Copyright = ""
+ info.Copyright += "(C) 2016-2017 Andrey Skvortsov\n"
info.Copyright += "(C) 2008-2015 Eduard Tisserant\n"
info.Copyright += "(C) 2008-2015 Laurent Bessard"
info.WebSite = ("http://beremiz.org", "beremiz.org")
-
+
info.Description = _("Open Source framework for automation, "
- "implemented IEC 61131 IDE with constantly growing set of extensions "
- "and flexible PLC runtime.")
-
- info.Developers = ("Andrey Skvortsov <andrej.skvortzov@gmail.com>",
- "Sergey Surkov <surkov.sv@summatechnology.ru>",
- "Edouard Tisserant <edouard.tisserant@gmail.com>",
- "Laurent Bessard <laurent.bessard@gmail.com>")
+ "implemented IEC 61131 IDE with constantly growing set of extensions "
+ "and flexible PLC runtime.")
+ info.Developers = (
+ "Andrey Skvortsov <andrej.skvortzov@gmail.com>",
+ "Sergey Surkov <surkov.sv@summatechnology.ru>",
+ "Edouard Tisserant <edouard.tisserant@gmail.com>",
+ "Laurent Bessard <laurent.bessard@gmail.com>")
- info.License = ('\n This program is free software; you can redistribute it and/or\n'
- ' modify it under the terms of the GNU General Public License\n'
- ' as published by the Free Software Foundation; either version 2\n'
- ' of the License, or (at your option) any later version.\n'
- '\n'
- ' This program is distributed in the hope that it will be useful,\n'
- ' but WITHOUT ANY WARRANTY; without even the implied warranty of\n'
- ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n'
- ' GNU General Public License below for more details.\n'
- '\n'
- '\n'
- '\n'
- '')
+ info.License = (
+ '\n This program is free software; you can redistribute it and/or\n'
+ ' modify it under the terms of the GNU General Public License\n'
+ ' as published by the Free Software Foundation; either version 2\n'
+ ' of the License, or (at your option) any later version.\n'
+ '\n'
+ ' This program is distributed in the hope that it will be useful,\n'
+ ' but WITHOUT ANY WARRANTY; without even the implied warranty of\n'
+ ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n'
+ ' GNU General Public License below for more details.\n'
+ '\n'
+ '\n'
+ '\n'
+ ''
+ )
# read license file
- path=paths.AbsDir(__file__)
+ path = paths.AbsDir(__file__)
license_path = os.path.join(path, "COPYING")
- license=''
+ license = ''
if os.path.exists(license_path):
with open(license_path) as f:
info.License += f.read()
info.Icon = wx.Icon(os.path.join(path, "images", "about_brz_logo.png"), wx.BITMAP_TYPE_PNG)
- info.Translators = ("Russian\t- Andrey Skvortsov <andrej.skvortzov@gmail.com>",
- "Korean\t- Reinhard Lee <lij3105@gmail.com>",
- "German\t- Mark Muzenhardt <mark.muzenhardt@gmail.com>",
- "French\t- Laurent Bessard <laurent.bessard@gmail.com>",
- " \t Fabien M <mail@fabienm.eu>",
- "Slovenian\t- Janez Pregelj",
- "Portuguese\t- Thiago Alves <thiagoralves@gmail.com>"
+ info.Translators = (
+ "Russian\t- Andrey Skvortsov <andrej.skvortzov@gmail.com>",
+ "Korean\t- Reinhard Lee <lij3105@gmail.com>",
+ "German\t- Mark Muzenhardt <mark.muzenhardt@gmail.com>",
+ "French\t- Laurent Bessard <laurent.bessard@gmail.com>",
+ " \t Fabien M <mail@fabienm.eu>",
+ "Slovenian\t- Janez Pregelj",
+ "Portuguese\t- Thiago Alves <thiagoralves@gmail.com>"
)
return info
-app_version = "1.2"
+
+app_version = "1.2"
rev = GetAppRevision()
if rev is not None:
app_version = app_version + "-" + rev.rstrip()
-
-
-
--- a/wxglade_hmi/wxglade_hmi.py Mon Aug 21 20:17:19 2017 +0000
+++ b/wxglade_hmi/wxglade_hmi.py Mon Aug 21 23:22:58 2017 +0300
@@ -24,19 +24,24 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import wx
-import os, sys, shutil
+import os
+import sys
+import shutil
from xml.dom import minidom
import util.paths as paths
from py_ext import PythonFileCTNMixin
+
class WxGladeHMI(PythonFileCTNMixin):
ConfNodeMethods = [
- {"bitmap" : "editWXGLADE",
- "name" : _("WXGLADE GUI"),
- "tooltip" : _("Edit a WxWidgets GUI with WXGlade"),
- "method" : "_editWXGLADE"},
+ {
+ "bitmap": "editWXGLADE",
+ "name": _("WXGLADE GUI"),
+ "tooltip": _("Edit a WxWidgets GUI with WXGlade"),
+ "method": "_editWXGLADE"
+ },
]
def GetIconName(self):
@@ -51,29 +56,28 @@
# define name for wxGlade gui file
return os.path.join(project_path, "hmi.wxg")
-
def GetWxGladePath(self):
path = None
try:
from wxglade import __file__ as fileName
- path = os.path.dirname(fileName)
+ path = os.path.dirname(fileName)
return path
except ImportError:
pass
- defLibDir="/usr/share/wxglade"
+ defLibDir = "/usr/share/wxglade"
if os.path.isdir(defLibDir):
path = defLibDir
return path
-
+
def launch_wxglade(self, options, wait=False):
path = self.GetWxGladePath()
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)
+ glade = "\"%s\"" % glade
+ mode = {False: os.P_NOWAIT, True: os.P_WAIT}[wait]
+ os.spawnv(mode, sys.executable, ["\"%s\"" % sys.executable] + [glade] + options)
def OnCTNSave(self, from_project_path=None):
if from_project_path is not None:
@@ -82,45 +86,45 @@
return PythonFileCTNMixin.OnCTNSave(self, from_project_path)
def CTNGenerate_C(self, buildpath, locations):
-
+
hmi_frames = []
-
- wxgfile_path=self._getWXGLADEpath()
+
+ wxgfile_path = self._getWXGLADEpath()
if os.path.exists(wxgfile_path):
wxgfile = open(wxgfile_path, 'r')
wxgtree = minidom.parse(wxgfile)
wxgfile.close()
-
+
for node in wxgtree.childNodes[1].childNodes:
if node.nodeType == wxgtree.ELEMENT_NODE:
hmi_frames.append({
- "name" : node.getAttribute("name"),
- "class" : node.getAttribute("class"),
- "handlers" : [
- hnode.firstChild.data for hnode in
+ "name": node.getAttribute("name"),
+ "class": node.getAttribute("class"),
+ "handlers": [
+ hnode.firstChild.data for hnode in
node.getElementsByTagName("handler")]})
-
- hmipyfile_path=os.path.join(self._getBuildPath(), "hmi.py")
+
+ hmipyfile_path = os.path.join(self._getBuildPath(), "hmi.py")
if wx.Platform == '__WXMSW__':
- wxgfile_path = "\"%s\""%wxgfile_path
- wxghmipyfile_path = "\"%s\""%hmipyfile_path
+ 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')
define_hmi = hmipyfile.read().decode('utf-8')
hmipyfile.close()
-
+
else:
define_hmi = ""
-
- declare_hmi = "\n".join(["%(name)s = None\n" % x +
- "\n".join(["%(class)s.%(h)s = %(h)s"%
- dict(x,h=h) for h in x['handlers']])
+
+ declare_hmi = "\n".join(["%(name)s = None\n" % x +
+ "\n".join(["%(class)s.%(h)s = %(h)s" %
+ dict(x, h=h) for h in x['handlers']])
for x in hmi_frames])
- global_hmi = ("global %s\n"%",".join(
- [x["name"] for x in hmi_frames])
+ global_hmi = ("global %s\n" % ",".join(
+ [x["name"] for x in hmi_frames])
if len(hmi_frames) > 0 else "")
init_hmi = "\n".join(["""\
def OnCloseFrame(evt):
@@ -131,17 +135,17 @@
%(name)s.Show()
""" % x for x in hmi_frames])
cleanup_hmi = "\n".join(
- ["if %(name)s is not None: %(name)s.Destroy()" % x
+ ["if %(name)s is not None: %(name)s.Destroy()" % x
for x in hmi_frames])
-
+
self.PreSectionsTexts = {
- "globals":define_hmi,
- "start":global_hmi,
- "stop":global_hmi + cleanup_hmi
+ "globals": define_hmi,
+ "start": global_hmi,
+ "stop": global_hmi + cleanup_hmi
}
self.PostSectionsTexts = {
- "globals":declare_hmi,
- "start":init_hmi,
+ "globals": declare_hmi,
+ "start": init_hmi,
}
return PythonFileCTNMixin.CTNGenerate_C(self, buildpath, locations)
@@ -153,13 +157,13 @@
dialog = wx.MessageDialog(self.GetCTRoot().AppFrame,
_("You don't have write permissions.\nOpen wxGlade anyway ?"),
_("Open wxGlade"),
- wx.YES_NO|wx.ICON_QUESTION)
+ 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("""<?xml version="1.0"?>
+ open(wxg_filename, "w").write("""<?xml version="1.0"?>
<application path="" name="" class="" option="0" language="python" top_window="%(name)s" encoding="UTF-8" use_gettext="0" overwrite="0" use_new_namespace="1" for_version="2.8" is_template="0">
<object class="%(class)s" name="%(name)s" base="EditFrame">
<style>wxDEFAULT_FRAME_STYLE</style>
@@ -172,6 +176,5 @@
</application>
""" % {"name": hmi_name, "class": "Class_%s" % hmi_name})
if wx.Platform == '__WXMSW__':
- wxg_filename = "\"%s\""%wxg_filename
+ wxg_filename = "\"%s\"" % wxg_filename
self.launch_wxglade([wxg_filename])
-
--- a/xmlclass/xmlclass.py Mon Aug 21 20:17:19 2017 +0000
+++ b/xmlclass/xmlclass.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,7 +22,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, sys
+import os
+import sys
import re
import datetime
from types import *
@@ -32,6 +33,7 @@
from new import classobj
from collections import OrderedDict
+
def CreateNode(name):
node = minidom.Node()
node.nodeName = name
@@ -39,9 +41,11 @@
node.childNodes = []
return node
+
def NodeRenameAttr(node, old_name, new_name):
node._attrs[new_name] = node._attrs.pop(old_name)
+
def NodeSetAttr(node, name, value):
attr = minidom.Attr(name)
text = minidom.Text()
@@ -49,6 +53,7 @@
attr.childNodes[0] = text
node._attrs[name] = attr
+
"""
Regular expression models for checking all kind of string values defined in XML
standard
@@ -72,14 +77,15 @@
date_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
datetime_model = re.compile('([0-9]{4})-([0-9]{2})-([0-9]{2})[ T]([0-9]{2}):([0-9]{2}):([0-9]{2}(?:\.[0-9]*)?)((?:[\-\+][0-9]{2}:[0-9]{2})|Z)?$')
+
class xml_timezone(datetime.tzinfo):
def SetOffset(self, offset):
if offset == "Z":
- self.__offset = timedelta(minutes = 0)
+ self.__offset = timedelta(minutes=0)
self.__name = "UTC"
else:
- sign = {"-" : -1, "+" : 1}[offset[0]]
+ sign = {"-": -1, "+": 1}[offset[0]]
hours, minutes = [int(val) for val in offset[1:].split(":")]
self.__offset = timedelta(minutes=sign * (hours * 60 + minutes))
self.__name = ""
@@ -93,10 +99,13 @@
def dst(self, dt):
return ZERO
-[SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE,
- ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
+
+[
+ SYNTAXELEMENT, SYNTAXATTRIBUTE, SIMPLETYPE, COMPLEXTYPE, COMPILEDCOMPLEXTYPE,
+ ATTRIBUTESGROUP, ELEMENTSGROUP, ATTRIBUTE, ELEMENT, CHOICE, ANY, TAG, CONSTRAINT,
] = range(13)
+
def NotSupportedYet(type):
"""
Function that generates a function that point out to user that datatype
@@ -105,14 +114,14 @@
@return: function generated
"""
def GetUnknownValue(attr):
- raise ValueError("\"%s\" type isn't supported by \"xmlclass\" yet!" % \
- type)
+ raise ValueError("\"%s\" type isn't supported by \"xmlclass\" yet!" % type)
return GetUnknownValue
-"""
-This function calculates the number of whitespace for indentation
-"""
+
def getIndent(indent, balise):
+ """
+ This function calculates the number of whitespace for indentation
+ """
first = indent * 2
second = first + len(balise) + 1
return u'\t'.expandtabs(first), u'\t'.expandtabs(second)
@@ -140,7 +149,7 @@
def GetNormalizedString(attr, extract=True):
"""
- Function that normalizes a string according to XML 1.0. Replace
+ Function that normalizes a string according to XML 1.0. Replace
tabulations, line feed and carriage return by white space
@param attr: tree node containing data to extract or data to normalize
@param extract: attr is a tree node or not
@@ -155,14 +164,14 @@
def GetToken(attr, extract=True):
"""
- Function that tokenizes a string according to XML 1.0. Remove any leading
- and trailing white space and replace internal sequence of two or more
+ Function that tokenizes a string according to XML 1.0. Remove any leading
+ and trailing white space and replace internal sequence of two or more
spaces by only one white space
@param attr: tree node containing data to extract or data to tokenize
@param extract: attr is a tree node or not
@return: data tokenized as string
"""
- return " ".join([part for part in
+ return " ".join([part for part in
GetNormalizedString(attr, extract).split(" ")
if part])
@@ -182,11 +191,11 @@
raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
try:
return int(value, 16)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid hexadecimal integer!" % value)
-def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None,
+def GenerateIntegerExtraction(minInclusive=None, maxInclusive=None,
minExclusive=None, maxExclusive=None):
"""
Function that generates an extraction function for integer defining min and
@@ -212,19 +221,19 @@
try:
# TODO: permit to write value like 1E2
value = int(value)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid integer!" % value)
if minInclusive is not None and value < minInclusive:
- raise ValueError("\"%d\" isn't greater or equal to %d!" % \
+ raise ValueError("\"%d\" isn't greater or equal to %d!" %
(value, minInclusive))
if maxInclusive is not None and value > maxInclusive:
- raise ValueError("\"%d\" isn't lesser or equal to %d!" % \
+ raise ValueError("\"%d\" isn't lesser or equal to %d!" %
(value, maxInclusive))
if minExclusive is not None and value <= minExclusive:
- raise ValueError("\"%d\" isn't greater than %d!" % \
+ raise ValueError("\"%d\" isn't greater than %d!" %
(value, minExclusive))
if maxExclusive is not None and value >= maxExclusive:
- raise ValueError("\"%d\" isn't lesser than %d!" % \
+ raise ValueError("\"%d\" isn't lesser than %d!" %
(value, maxExclusive))
return value
return GetInteger
@@ -236,7 +245,7 @@
@param type: name of the type of float
@return: function generated
"""
- def GetFloat(attr, extract = True):
+ def GetFloat(attr, extract=True):
"""
Function that extracts a float from a tree node or a string
@param attr: tree node containing data to extract or data as a string
@@ -251,7 +260,7 @@
return value
try:
return float(value)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid %s!" % (value, type))
return GetFloat
@@ -401,7 +410,7 @@
raise ValueError("Member limit can't be defined to \"unbounded\"!")
try:
limit = int(value)
- except:
+ except Exception:
raise ValueError("\"%s\" isn't a valid value for this member limit!" % value)
if limit < 0:
raise ValueError("Member limit can't be negative!")
@@ -435,8 +444,8 @@
if value in list:
return value
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError(
+ "\"%s\" isn't a valid value for %s!" % (value, type))
return GetEnumerated
@@ -497,8 +506,8 @@
if item in list:
values.append(item)
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError(
+ "\"%s\" isn't a valid value for %s!" % (value, type))
return values
return GetLists
@@ -517,7 +526,7 @@
check that all extracted items match the model
@param attr: tree node containing data to extract or data as a string
@param extract: attr is a tree node or not
- @return: data as a list of string if matching
+ @return: data as a list of string if matching
"""
if extract:
value = GetAttributeValue(attr)
@@ -529,24 +538,24 @@
if result is not None:
values.append(item)
else:
- raise ValueError("\"%s\" isn't a valid value for %s!" % \
- (value, type))
+ raise ValueError("\"%s\" isn't a valid value for %s!" % (value, type))
return values
return GetModelNameList
+
def GenerateAnyInfos(infos):
-
+
def GetTextElement(tree):
if infos["namespace"][0] == "##any":
return tree.xpath("p")[0]
return tree.xpath("ns:p", namespaces={"ns": infos["namespace"][0]})[0]
-
+
def ExtractAny(tree):
return GetTextElement(tree).text
-
+
def GenerateAny(tree, value):
GetTextElement(tree).text = etree.CDATA(value)
-
+
def InitialAny():
if infos["namespace"][0] == "##any":
element_name = "p"
@@ -555,15 +564,16 @@
p = etree.Element(element_name)
p.text = etree.CDATA("")
return p
-
+
return {
- "type": COMPLEXTYPE,
+ "type": COMPLEXTYPE,
"extract": ExtractAny,
"generate": GenerateAny,
"initial": InitialAny,
"check": lambda x: isinstance(x, (StringType, UnicodeType, etree.ElementBase))
}
+
def GenerateTagInfos(infos):
def ExtractTag(tree):
if len(tree._attrs) > 0:
@@ -574,28 +584,30 @@
return True
else:
return None
-
+
def GenerateTag(value, name=None, indent=0):
if name is not None and not (infos["minOccurs"] == 0 and value is None):
ind1, ind2 = getIndent(indent, name)
return ind1 + "<%s/>\n" % name
else:
return ""
-
+
return {
- "type": TAG,
+ "type": TAG,
"extract": ExtractTag,
"generate": GenerateTag,
"initial": lambda: None,
- "check": lambda x: x == None or infos["minOccurs"] == 0 and value == True
+ "check": lambda x: x is None or infos["minOccurs"] == 0 and value
}
+
def FindTypeInfos(factory, infos):
if isinstance(infos, (UnicodeType, StringType)):
namespace, name = DecomposeQualifiedName(infos)
return factory.GetQualifiedNameInfos(name, namespace)
return infos
-
+
+
def GetElementInitialValue(factory, infos):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
if infos["minOccurs"] == 1:
@@ -616,6 +628,7 @@
else:
return []
+
def GetContentInfos(name, choices):
for choice_infos in choices:
if choices_infos["type"] == "sequence":
@@ -629,6 +642,7 @@
return choices_infos
return None
+
def ComputeContentChoices(factory, name, infos):
choices = []
for choice in infos["choices"]:
@@ -649,6 +663,7 @@
choices.append((choice["name"], choice))
return choices
+
def GenerateContentInfos(factory, name, choices):
choices_dict = {}
for choice_name, infos in choices:
@@ -656,18 +671,18 @@
for element in infos["elements"]:
if element["type"] == CHOICE:
element["elmt_type"] = GenerateContentInfos(factory, name, ComputeContentChoices(factory, name, element))
- elif choices_dict.has_key(element["name"]):
+ elif element["name"] in choices_dict:
raise ValueError("'%s' element defined two times in choice" % choice_name)
else:
choices_dict[element["name"]] = infos
else:
- if choices_dict.has_key(choice_name):
+ if choice_name in choices_dict:
raise ValueError("'%s' element defined two times in choice" % choice_name)
choices_dict[choice_name] = infos
prefix = ("%s:" % factory.TargetNamespace
if factory.TargetNamespace is not None else "")
choices_xpath = "|".join(map(lambda x: prefix + x, choices_dict.keys()))
-
+
def GetContentInitial():
content_name, infos = choices[0]
if content_name == "sequence":
@@ -678,28 +693,29 @@
else:
content_value = GetElementInitialValue(factory, infos)
return content_value
-
+
return {
"type": COMPLEXTYPE,
"choices_xpath": etree.XPath(choices_xpath, namespaces=factory.NSMAP),
"initial": GetContentInitial,
}
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Structure extraction functions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
def DecomposeQualifiedName(name):
result = QName_model.match(name)
if not result:
- raise ValueError("\"%s\" isn't a valid QName value!" % name)
+ raise ValueError("\"%s\" isn't a valid QName value!" % name)
parts = result.groups()[0].split(':')
if len(parts) == 1:
return None, parts[0]
return parts
-
-def GenerateElement(element_name, attributes, elements_model,
+
+
+def GenerateElement(element_name, attributes, elements_model,
accept_text=False):
def ExtractElement(factory, node):
attrs = factory.ExtractNodeAttrs(element_name, node, attributes)
@@ -709,7 +725,7 @@
for child in node.childNodes:
if child.nodeName not in ["#comment", "#text"]:
namespace, childname = DecomposeQualifiedName(child.nodeName)
- children_structure += "%s "%childname
+ children_structure += "%s " % childname
result = elements_model.match(children_structure)
if not result:
raise ValueError("Invalid structure for \"%s\" children!. First element invalid." % node.nodeName)
@@ -726,7 +742,7 @@
infos = factory.GetQualifiedNameInfos(childname, namespace)
if infos["type"] != SYNTAXELEMENT:
raise ValueError("\"%s\" can't be a member child!" % name)
- if infos["extract"].has_key(element_name):
+ if element_name in infos["extract"]:
children.append(infos["extract"][element_name](factory, child))
else:
children.append(infos["extract"]["default"](factory, child))
@@ -734,10 +750,10 @@
return ExtractElement
-"""
-Class that generate class from an XML Tree
-"""
class ClassFactory:
+ """
+ Class that generate class from an XML Tree
+ """
def __init__(self, document, filepath=None, debug=False):
self.Document = document
@@ -746,20 +762,20 @@
else:
self.BaseFolder = self.FileName = None
self.Debug = debug
-
+
# Dictionary for stocking Classes and Types definitions created from
# the XML tree
self.XMLClassDefinitions = {}
-
+
self.DefinedNamespaces = {}
self.NSMAP = {}
self.Namespaces = {}
self.SchemaNamespace = None
self.TargetNamespace = None
self.etreeNamespaceFormat = "%s"
-
+
self.CurrentCompilations = []
-
+
# Dictionaries for stocking Classes and Types generated
self.ComputeAfter = []
if self.FileName is not None:
@@ -773,36 +789,36 @@
def GetQualifiedNameInfos(self, name, namespace=None, canbenone=False):
if namespace is None:
- if self.Namespaces[self.SchemaNamespace].has_key(name):
+ if name in self.Namespaces[self.SchemaNamespace]:
return self.Namespaces[self.SchemaNamespace][name]
for space, elements in self.Namespaces.iteritems():
- if space != self.SchemaNamespace and elements.has_key(name):
+ if space != self.SchemaNamespace and name in elements:
return elements[name]
parts = name.split("_", 1)
if len(parts) > 1:
group = self.GetQualifiedNameInfos(parts[0], namespace)
if group is not None and group["type"] == ELEMENTSGROUP:
elements = []
- if group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
return element
if not canbenone:
raise ValueError("Unknown element \"%s\" for any defined namespaces!" % name)
- elif self.Namespaces.has_key(namespace):
- if self.Namespaces[namespace].has_key(name):
+ elif namespace in self.Namespaces:
+ if name in self.Namespaces[namespace]:
return self.Namespaces[namespace][name]
parts = name.split("_", 1)
if len(parts) > 1:
group = self.GetQualifiedNameInfos(parts[0], namespace)
if group is not None and group["type"] == ELEMENTSGROUP:
elements = []
- if group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
@@ -815,36 +831,36 @@
def SplitQualifiedName(self, name, namespace=None, canbenone=False):
if namespace is None:
- if self.Namespaces[self.SchemaNamespace].has_key(name):
+ if name in self.Namespaces[self.SchemaNamespace]:
return name, None
for space, elements in self.Namespaces.items():
- if space != self.SchemaNamespace and elements.has_key(name):
+ if space != self.SchemaNamespace and name in elements:
return name, None
parts = name.split("_", 1)
if len(parts) > 1:
group = self.GetQualifiedNameInfos(parts[0], namespace)
if group is not None and group["type"] == ELEMENTSGROUP:
elements = []
- if group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
return part[1], part[0]
if not canbenone:
raise ValueError("Unknown element \"%s\" for any defined namespaces!" % name)
- elif self.Namespaces.has_key(namespace):
- if self.Namespaces[namespace].has_key(name):
+ elif namespace in self.Namespaces:
+ if name in self.Namespaces[namespace]:
return name, None
parts = name.split("_", 1)
if len(parts) > 1:
group = self.GetQualifiedNameInfos(parts[0], namespace)
if group is not None and group["type"] == ELEMENTSGROUP:
elements = []
- if group.has_key("elements"):
+ if "elements" in group:
elements = group["elements"]
- elif group.has_key("choices"):
+ elif "choices" in group:
elements = group["choices"]
for element in elements:
if element["name"] == parts[1]:
@@ -858,7 +874,7 @@
def ExtractNodeAttrs(self, element_name, node, valid_attrs):
attrs = {}
for qualified_name, attr in node._attrs.items():
- namespace, name = DecomposeQualifiedName(qualified_name)
+ namespace, name = DecomposeQualifiedName(qualified_name)
if name in valid_attrs:
infos = self.GetQualifiedNameInfos(name, namespace)
if infos["type"] != SYNTAXATTRIBUTE:
@@ -878,9 +894,9 @@
raise ValueError("Invalid attribute \"%s\" for member \"%s\"!" % (qualified_name, node.nodeName))
for attr in valid_attrs:
if attr not in attrs and \
- self.Namespaces[self.SchemaNamespace].has_key(attr) and \
- self.Namespaces[self.SchemaNamespace][attr].has_key("default"):
- if self.Namespaces[self.SchemaNamespace][attr]["default"].has_key(element_name):
+ attr in self.Namespaces[self.SchemaNamespace] and \
+ "default" in self.Namespaces[self.SchemaNamespace][attr]:
+ if element_name in self.Namespaces[self.SchemaNamespace][attr]["default"]:
default = self.Namespaces[self.SchemaNamespace][attr]["default"][element_name]
else:
default = self.Namespaces[self.SchemaNamespace][attr]["default"]["default"]
@@ -892,7 +908,7 @@
result = []
for child_infos in elements:
if child_infos is not None:
- if child_infos[1].has_key("name") and schema:
+ if "name" in child_infos[1] and schema:
self.CurrentCompilations.append(child_infos[1]["name"])
namespace, name = DecomposeQualifiedName(child_infos[0])
infos = self.GetQualifiedNameInfos(name, namespace)
@@ -901,7 +917,7 @@
element = infos["reduce"](self, child_infos[1], child_infos[2])
if element is not None:
result.append(element)
- if child_infos[1].has_key("name") and schema:
+ if "name" in child_infos[1] and schema:
self.CurrentCompilations.pop(-1)
annotations = []
children = []
@@ -913,22 +929,22 @@
return annotations, children
def AddComplexType(self, typename, infos):
- if not self.XMLClassDefinitions.has_key(typename):
+ if typename not in self.XMLClassDefinitions:
self.XMLClassDefinitions[typename] = infos
else:
raise ValueError("\"%s\" class already defined. Choose another name!" % typename)
def ParseSchema(self):
pass
-
+
def AddEquivalentClass(self, name, base):
if name != base:
equivalences = self.EquivalentClassesParent.setdefault(self.etreeNamespaceFormat % base, {})
equivalences[self.etreeNamespaceFormat % name] = True
-
+
def AddDistinctionBetweenParentsInLookupClass(
self, lookup_classes, parent, typeinfos):
- parent = (self.etreeNamespaceFormat % parent
+ parent = (self.etreeNamespaceFormat % parent
if parent is not None else None)
parent_class = lookup_classes.get(parent)
if parent_class is not None:
@@ -939,7 +955,7 @@
lookup_classes[parent] = [typeinfos, parent_class]
else:
lookup_classes[parent] = typeinfos
-
+
def AddToLookupClass(self, name, parent, typeinfos):
lookup_name = self.etreeNamespaceFormat % name
if isinstance(typeinfos, (StringType, UnicodeType)):
@@ -958,7 +974,7 @@
self.AddDistinctionBetweenParentsInLookupClass(
lookup_classes, parent, typeinfos)
self.ComputedClassesLookUp[lookup_name] = lookup_classes
-
+
def ExtractTypeInfos(self, name, parent, typeinfos):
if isinstance(typeinfos, (StringType, UnicodeType)):
namespace, type_name = DecomposeQualifiedName(typeinfos)
@@ -986,12 +1002,12 @@
return self.CreateClass(name, parent, typeinfos)
elif typeinfos["type"] == SIMPLETYPE:
return typeinfos
-
+
def GetEquivalentParents(self, parent):
return reduce(lambda x, y: x + y,
- [[p] + self.GetEquivalentParents(p)
- for p in self.EquivalentClassesParent.get(parent, {}).keys()], [])
-
+ [[p] + self.GetEquivalentParents(p)
+ for p in self.EquivalentClassesParent.get(parent, {}).keys()], [])
+
"""
Methods that generates the classes
"""
@@ -1015,9 +1031,9 @@
self.Namespaces[self.TargetNamespace][result["name"]] = result
elif infos["type"] == ELEMENTSGROUP:
elements = []
- if infos.has_key("elements"):
+ if "elements" in infos:
elements = infos["elements"]
- elif infos.has_key("choices"):
+ elif "choices" in infos:
elements = infos["choices"]
for element in elements:
if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and \
@@ -1028,7 +1044,7 @@
if result is not None and \
not isinstance(result, (UnicodeType, StringType)):
self.Namespaces[self.TargetNamespace][result["name"]] = result
-
+
for name, parents in self.ComputedClassesLookUp.iteritems():
if isinstance(parents, DictType):
computed_classes = parents.items()
@@ -1042,19 +1058,19 @@
parents = dict(computed_classes)
self.ComputedClassesLookUp[name] = parents
parents[equivalent_parent] = computed_class
-
+
return self.ComputedClasses
- def CreateClass(self, name, parent, classinfos, baseclass = False):
+ def CreateClass(self, name, parent, classinfos, baseclass=False):
if parent is not None:
classname = "%s_%s" % (parent, name)
else:
classname = name
-
+
# Checks that classe haven't been generated yet
if self.AlreadyComputed.get(classname, False):
return self.ComputedClassesInfos.get(classname, None)
-
+
# If base classes haven't been generated
bases = []
base_infos = classinfos.get("base", None)
@@ -1088,29 +1104,29 @@
bases.append(DefaultElementClass)
bases = tuple(bases)
classmembers = {"__doc__": classinfos.get("doc", ""), "IsBaseClass": baseclass}
-
+
self.AlreadyComputed[classname] = True
-
+
for attribute in classinfos["attributes"]:
infos = self.ExtractTypeInfos(attribute["name"], name, attribute["attr_type"])
- if infos is not None:
+ if infos is not None:
if infos["type"] != SIMPLETYPE:
raise ValueError("\"%s\" type is not a simple type!" % attribute["attr_type"])
attrname = attribute["name"]
if attribute["use"] == "optional":
- classmembers["add%s"%attrname] = generateAddMethod(attrname, self, attribute)
- classmembers["delete%s"%attrname] = generateDeleteMethod(attrname)
- classmembers["set%s"%attrname] = generateSetMethod(attrname)
- classmembers["get%s"%attrname] = generateGetMethod(attrname)
+ classmembers["add%s" % attrname] = generateAddMethod(attrname, self, attribute)
+ classmembers["delete%s" % attrname] = generateDeleteMethod(attrname)
+ classmembers["set%s" % attrname] = generateSetMethod(attrname)
+ classmembers["get%s" % attrname] = generateGetMethod(attrname)
else:
raise ValueError("\"%s\" type unrecognized!" % attribute["attr_type"])
attribute["attr_type"] = infos
-
+
for element in classinfos["elements"]:
if element["type"] == CHOICE:
elmtname = element["name"]
choices = ComputeContentChoices(self, name, element)
- classmembers["get%schoices"%elmtname] = generateGetChoicesMethod(element["choices"])
+ classmembers["get%schoices" % elmtname] = generateGetChoicesMethod(element["choices"])
if element["maxOccurs"] == "unbounded" or element["maxOccurs"] > 1:
classmembers["append%sbytype" % elmtname] = generateAppendChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
classmembers["insert%sbytype" % elmtname] = generateInsertChoiceByTypeMethod(element["maxOccurs"], self, element["choices"])
@@ -1141,30 +1157,31 @@
classmembers["delete%s" % elmtname] = generateDeleteMethod(elmtname)
classmembers["set%s" % elmtname] = generateSetMethod(elmtname)
classmembers["get%s" % elmtname] = generateGetMethod(elmtname)
-
+
classmembers["_init_"] = generateInitMethod(self, classinfos)
classmembers["StructurePattern"] = GetStructurePattern(classinfos)
classmembers["getElementAttributes"] = generateGetElementAttributes(self, classinfos)
classmembers["getElementInfos"] = generateGetElementInfos(self, classinfos)
classmembers["setElementValue"] = generateSetElementValue(self, classinfos)
-
+
class_definition = classobj(str(name), bases, classmembers)
setattr(class_definition, "__getattr__", generateGetattrMethod(self, class_definition, classinfos))
setattr(class_definition, "__setattr__", generateSetattrMethod(self, class_definition, classinfos))
- class_infos = {"type": COMPILEDCOMPLEXTYPE,
- "name": classname,
- "initial": generateClassCreateFunction(class_definition),
+ class_infos = {
+ "type": COMPILEDCOMPLEXTYPE,
+ "name": classname,
+ "initial": generateClassCreateFunction(class_definition),
}
-
+
if self.FileName is not None:
self.ComputedClasses[self.FileName][classname] = class_definition
else:
self.ComputedClasses[classname] = class_definition
self.ComputedClassesInfos[classname] = class_infos
-
+
self.AddToLookupClass(name, parent, class_definition)
self.AddToLookupClass(classname, None, class_definition)
-
+
return class_infos
"""
@@ -1183,18 +1200,19 @@
else:
for classname, xmlclass in items:
print "%s: %s" % (classname, str(xmlclass))
-
+
def PrintClassNames(self):
classnames = self.XMLClassDefinitions.keys()
classnames.sort()
for classname in classnames:
print classname
-"""
-Method that generate the method for generating the xml tree structure model by
-following the attributes list defined
-"""
+
def ComputeMultiplicity(name, infos):
+ """
+ Method that generate the method for generating the xml tree structure model by
+ following the attributes list defined
+ """
if infos["minOccurs"] == 0:
if infos["maxOccurs"] == "unbounded":
return "(?:%s)*" % name
@@ -1213,13 +1231,15 @@
if infos["maxOccurs"] == "unbounded":
return "(?:%s){%d,}" % (name, infos["minOccurs"], name)
else:
- return "(?:%s){%d,%d}" % (name, infos["minOccurs"],
- infos["maxOccurs"])
+ return "(?:%s){%d,%d}" % (name,
+ infos["minOccurs"],
+ infos["maxOccurs"])
+
def GetStructurePattern(classinfos):
base_structure_pattern = (
classinfos["base"].StructurePattern.pattern[:-1]
- if classinfos.has_key("base") else "")
+ if "base" in classinfos else "")
elements = []
for element in classinfos["elements"]:
if element["type"] == ANY:
@@ -1244,33 +1264,35 @@
else:
raise ValueError("XSD structure not yet supported!")
-"""
-Method that generate the method for creating a class instance
-"""
+
def generateClassCreateFunction(class_definition):
+ """
+ Method that generate the method for creating a class instance
+ """
def classCreatefunction():
return class_definition()
return classCreatefunction
+
def generateGetattrMethod(factory, class_definition, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
elements = dict([(element["name"], element) for element in classinfos["elements"]])
-
+
def getattrMethod(self, name):
- if attributes.has_key(name):
+ if name in attributes:
attribute_infos = attributes[name]
attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
value = self.get(name)
if value is not None:
return attribute_infos["attr_type"]["extract"](value, extract=False)
- elif attribute_infos.has_key("fixed"):
+ elif "fixed" in attribute_infos:
return attribute_infos["attr_type"]["extract"](attribute_infos["fixed"], extract=False)
- elif attribute_infos.has_key("default"):
+ elif "default" in attribute_infos:
return attribute_infos["attr_type"]["extract"](attribute_infos["default"], extract=False)
return None
-
- elif elements.has_key(name):
+
+ elif name in elements:
element_infos = elements[name]
element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
if element_infos["type"] == CHOICE:
@@ -1279,7 +1301,7 @@
return content
elif len(content) > 0:
return content[0]
- return None
+ return None
elif element_infos["type"] == ANY:
return element_infos["elmt_type"]["extract"](self)
elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
@@ -1290,29 +1312,30 @@
values = self.findall(element_name)
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
return map(lambda value:
- element_infos["elmt_type"]["extract"](value.text, extract=False),
- values)
+ element_infos["elmt_type"]["extract"](value.text, extract=False),
+ values)
return values
else:
value = self.find(element_name)
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
return element_infos["elmt_type"]["extract"](value.text, extract=False)
return value
-
- elif classinfos.has_key("base"):
+
+ elif "base" in classinfos:
return classinfos["base"].__getattr__(self, name)
-
+
return DefaultElementClass.__getattribute__(self, name)
-
+
return getattrMethod
+
def generateSetattrMethod(factory, class_definition, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
optional_attributes = dict([(attr["name"], True) for attr in classinfos["attributes"] if attr["use"] == "optional"])
elements = OrderedDict([(element["name"], element) for element in classinfos["elements"]])
-
+
def setattrMethod(self, name, value):
- if attributes.has_key(name):
+ if name in attributes:
attribute_infos = attributes[name]
attribute_infos["attr_type"] = FindTypeInfos(factory, attribute_infos["attr_type"])
if optional_attributes.get(name, False):
@@ -1320,65 +1343,66 @@
if value is None or value == default:
self.attrib.pop(name, None)
return
- elif attribute_infos.has_key("fixed"):
+ elif "fixed" in attribute_infos:
return
return self.set(name, attribute_infos["attr_type"]["generate"](value))
-
- elif elements.has_key(name):
+
+ elif name in elements:
element_infos = elements[name]
element_infos["elmt_type"] = FindTypeInfos(factory, element_infos["elmt_type"])
if element_infos["type"] == ANY:
element_infos["elmt_type"]["generate"](self, value)
-
+
elif name == "content" and element_infos["elmt_type"]["type"] == SIMPLETYPE:
self.text = element_infos["elmt_type"]["generate"](value)
-
+
else:
prefix = ("%s:" % factory.TargetNamespace
if factory.TargetNamespace is not None else "")
element_xpath = (prefix + name
if name != "content"
else elements["content"]["elmt_type"]["choices_xpath"].path)
-
+
for element in self.xpath(element_xpath, namespaces=factory.NSMAP):
self.remove(element)
-
+
if value is not None:
element_idx = elements.keys().index(name)
if element_idx > 0:
previous_elements_xpath = "|".join(map(
lambda x: prefix + x
- if x != "content"
- else elements["content"]["elmt_type"]["choices_xpath"].path,
+ if x != "content"
+ else elements["content"]["elmt_type"]["choices_xpath"].path,
elements.keys()[:element_idx]))
-
+
insertion_point = len(self.xpath(previous_elements_xpath, namespaces=factory.NSMAP))
else:
insertion_point = 0
-
+
if not isinstance(value, ListType):
value = [value]
-
+
for element in reversed(value):
if element_infos["elmt_type"]["type"] == SIMPLETYPE:
tmp_element = etree.Element(factory.etreeNamespaceFormat % name)
tmp_element.text = element_infos["elmt_type"]["generate"](element)
element = tmp_element
self.insert(insertion_point, element)
-
- elif classinfos.has_key("base"):
+
+ elif "base" in classinfos:
return classinfos["base"].__setattr__(self, name, value)
-
+
else:
raise AttributeError("'%s' can't have an attribute '%s'." % (self.__class__.__name__, name))
-
+
return setattrMethod
+
def gettypeinfos(name, facets):
- if facets.has_key("enumeration") and facets["enumeration"][0] is not None:
+ if "enumeration" in facets and facets["enumeration"][0] is not None:
return facets["enumeration"][0]
- elif facets.has_key("maxInclusive"):
- limits = {"max" : None, "min" : None}
+ elif "maxInclusive" in facets:
+ limits = {"max": None, "min": None}
if facets["maxInclusive"][0] is not None:
limits["max"] = facets["maxInclusive"][0]
elif facets["maxExclusive"][0] is not None:
@@ -1391,24 +1415,28 @@
return limits
return name
+
def generateGetElementAttributes(factory, classinfos):
def getElementAttributes(self):
attr_list = []
- if classinfos.has_key("base"):
+ if "base" in classinfos:
attr_list.extend(classinfos["base"].getElementAttributes(self))
for attr in classinfos["attributes"]:
if attr["use"] != "prohibited":
- attr_params = {"name" : attr["name"], "use" : attr["use"],
- "type" : gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]),
- "value" : getattr(self, attr["name"], "")}
+ attr_params = {
+ "name": attr["name"],
+ "use": attr["use"],
+ "type": gettypeinfos(attr["attr_type"]["basename"], attr["attr_type"]["facets"]),
+ "value": getattr(self, attr["name"], "")}
attr_list.append(attr_params)
return attr_list
return getElementAttributes
+
def generateGetElementInfos(factory, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
elements = dict([(element["name"], element) for element in classinfos["elements"]])
-
+
def getElementInfos(self, name, path=None, derived=False):
attr_type = "element"
value = None
@@ -1416,17 +1444,17 @@
children = []
if path is not None:
parts = path.split(".", 1)
- if attributes.has_key(parts[0]):
+ if parts[0] in attributes:
if len(parts) != 1:
raise ValueError("Wrong path!")
- attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"],
+ attr_type = gettypeinfos(attributes[parts[0]]["attr_type"]["basename"],
attributes[parts[0]]["attr_type"]["facets"])
value = getattr(self, parts[0], "")
- elif elements.has_key(parts[0]):
+ elif parts[0] in elements:
if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
if len(parts) != 1:
raise ValueError("Wrong path!")
- attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"],
+ attr_type = gettypeinfos(elements[parts[0]]["elmt_type"]["basename"],
elements[parts[0]]["elmt_type"]["facets"])
value = getattr(self, parts[0], "")
elif parts[0] == "content":
@@ -1439,17 +1467,17 @@
return attr.getElementInfos(parts[0])
else:
return attr.getElementInfos(parts[0], parts[1])
- elif elements.has_key("content"):
+ elif "content" in elements:
if len(parts) > 0:
return self.content.getElementInfos(name, path)
- elif classinfos.has_key("base"):
+ elif "base" in classinfos:
classinfos["base"].getElementInfos(name, path)
else:
raise ValueError("Wrong path!")
else:
if not derived:
children.extend(self.getElementAttributes())
- if classinfos.has_key("base"):
+ if "base" in classinfos:
children.extend(classinfos["base"].getElementInfos(self, name, derived=True)["children"])
for element_name, element in elements.items():
if element["minOccurs"] == 0:
@@ -1463,8 +1491,10 @@
if self.content is not None:
children.extend(self.content.getElementInfos(value)["children"])
elif element["elmt_type"]["type"] == SIMPLETYPE:
- children.append({"name": element_name, "require": element["minOccurs"] != 0,
- "type": gettypeinfos(element["elmt_type"]["basename"],
+ children.append({
+ "name": element_name,
+ "require": element["minOccurs"] != 0,
+ "type": gettypeinfos(element["elmt_type"]["basename"],
element["elmt_type"]["facets"]),
"value": getattr(self, element_name, None)})
else:
@@ -1475,28 +1505,29 @@
return {"name": name, "type": attr_type, "value": value, "use": use, "children": children}
return getElementInfos
+
def generateSetElementValue(factory, classinfos):
attributes = dict([(attr["name"], attr) for attr in classinfos["attributes"] if attr["use"] != "prohibited"])
elements = dict([(element["name"], element) for element in classinfos["elements"]])
-
+
def setElementValue(self, path, value):
if path is not None:
parts = path.split(".", 1)
- if attributes.has_key(parts[0]):
+ if parts[0] in attributes:
if len(parts) != 1:
raise ValueError("Wrong path!")
if attributes[parts[0]]["attr_type"]["basename"] == "boolean":
setattr(self, parts[0], value)
elif attributes[parts[0]]["use"] == "optional" and value == "":
- if attributes[parts[0]].has_key("default"):
- setattr(self, parts[0],
- attributes[parts[0]]["attr_type"]["extract"](
- attributes[parts[0]]["default"], False))
+ if "default" in attributes[parts[0]]:
+ setattr(self, parts[0],
+ attributes[parts[0]]["attr_type"]["extract"](
+ attributes[parts[0]]["default"], False))
else:
setattr(self, parts[0], None)
else:
setattr(self, parts[0], attributes[parts[0]]["attr_type"]["extract"](value, False))
- elif elements.has_key(parts[0]):
+ elif parts[0] in elements:
if elements[parts[0]]["elmt_type"]["type"] == SIMPLETYPE:
if len(parts) != 1:
raise ValueError("Wrong path!")
@@ -1511,17 +1542,17 @@
if instance is None and elements[parts[0]]["minOccurs"] == 0:
instance = elements[parts[0]]["elmt_type"]["initial"]()
setattr(self, parts[0], instance)
- if instance != None:
+ if instance is not None:
if len(parts) > 1:
instance.setElementValue(parts[1], value)
else:
instance.setElementValue(None, value)
- elif elements.has_key("content"):
+ elif "content" in elements:
if len(parts) > 0:
self.content.setElementValue(path, value)
- elif classinfos.has_key("base"):
+ elif "base" in classinfos:
classinfos["base"].setElementValue(self, path, value)
- elif elements.has_key("content"):
+ elif "content" in elements:
if value == "":
if elements["content"]["minOccurs"] == 0:
self.setcontent([])
@@ -1531,12 +1562,14 @@
self.setcontentbytype(value)
return setElementValue
-"""
-Methods that generates the different methods for setting and getting the attributes
-"""
+
def generateInitMethod(factory, classinfos):
+ """
+ Methods that generates the different methods for setting and getting the attributes
+ """
+
def initMethod(self):
- if classinfos.has_key("base"):
+ if "base" in classinfos:
classinfos["base"]._init_(self)
for attribute in classinfos["attributes"]:
attribute["attr_type"] = FindTypeInfos(factory, attribute["attr_type"])
@@ -1553,21 +1586,24 @@
map(self.append, initial)
return initMethod
+
def generateSetMethod(attr):
def setMethod(self, value):
setattr(self, attr, value)
return setMethod
+
def generateGetMethod(attr):
def getMethod(self):
return getattr(self, attr, None)
return getMethod
+
def generateAddMethod(attr, factory, infos):
def addMethod(self):
if infos["type"] == ATTRIBUTE:
infos["attr_type"] = FindTypeInfos(factory, infos["attr_type"])
- if not infos.has_key("default"):
+ if "default" not in infos:
setattr(self, attr, infos["attr_type"]["initial"]())
elif infos["type"] == ELEMENT:
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1579,11 +1615,13 @@
raise ValueError("Invalid class attribute!")
return addMethod
+
def generateDeleteMethod(attr):
def deleteMethod(self):
setattr(self, attr, None)
return deleteMethod
+
def generateAppendMethod(attr, maxOccurs, factory, infos):
def appendMethod(self, value):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1597,6 +1635,7 @@
raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
return appendMethod
+
def generateInsertMethod(attr, maxOccurs, factory, infos):
def insertMethod(self, index, value):
infos["elmt_type"] = FindTypeInfos(factory, infos["elmt_type"])
@@ -1612,15 +1651,18 @@
raise ValueError("There can't be more than %d values in \"%s\"!" % (maxOccurs, attr))
return insertMethod
+
def generateGetChoicesMethod(choice_types):
def getChoicesMethod(self):
return [choice["name"] for choice in choice_types]
return getChoicesMethod
+
def generateSetChoiceByTypeMethod(factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def setChoiceMethod(self, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
new_content = choices[content_type]["elmt_type"]["initial"]()
@@ -1629,10 +1671,12 @@
return new_content
return setChoiceMethod
+
def generateAppendChoiceByTypeMethod(maxOccurs, factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def appendChoiceMethod(self, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[content_type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
@@ -1644,10 +1688,12 @@
raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
return appendChoiceMethod
+
def generateInsertChoiceByTypeMethod(maxOccurs, factory, choice_types):
choices = dict([(choice["name"], choice) for choice in choice_types])
+
def insertChoiceMethod(self, index, content_type):
- if not choices.has_key(content_type):
+ if content_type not in choices:
raise ValueError("Unknown \"%s\" choice type for \"content\"!" % content_type)
choices[type]["elmt_type"] = FindTypeInfos(factory, choices[content_type]["elmt_type"])
if maxOccurs == "unbounded" or len(self.content) < maxOccurs:
@@ -1659,6 +1705,7 @@
raise ValueError("There can't be more than %d values in \"content\"!" % maxOccurs)
return insertChoiceMethod
+
def generateRemoveMethod(attr, minOccurs):
def removeMethod(self, index):
attr_list = getattr(self, attr)
@@ -1668,52 +1715,56 @@
raise ValueError("There can't be less than %d values in \"%s\"!" % (minOccurs, attr))
return removeMethod
+
def generateCountMethod(attr):
def countMethod(self):
return len(getattr(self, attr))
return countMethod
+
"""
This function generate a xml parser from a class factory
"""
NAMESPACE_PATTERN = re.compile("xmlns(?:\:[^\=]*)?=\"[^\"]*\" ")
+
class DefaultElementClass(etree.ElementBase):
-
+
StructurePattern = re.compile("$")
-
+
def _init_(self):
pass
-
+
def getLocalTag(self):
return etree.QName(self.tag).localname
-
+
def tostring(self):
return NAMESPACE_PATTERN.sub("", etree.tostring(self, pretty_print=True, encoding='utf-8')).decode('utf-8')
+
class XMLElementClassLookUp(etree.PythonElementClassLookup):
-
+
def __init__(self, classes, *args, **kwargs):
etree.PythonElementClassLookup.__init__(self, *args, **kwargs)
self.LookUpClasses = classes
-
+
def GetElementClass(self, element_tag, parent_tag=None, default=DefaultElementClass):
element_class = self.LookUpClasses.get(element_tag, (default, None))
if not isinstance(element_class, DictType):
if isinstance(element_class[0], (StringType, UnicodeType)):
return self.GetElementClass(element_class[0], default=default)
return element_class[0]
-
+
element_with_parent_class = element_class.get(parent_tag, default)
if isinstance(element_with_parent_class, (StringType, UnicodeType)):
return self.GetElementClass(element_with_parent_class, default=default)
return element_with_parent_class
-
+
def lookup(self, document, element):
parent = element.getparent()
- element_class = self.GetElementClass(element.tag,
- parent.tag if parent is not None else None)
+ element_class = self.GetElementClass(
+ element.tag, parent.tag if parent is not None else None)
if isinstance(element_class, ListType):
children = "".join([
"%s " % etree.QName(child.tag).localname
@@ -1726,6 +1777,7 @@
return element_class[0]
return element_class
+
class XMLClassParser(etree.XMLParser):
def __init__(self, namespaces, default_namespace_format, base_class, xsd_schema, *args, **kwargs):
@@ -1741,24 +1793,24 @@
self.RootNSMAP = namespaces
self.BaseClass = base_class
self.XSDSchema = xsd_schema
-
+
def set_element_class_lookup(self, class_lookup):
etree.XMLParser.set_element_class_lookup(self, class_lookup)
self.ClassLookup = class_lookup
-
+
def LoadXMLString(self, xml_string):
tree = etree.fromstring(xml_string, self)
if not self.XSDSchema.validate(tree):
error = self.XSDSchema.error_log.last_error
return tree, (error.line, error.message)
- return tree, None
-
+ return tree, None
+
def Dumps(self, xml_obj):
return etree.tostring(xml_obj, encoding='utf-8')
-
+
def Loads(self, xml_string):
return etree.fromstring(xml_string, self)
-
+
def CreateRoot(self):
if self.BaseClass is not None:
root = self.makeelement(
@@ -1767,42 +1819,42 @@
root._init_()
return root
return None
-
+
def GetElementClass(self, element_tag, parent_tag=None):
return self.ClassLookup.GetElementClass(
- self.DefaultNamespaceFormat % element_tag,
- self.DefaultNamespaceFormat % parent_tag
- if parent_tag is not None else parent_tag,
+ self.DefaultNamespaceFormat % element_tag,
+ self.DefaultNamespaceFormat % parent_tag
+ if parent_tag is not None else parent_tag,
None)
-
+
def CreateElement(self, element_tag, parent_tag=None, class_idx=None):
element_class = self.GetElementClass(element_tag, parent_tag)
if isinstance(element_class, ListType):
if class_idx is not None and class_idx < len(element_class):
new_element = element_class[class_idx]()
else:
- raise ValueError, "No corresponding class found!"
+ raise ValueError("No corresponding class found!")
else:
new_element = element_class()
DefaultElementClass.__setattr__(new_element, "tag", self.DefaultNamespaceFormat % element_tag)
new_element._init_()
return new_element
-
+
+
def GenerateParser(factory, xsdstring):
ComputedClasses = factory.CreateClasses()
-
+
if factory.FileName is not None:
ComputedClasses = ComputedClasses[factory.FileName]
BaseClass = [(name, XSDclass) for name, XSDclass in ComputedClasses.items() if XSDclass.IsBaseClass]
-
+
parser = XMLClassParser(
factory.NSMAP,
factory.etreeNamespaceFormat,
BaseClass[0] if len(BaseClass) == 1 else None,
etree.XMLSchema(etree.fromstring(xsdstring)),
- strip_cdata = False, remove_blank_text=True)
+ strip_cdata=False, remove_blank_text=True)
class_lookup = XMLElementClassLookUp(factory.ComputedClassesLookUp)
parser.set_element_class_lookup(class_lookup)
-
+
return parser
-
--- a/xmlclass/xsdschema.py Mon Aug 21 20:17:19 2017 +0000
+++ b/xmlclass/xsdschema.py Mon Aug 21 23:22:58 2017 +0300
@@ -22,16 +22,19 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-import os, re
+import os
+import re
import datetime
from xml.dom import minidom
from types import *
from xmlclass import *
+
def GenerateDictFacets(facets):
return dict([(name, (None, False)) for name in facets])
+
def GenerateSimpleTypeXMLText(function):
def generateXMLTextMethod(value, name=None, indent=0):
text = ""
@@ -44,9 +47,11 @@
return text
return generateXMLTextMethod
+
def GenerateFloatXMLText(extra_values=[], decimal=None):
float_format = (lambda x: "{:.{width}f}".format(x, width=decimal).rstrip('0')
if decimal is not None else str)
+
def generateXMLTextMethod(value, name=None, indent=0):
text = ""
if name is not None:
@@ -62,31 +67,32 @@
text += "</%s>\n" % name
return text
return generateXMLTextMethod
-
+
+
DEFAULT_FACETS = GenerateDictFacets(["pattern", "whiteSpace", "enumeration"])
NUMBER_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["maxInclusive", "maxExclusive", "minInclusive", "minExclusive"])
DECIMAL_FACETS = GenerateDictFacets(NUMBER_FACETS.keys() + ["totalDigits", "fractionDigits"])
STRING_FACETS = GenerateDictFacets(DEFAULT_FACETS.keys() + ["length", "minLength", "maxLength"])
-ALL_FACETS = ["pattern", "whiteSpace", "enumeration", "maxInclusive",
- "maxExclusive", "minInclusive", "minExclusive", "totalDigits",
- "fractionDigits", "length", "minLength", "maxLength"]
-
-
-#-------------------------------------------------------------------------------
+ALL_FACETS = ["pattern", "whiteSpace", "enumeration", "maxInclusive",
+ "maxExclusive", "minInclusive", "minExclusive", "totalDigits",
+ "fractionDigits", "length", "minLength", "maxLength"]
+
+
+# -------------------------------------------------------------------------------
# Structure reducing functions
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# Documentation elements
def ReduceAppInfo(factory, attributes, elements):
- return {"type": "appinfo", "source": attributes.get("source", None),
+ return {"type": "appinfo", "source": attributes.get("source", None),
"content": "\n".join(elements)}
def ReduceDocumentation(factory, attributes, elements):
- return {"type": "documentation", "source": attributes.get("source", None),
+ return {"type": "documentation", "source": attributes.get("source", None),
"language": attributes.get("lang", "any"), "content": "\n".join(elements)}
@@ -98,10 +104,10 @@
annotation["appinfo"].append((child["source"], child["content"]))
elif child["type"] == "documentation":
if child["source"] is not None:
- text = "(source: %(source)s):\n%(content)s\n\n"%child
+ text = "(source: %(source)s):\n%(content)s\n\n" % child
else:
text = child["content"] + "\n\n"
- if not annotation["documentation"].has_key(child["language"]):
+ if not child["language"] in annotation["documentation"]:
annotation["documentation"] = text
else:
annotation["documentation"] += text
@@ -109,10 +115,11 @@
# Simple type elements
+
def GenerateFacetReducing(facetname, canbefixed):
def ReduceFacet(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
- if attributes.has_key("value"):
+ if "value" in attributes:
facet = {"type": facetname, "value": attributes["value"], "doc": annotations}
if canbefixed:
facet["fixed"] = attributes.get("fixed", False)
@@ -124,7 +131,7 @@
def ReduceList(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
list = {"type": "list", "itemType": attributes.get("itemType", None), "doc": annotations}
-
+
if len(children) > 0 and children[0]["type"] == SIMPLETYPE:
if list["itemType"] is None:
list["itemType"] = children[0]
@@ -138,7 +145,7 @@
def ReduceUnion(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
union = {"type": "union", "memberTypes": attributes.get("memberTypes", []), "doc": annotations}
-
+
for child in children:
if child["type"] == SIMPLETYPE:
union["memberTypes"].appendchild
@@ -151,35 +158,35 @@
# Initialize type informations
facets = {}
simpleType = {"type": SIMPLETYPE, "final": attributes.get("final", [])}
- if attributes.has_key("name"):
+ if "name" in attributes:
simpleType["name"] = attributes["name"]
-
+
if typeinfos["type"] in ["restriction", "extension"]:
# Search for base type definition
if isinstance(typeinfos["base"], (StringType, UnicodeType)):
basetypeinfos = factory.FindSchemaElement(typeinfos["base"], SIMPLETYPE)
if basetypeinfos is None:
- raise "\"%s\" isn't defined!" % typeinfos["base"]
+ raise "\"%s\" isn't defined!" % typeinfos["base"]
else:
basetypeinfos = typeinfos["base"]
-
+
# Check that base type is a simple type
if basetypeinfos["type"] != SIMPLETYPE:
raise ValueError("Base type given isn't a simpleType!")
-
+
simpleType["basename"] = basetypeinfos["basename"]
-
+
# Check that derivation is allowed
- if basetypeinfos.has_key("final"):
+ if "final" in basetypeinfos:
if "#all" in basetypeinfos["final"]:
raise ValueError("Base type can't be derivated!")
if "restriction" in basetypeinfos["final"] and typeinfos["type"] == "restriction":
raise ValueError("Base type can't be derivated by restriction!")
-
+
# Extract simple type facets
for facet in typeinfos.get("facets", []):
facettype = facet["type"]
- if not basetypeinfos["facets"].has_key(facettype):
+ if facettype not in basetypeinfos["facets"]:
raise ValueError("\"%s\" facet can't be defined for \"%s\" type!" % (facettype, type))
elif basetypeinfos["facets"][facettype][1]:
raise ValueError("\"%s\" facet is fixed on base type!" % facettype)
@@ -195,103 +202,103 @@
continue
else:
raise ValueError("\"%s\" facet can't be defined with another facet type!" % facettype)
- elif facets.has_key("enumeration"):
+ elif "enumeration" in facets:
raise ValueError("\"enumeration\" facet can't be defined with another facet type!")
- elif facets.has_key("pattern"):
+ elif "pattern" in facets:
raise ValueError("\"pattern\" facet can't be defined with another facet type!")
- elif facets.has_key(facettype):
+ elif facettype in facets:
raise ValueError("\"%s\" facet can't be defined two times!" % facettype)
elif facettype == "length":
- if facets.has_key("minLength"):
+ if "minLength" in facets:
raise ValueError("\"length\" and \"minLength\" facets can't be defined at the same time!")
- if facets.has_key("maxLength"):
+ if "maxLength" in facets:
raise ValueError("\"length\" and \"maxLength\" facets can't be defined at the same time!")
try:
value = int(value)
- except:
+ except Exception:
raise ValueError("\"length\" must be an integer!")
if value < 0:
raise ValueError("\"length\" can't be negative!")
elif basevalue is not None and basevalue != value:
raise ValueError("\"length\" can't be different from \"length\" defined in base type!")
elif facettype == "minLength":
- if facets.has_key("length"):
+ if "length" in facets:
raise ValueError("\"length\" and \"minLength\" facets can't be defined at the same time!")
try:
value = int(value)
- except:
+ except Exception:
raise ValueError("\"minLength\" must be an integer!")
if value < 0:
raise ValueError("\"minLength\" can't be negative!")
- elif facets.has_key("maxLength") and value > facets["maxLength"]:
+ elif "maxLength" in facets and value > facets["maxLength"]:
raise ValueError("\"minLength\" must be lesser than or equal to \"maxLength\"!")
elif basevalue is not None and basevalue < value:
raise ValueError("\"minLength\" can't be lesser than \"minLength\" defined in base type!")
elif facettype == "maxLength":
- if facets.has_key("length"):
+ if "length" in facets:
raise ValueError("\"length\" and \"maxLength\" facets can't be defined at the same time!")
try:
value = int(value)
- except:
+ except Exception:
raise ValueError("\"maxLength\" must be an integer!")
if value < 0:
raise ValueError("\"maxLength\" can't be negative!")
- elif facets.has_key("minLength") and value < facets["minLength"]:
+ elif "minLength" in facets and value < facets["minLength"]:
raise ValueError("\"minLength\" must be lesser than or equal to \"maxLength\"!")
elif basevalue is not None and basevalue > value:
raise ValueError("\"maxLength\" can't be greater than \"maxLength\" defined in base type!")
elif facettype == "minInclusive":
- if facets.has_key("minExclusive"):
+ if "minExclusive" in facets:
raise ValueError("\"minExclusive\" and \"minInclusive\" facets can't be defined at the same time!")
value = basetypeinfos["extract"](facet["value"], False)
- if facets.has_key("maxInclusive") and value > facets["maxInclusive"][0]:
+ if "maxInclusive" in facets and value > facets["maxInclusive"][0]:
raise ValueError("\"minInclusive\" must be lesser than or equal to \"maxInclusive\"!")
- elif facets.has_key("maxExclusive") and value >= facets["maxExclusive"][0]:
+ elif "maxExclusive" in facets and value >= facets["maxExclusive"][0]:
raise ValueError("\"minInclusive\" must be lesser than \"maxExclusive\"!")
elif facettype == "minExclusive":
- if facets.has_key("minInclusive"):
+ if "minInclusive" in facets:
raise ValueError("\"minExclusive\" and \"minInclusive\" facets can't be defined at the same time!")
value = basetypeinfos["extract"](facet["value"], False)
- if facets.has_key("maxInclusive") and value >= facets["maxInclusive"][0]:
+ if "maxInclusive" in facets and value >= facets["maxInclusive"][0]:
raise ValueError("\"minExclusive\" must be lesser than \"maxInclusive\"!")
- elif facets.has_key("maxExclusive") and value >= facets["maxExclusive"][0]:
+ elif "maxExclusive" in facets and value >= facets["maxExclusive"][0]:
raise ValueError("\"minExclusive\" must be lesser than \"maxExclusive\"!")
elif facettype == "maxInclusive":
- if facets.has_key("maxExclusive"):
+ if "maxExclusive" in facets:
raise ValueError("\"maxExclusive\" and \"maxInclusive\" facets can't be defined at the same time!")
value = basetypeinfos["extract"](facet["value"], False)
- if facets.has_key("minInclusive") and value < facets["minInclusive"][0]:
+ if "minInclusive" in facets and value < facets["minInclusive"][0]:
raise ValueError("\"minInclusive\" must be lesser than or equal to \"maxInclusive\"!")
- elif facets.has_key("minExclusive") and value <= facets["minExclusive"][0]:
+ elif "minExclusive" in facets and value <= facets["minExclusive"][0]:
raise ValueError("\"minExclusive\" must be lesser than \"maxInclusive\"!")
elif facettype == "maxExclusive":
- if facets.has_key("maxInclusive"):
+ if "maxInclusive" in facets:
raise ValueError("\"maxExclusive\" and \"maxInclusive\" facets can't be defined at the same time!")
value = basetypeinfos["extract"](facet["value"], False)
- if facets.has_key("minInclusive") and value <= facets["minInclusive"][0]:
+ if "minInclusive" in facets and value <= facets["minInclusive"][0]:
raise ValueError("\"minInclusive\" must be lesser than \"maxExclusive\"!")
- elif facets.has_key("minExclusive") and value <= facets["minExclusive"][0]:
+ elif "minExclusive" in facets and value <= facets["minExclusive"][0]:
raise ValueError("\"minExclusive\" must be lesser than \"maxExclusive\"!")
elif facettype == "whiteSpace":
if basevalue == "collapse" and value in ["preserve", "replace"] or basevalue == "replace" and value == "preserve":
- raise ValueError("\"whiteSpace\" is incompatible with \"whiteSpace\" defined in base type!")
+ raise ValueError("\"whiteSpace\" is incompatible with \"whiteSpace\" defined in base type!")
elif facettype == "totalDigits":
- if facets.has_key("fractionDigits") and value <= facets["fractionDigits"][0]:
+ if "fractionDigits" in facets and value <= facets["fractionDigits"][0]:
raise ValueError("\"fractionDigits\" must be lesser than or equal to \"totalDigits\"!")
elif basevalue is not None and value > basevalue:
raise ValueError("\"totalDigits\" can't be greater than \"totalDigits\" defined in base type!")
elif facettype == "fractionDigits":
- if facets.has_key("totalDigits") and value <= facets["totalDigits"][0]:
+ if "totalDigits" in facets and value <= facets["totalDigits"][0]:
raise ValueError("\"fractionDigits\" must be lesser than or equal to \"totalDigits\"!")
elif basevalue is not None and value > basevalue:
raise ValueError("\"totalDigits\" can't be greater than \"totalDigits\" defined in base type!")
facets[facettype] = (value, facet.get("fixed", False))
-
- # Report not redefined facet from base type to new created type
+
+ # Report not redefined facet from base type to new created type
for facettype, facetvalue in basetypeinfos["facets"].items():
- if not facets.has_key(facettype):
+ if facettype not in facets:
facets[facettype] = facetvalue
-
+
# Generate extract value for new created type
def ExtractSimpleTypeValue(attr, extract=True):
value = basetypeinfos["extract"](attr, extract)
@@ -311,13 +318,13 @@
raise ValueError("value must be greater than %s" % str(facetvalue))
elif facetname == "maxInclusive" and value > facetvalue:
raise ValueError("value must be lesser than or equal to %s" % str(facetvalue))
- elif facetname == "maxExclusive" and value >= facetvalue:
+ elif facetname == "maxExclusive" and value >= facetvalue:
raise ValueError("value must be lesser than %s" % str(facetvalue))
elif facetname == "pattern":
model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue)))
result = model.match(value)
if result is None:
- if len(facetvalue) > 1:
+ if len(facetvalue) > 1:
raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue))
else:
raise ValueError("value doesn't follow the pattern %s" % facetvalue[0])
@@ -327,7 +334,7 @@
elif facetvalue == "collapse":
value = GetToken(value, False)
return value
-
+
def CheckSimpleTypeValue(value):
for facetname, (facetvalue, facetfixed) in facets.items():
if facetvalue is not None:
@@ -345,18 +352,18 @@
return False
elif facetname == "maxInclusive" and value > facetvalue:
return False
- elif facetname == "maxExclusive" and value >= facetvalue:
+ elif facetname == "maxExclusive" and value >= facetvalue:
return False
elif facetname == "pattern":
model = re.compile("(?:%s)?$" % "|".join(map(lambda x: "(?:%s)" % x, facetvalue)))
result = model.match(value)
if result is None:
- if len(facetvalue) > 1:
+ if len(facetvalue) > 1:
raise ValueError("value doesn't follow any of the patterns %s" % ",".join(facetvalue))
else:
raise ValueError("value doesn't follow the pattern %s" % facetvalue[0])
return True
-
+
def SimpleTypeInitialValue():
for facetname, (facetvalue, facetfixed) in facets.items():
if facetvalue is not None:
@@ -372,12 +379,12 @@
return facetvalue + 1
elif facetname == "maxInclusive" and facetvalue < 0:
return facetvalue
- elif facetname == "maxExclusive" and facetvalue <= 0:
+ elif facetname == "maxExclusive" and facetvalue <= 0:
return facetvalue - 1
return basetypeinfos["initial"]()
-
+
GenerateSimpleType = basetypeinfos["generate"]
-
+
elif typeinfos["type"] == "list":
# Search for item type definition
if isinstance(typeinfos["itemType"], (StringType, UnicodeType)):
@@ -386,41 +393,42 @@
raise "\"%s\" isn't defined!" % typeinfos["itemType"]
else:
itemtypeinfos = typeinfos["itemType"]
-
+
# Check that item type is a simple type
if itemtypeinfos["type"] != SIMPLETYPE:
- raise ValueError, "Item type given isn't a simpleType!"
-
+ raise ValueError("Item type given isn't a simpleType!")
+
simpleType["basename"] = "list"
-
+
# Check that derivation is allowed
- if itemtypeinfos.has_key("final"):
- if itemtypeinfos["final"].has_key("#all"):
+ if "final" in itemtypeinfos:
+ if "#all" in itemtypeinfos["final"]:
raise ValueError("Item type can't be derivated!")
- if itemtypeinfos["final"].has_key("list"):
+ if "list" in itemtypeinfos["final"]:
raise ValueError("Item type can't be derivated by list!")
-
+
# Generate extract value for new created type
- def ExtractSimpleTypeValue(attr, extract = True):
+ def ExtractSimpleTypeValue(attr, extract=True):
values = []
for value in GetToken(attr, extract).split(" "):
values.append(itemtypeinfos["extract"](value, False))
return values
-
+
def CheckSimpleTypeValue(value):
for item in value:
result = itemtypeinfos["check"](item)
if not result:
return result
return True
-
- SimpleTypeInitialValue = lambda: []
-
+
+ def SimpleTypeInitialValue():
+ return []
+
GenerateSimpleType = GenerateSimpleTypeXMLText(lambda x: " ".join(map(itemtypeinfos["generate"], x)))
-
+
facets = GenerateDictFacets(["length", "maxLength", "minLength", "enumeration", "pattern"])
facets["whiteSpace"] = ("collapse", False)
-
+
elif typeinfos["type"] == "union":
# Search for member types definition
membertypesinfos = []
@@ -431,24 +439,24 @@
raise ValueError("\"%s\" isn't defined!" % membertype)
else:
infos = membertype
-
+
# Check that member type is a simple type
if infos["type"] != SIMPLETYPE:
raise ValueError("Member type given isn't a simpleType!")
-
+
# Check that derivation is allowed
- if infos.has_key("final"):
- if infos["final"].has_key("#all"):
+ if "final" in infos:
+ if "#all" in infos["final"]:
raise ValueError("Item type can't be derivated!")
- if infos["final"].has_key("union"):
+ if "union" in infos["final"]:
raise ValueError("Member type can't be derivated by union!")
-
+
membertypesinfos.append(infos)
-
+
simpleType["basename"] = "union"
-
+
# Generate extract value for new created type
- def ExtractSimpleTypeValue(attr, extract = True):
+ def ExtractSimpleTypeValue(attr, extract=True):
if extract:
value = GetAttributeValue(attr)
else:
@@ -456,28 +464,28 @@
for infos in membertypesinfos:
try:
return infos["extract"](attr, False)
- except:
+ except Exception:
pass
raise ValueError("\"%s\" isn't valid for type defined for union!")
-
+
def CheckSimpleTypeValue(value):
for infos in membertypesinfos:
result = infos["check"](value)
if result:
return result
return False
-
+
SimpleTypeInitialValue = membertypesinfos[0]["initial"]
-
+
def GenerateSimpleTypeFunction(value):
if isinstance(value, BooleanType):
return {True: "true", False: "false"}[value]
else:
return str(value)
GenerateSimpleType = GenerateSimpleTypeXMLText(GenerateSimpleTypeFunction)
-
+
facets = GenerateDictFacets(["pattern", "enumeration"])
-
+
simpleType["facets"] = facets
simpleType["extract"] = ExtractSimpleTypeValue
simpleType["initial"] = SimpleTypeInitialValue
@@ -485,25 +493,27 @@
simpleType["generate"] = GenerateSimpleType
return simpleType
+
def ReduceSimpleType(factory, attributes, elements):
# Reduce all the simple type children
annotations, children = factory.ReduceElements(elements)
-
+
simpleType = CreateSimpleType(factory, attributes, children[0])
simpleType["doc"] = annotations
-
+
return simpleType
# Complex type
+
def ExtractAttributes(factory, elements, base=None):
attrs = []
attrnames = {}
if base is not None:
basetypeinfos = factory.FindSchemaElement(base)
if not isinstance(basetypeinfos, (UnicodeType, StringType)) and basetypeinfos["type"] == COMPLEXTYPE:
- attrnames = dict(map(lambda x:(x["name"], True), basetypeinfos["attributes"]))
-
+ attrnames = dict(map(lambda x: (x["name"], True), basetypeinfos["attributes"]))
+
for element in elements:
if element["type"] == ATTRIBUTE:
if attrnames.get(element["name"], False):
@@ -534,7 +544,7 @@
raise ValueError("Only one base type can be defined for restriction!")
if restriction["base"] is None:
raise ValueError("No base type has been defined for restriction!")
-
+
while len(children) > 0 and children[0]["type"] in ALL_FACETS:
restriction["facets"].append(children.pop(0))
restriction["attributes"] = ExtractAttributes(factory, children, restriction["base"])
@@ -543,7 +553,7 @@
def ReduceExtension(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
- if not attributes.has_key("base"):
+ if "base" not in attributes:
raise ValueError("No base type has been defined for extension!")
extension = {"type": "extension", "attributes": [], "elements": [], "base": attributes["base"], "doc": annotations}
if len(children) > 0:
@@ -558,7 +568,7 @@
extension["elements"].append(content)
elif group["type"] == "group":
elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
- if elmtgroup.has_key("elements"):
+ if "elements" in elmtgroup:
extension["elements"] = elmtgroup["elements"]
extension["order"] = elmtgroup["order"]
else:
@@ -571,24 +581,24 @@
def ReduceSimpleContent(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
simpleContent = children[0].copy()
-
+
basetypeinfos = factory.FindSchemaElement(simpleContent["base"])
if basetypeinfos["type"] == SIMPLETYPE:
contenttypeinfos = simpleContent.copy()
simpleContent.pop("base")
- elif basetypeinfos["type"] == COMPLEXTYPE and \
- len(basetypeinfos["elements"]) == 1 and \
- basetypeinfos["elements"][0]["name"] == "content" and \
- basetypeinfos["elements"][0].has_key("elmt_type") and \
- basetypeinfos["elements"][0]["elmt_type"]["type"] == SIMPLETYPE:
+ elif (basetypeinfos["type"] == COMPLEXTYPE and
+ len(basetypeinfos["elements"]) == 1 and
+ basetypeinfos["elements"][0]["name"] == "content" and
+ "elmt_type" in basetypeinfos["elements"][0] and
+ basetypeinfos["elements"][0]["elmt_type"]["type"] == SIMPLETYPE):
contenttypeinfos = simpleContent.copy()
contenttypeinfos["base"] = basetypeinfos["elements"][0]["elmt_type"]
else:
raise ValueError("No compatible base type defined for simpleContent!")
contenttypeinfos = CreateSimpleType(factory, attributes, contenttypeinfos)
-
+
simpleContent["elements"] = [{"name": "content", "type": ELEMENT,
"elmt_type": contenttypeinfos, "doc": annotations,
"minOccurs": 1, "maxOccurs": 1}]
@@ -605,7 +615,7 @@
def ReduceComplexType(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
if len(children) > 0:
if children[0]["type"] in ["simpleContent", "complexContent"]:
complexType = children[0].copy()
@@ -641,7 +651,7 @@
complexType["elements"].append(content)
elif group["type"] == "group":
elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
- if elmtgroup.has_key("elements"):
+ if "elements" in elmtgroup:
complexType["elements"] = elmtgroup["elements"]
complexType["order"] = elmtgroup["order"]
else:
@@ -661,36 +671,36 @@
# Attribute elements
def ReduceAnyAttribute(factory, attributes, elements):
- return {"type" : "anyAttribute"}
+ return {"type": "anyAttribute"}
def ReduceAttribute(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
- if attributes.has_key("default"):
- if attributes.has_key("fixed"):
+
+ if "default" in attributes:
+ if "fixed" in attributes:
raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!")
elif attributes.get("use", "optional") != "optional":
raise ValueError("if \"default\" present, \"use\" can only have the value \"optional\"!")
-
+
attribute = {"type": ATTRIBUTE, "attr_type": attributes.get("type", None), "doc": annotations}
if len(children) > 0:
if attribute["attr_type"] is None:
attribute["attr_type"] = children[0]
else:
raise ValueError("Only one type can be defined for attribute!")
-
- if attributes.has_key("ref"):
- if attributes.has_key("name"):
+
+ if "ref" in attributes:
+ if "name" in attributes:
raise ValueError("\"ref\" and \"name\" can't be defined at the same time!")
- elif attributes.has_key("form"):
+ elif "form" in attributes:
raise ValueError("\"ref\" and \"form\" can't be defined at the same time!")
elif attribute["attr_type"] is not None:
raise ValueError("if \"ref\" is present, no type can be defined!")
elif attribute["attr_type"] is None:
raise ValueError("No type has been defined for attribute \"%s\"!" % attributes["name"])
-
- if attributes.has_key("type"):
+
+ if "type" in attributes:
tmp_attrs = attributes.copy()
tmp_attrs.pop("type")
attribute.update(tmp_attrs)
@@ -701,7 +711,7 @@
def ReduceAttributeGroup(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
- if attributes.has_key("ref"):
+ if "ref" in attributes:
return {"type": "attributeGroup", "ref": attributes["ref"], "doc": annotations}
else:
return {"type": ATTRIBUTESGROUP, "attributes": ExtractAttributes(factory, children), "doc": annotations}
@@ -711,14 +721,15 @@
def ReduceAny(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
any = {"type": ANY, "doc": annotations}
any.update(attributes)
return any
+
def ReduceElement(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
types = []
constraints = []
for child in children:
@@ -726,19 +737,19 @@
constraints.append(child)
else:
types.append(child)
-
- if attributes.has_key("default") and attributes.has_key("fixed"):
+
+ if "default" in attributes and "fixed" in attributes:
raise ValueError("\"default\" and \"fixed\" can't be defined at the same time!")
-
- if attributes.has_key("ref"):
+
+ if "ref" in attributes:
for attr in ["name", "default", "fixed", "form", "block", "type"]:
- if attributes.has_key(attr):
+ if attr in attributes:
raise ValueError("\"ref\" and \"%s\" can't be defined at the same time!" % attr)
- if attributes.has_key("nillable"):
+ if "nillable" in attributes:
raise ValueError("\"ref\" and \"nillable\" can't be defined at the same time!")
if len(types) > 0:
raise ValueError("No type and no constraints can be defined where \"ref\" is defined!")
-
+
infos = factory.FindSchemaElement(attributes["ref"], ELEMENT)
if infos is not None:
element = infos.copy()
@@ -748,8 +759,8 @@
return element
else:
raise ValueError("\"%s\" base type isn't defined or circular referenced!" % name)
-
- elif attributes.has_key("name"):
+
+ elif "name" in attributes:
element = {"type": ELEMENT, "elmt_type": attributes.get("type", None), "constraints": constraints, "doc": annotations}
if len(types) > 0:
if element["elmt_type"] is None:
@@ -759,8 +770,8 @@
elif element["elmt_type"] is None:
element["elmt_type"] = "tag"
element["type"] = TAG
-
- if attributes.has_key("type"):
+
+ if "type" in attributes:
tmp_attrs = attributes.copy()
tmp_attrs.pop("type")
element.update(tmp_attrs)
@@ -770,20 +781,21 @@
else:
raise ValueError("\"Element\" must have at least a \"ref\" or a \"name\" defined!")
+
def ReduceAll(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
for child in children:
if children["maxOccurs"] == "unbounded" or children["maxOccurs"] > 1:
raise ValueError("\"all\" item can't have \"maxOccurs\" attribute greater than 1!")
-
+
return {"type": "all", "elements": children, "minOccurs": attributes["minOccurs"],
"maxOccurs": attributes["maxOccurs"], "order": False, "doc": annotations}
def ReduceChoice(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
choices = []
for child in children:
if child["type"] in [ELEMENT, ANY, TAG]:
@@ -791,12 +803,12 @@
elif child["type"] == "sequence":
child["minOccurs"] = child["maxOccurs"] = 1
choices.append(child)
- #raise ValueError("\"sequence\" in \"choice\" is not supported. Create instead a new complex type!")
+ # raise ValueError("\"sequence\" in \"choice\" is not supported. Create instead a new complex type!")
elif child["type"] == CHOICE:
choices.extend(child["choices"])
elif child["type"] == "group":
- elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
- if not elmtgroup.has_key("choices"):
+ elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
+ if "choices" not in elmtgroup:
raise ValueError("Only group composed of \"choice\" can be referenced in \"choice\" element!")
choices_tmp = []
for choice in elmtgroup["choices"]:
@@ -810,18 +822,18 @@
else:
choices_tmp.append(choice)
choices.extend(choices_tmp)
-
+
for choice in choices:
attributes["minOccurs"] = min(attributes["minOccurs"], choice["minOccurs"])
choice["minOccurs"] = 1
-
+
return {"type": CHOICE, "choices": choices, "minOccurs": attributes["minOccurs"],
"maxOccurs": attributes["maxOccurs"], "doc": annotations}
def ReduceSequence(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
sequence = []
for child in children:
if child["type"] in [ELEMENT, ANY, TAG, CHOICE]:
@@ -830,12 +842,12 @@
sequence.extend(child["elements"])
elif child["type"] == "group":
elmtgroup = factory.FindSchemaElement(child["ref"], ELEMENTSGROUP)
- if not elmtgroup.has_key("elements") or not elmtgroup["order"]:
+ if "elements" not in elmtgroup or not elmtgroup["order"]:
raise ValueError("Only group composed of \"sequence\" can be referenced in \"sequence\" element!")
elements_tmp = []
for element in elmtgroup["elements"]:
if not isinstance(element["elmt_type"], (UnicodeType, StringType)) and element["elmt_type"]["type"] == COMPLEXTYPE:
- elmt_type = "%s_%s"%(elmtgroup["name"], element["name"])
+ elmt_type = "%s_%s" % (elmtgroup["name"], element["name"])
if factory.TargetNamespace is not None:
elmt_type = "%s:%s" % (factory.TargetNamespace, elmt_type)
new_element = element.copy()
@@ -844,15 +856,15 @@
else:
elements_tmp.append(element)
sequence.extend(elements_tmp)
-
+
return {"type": "sequence", "elements": sequence, "minOccurs": attributes["minOccurs"],
"maxOccurs": attributes["maxOccurs"], "order": True, "doc": annotations}
-
-
+
+
def ReduceGroup(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
- if attributes.has_key("ref"):
+
+ if "ref" in attributes:
return {"type": "group", "ref": attributes["ref"], "doc": annotations}
else:
element = children[0]
@@ -866,41 +878,46 @@
# Constraint elements
+
def ReduceUnique(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
unique = {"type": CONSTRAINT, "const_type": "unique", "selector": children[0], "fields": children[1:]}
unique.update(attributes)
return unique
-
+
+
def ReduceKey(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
key = {"type": CONSTRAINT, "const_type": "key", "selector": children[0], "fields": children[1:]}
key.update(attributes)
return key
+
def ReduceKeyRef(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
keyref = {"type": CONSTRAINT, "const_type": "keyref", "selector": children[0], "fields": children[1:]}
keyref.update(attributes)
return keyref
-
+
+
def ReduceSelector(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
selector = {"type": CONSTRAINT, "const_type": "selector"}
selector.update(attributes)
return selector
+
def ReduceField(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
field = {"type": CONSTRAINT, "const_type": "field"}
field.update(attributes)
return field
-
+
# Inclusion elements
@@ -908,9 +925,10 @@
annotations, children = factory.ReduceElements(elements)
raise ValueError("\"import\" element isn't supported yet!")
+
def ReduceInclude(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
-
+
if factory.FileName is None:
raise ValueError("Include in XSD string not yet supported")
filepath = attributes["schemaLocation"]
@@ -922,7 +940,7 @@
include_factory = XSDClassFactory(minidom.parse(xsdfile), filepath)
xsdfile.close()
include_factory.CreateClasses()
-
+
if factory.TargetNamespace == include_factory.TargetNamespace:
factory.Namespaces[factory.TargetNamespace].update(include_factory.Namespaces[include_factory.TargetNamespace])
else:
@@ -931,7 +949,8 @@
factory.ComputedClassesLookUp.update(include_factory.ComputedClassesLookUp)
factory.EquivalentClassesParent.update(include_factory.EquivalentClassesParent)
return None
-
+
+
def ReduceRedefine(factory, attributes, elements):
annotations, children = factory.ReduceElements(elements)
raise ValueError("\"redefine\" element isn't supported yet!")
@@ -944,23 +963,24 @@
factory.ElementFormDefault = attributes["elementFormDefault"]
factory.BlockDefault = attributes["blockDefault"]
factory.FinalDefault = attributes["finalDefault"]
-
+
targetNamespace = attributes.get("targetNamespace", None)
factory.TargetNamespace = factory.DefinedNamespaces.get(targetNamespace, None)
if factory.TargetNamespace is not None:
factory.etreeNamespaceFormat = "{%s}%%s" % targetNamespace
factory.Namespaces[factory.TargetNamespace] = {}
-
+
annotations, children = factory.ReduceElements(elements, True)
-
+
for child in children:
- if child.has_key("name"):
+ if "name" in child:
infos = factory.GetQualifiedNameInfos(child["name"], factory.TargetNamespace, True)
if infos is None:
factory.Namespaces[factory.TargetNamespace][child["name"]] = child
elif not CompareSchema(infos, child):
raise ValueError("\"%s\" is defined twice in targetNamespace!" % child["name"])
+
def CompareSchema(schema, reference):
if isinstance(schema, ListType):
if not isinstance(reference, ListType) or len(schema) != len(reference):
@@ -975,7 +995,7 @@
return False
for name, value in schema.items():
ref_value = reference.get(name, None)
- if ref_value is None and value != None:
+ if ref_value is None and value is not None:
return False
result = CompareSchema(value, ref_value)
if not result:
@@ -987,10 +1007,11 @@
else:
return True
return schema == reference
-
-#-------------------------------------------------------------------------------
+
+
+# -------------------------------------------------------------------------------
# Base class for XSD schema extraction
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
class XSDClassFactory(ClassFactory):
@@ -999,7 +1020,7 @@
ClassFactory.__init__(self, document, filepath, debug)
self.Namespaces["xml"] = {
"lang": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("lang", LANGUAGE_model)
}
@@ -1007,31 +1028,31 @@
}
self.Namespaces["xsi"] = {
"noNamespaceSchemaLocation": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": NotSupportedYet("noNamespaceSchemaLocation")
}
},
"nil": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": NotSupportedYet("nil")
}
},
"schemaLocation": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": NotSupportedYet("schemaLocation")
}
},
"type": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": NotSupportedYet("type")
}
}
}
-
+
def ParseSchema(self):
for child in self.Document.childNodes:
if child.nodeType == self.Document.ELEMENT_NODE:
@@ -1067,7 +1088,7 @@
if element_type is not None and element["type"] != element_type:
raise ValueError("\"%s\" isn't of the expected type!" % element_name)
return element
-
+
def CreateSchemaElement(self, element_name, element_type):
for type, attributes, elements in self.Schema[2]:
namespace, name = DecomposeQualifiedName(type)
@@ -1090,11 +1111,12 @@
return element_infos
return None
-"""
-This function opens the xsd file and generate a xml parser with class lookup from
-the xml tree
-"""
+
def GenerateParserFromXSD(filepath):
+ """
+ This function opens the xsd file and generate a xml parser with class lookup from
+ the xml tree
+ """
xsdfile = open(filepath, 'r')
xsdstring = xsdfile.read()
xsdfile.close()
@@ -1104,24 +1126,27 @@
os.chdir(cwd)
return parser
-"""
-This function generate a xml from the xsd given as a string
-"""
+
def GenerateParserFromXSDstring(xsdstring):
+ """
+ This function generate a xml from the xsd given as a string
+ """
return GenerateParser(XSDClassFactory(minidom.parseString(xsdstring)), xsdstring)
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
# XSD schema syntax elements
-#-------------------------------------------------------------------------------
+# -------------------------------------------------------------------------------
+
XSD_NAMESPACE = {
-#-------------------------------------------------------------------------------
-# Syntax elements definition
-#-------------------------------------------------------------------------------
-
- "all": {"struct": """
+ # -------------------------------------------------------------------------------
+ # Syntax elements definition
+ # -------------------------------------------------------------------------------
+
+ "all": {
+ "struct": """
<all
id = ID
maxOccurs = 1 : 1
@@ -1129,29 +1154,33 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, element*)
</all>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("all", ["id", "maxOccurs", "minOccurs"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "all", ["id", "maxOccurs", "minOccurs"],
re.compile("((?:annotation )?(?:element )*)"))
},
"reduce": ReduceAll
},
- "annotation": {"struct": """
+ "annotation": {
+ "struct": """
<annotation
id = ID
{any attributes with non-schema namespace . . .}>
Content: (appinfo | documentation)*
</annotation>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("annotation", ["id"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "annotation", ["id"],
re.compile("((?:app_info |documentation )*)"))
},
"reduce": ReduceAnnotation
},
- "any": {"struct": """
+ "any": {
+ "struct": """
<any
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
@@ -1161,16 +1190,18 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</any>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("any",
- ["id", "maxOccurs", "minOccurs", "namespace", "processContents"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "any",
+ ["id", "maxOccurs", "minOccurs", "namespace", "processContents"],
re.compile("((?:annotation )?(?:simpleType )*)"))
},
"reduce": ReduceAny
},
- "anyAttribute": {"struct": """
+ "anyAttribute": {
+ "struct": """
<anyAttribute
id = ID
namespace = ((##any | ##other) | List of (anyURI | (##targetNamespace | ##local)) ) : ##any
@@ -1178,28 +1209,30 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</anyAttribute>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("anyAttribute",
- ["id", "namespace", "processContents"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "anyAttribute", ["id", "namespace", "processContents"], ONLY_ANNOTATION)
},
"reduce": ReduceAnyAttribute
},
- "appinfo": {"struct": """
+ "appinfo": {
+ "struct": """
<appinfo
source = anyURI
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</appinfo>""",
- "type": SYNTAXELEMENT,
+ "type": SYNTAXELEMENT,
"extract": {
"default": GenerateElement("appinfo", ["source"], re.compile("(.*)"), True)
},
"reduce": ReduceAppInfo
},
- "attribute": {"struct": """
+ "attribute": {
+ "struct": """
<attribute
default = string
fixed = string
@@ -1212,19 +1245,22 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, simpleType?)
</attribute>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("attribute",
- ["default", "fixed", "form", "id", "name", "ref", "type", "use"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "attribute",
+ ["default", "fixed", "form", "id", "name", "ref", "type", "use"],
re.compile("((?:annotation )?(?:simpleType )?)")),
- "schema": GenerateElement("attribute",
- ["default", "fixed", "form", "id", "name", "type"],
+ "schema": GenerateElement(
+ "attribute",
+ ["default", "fixed", "form", "id", "name", "type"],
re.compile("((?:annotation )?(?:simpleType )?)"))
},
"reduce": ReduceAttribute
},
- "attributeGroup": {"struct": """
+ "attributeGroup": {
+ "struct": """
<attributeGroup
id = ID
name = NCName
@@ -1232,18 +1268,21 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((attribute | attributeGroup)*, anyAttribute?))
</attributeGroup>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("attributeGroup",
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "attributeGroup",
["id", "ref"], ONLY_ANNOTATION),
- "schema": GenerateElement("attributeGroup",
- ["id", "name"],
+ "schema": GenerateElement(
+ "attributeGroup",
+ ["id", "name"],
re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))"))
},
"reduce": ReduceAttributeGroup
},
- "choice": {"struct": """
+ "choice": {
+ "struct": """
<choice
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
@@ -1251,30 +1290,36 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</choice>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("choice", ["id", "maxOccurs", "minOccurs"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "choice",
+ ["id", "maxOccurs", "minOccurs"],
re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)"))
},
"reduce": ReduceChoice
},
- "complexContent": {"struct": """
+ "complexContent": {
+ "struct": """
<complexContent
id = ID
mixed = boolean
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (restriction | extension))
</complexContent>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("complexContent", ["id", "mixed"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "complexContent",
+ ["id", "mixed"],
re.compile("((?:annotation )?(?:restriction |extension ))"))
},
"reduce": ReduceComplexContent
},
- "complexType": {"struct": """
+ "complexType": {
+ "struct": """
<complexType
abstract = boolean : false
block = (#all | List of (extension | restriction))
@@ -1285,31 +1330,36 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))))
</complexType>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("complexType",
- ["abstract", "block", "final", "id", "mixed", "name"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "complexType",
+ ["abstract", "block", "final", "id", "mixed", "name"],
re.compile("((?:annotation )?(?:simpleContent |complexContent |(?:(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))))"))
},
"reduce": ReduceComplexType
},
- "documentation": {"struct" : """
+ "documentation": {
+ "struct": """
<documentation
source = anyURI
xml:lang = language
{any attributes with non-schema namespace . . .}>
Content: ({any})*
</documentation>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("documentation",
- ["source", "lang"], re.compile("(.*)"), True)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "documentation",
+ ["source", "lang"],
+ re.compile("(.*)"), True)
},
"reduce": ReduceDocumentation
},
- "element": {"struct": """
+ "element": {
+ "struct": """
<element
abstract = boolean : false
block = (#all | List of (extension | restriction | substitution))
@@ -1328,64 +1378,74 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))
</element>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("element",
- ["abstract", "block", "default", "final", "fixed", "form", "id", "maxOccurs", "minOccurs", "name", "nillable", "ref", "substitutionGroup", "type"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "element",
+ ["abstract", "block", "default", "final", "fixed", "form", "id", "maxOccurs", "minOccurs", "name", "nillable", "ref", "substitutionGroup", "type"],
re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)")),
- "schema": GenerateElement("element",
- ["abstract", "block", "default", "final", "fixed", "form", "id", "name", "nillable", "substitutionGroup", "type"],
+ "schema": GenerateElement(
+ "element",
+ ["abstract", "block", "default", "final", "fixed", "form", "id", "name", "nillable", "substitutionGroup", "type"],
re.compile("((?:annotation )?(?:simpleType |complexType )?(?:unique |key |keyref )*)"))
},
"reduce": ReduceElement
},
- "enumeration": {"struct": """
+ "enumeration": {
+ "struct": """
<enumeration
id = ID
value = anySimpleType
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</enumeration>""",
- "type": SYNTAXELEMENT,
+ "type": SYNTAXELEMENT,
"extract": {
"default": GenerateElement("enumeration", ["id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("enumeration", False)
},
- "extension": {"struct": """
+ "extension": {
+ "struct": """
<extension
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))
</extension>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("extension", ["base", "id"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "extension",
+ ["base", "id"],
re.compile("((?:annotation )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))")),
- "complexContent": GenerateElement("extension", ["base", "id"],
+ "complexContent": GenerateElement(
+ "extension",
+ ["base", "id"],
re.compile("((?:annotation )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?))"))
},
"reduce": ReduceExtension
},
- "field": {"struct": """
+ "field": {
+ "struct": """
<field
id = ID
xpath = a subset of XPath expression, see below
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</field>""",
- "type": SYNTAXELEMENT,
+ "type": SYNTAXELEMENT,
"extract": {
"default": GenerateElement("field", ["id", "xpath"], ONLY_ANNOTATION)
},
"reduce": ReduceField
},
- "fractionDigits": {"struct": """
+ "fractionDigits": {
+ "struct": """
<fractionDigits
fixed = boolean : false
id = ID
@@ -1393,15 +1453,18 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</fractionDigits>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("fractionDigits",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "fractionDigits",
+ ["fixed", "id", "value"],
+ ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("fractionDigits", True)
},
- "group": {"struct": """
+ "group": {
+ "struct": """
<group
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
@@ -1411,19 +1474,22 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (all | choice | sequence)?)
</group>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("group",
- ["id", "maxOccurs", "minOccurs", "ref"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "group",
+ ["id", "maxOccurs", "minOccurs", "ref"],
re.compile("((?:annotation )?(?:all |choice |sequence )?)")),
- "schema": GenerateElement("group",
- ["id", "name"],
+ "schema": GenerateElement(
+ "group",
+ ["id", "name"],
re.compile("((?:annotation )?(?:all |choice |sequence )?)"))
},
"reduce": ReduceGroup
},
- "import": {"struct": """
+ "import": {
+ "struct": """
<import
id = ID
namespace = anyURI
@@ -1431,45 +1497,53 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</import>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("import",
- ["id", "namespace", "schemaLocation"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "import",
+ ["id", "namespace", "schemaLocation"],
+ ONLY_ANNOTATION)
},
"reduce": ReduceImport
},
- "include": {"struct": """
+ "include": {
+ "struct": """
<include
id = ID
schemaLocation = anyURI
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</include>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("include",
- ["id", "schemaLocation"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "include",
+ ["id", "schemaLocation"],
+ ONLY_ANNOTATION)
},
"reduce": ReduceInclude
},
- "key": {"struct": """
+ "key": {
+ "struct": """
<key
id = ID
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (selector, field+))
</key>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("key", ["id", "name"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "key", ["id", "name"],
re.compile("((?:annotation )?(?:selector (?:field )+))"))
},
"reduce": ReduceKey
},
- "keyref": {"struct": """
+ "keyref": {
+ "struct": """
<keyref
id = ID
name = NCName
@@ -1477,15 +1551,17 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (selector, field+))
</keyref>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("keyref", ["id", "name", "refer"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "keyref", ["id", "name", "refer"],
re.compile("((?:annotation )?(?:selector (?:field )+))"))
},
"reduce": ReduceKeyRef
},
- "length": {"struct" : """
+ "length": {
+ "struct": """
<length
fixed = boolean : false
id = ID
@@ -1493,30 +1569,33 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</length>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("length",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "length", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("length", True)
},
- "list": {"struct": """
+ "list": {
+ "struct": """
<list
id = ID
itemType = QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, simpleType?)
</list>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("list", ["id", "itemType"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "list", ["id", "itemType"],
re.compile("((?:annotation )?(?:simpleType )?)$"))
},
"reduce": ReduceList
},
- "maxExclusive": {"struct": """
+ "maxExclusive": {
+ "struct": """
<maxInclusive
fixed = boolean : false
id = ID
@@ -1524,15 +1603,16 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxInclusive>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("maxExclusive",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "maxExclusive", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("maxExclusive", True)
},
- "maxInclusive": {"struct": """
+ "maxInclusive": {
+ "struct": """
<maxExclusive
fixed = boolean : false
id = ID
@@ -1540,15 +1620,16 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxExclusive>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("maxInclusive",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "maxInclusive", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("maxInclusive", True)
},
- "maxLength": {"struct": """
+ "maxLength": {
+ "struct": """
<maxLength
fixed = boolean : false
id = ID
@@ -1556,15 +1637,16 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</maxLength>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("maxLength",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "maxLength", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("maxLength", True)
},
- "minExclusive": {"struct": """
+ "minExclusive": {
+ "struct": """
<minExclusive
fixed = boolean : false
id = ID
@@ -1572,15 +1654,16 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minExclusive>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("minExclusive",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "minExclusive", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("minExclusive", True)
},
- "minInclusive": {"struct": """
+ "minInclusive": {
+ "struct": """
<minInclusive
fixed = boolean : false
id = ID
@@ -1588,15 +1671,16 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minInclusive>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("minInclusive",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "minInclusive", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("minInclusive", True)
},
- "minLength": {"struct": """
+ "minLength": {
+ "struct": """
<minLength
fixed = boolean : false
id = ID
@@ -1604,63 +1688,74 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</minLength>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("minLength",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "minLength", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("minLength", True)
},
- "pattern": {"struct": """
+ "pattern": {
+ "struct": """
<pattern
id = ID
value = string
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</pattern>""",
- "type": SYNTAXELEMENT,
+ "type": SYNTAXELEMENT,
"extract": {
"default": GenerateElement("pattern", ["id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("pattern", False)
},
- "redefine": {"struct": """
+ "redefine": {
+ "struct": """
<redefine
id = ID
schemaLocation = anyURI
{any attributes with non-schema namespace . . .}>
Content: (annotation | (simpleType | complexType | group | attributeGroup))*
</redefine>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("refine", ["id", "schemaLocation"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "refine", ["id", "schemaLocation"],
re.compile("((?:annotation |(?:simpleType |complexType |group |attributeGroup ))*)"))
},
"reduce": ReduceRedefine
},
- "restriction": {"struct": """
+ "restriction": {
+ "struct": """
<restriction
base = QName
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?))
</restriction>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("restriction", ["base", "id"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "restriction",
+ ["base", "id"],
re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)))")),
- "simpleContent": GenerateElement("restriction", ["base", "id"],
+ "simpleContent": GenerateElement(
+ "restriction",
+ ["base", "id"],
re.compile("((?:annotation )?(?:(?:simpleType )?(?:(?:minExclusive |minInclusive |maxExclusive |maxInclusive |totalDigits |fractionDigits |length |minLength |maxLength |enumeration |whiteSpace |pattern )*)?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")),
- "complexContent": GenerateElement("restriction", ["base", "id"],
+ "complexContent": GenerateElement(
+ "restriction",
+ ["base", "id"],
re.compile("((?:annotation )?(?:(?:simpleType )?(?:group |all |choice |sequence )?(?:(?:attribute |attributeGroup )*(?:anyAttribute )?)))")),
},
"reduce": ReduceRestriction
},
- "schema": {"struct": """
+ "schema": {
+ "struct": """
<schema
attributeFormDefault = (qualified | unqualified) : unqualified
blockDefault = (#all | List of (extension | restriction | substitution)) : ''
@@ -1673,29 +1768,39 @@
{any attributes with non-schema namespace . . .}>
Content: ((include | import | redefine | annotation)*, (((simpleType | complexType | group | attributeGroup) | element | attribute | notation), annotation*)*)
</schema>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("schema",
- ["attributeFormDefault", "blockDefault", "elementFormDefault", "finalDefault", "id", "targetNamespace", "version", "lang"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "schema",
+ ["attributeFormDefault",
+ "blockDefault",
+ "elementFormDefault",
+ "finalDefault",
+ "id",
+ "targetNamespace",
+ "version",
+ "lang"],
re.compile("((?:include |import |redefine |annotation )*(?:(?:(?:simpleType |complexType |group |attributeGroup )|element |attribute |annotation )(?:annotation )*)*)"))
}
},
- "selector": {"struct": """
+ "selector": {
+ "struct": """
<selector
id = ID
xpath = a subset of XPath expression, see below
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</selector>""",
- "type": SYNTAXELEMENT,
+ "type": SYNTAXELEMENT,
"extract": {
"default": GenerateElement("selector", ["id", "xpath"], ONLY_ANNOTATION)
},
"reduce": ReduceSelector
},
- "sequence": {"struct": """
+ "sequence": {
+ "struct": """
<sequence
id = ID
maxOccurs = (nonNegativeInteger | unbounded) : 1
@@ -1703,29 +1808,33 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (element | group | choice | sequence | any)*)
</sequence>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("sequence", ["id", "maxOccurs", "minOccurs"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "sequence", ["id", "maxOccurs", "minOccurs"],
re.compile("((?:annotation )?(?:element |group |choice |sequence |any )*)"))
},
"reduce": ReduceSequence
},
- "simpleContent": {"struct" : """
+ "simpleContent": {
+ "struct": """
<simpleContent
id = ID
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (restriction | extension))
</simpleContent>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("simpleContent", ["id"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "simpleContent", ["id"],
re.compile("((?:annotation )?(?:restriction |extension ))"))
},
"reduce": ReduceSimpleContent
},
- "simpleType": {"struct" : """
+ "simpleType": {
+ "struct": """
<simpleType
final = (#all | List of (list | union | restriction))
id = ID
@@ -1733,15 +1842,17 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (restriction | list | union))
</simpleType>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("simpleType", ["final", "id", "name"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "simpleType", ["final", "id", "name"],
re.compile("((?:annotation )?(?:restriction |list |union ))"))
},
"reduce": ReduceSimpleType
},
- "totalDigits": {"struct" : """
+ "totalDigits": {
+ "struct": """
<totalDigits
fixed = boolean : false
id = ID
@@ -1749,45 +1860,50 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</totalDigits>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("totalDigits",
- ["fixed", "id", "value"], ONLY_ANNOTATION),
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "totalDigits", ["fixed", "id", "value"], ONLY_ANNOTATION),
},
"reduce": GenerateFacetReducing("totalDigits", True)
},
- "union": {"struct": """
+ "union": {
+ "struct": """
<union
id = ID
memberTypes = List of QName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, simpleType*)
</union>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("union", ["id", "memberTypes"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "union", ["id", "memberTypes"],
re.compile("((?:annotation )?(?:simpleType )*)"))
},
"reduce": ReduceUnion
},
- "unique": {"struct": """
+ "unique": {
+ "struct": """
<unique
id = ID
name = NCName
{any attributes with non-schema namespace . . .}>
Content: (annotation?, (selector, field+))
</unique>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("unique", ["id", "name"],
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "unique", ["id", "name"],
re.compile("((?:annotation )?(?:selector |(?:field )+))"))
},
"reduce": ReduceUnique
},
-
- "whiteSpace": {"struct" : """
+
+ "whiteSpace": {
+ "struct": """
<whiteSpace
fixed = boolean : false
id = ID
@@ -1795,20 +1911,20 @@
{any attributes with non-schema namespace . . .}>
Content: (annotation?)
</whiteSpace>""",
- "type": SYNTAXELEMENT,
- "extract": {
- "default": GenerateElement("whiteSpace",
- ["fixed", "id", "value"], ONLY_ANNOTATION)
+ "type": SYNTAXELEMENT,
+ "extract": {
+ "default": GenerateElement(
+ "whiteSpace", ["fixed", "id", "value"], ONLY_ANNOTATION)
},
"reduce": GenerateFacetReducing("whiteSpace", True)
},
-#-------------------------------------------------------------------------------
-# Syntax attributes definition
-#-------------------------------------------------------------------------------
+ # -------------------------------------------------------------------------------
+ # Syntax attributes definition
+ # -------------------------------------------------------------------------------
"abstract": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetBoolean
},
@@ -1818,31 +1934,32 @@
},
"attributeFormDefault": {
- "type": SYNTAXATTRIBUTE,
- "extract": {
- "default": GenerateEnumeratedExtraction("member attributeFormDefault", ["qualified", "unqualified"])
+ "type": SYNTAXATTRIBUTE,
+ "extract": {
+ "default": GenerateEnumeratedExtraction(
+ "member attributeFormDefault", ["qualified", "unqualified"])
},
"default": {
"default": "unqualified"
}
},
-
+
"base": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member base", QName_model)
}
},
-
+
"block": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateGetList("block", ["restriction", "extension", "substitution"])
}
},
-
+
"blockDefault": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateGetList("block", ["restriction", "extension", "substitution"])
},
@@ -1850,16 +1967,16 @@
"default": ""
}
},
-
+
"default": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetAttributeValue
}
},
"elementFormDefault": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateEnumeratedExtraction("member elementFormDefault", ["qualified", "unqualified"])
},
@@ -1867,9 +1984,9 @@
"default": "unqualified"
}
},
-
+
"final": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateGetList("final", ["restriction", "extension", "substitution"]),
"simpleType": GenerateGetList("final", ["list", "union", "restriction"])
@@ -1877,7 +1994,7 @@
},
"finalDefault": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateGetList("finalDefault", ["restriction", "extension", "list", "union"])
},
@@ -1885,9 +2002,9 @@
"default": ""
}
},
-
+
"fixed": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetBoolean,
"attribute": GetAttributeValue,
@@ -1901,35 +2018,35 @@
},
"form": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateEnumeratedExtraction("member form", ["qualified", "unqualified"])
}
},
"id": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member id", NCName_model)
}
},
-
+
"itemType": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member itemType", QName_model)
}
},
"memberTypes": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameListExtraction("member memberTypes", QNames_model)
},
},
-
+
"maxOccurs": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateLimitExtraction(),
"all": GenerateLimitExtraction(1, 1, False)
@@ -1940,9 +2057,9 @@
},
"minOccurs": {
- "type": SYNTAXATTRIBUTE,
- "extract": {
- "default": GenerateLimitExtraction(unbounded = False),
+ "type": SYNTAXATTRIBUTE,
+ "extract": {
+ "default": GenerateLimitExtraction(unbounded=False),
"all": GenerateLimitExtraction(0, 1, False)
},
"default": {
@@ -1951,7 +2068,7 @@
},
"mixed": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetBoolean
},
@@ -1960,16 +2077,16 @@
"complexType": False
}
},
-
+
"name": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member name", NCName_model)
}
},
-
+
"namespace": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member namespace", URI_model),
"any": GetNamespaces
@@ -1981,14 +2098,14 @@
},
"nillable": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetBoolean
},
},
-
+
"processContents": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateEnumeratedExtraction("member processContents", ["lax", "skip", "strict"])
},
@@ -1996,9 +2113,9 @@
"default": "strict"
}
},
-
+
"ref": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member ref", QName_model)
}
@@ -2010,44 +2127,44 @@
"default": GenerateModelNameExtraction("member refer", QName_model)
}
},
-
+
"schemaLocation": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member schemaLocation", URI_model)
}
},
-
+
"source": {
"type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member source", URI_model)
}
},
-
+
"substitutionGroup": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member substitutionGroup", QName_model)
}
},
"targetNamespace": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member targetNamespace", URI_model)
}
},
-
+
"type": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateModelNameExtraction("member type", QName_model)
}
},
"use": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GenerateEnumeratedExtraction("member usage", ["required", "optional", "prohibited"])
},
@@ -2057,7 +2174,7 @@
},
"value": {
- "type": SYNTAXATTRIBUTE,
+ "type": SYNTAXATTRIBUTE,
"extract": {
"default": GetAttributeValue,
"fractionDigits": GenerateIntegerExtraction(minInclusive=0),
@@ -2077,23 +2194,23 @@
},
"xpath": {
- "type": SYNTAXATTRIBUTE,
- "extract": {
-# "default": NotSupportedYet("xpath")
+ "type": SYNTAXATTRIBUTE,
+ "extract": {
+ # "default": NotSupportedYet("xpath")
"default": GetAttributeValue
}
},
-
-#-------------------------------------------------------------------------------
-# Simple types definition
-#-------------------------------------------------------------------------------
+
+ # -------------------------------------------------------------------------------
+ # Simple types definition
+ # -------------------------------------------------------------------------------
"string": {
"type": SIMPLETYPE,
"basename": "string",
"extract": GetAttributeValue,
"facets": STRING_FACETS,
- "generate": GenerateSimpleTypeXMLText(lambda x : x),
+ "generate": GenerateSimpleTypeXMLText(lambda x: x),
"initial": lambda: "",
"check": lambda x: isinstance(x, (StringType, UnicodeType))
},
@@ -2103,61 +2220,61 @@
"basename": "normalizedString",
"extract": GetNormalizedString,
"facets": STRING_FACETS,
- "generate": GenerateSimpleTypeXMLText(lambda x : x),
+ "generate": GenerateSimpleTypeXMLText(lambda x: x),
"initial": lambda: "",
"check": lambda x: isinstance(x, (StringType, UnicodeType))
},
"token": {
"type": SIMPLETYPE,
- "basename": "token",
+ "basename": "token",
"extract": GetToken,
"facets": STRING_FACETS,
- "generate": GenerateSimpleTypeXMLText(lambda x : x),
+ "generate": GenerateSimpleTypeXMLText(lambda x: x),
"initial": lambda: "",
"check": lambda x: isinstance(x, (StringType, UnicodeType))
},
-
+
"base64Binary": {
- "type": SIMPLETYPE,
- "basename": "base64Binary",
+ "type": SIMPLETYPE,
+ "basename": "base64Binary",
"extract": NotSupportedYet("base64Binary"),
"facets": STRING_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
"check": lambda x: isinstance(x, (IntType, LongType))
},
-
+
"hexBinary": {
"type": SIMPLETYPE,
- "basename": "hexBinary",
+ "basename": "hexBinary",
"extract": GetHexInteger,
"facets": STRING_FACETS,
- "generate": GenerateSimpleTypeXMLText(lambda x: ("%."+str(int(round(len("%X"%x)/2.)*2))+"X")%x),
+ "generate": GenerateSimpleTypeXMLText(lambda x: ("%."+str(int(round(len("%X" % x)/2.)*2))+"X") % x),
"initial": lambda: 0,
"check": lambda x: isinstance(x, (IntType, LongType))
},
"integer": {
"type": SIMPLETYPE,
- "basename": "integer",
+ "basename": "integer",
"extract": GenerateIntegerExtraction(),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
"check": lambda x: isinstance(x, IntType)
},
-
+
"positiveInteger": {
"type": SIMPLETYPE,
- "basename": "positiveInteger",
+ "basename": "positiveInteger",
"extract": GenerateIntegerExtraction(minExclusive=0),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 1,
"check": lambda x: isinstance(x, IntType)
},
-
+
"negativeInteger": {
"type": SIMPLETYPE,
"basename": "negativeInteger",
@@ -2167,41 +2284,41 @@
"initial": lambda: -1,
"check": lambda x: isinstance(x, IntType)
},
-
+
"nonNegativeInteger": {
- "type": SIMPLETYPE,
- "basename": "nonNegativeInteger",
+ "type": SIMPLETYPE,
+ "basename": "nonNegativeInteger",
"extract": GenerateIntegerExtraction(minInclusive=0),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
"check": lambda x: isinstance(x, IntType)
},
-
+
"nonPositiveInteger": {
"type": SIMPLETYPE,
- "basename": "nonPositiveInteger",
+ "basename": "nonPositiveInteger",
"extract": GenerateIntegerExtraction(maxInclusive=0),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
"check": lambda x: isinstance(x, IntType)
},
-
+
"long": {
"type": SIMPLETYPE,
"basename": "long",
- "extract": GenerateIntegerExtraction(minInclusive=-2**63,maxExclusive=2**63),
+ "extract": GenerateIntegerExtraction(minInclusive=-2**63, maxExclusive=2**63),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
"check": lambda x: isinstance(x, IntType)
},
-
+
"unsignedLong": {
"type": SIMPLETYPE,
"basename": "unsignedLong",
- "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**64),
+ "extract": GenerateIntegerExtraction(minInclusive=0, maxExclusive=2**64),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2211,7 +2328,7 @@
"int": {
"type": SIMPLETYPE,
"basename": "int",
- "extract": GenerateIntegerExtraction(minInclusive=-2**31,maxExclusive=2**31),
+ "extract": GenerateIntegerExtraction(minInclusive=-2**31, maxExclusive=2**31),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2221,7 +2338,7 @@
"unsignedInt": {
"type": SIMPLETYPE,
"basename": "unsignedInt",
- "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**32),
+ "extract": GenerateIntegerExtraction(minInclusive=0, maxExclusive=2**32),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2231,7 +2348,7 @@
"short": {
"type": SIMPLETYPE,
"basename": "short",
- "extract": GenerateIntegerExtraction(minInclusive=-2**15,maxExclusive=2**15),
+ "extract": GenerateIntegerExtraction(minInclusive=-2**15, maxExclusive=2**15),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2240,8 +2357,8 @@
"unsignedShort": {
"type": SIMPLETYPE,
- "basename": "unsignedShort",
- "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**16),
+ "basename": "unsignedShort",
+ "extract": GenerateIntegerExtraction(minInclusive=0, maxExclusive=2**16),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2251,7 +2368,7 @@
"byte": {
"type": SIMPLETYPE,
"basename": "byte",
- "extract": GenerateIntegerExtraction(minInclusive=-2**7,maxExclusive=2**7),
+ "extract": GenerateIntegerExtraction(minInclusive=-2**7, maxExclusive=2**7),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2261,7 +2378,7 @@
"unsignedByte": {
"type": SIMPLETYPE,
"basename": "unsignedByte",
- "extract": GenerateIntegerExtraction(minInclusive=0,maxExclusive=2**8),
+ "extract": GenerateIntegerExtraction(minInclusive=0, maxExclusive=2**8),
"facets": DECIMAL_FACETS,
"generate": GenerateSimpleTypeXMLText(str),
"initial": lambda: 0,
@@ -2285,7 +2402,7 @@
"facets": NUMBER_FACETS,
"generate": GenerateFloatXMLText(["INF", "-INF", "NaN"]),
"initial": lambda: 0.,
- "check": lambda x: {"INF" : True, "-INF" : True, "NaN" : True}.get(x, isinstance(x, (IntType, FloatType)))
+ "check": lambda x: {"INF": True, "-INF": True, "NaN": True}.get(x, isinstance(x, (IntType, FloatType)))
},
"double": {
@@ -2295,7 +2412,7 @@
"facets": NUMBER_FACETS,
"generate": GenerateFloatXMLText(["INF", "-INF", "NaN"]),
"initial": lambda: 0.,
- "check": lambda x: {"INF" : True, "-INF" : True, "NaN" : True}.get(x, isinstance(x, (IntType, FloatType)))
+ "check": lambda x: {"INF": True, "-INF": True, "NaN": True}.get(x, isinstance(x, (IntType, FloatType)))
},
"boolean": {
@@ -2303,10 +2420,10 @@
"basename": "boolean",
"extract": GetBoolean,
"facets": GenerateDictFacets(["pattern", "whiteSpace"]),
- "generate": GenerateSimpleTypeXMLText(lambda x:{True : "true", False : "false"}[x]),
+ "generate": GenerateSimpleTypeXMLText(lambda x: {True: "true", False: "false"}[x]),
"initial": lambda: False,
"check": lambda x: isinstance(x, BooleanType)
- },
+ },
"duration": {
"type": SIMPLETYPE,
@@ -2324,7 +2441,7 @@
"extract": GetDateTime,
"facets": NUMBER_FACETS,
"generate": GenerateSimpleTypeXMLText(datetime.datetime.isoformat),
- "initial": lambda: datetime.datetime(1,1,1,0,0,0,0),
+ "initial": lambda: datetime.datetime(1, 1, 1, 0, 0, 0, 0),
"check": lambda x: isinstance(x, datetime.datetime)
},
@@ -2334,17 +2451,17 @@
"extract": GetDate,
"facets": NUMBER_FACETS,
"generate": GenerateSimpleTypeXMLText(datetime.date.isoformat),
- "initial": lambda: datetime.date(1,1,1),
+ "initial": lambda: datetime.date(1, 1, 1),
"check": lambda x: isinstance(x, datetime.date)
},
-
+
"time": {
"type": SIMPLETYPE,
"basename": "time",
"extract": GetTime,
"facets": NUMBER_FACETS,
"generate": GenerateSimpleTypeXMLText(datetime.time.isoformat),
- "initial": lambda: datetime.time(0,0,0,0),
+ "initial": lambda: datetime.time(0, 0, 0, 0),
"check": lambda x: isinstance(x, datetime.time)
},
@@ -2407,7 +2524,7 @@
"initial": lambda: "",
"check": lambda x: isinstance(x, (StringType, UnicodeType))
},
-
+
"QName": {
"type": SIMPLETYPE,
"basename": "QName",
@@ -2529,6 +2646,5 @@
},
# Complex Types
- "anyType": {"type": COMPLEXTYPE, "extract": lambda x:None},
+ "anyType": {"type": COMPLEXTYPE, "extract": lambda x: None},
}
-