--- a/Beremiz.py Wed Mar 13 12:34:55 2013 +0900
+++ b/Beremiz.py Wed Jul 31 10:45:07 2013 +0900
@@ -130,7 +130,7 @@
AddBitmapFolder(os.path.join(extension_folder, "images"))
execfile(extfilename, locals())
-import wx.lib.buttons, wx.lib.statbmp
+import wx.lib.buttons, wx.lib.statbmp, wx.stc import types, time, re, platform, time, traceback, commands
@@ -146,6 +146,8 @@
from editors.DataTypeEditor import DataTypeEditor
from util.MiniTextControler import MiniTextControler
from util.ProcessLogger import ProcessLogger
+from controls.LogViewer import LogViewer +from controls.CustomStyledTextCtrl import CustomStyledTextCtrl 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, MATIEC_ERROR_MODEL, ITEM_CONFNODE
@@ -176,7 +178,17 @@
dc.DrawBitmap(self._bitmap, 0, 0, True)
+if wx.Platform == '__WXMSW__': + 'mono' : 'Courier New', from threading import Lock,Timer,currentThread
MainThread = currentThread().ident
@@ -184,10 +196,9 @@
""" Base class for file like objects to facilitate StdOut for the Shell."""
def __init__(self, output, risecall):
- self.red_white = wx.TextAttr("RED", "WHITE")
- self.red_yellow = wx.TextAttr("RED", "YELLOW")
- self.black_white = wx.TextAttr("BLACK", "WHITE")
- self.default_style = None
+ self.black_white = wx.stc.STC_STYLE_DEFAULT # to prevent rapid fire on rising log panel
@@ -242,14 +253,21 @@
for s, style in self.stack:
if style is None : style=self.black_white
- if self.default_style != style:
- self.output.SetDefaultStyle(style)
- self.default_style = style
+ if style != self.black_white: + self.output.StartStyling(self.output.GetLength(), 0xff) + # Temporary deactivate read only mode on StyledTextCtrl for + # adding text. It seems that text modifications, even + # programmatically, are disabled in StyledTextCtrl when read + self.output.SetReadOnly(False) self.output.AppendText(s)
- self.output.ScrollLines(s.count('\n')+1)
+ self.output.SetReadOnly(True) + if style != self.black_white: + self.output.SetStyling(len(s), style) - self.output.ShowPosition(self.output.GetLastPosition())
self.LastRefreshTime = gettime()
@@ -258,7 +276,7 @@
if newtime - self.rising_timer > 1:
+ self.risecall(self.output) self.rising_timer = newtime
def write_warning(self, s):
@@ -272,10 +290,15 @@
- self.output.SetValue("")
+ # Temporary deactivate read only mode on StyledTextCtrl for clearing + # text. It seems that text modifications, even programmatically, are + # disabled in StyledTextCtrl when read only is active + self.output.SetReadOnly(False) + self.output.SetText("") + self.output.SetReadOnly(True)
[ID_BEREMIZ, ID_BEREMIZMAINSPLITTER,
ID_BEREMIZPLCCONFIG, ID_BEREMIZLOGCONSOLE,
@@ -287,7 +310,7 @@
CONFNODEMENU_POSITION = 3
self.ConfNodeMenu = wx.Menu(title='')
self.RecentProjectsMenu = wx.Menu(title='')
@@ -339,10 +362,13 @@
def _init_coll_AddMenu_Items(self, parent):
IDEFrame._init_coll_AddMenu_Items(self, parent, False)
- AppendMenu(parent, help='', id=new_id,
- kind=wx.ITEM_NORMAL, text=_(u'&Resource'))
- self.Bind(wx.EVT_MENU, self.AddResourceMenu, id=new_id)
+ # Disable add resource until matiec is able to handle multiple ressource definition + #AppendMenu(parent, help='', id=new_id, + # kind=wx.ITEM_NORMAL, text=_(u'&Resource')) + #self.Bind(wx.EVT_MENU, self.AddResourceMenu, id=new_id) for name, XSDClass, help in ProjectController.CTNChildrenTypes:
AppendMenu(parent, help='', id=new_id,
@@ -354,6 +380,15 @@
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): + parent.SetFieldsCount(3) + parent.SetStatusText(number=0, text='') + parent.SetStatusText(number=1, text='') + parent.SetStatusText(number=2, text='') + parent.SetStatusWidths([-1, 300, 200]) def _init_ctrls(self, prnt):
IDEFrame._init_ctrls(self, prnt)
@@ -378,14 +413,40 @@
self.SetAcceleratorTable(wx.AcceleratorTable(accels))
- self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
+ self.LogConsole = CustomStyledTextCtrl(id=ID_BEREMIZLOGCONSOLE, name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
- size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
- self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
- self.MainTabs["LogConsole"] = (self.LogConsole, _("Log Console"))
+ self.LogConsole.Bind(wx.EVT_SET_FOCUS, self.OnLogConsoleFocusChanged) + self.LogConsole.Bind(wx.EVT_KILL_FOCUS, self.OnLogConsoleFocusChanged) + self.LogConsole.Bind(wx.stc.EVT_STC_UPDATEUI, self.OnLogConsoleUpdateUI) + self.LogConsole.SetReadOnly(True) + self.LogConsole.SetWrapMode(wx.stc.STC_WRAP_CHAR) + # Define Log Console styles + self.LogConsole.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) + self.LogConsole.StyleClearAll() + self.LogConsole.StyleSetSpec(1, "face:%(mono)s,fore:#FF0000,size:%(size)d" % faces) + self.LogConsole.StyleSetSpec(2, "face:%(mono)s,fore:#FF0000,back:#FFFF00,size:%(size)d" % faces) + # Define Log Console markers + self.LogConsole.SetMarginSensitive(1, True) + self.LogConsole.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL) + self.LogConsole.MarkerDefine(0, wx.stc.STC_MARK_CIRCLE, "BLACK", "RED") + self.LogConsole.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT) + self.LogConsole.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnLogConsoleMarginClick) + self.LogConsole.Bind(wx.stc.EVT_STC_MODIFIED, self.OnLogConsoleModified) + self.MainTabs["LogConsole"] = (self.LogConsole, _("Console")) self.BottomNoteBook.AddPage(*self.MainTabs["LogConsole"])
#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) StatusToolBar = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize,
wx.TB_FLAT | wx.TB_NODIVIDER | wx.NO_BORDER)
StatusToolBar.SetToolBitmapSize(wx.Size(25, 25))
@@ -398,9 +459,13 @@
+ self.ConnectionStatusBar = wx.StatusBar(self, style=wx.ST_SIZEGRIP) + self._init_coll_ConnectionStatusBar_Fields(self.ConnectionStatusBar) + self.SetStatusBar(self.ConnectionStatusBar) def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
IDEFrame.__init__(self, parent, debug)
- self.Log = LogPseudoFile(self.LogConsole,self.RiseLogConsole)
+ self.Log = LogPseudoFile(self.LogConsole,self.SelectTab) self.local_runtime = None
@@ -433,15 +498,6 @@
if projectOpen is not None:
projectOpen = DecodeFileSystemPath(projectOpen, False)
- if (self.EnableSaveProjectState() and ctr is None and
- projectOpen is None and self.Config.HasEntry("currenteditedproject")):
- projectOpen = DecodeFileSystemPath(self.Config.Read("currenteditedproject"))
if projectOpen is not None and os.path.isdir(projectOpen):
self.CTR = ProjectController(self, self.Log)
self.Controler = self.CTR
@@ -472,9 +528,6 @@
self.LogConsole.SetFocus()
- def RiseLogConsole(self):
- self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.LogConsole))
@@ -527,21 +580,37 @@
InspectionTool().Show(wnd, True)
- def OnLogConsoleDClick(self, event):
- wx.CallAfter(self.SearchLineForError)
+ def OnLogConsoleFocusChanged(self, event): + def OnLogConsoleUpdateUI(self, event): + self.SetCopyBuffer(self.LogConsole.GetSelectedText(), True) - def SearchLineForError(self):
+ def OnLogConsoleMarginClick(self, event): + line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) + wx.CallAfter(self.SearchLineForError, self.LogConsole.GetLine(line_idx)) + def OnLogConsoleModified(self, event): + line_idx = self.LogConsole.LineFromPosition(event.GetPosition()) + line = self.LogConsole.GetLine(line_idx) + result = MATIEC_ERROR_MODEL.match(line) + self.LogConsole.MarkerAdd(line_idx, 0) + def SearchLineForError(self, line): - text = self.LogConsole.GetRange(0, self.LogConsole.GetInsertionPoint())
- line = self.LogConsole.GetLineText(len(text.splitlines()) - 1)
result = MATIEC_ERROR_MODEL.match(line)
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.
def CheckSaveBeforeClosing(self, title=_("Close Project")):
@@ -590,6 +659,10 @@
return IDEFrame.LoadTab(self, notebook, page_infos)
def OnCloseFrame(self, event):
+ for evt_type in [wx.EVT_SET_FOCUS, + wx.stc.EVT_STC_UPDATEUI]: + self.LogConsole.Unbind(evt_type) if self.CTR is None or self.CheckSaveBeforeClosing(_("Close Application")):
self.CTR.KillDebugThread()
@@ -597,13 +670,6 @@
- if self.CTR is not None:
- project_path = os.path.realpath(self.CTR.GetProjectPath())
- self.Config.Write("currenteditedproject", EncodeFileSystemPath(project_path))
@@ -728,6 +794,9 @@
def RefreshEditMenu(self):
IDEFrame.RefreshEditMenu(self)
+ if self.FindFocus() == self.LogConsole: + self.EditMenu.Enable(wx.ID_COPY, True) + self.Panes["MenuToolBar"].EnableTool(wx.ID_COPY, True) selected = self.TabsOpened.GetSelection()
@@ -781,6 +850,10 @@
def GetConfigEntry(self, entry_name, default):
return cPickle.loads(str(self.Config.Read(entry_name, cPickle.dumps(default))))
+ def ResetConnectionStatusBar(self): + for field in xrange(self.ConnectionStatusBar.GetFieldsCount()): + self.ConnectionStatusBar.SetStatusText('', field) @@ -790,6 +863,7 @@
self.DebugVariablePanel.SetDataProducer(None)
+ self.ResetConnectionStatusBar() def RefreshConfigRecentProjects(self, projectpath):
@@ -808,10 +882,6 @@
IDEFrame.ResetPerspective(self)
self.RefreshStatusToolBar()
- def RestoreLastLayout(self):
- IDEFrame.RestoreLastLayout(self)
- self.RefreshStatusToolBar()
def OnNewProjectMenu(self, event):
if self.CTR is not None and not self.CheckSaveBeforeClosing():
@@ -878,8 +948,6 @@
self.RefreshConfigRecentProjects(projectpath)
self.DebugVariablePanel.SetDataProducer(self.CTR)
- if self.EnableSaveProjectState():
- self.LoadProjectLayout()
self._Refresh(PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
@@ -893,7 +961,6 @@
if self.CTR is not None and not self.CheckSaveBeforeClosing():
- self.SaveProjectLayout()
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU)
@@ -917,7 +984,6 @@
self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES)
def OnQuitMenu(self, event):
@@ -933,10 +999,7 @@
IDEFrame.OnProjectTreeItemBeginEdit(self, event)
def OnProjectTreeRightUp(self, event):
- if wx.Platform == '__WXMSW__':
- item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY()))
item_infos = self.ProjectTree.GetPyData(item)
if item_infos["type"] == ITEM_CONFNODE:
@@ -964,6 +1027,11 @@
+ elif item_infos["type"] != ITEM_PROJECT: + parent = self.ProjectTree.GetItemParent(item) + parent_name = self.ProjectTree.GetItemText(parent) + if item_infos["type"] != ITEM_RESOURCE or parent_name == _("Resources"): + IDEFrame.OnProjectTreeRightUp(self, event) IDEFrame.OnProjectTreeRightUp(self, event)
@@ -980,15 +1048,15 @@
IDEFrame.OnProjectTreeItemActivated(self, event)
def ProjectTreeItemSelect(self, select_item):
- name = self.ProjectTree.GetItemText(select_item)
- item_infos = self.ProjectTree.GetPyData(select_item)
- if item_infos["type"] == ITEM_CONFNODE:
- item_infos["confnode"]._OpenView(onlyopened=True)
- elif item_infos["type"] == ITEM_PROJECT:
- self.CTR._OpenView(onlyopened=True)
- IDEFrame.ProjectTreeItemSelect(self, select_item)
+ if select_item is not None and select_item.IsOk(): + name = self.ProjectTree.GetItemText(select_item) + item_infos = self.ProjectTree.GetPyData(select_item) + if item_infos["type"] == ITEM_CONFNODE: + item_infos["confnode"]._OpenView(onlyopened=True) + elif item_infos["type"] == ITEM_PROJECT: + self.CTR._OpenView(onlyopened=True) + IDEFrame.ProjectTreeItemSelect(self, select_item) def SelectProjectTreeItem(self, tagname):
if self.ProjectTree is not None:
@@ -999,13 +1067,13 @@
self.ProjectTree.SelectItem(root)
- wx.CallAfter(self.ResetSelectedItem)
+ self.ResetSelectedItem() return self.RecursiveProjectTreeItemSelection(root,
[(word, ITEM_CONFNODE) for word in tagname.split(".")])
return self.RecursiveProjectTreeItemSelection(root, [(words[2], ITEM_RESOURCE)])
+ elif not os.path.exists(words[0]): IDEFrame.SelectProjectTreeItem(self, tagname)
def GetAddConfNodeFunction(self, name, confnode=None):
@@ -1065,6 +1133,7 @@
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
+import threading, traceback Max_Traceback_List_Size = 20
@@ -1159,11 +1228,26 @@
#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) + def run_with_except_hook(*args, **kw): + except (KeyboardInterrupt, SystemExit): + sys.excepthook(*sys.exc_info()) + self.run = run_with_except_hook + threading.Thread.__init__ = init if __name__ == '__main__':
# Install a exception handle for bug reports
AddExceptHook(os.getcwd(),updateinfo_url)
frame = Beremiz(None, projectOpen, buildpath)
--- a/IDEFrame.py Wed Mar 13 12:34:55 2013 +0900
+++ b/IDEFrame.py Wed Jul 31 10:45:07 2013 +0900
@@ -22,7 +22,8 @@
from editors.ResourceEditor import ConfigurationEditor, ResourceEditor
from editors.DataTypeEditor import DataTypeEditor
from PLCControler import *
-from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, DebugVariablePanel, SearchResultPanel
+from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, SearchResultPanel +from controls.DebugVariablePanel import DebugVariablePanel from dialogs import ProjectDialog, PouDialog, PouTransitionDialog, PouActionDialog, FindInPouDialog, SearchInProjectDialog
from util.BitmapLibrary import GetBitmap
@@ -210,15 +211,13 @@
def GetDeleteElementFunction(remove_function, parent_type=None, check_function=None):
def DeleteElementFunction(self, selected):
name = self.ProjectTree.GetItemText(selected)
- if check_function is None or not check_function(self.Controler, name):
+ if check_function is None or check_function(name): if parent_type is not None:
item_infos = self.ProjectTree.GetPyData(selected)
parent_name = item_infos["tagname"].split("::")[1]
remove_function(self.Controler, parent_name, name)
remove_function(self.Controler, name)
- self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!")%name)
return DeleteElementFunction
if wx.Platform == '__WXMSW__':
@@ -308,8 +307,6 @@
class IDEFrame(wx.Frame):
# Compatibility function for wx versions < 2.6
if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
@@ -457,7 +454,6 @@
style=wx.DEFAULT_FRAME_STYLE)
self.SetClientSize(wx.Size(1000, 600))
self.Bind(wx.EVT_ACTIVATE, self.OnActivated)
- self.Bind(wx.EVT_SIZE, self.OnResize)
self.TabsImageList = wx.ImageList(31, 16)
self.TabsImageListIndexes = {}
@@ -526,22 +522,18 @@
self.ProjectTree = CustomTree(id=ID_PLCOPENEDITORPROJECTTREE,
name='ProjectTree', parent=self.ProjectPanel,
pos=wx.Point(0, 0), size=wx.Size(0, 0),
- style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_EDIT_LABELS)
+ 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)
self._init_coll_AddMenu_Items(add_menu)
self.ProjectTree.SetAddMenu(add_menu)
- if wx.Platform == '__WXMSW__':
- self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp,
- id=ID_PLCOPENEDITORPROJECTTREE)
- self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnProjectTreeItemSelected,
- id=ID_PLCOPENEDITORPROJECTTREE)
- self.ProjectTree.Bind(wx.EVT_RIGHT_UP, self.OnProjectTreeRightUp)
- self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp)
- self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging,
- id=ID_PLCOPENEDITORPROJECTTREE)
+ self.Bind(wx.EVT_TREE_ITEM_RIGHT_CLICK, self.OnProjectTreeRightUp, + id=ID_PLCOPENEDITORPROJECTTREE) + self.ProjectTree.Bind(wx.EVT_LEFT_UP, self.OnProjectTreeLeftUp) + self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnProjectTreeItemChanging, + id=ID_PLCOPENEDITORPROJECTTREE) self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnProjectTreeBeginDrag,
id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnProjectTreeItemBeginEdit,
@@ -550,6 +542,7 @@
id=ID_PLCOPENEDITORPROJECTTREE)
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnProjectTreeItemActivated,
id=ID_PLCOPENEDITORPROJECTTREE)
+ self.ProjectTree.Bind(wx.EVT_MOTION, self.OnProjectTreeMotion) #-----------------------------------------------------------------------
# Creating PLCopen Project POU Instance Variables Panel
@@ -677,12 +670,24 @@
self.CurrentEditorToolBar = []
+ self.LastToolTipItem = None self.DrawingMode = FREEDRAWING_MODE
#self.DrawingMode = DRIVENDRAWING_MODE
- self.DefaultPerspective = None
+ # Save default perspective + for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"), + (self.BottomNoteBook, "bottomnotebook"), + (self.RightNoteBook, "rightnotebook")]: + notebooks[entry_name] = self.SaveTabLayout(notebook) + self.DefaultPerspective = { + "perspective": self.AUIManager.SavePerspective(), + "notebooks": notebooks, # Initialize Printing configuring elements
self.PrintData = wx.PrintData()
@@ -693,13 +698,11 @@
self.PageSetupData.SetMarginBottomRight(wx.Point(10, 20))
self.SetRefreshFunctions()
+ self.SetDeleteFunctions() self.FindDialog.Destroy()
- def ResetStarting(self):
wx.CallAfter(self.RestoreLastState)
@@ -709,59 +712,21 @@
wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
+ def SelectTab(self, tab): + for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]: + idx = notebook.GetPageIndex(tab) + if idx != wx.NOT_FOUND and idx != notebook.GetSelection(): + notebook.SetSelection(idx) #-------------------------------------------------------------------------------
# Saving and restoring frame organization functions
#-------------------------------------------------------------------------------
- def OnResize(self, event):
- self.RestoreLastLayout()
- def EnableSaveProjectState(self):
- def GetProjectConfiguration(self):
- if self.Config.HasEntry("projects"):
- projects = cPickle.loads(str(self.Config.Read("projects")))
- EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
- def SavePageState(self, page):
- state = page.GetState()
- if self.Config.HasEntry("projects"):
- projects = cPickle.loads(str(self.Config.Read("projects")))
- project_infos = projects.setdefault(
- EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
- editors_state = project_infos.setdefault("editors_state", {})
- editors_state[page.GetInstancePath()] = state
- editors_state[page.GetTagName()] = state
- self.Config.Write("projects", cPickle.dumps(projects))
def GetTabInfos(self, tab):
- if isinstance(tab, EditorPanel):
- return ("debug", tab.GetInstancePath())
- return ("editor", tab.GetTagName())
- for page_name, (page_ref, page_title) in self.MainTabs.iteritems():
- return ("main", page_name)
+ for page_name, (page_ref, page_title) in self.MainTabs.iteritems(): + return ("main", page_name) def SaveTabLayout(self, notebook):
@@ -854,115 +819,19 @@
if self.Config.HasEntry("framesize"):
frame_size = cPickle.loads(str(self.Config.Read("framesize")))
self.SetClientSize(frame_size)
- wx.CallAfter(self.RestoreLastLayout)
- def RestoreLastLayout(self):
- for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
- (self.BottomNoteBook, "bottomnotebook"),
- (self.RightNoteBook, "rightnotebook")]:
- notebooks[entry_name] = self.SaveTabLayout(notebook)
- self.DefaultPerspective = {
- "perspective": self.AUIManager.SavePerspective(),
- "notebooks": notebooks,
- if self.Config.HasEntry("perspective"):
- self.AUIManager.LoadPerspective(unicode(self.Config.Read("perspective")))
- if self.Config.HasEntry("notebooks"):
- notebooks = cPickle.loads(str(self.Config.Read("notebooks")))
- for notebook in [self.LeftNoteBook, self.BottomNoteBook, self.RightNoteBook]:
- for idx in xrange(notebook.GetPageCount()):
- for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
- (self.BottomNoteBook, "bottomnotebook"),
- (self.RightNoteBook, "rightnotebook")]:
- self.LoadTabLayout(notebook, notebooks.get(entry_name))
- self.ResetPerspective()
- if self.EnableSaveProjectState():
- self.LoadProjectLayout()
- self._Refresh(EDITORTOOLBAR)
- if wx.Platform == '__WXMSW__':
- wx.CallAfter(self.ResetStarting)
- wx.CallAfter(self.RefreshEditor)
if not self.IsMaximized():
self.Config.Write("framesize", cPickle.dumps(self.GetClientSize()))
elif self.Config.HasEntry("framesize"):
self.Config.DeleteEntry("framesize")
- for notebook, entry_name in [(self.LeftNoteBook, "leftnotebook"),
- (self.BottomNoteBook, "bottomnotebook"),
- (self.RightNoteBook, "rightnotebook")]:
- notebooks[entry_name] = self.SaveTabLayout(notebook)
- self.Config.Write("notebooks", cPickle.dumps(notebooks))
- pane = self.AUIManager.GetPane(self.TabsOpened)
- self.AUIManager.RestorePane(pane)
- self.Config.Write("perspective", self.AUIManager.SavePerspective())
- if self.EnableSaveProjectState():
- self.SaveProjectLayout()
- for i in xrange(self.TabsOpened.GetPageCount()):
- self.SavePageState(self.TabsOpened.GetPage(i))
- def SaveProjectLayout(self):
- if self.Controler is not None:
- if self.Config.HasEntry("projects"):
- projects = cPickle.loads(str(self.Config.Read("projects")))
- project_infos = projects.setdefault(
- EncodeFileSystemPath(os.path.realpath(self.Controler.GetFilePath())), {})
- project_infos["tabs"] = self.SaveTabLayout(self.TabsOpened)
- project_infos["debug_vars"] = self.DebugVariablePanel.GetDebugVariables()
- self.Config.Write("projects", cPickle.dumps(projects))
- def LoadProjectLayout(self):
- if self.Controler is not None:
- project = self.GetProjectConfiguration()
- if project.has_key("tabs"):
- self.LoadTabLayout(self.TabsOpened, project["tabs"])
- self.DebugVariablePanel.SetDebugVariables(project.get("debug_vars", []))
- # self.DebugVariablePanel.ResetView()
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
@@ -998,8 +867,6 @@
window = self.TabsOpened.GetPage(selected)
if window.CheckSaveBeforeClosing():
- if self.EnableSaveProjectState():
- self.SavePageState(window)
# Refresh all window elements that have changed
wx.CallAfter(self._Refresh, TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU)
@@ -1010,8 +877,12 @@
- def GetCopyBuffer(self):
+ def GetCopyBuffer(self, primary_selection=False): + if primary_selection and wx.Platform == '__WXMSW__': + wx.TheClipboard.UsePrimarySelection(primary_selection) if wx.TheClipboard.Open():
dataobj = wx.TextDataObject()
if wx.TheClipboard.GetData(dataobj):
@@ -1019,7 +890,11 @@
- def SetCopyBuffer(self, text):
+ def SetCopyBuffer(self, text, primary_selection=False): + if primary_selection and wx.Platform == '__WXMSW__': + wx.TheClipboard.UsePrimarySelection(primary_selection) if wx.TheClipboard.Open():
data = wx.TextDataObject()
@@ -1317,20 +1192,29 @@
elif isinstance(control, wx.ComboBox):
control.SetMark(0, control.GetLastPosition() + 1)
- ITEM_DATATYPE: GetDeleteElementFunction(PLCControler.ProjectRemoveDataType, check_function=PLCControler.DataTypeIsUsed),
- ITEM_POU: GetDeleteElementFunction(PLCControler.ProjectRemovePou, check_function=PLCControler.PouIsUsed),
- ITEM_TRANSITION: GetDeleteElementFunction(PLCControler.ProjectRemovePouTransition, ITEM_POU),
- ITEM_ACTION: GetDeleteElementFunction(PLCControler.ProjectRemovePouAction, ITEM_POU),
- ITEM_CONFIGURATION: GetDeleteElementFunction(PLCControler.ProjectRemoveConfiguration),
- ITEM_RESOURCE: GetDeleteElementFunction(PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION)
+ def SetDeleteFunctions(self): + self.DeleteFunctions = { + ITEM_DATATYPE: GetDeleteElementFunction( + PLCControler.ProjectRemoveDataType, + check_function=self.CheckDataTypeIsUsedBeforeDeletion), + ITEM_POU: GetDeleteElementFunction( + PLCControler.ProjectRemovePou, + check_function=self.CheckPouIsUsedBeforeDeletion), + ITEM_TRANSITION: GetDeleteElementFunction( + PLCControler.ProjectRemovePouTransition, ITEM_POU), + ITEM_ACTION: GetDeleteElementFunction( + PLCControler.ProjectRemovePouAction, ITEM_POU), + ITEM_CONFIGURATION: GetDeleteElementFunction( + PLCControler.ProjectRemoveConfiguration), + ITEM_RESOURCE: GetDeleteElementFunction( + PLCControler.ProjectRemoveConfigurationResource, ITEM_CONFIGURATION) def OnDeleteMenu(self, event):
window = self.FindFocus()
if window == self.ProjectTree or window is None:
selected = self.ProjectTree.GetSelection()
+ if selected is not None and selected.IsOk(): function = self.DeleteFunctions.get(self.ProjectTree.GetPyData(selected)["type"], None)
@@ -1372,7 +1256,7 @@
result = self.Controler.SearchInProject(criteria)
self.ClearSearchResults()
self.SearchResultPanel.SetSearchResults(criteria, result)
- self.BottomNoteBook.SetSelection(self.BottomNoteBook.GetPageIndex(self.SearchResultPanel))
+ self.SelectTab(self.SearchResultPanel) #-------------------------------------------------------------------------------
@@ -1455,33 +1339,31 @@
notebook.SetSelection(notebook.GetPageIndex(tab))
def OnPouSelectedChanging(self, event):
- selected = self.TabsOpened.GetSelection()
- window = self.TabsOpened.GetPage(selected)
- if not window.IsDebugging():
+ selected = self.TabsOpened.GetSelection() + window = self.TabsOpened.GetPage(selected) + if not window.IsDebugging(): def OnPouSelectedChanged(self, event):
- selected = self.TabsOpened.GetSelection()
- window = self.TabsOpened.GetPage(selected)
- tagname = window.GetTagName()
- if not window.IsDebugging():
- wx.CallAfter(self.SelectProjectTreeItem, tagname)
- wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname)
- self.EnsureTabVisible(self.LibraryPanel)
- instance_path = window.GetInstancePath()
- instance_path = instance_path.rsplit(".", 1)[0]
- tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug)
- self.EnsureTabVisible(self.DebugVariablePanel)
- wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path)
- wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR)
+ selected = self.TabsOpened.GetSelection() + window = self.TabsOpened.GetPage(selected) + tagname = window.GetTagName() + if not window.IsDebugging(): + self.SelectProjectTreeItem(tagname) + self.PouInstanceVariablesPanel.SetPouType(tagname) + self.EnsureTabVisible(self.LibraryPanel) + instance_path = window.GetInstancePath() + instance_path = instance_path.rsplit(".", 1)[0] + tagname = self.Controler.GetPouInstanceTagName(instance_path, self.EnableDebug) + self.EnsureTabVisible(self.DebugVariablePanel) + wx.CallAfter(self.PouInstanceVariablesPanel.SetPouType, tagname, instance_path) + wx.CallAfter(self._Refresh, FILEMENU, EDITMENU, DISPLAYMENU, EDITORTOOLBAR) @@ -1544,30 +1426,44 @@
#-------------------------------------------------------------------------------
def RefreshProjectTree(self):
+ # Extract current selected item tagname + selected = self.ProjectTree.GetSelection() + if selected is not None and selected.IsOk(): + item_infos = self.ProjectTree.GetPyData(selected) + tagname = item_infos.get("tagname", None) + # Refresh treectrl items according to project infos infos = self.Controler.GetProjectInfos()
root = self.ProjectTree.GetRootItem()
+ if root is None or not root.IsOk(): root = self.ProjectTree.AddRoot(infos["name"])
self.GenerateProjectTreeBranch(root, infos)
self.ProjectTree.Expand(root)
+ # Select new item corresponding to previous selected item + if tagname is not None: + self.SelectProjectTreeItem(tagname) - def ResetSelectedItem(self):
- self.SelectedItem = None
- def GenerateProjectTreeBranch(self, root, infos):
+ def GenerateProjectTreeBranch(self, root, infos, item_alone=False): item_name = infos["name"]
if infos["type"] in ITEMS_UNEDITABLE:
if len(infos["values"]) == 1:
- return self.GenerateProjectTreeBranch(root, infos["values"][0])
+ return self.GenerateProjectTreeBranch(root, infos["values"][0], True) self.ProjectTree.SetItemText(root, item_name)
self.ProjectTree.SetPyData(root, infos)
highlight_colours = self.Highlights.get(infos.get("tagname", None), (wx.WHITE, wx.BLACK))
self.ProjectTree.SetItemBackgroundColour(root, highlight_colours[0])
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"])]) + self.ProjectTree.SetItemExtraImage(root, self.Controler.GetPouType(infos["name"])) elif infos.has_key("icon") and infos["icon"] is not None:
icon_name = infos["icon"]
if not self.TreeImageDict.has_key(icon_name):
@@ -1576,56 +1472,48 @@
elif self.TreeImageDict.has_key(infos["type"]):
self.ProjectTree.SetItemImage(root, self.TreeImageDict[infos["type"]])
- if wx.VERSION >= (2, 6, 0):
- item, root_cookie = self.ProjectTree.GetFirstChild(root)
- item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
+ item, root_cookie = self.ProjectTree.GetFirstChild(root) for values in infos["values"]:
if values["type"] not in ITEMS_UNEDITABLE or len(values["values"]) > 0:
+ if item is None or not item.IsOk(): item = self.ProjectTree.AppendItem(root, "")
- if wx.Platform != '__WXMSW__':
- item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie) self.GenerateProjectTreeBranch(item, values)
item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ while item is not None and item.IsOk(): item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
self.ProjectTree.Delete(item)
+ TagNamePartsItemTypes = { + "T": [ITEM_POU, ITEM_TRANSITION], + "A": [ITEM_POU, ITEM_ACTION], + "C": [ITEM_CONFIGURATION], + "R": [ITEM_CONFIGURATION, ITEM_RESOURCE]} def SelectProjectTreeItem(self, tagname):
if self.ProjectTree is not None:
root = self.ProjectTree.GetRootItem()
+ if root is not None and root.IsOk(): words = tagname.split("::")
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_DATATYPE)])
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU)])
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)])
- return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
+ result = self.RecursiveProjectTreeItemSelection(root, + zip(words[1:], self.TagNamePartsItemTypes.get(words[0], []))) def RecursiveProjectTreeItemSelection(self, root, items):
- if wx.VERSION >= (2, 6, 0):
- item, root_cookie = self.ProjectTree.GetFirstChild(root)
- item, root_cookie = self.ProjectTree.GetFirstChild(root, 0)
- while item.IsOk() and not found:
+ item, root_cookie = self.ProjectTree.GetFirstChild(root) + while item is not None and item.IsOk() and not found: item_infos = self.ProjectTree.GetPyData(item)
if (item_infos["name"].split(":")[-1].strip(), item_infos["type"]) == items[0]:
- wx.CallAfter(self.ProjectTree.SelectItem, item)
- wx.CallAfter(self.ResetSelectedItem)
+ self.ProjectTree.SelectItem(item) + self.ResetSelectedItem() found = self.RecursiveProjectTreeItemSelection(item, items[1:])
@@ -1634,11 +1522,15 @@
item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
+ def ResetSelectedItem(self): + self.SelectedItem = None def OnProjectTreeBeginDrag(self, event):
- if wx.Platform == '__WXMSW__':
- self.SelectedItem = event.GetItem()
- if self.SelectedItem is not None and self.ProjectTree.GetPyData(self.SelectedItem)["type"] == ITEM_POU:
- block_name = self.ProjectTree.GetItemText(self.SelectedItem)
+ selected_item = (self.SelectedItem + if self.SelectedItem is not None + if selected_item.IsOk() and self.ProjectTree.GetPyData(selected_item)["type"] == ITEM_POU: + block_name = self.ProjectTree.GetItemText(selected_item) block_type = self.Controler.GetPouType(block_name)
if block_type != "program":
data = wx.TextDataObject(str((block_name, block_type, "")))
@@ -1682,7 +1574,7 @@
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames() if name != old_name]:
message = _("\"%s\" pou already exists!")%new_name
- elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ 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)
if messageDialog.ShowModal() == wx.ID_NO:
@@ -1696,7 +1588,7 @@
elif item_infos["type"] == ITEM_TRANSITION:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
message = _("A POU named \"%s\" already exists!")%new_name
- elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+ 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
words = item_infos["tagname"].split("::")
@@ -1707,7 +1599,7 @@
elif item_infos["type"] == ITEM_ACTION:
if new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames()]:
message = _("A POU named \"%s\" already exists!")%new_name
- elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables(pou_name) if name != old_name]:
+ 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
words = item_infos["tagname"].split("::")
@@ -1724,7 +1616,7 @@
if messageDialog.ShowModal() == wx.ID_NO:
- elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ 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)
if messageDialog.ShowModal() == wx.ID_NO:
@@ -1743,7 +1635,7 @@
if messageDialog.ShowModal() == wx.ID_NO:
- elif new_name.upper() in [name.upper() for name in self.Controler.GetProjectPouVariables()]:
+ 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)
if messageDialog.ShowModal() == wx.ID_NO:
@@ -1780,23 +1672,52 @@
def ProjectTreeItemSelect(self, select_item):
- name = self.ProjectTree.GetItemText(select_item)
- item_infos = self.ProjectTree.GetPyData(select_item)
- if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU,
- ITEM_CONFIGURATION, ITEM_RESOURCE,
- ITEM_TRANSITION, ITEM_ACTION]:
- self.EditProjectElement(item_infos["type"], item_infos["tagname"], True)
- self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"])
+ if select_item is not None and select_item.IsOk(): + name = self.ProjectTree.GetItemText(select_item) + item_infos = self.ProjectTree.GetPyData(select_item) + if item_infos["type"] in [ITEM_DATATYPE, ITEM_POU, + ITEM_CONFIGURATION, ITEM_RESOURCE, + ITEM_TRANSITION, ITEM_ACTION]: + self.EditProjectElement(item_infos["type"], item_infos["tagname"], True) + self.PouInstanceVariablesPanel.SetPouType(item_infos["tagname"]) def OnProjectTreeLeftUp(self, event):
if self.SelectedItem is not None:
self.ProjectTree.SelectItem(self.SelectedItem)
self.ProjectTreeItemSelect(self.SelectedItem)
- wx.CallAfter(self.ResetSelectedItem)
+ self.ResetSelectedItem() - def OnProjectTreeItemSelected(self, event):
- self.ProjectTreeItemSelect(event.GetItem())
+ def OnProjectTreeMotion(self, event): + if not event.Dragging(): + pt = wx.Point(event.GetX(), event.GetY()) + item, flags = self.ProjectTree.HitTest(pt) + if item is not None and item.IsOk() and flags & wx.TREE_HITTEST_ONITEMLABEL: + item_infos = self.ProjectTree.GetPyData(item) + 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]): + bodytype = self.Controler.GetEditedElementBodyType( + if item_infos["type"] == ITEM_POU: + "program": _("Program"), + "functionBlock": _("Function Block"), + "function": _("Function") + }[self.Controler.GetPouType(item_infos["name"])] + elif item_infos["type"] == ITEM_TRANSITION: + block_type = "Transition" + self.LastToolTipItem = item + wx.CallAfter(self.ProjectTree.SetToolTipString, + block_type, bodytype, item_infos["name"])) + elif self.LastToolTipItem is not None: + self.ProjectTree.SetToolTip(None) + self.LastToolTipItem = None def OnProjectTreeItemChanging(self, event):
@@ -1861,16 +1782,6 @@
new_window.SetIcon(GetBitmap("DATATYPE"))
self.AddPage(new_window, "")
if new_window is not None:
- if self.EnableSaveProjectState():
- project_infos = self.GetProjectConfiguration()
- if project_infos.has_key("editors_state"):
- if new_window.IsDebugging():
- state = project_infos["editors_state"].get(new_window.GetInstancePath())
- state = project_infos["editors_state"].get(tagname)
- wx.CallAfter(new_window.SetState, state)
openedidx = self.IsOpened(tagname)
old_selected = self.TabsOpened.GetSelection()
if old_selected != openedidx:
@@ -1885,10 +1796,7 @@
def OnProjectTreeRightUp(self, event):
- if wx.Platform == '__WXMSW__':
- item, flags = self.ProjectTree.HitTest(wx.Point(event.GetX(), event.GetY()))
self.ProjectTree.SelectItem(item)
self.ProjectTreeItemSelect(item)
name = self.ProjectTree.GetItemText(item)
@@ -1931,8 +1839,8 @@
AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Add Transition"))
- parent = self.ProjectTree.GetItemParent(item)["type"]
- parent_type = self.ProjectTree.GetPyData(parent)
+ parent = self.ProjectTree.GetItemParent(item) + parent_type = self.ProjectTree.GetPyData(parent)["type"] while parent_type != ITEM_POU:
parent = self.ProjectTree.GetItemParent(parent)
parent_type = self.ProjectTree.GetPyData(parent)["type"]
@@ -1958,11 +1866,15 @@
while parent_type not in [ITEM_CONFIGURATION, ITEM_PROJECT]:
parent = self.ProjectTree.GetItemParent(parent)
parent_type = self.ProjectTree.GetPyData(parent)["type"]
if parent_type == ITEM_PROJECT:
+ config_names = self.Controler.GetProjectConfigNames() + if len(config_names) > 0: + parent_name = config_names[0] parent_name = self.ProjectTree.GetItemText(parent)
- self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id)
+ if parent_name is not None: + self.Bind(wx.EVT_MENU, self.GenerateAddResourceFunction(parent_name), id=new_id) if item_infos["type"] == ITEM_POU:
@@ -2013,6 +1925,8 @@
+ self.ResetSelectedItem() @@ -2073,13 +1987,6 @@
icon = GetBitmap("ACTION", bodytype)
if new_window is not None:
- if self.EnableSaveProjectState():
- project_infos = self.GetProjectConfiguration()
- if project_infos.has_key("editors_state"):
- state = project_infos["editors_state"].get(instance_path)
- wx.CallAfter(new_window.SetState, state)
self.AddPage(new_window, "")
@@ -2108,14 +2015,14 @@
elif isinstance(editor, GraphicViewer):
+ editor.SubscribeAllDataConsumers() elif editor.IsDebugging():
- editor.RegisterVariables()
- self.DebugVariablePanel.UnregisterObsoleteData()
+ editor.SubscribeAllDataConsumers() + self.DebugVariablePanel.SubscribeAllDataConsumers() - def AddDebugVariable(self, iec_path, force=False):
+ def AddDebugVariable(self, iec_path, force=False, graph=False): - self.DebugVariablePanel.InsertValue(iec_path, force=force)
+ self.DebugVariablePanel.InsertValue(iec_path, force=force, graph=graph) self.EnsureTabVisible(self.DebugVariablePanel)
#-------------------------------------------------------------------------------
@@ -2349,7 +2256,7 @@
dialog = PouDialog(self, pou_type)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
- dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames()) dialog.SetValues({"pouName": self.Controler.GenerateNewName(None, None, "%s%%d" % pou_type)})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
@@ -2364,7 +2271,7 @@
def OnAddTransitionMenu(event):
dialog = PouTransitionDialog(self)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
- dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames(pou_name)) dialog.SetValues({"transitionName": self.Controler.GenerateNewName(None, None, "transition%d")})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
@@ -2379,7 +2286,7 @@
def OnAddActionMenu(event):
dialog = PouActionDialog(self)
dialog.SetPouNames(self.Controler.GetProjectPouNames())
- dialog.SetPouElementNames(self.Controler.GetProjectPouVariables(pou_name))
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariableNames(pou_name)) dialog.SetValues({"actionName": self.Controler.GenerateNewName(None, None, "action%d")})
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
@@ -2437,9 +2344,7 @@
result = self.Controler.PastePou(pou_type, pou_xml)
if not isinstance(result, TupleType):
- message = wx.MessageDialog(self, result, _("Error"), wx.OK|wx.ICON_ERROR)
+ self.ShowErrorMessage(result) self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, LIBRARYTREE)
self.EditProjectElement(ITEM_POU, result[0])
@@ -2448,20 +2353,39 @@
# Remove Project Elements Functions
#-------------------------------------------------------------------------------
+ def CheckElementIsUsedBeforeDeletion(self, check_function, title, name): + if not check_function(name): + 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) + answer = dialog.ShowModal() + return answer == wx.ID_YES + def CheckDataTypeIsUsedBeforeDeletion(self, name): + return self.CheckElementIsUsedBeforeDeletion( + self.Controler.DataTypeIsUsed, + _("Remove Datatype"), name) + def CheckPouIsUsedBeforeDeletion(self, name): + return self.CheckElementIsUsedBeforeDeletion( + self.Controler.PouIsUsed, def OnRemoveDataTypeMenu(self, event):
selected = self.ProjectTree.GetSelection()
if self.ProjectTree.GetPyData(selected)["type"] == ITEM_DATATYPE:
name = self.ProjectTree.GetItemText(selected)
- if not self.Controler.DataTypeIsUsed(name):
+ if self.CheckDataTypeIsUsedBeforeDeletion(name): self.Controler.ProjectRemoveDataType(name)
tagname = self.Controler.ComputeDataTypeName(name)
idx = self.IsOpened(tagname)
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE)
- self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
def OnRenamePouMenu(self, event):
selected = self.ProjectTree.GetSelection()
if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
@@ -2471,15 +2395,13 @@
selected = self.ProjectTree.GetSelection()
if self.ProjectTree.GetPyData(selected)["type"] == ITEM_POU:
name = self.ProjectTree.GetItemText(selected)
- if not self.Controler.PouIsUsed(name):
+ if self.CheckPouIsUsedBeforeDeletion(name): self.Controler.ProjectRemovePou(name)
tagname = self.Controler.ComputePouName(name)
idx = self.IsOpened(tagname)
self.TabsOpened.DeletePage(idx)
self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, PROJECTTREE, POUINSTANCEVARIABLESPANEL, LIBRARYTREE)
- self.ShowErrorMessage(_("\"%s\" is used by one or more POUs. It can't be removed!"))
def OnRemoveTransitionMenu(self, event):
selected = self.ProjectTree.GetSelection()
--- a/ProjectController.py Wed Mar 13 12:34:55 2013 +0900
+++ b/ProjectController.py Wed Jul 31 10:45:07 2013 +0900
@@ -21,7 +21,7 @@
from editors.FileManagementPanel import FileManagementPanel
from editors.ProjectNodeEditor import ProjectNodeEditor
from editors.IECCodeViewer import IECCodeViewer
-from graphics import DebugViewer
+from editors.DebugViewer import DebugViewer from dialogs import DiscoveryDialog
from PLCControler import PLCControler
from plcopen.structures import IEC_KEYWORDS
@@ -85,9 +85,9 @@
PLCControler.__init__(self)
self.MandatoryParams = None
- self.SetAppFrame(frame, logger)
+ self.SetAppFrame(frame, logger) self.iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+(".exe" if wx.Platform == '__WXMSW__' else ""))
self.ieclib_path = os.path.join(base_folder, "matiec", "lib")
@@ -113,7 +113,6 @@
self.previous_plcstate = None
- self.previous_log_count = [None]*LogLevelsCount
# copy ConfNodeMethods so that it can be later customized
self.StatusMethods = [dic.copy() for dic in self.StatusMethods]
@@ -137,6 +136,8 @@
+ frame.LogViewer.SetLogSource(self._connector) # Timer to pull PLC status
ID_STATUSTIMER = wx.NewId()
self.StatusTimer = wx.Timer(self.AppFrame, ID_STATUSTIMER)
@@ -213,27 +214,33 @@
def SetParamsAttribute(self, path, value):
if path.startswith("BeremizRoot.TargetType.") and self.BeremizRoot.getTargetType().getcontent() is None:
self.BeremizRoot.setTargetType(self.GetTarget())
- return ConfigTreeNode.SetParamsAttribute(self, path, value)
+ res = ConfigTreeNode.SetParamsAttribute(self, path, value) + if path.startswith("BeremizRoot.Libraries."): + wx.CallAfter(self.RefreshConfNodesBlockLists) # helper func to check project path write permission
def CheckProjectPathPerm(self, dosave=True):
if CheckPathPerm(self.ProjectPath):
- dialog = wx.MessageDialog(self.AppFrame,
- _('You must have permission to work on the project\nWork on a project copy ?'),
- wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
- answer = dialog.ShowModal()
- if answer == wx.ID_YES:
- if self.SaveProjectAs():
- self.AppFrame.RefreshTitle()
- self.AppFrame.RefreshFileMenu()
- self.AppFrame.RefreshPageTitles()
+ 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 ?'), + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + answer = dialog.ShowModal() + if answer == wx.ID_YES: + if self.SaveProjectAs(): + self.AppFrame.RefreshTitle() + self.AppFrame.RefreshFileMenu() + self.AppFrame.RefreshPageTitles() - def _getProjectFilesPath(self):
+ def _getProjectFilesPath(self, project_path=None): + if project_path is not None: + return os.path.join(project_path, "project_files") projectfiles_path = os.path.join(self.GetProjectPath(), "project_files")
if not os.path.exists(projectfiles_path):
os.mkdir(projectfiles_path)
@@ -281,7 +288,7 @@
if os.path.basename(ProjectPath) == "":
ProjectPath = os.path.dirname(ProjectPath)
- # Verify that project contains a PLCOpen program
+ # Verify that project contains a PLCOpen program plc_file = os.path.join(ProjectPath, "plc.xml")
if not os.path.isfile(plc_file):
return _("Chosen folder doesn't contain a program. It's not a valid project!")
@@ -310,9 +317,11 @@
if os.path.exists(self._getBuildPath()):
self.EnableMethod("_Clean", True)
- if os.path.isfile(self._getIECrawcodepath()):
+ if os.path.isfile(self._getIECcodepath()): self.ShowMethod("_showIECcode", True)
+ self.UpdateMethodsFromPLCStatus() def RecursiveConfNodeInfos(self, confnode):
@@ -321,6 +330,7 @@
{"name": "%s: %s" % (CTNChild.GetFullIEC_Channel(),
+ "tagname": CTNChild.CTNFullName(), "icon": CTNChild.GetIconName(),
@@ -345,14 +355,19 @@
+ def SaveProject(self, from_project_path=None): if self.CheckProjectPathPerm(False):
+ if from_project_path is not None: + old_projectfiles_path = self._getProjectFilesPath(from_project_path) + if os.path.isdir(old_projectfiles_path): + shutil.copytree(old_projectfiles_path, + self._getProjectFilesPath(self.ProjectPath)) self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
- result = self.CTNRequestSave()
+ result = self.CTNRequestSave(from_project_path) self.logger.write_error(result)
- def SaveProjectAs(self, dosave=True):
+ def SaveProjectAs(self): # Ask user to choose a path with write permissions
if wx.Platform == '__WXMSW__':
path = os.getenv("USERPROFILE")
@@ -364,9 +379,8 @@
newprojectpath = dirdialog.GetPath()
if os.path.isdir(newprojectpath):
- self.ProjectPath = newprojectpath
+ self.ProjectPath, old_project_path = newprojectpath, self.ProjectPath + self.SaveProject(old_project_path) self._setBuildPath(self.BuildPath)
@@ -599,6 +613,15 @@
# transform those base names to full names with path
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.remove("LOCATED_VARIABLES.h") + H_files = map(lambda filename:os.path.join(buildpath, filename), 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) self.logger.write(_("Extracting Located Variables...\n"))
# Keep track of generated located variables for later use by self._Generate_C
self.PLCGeneratedLocatedVars = self.GetLocations()
@@ -776,7 +799,7 @@
- def Generate_plc_common_main(self):
+ def Generate_plc_main(self): Use confnodes layout given in LocationCFilesAndCFLAGS to
generate glue code that dispatch calls to all confnodes
@@ -785,19 +808,19 @@
# in retreive, publish, init, cleanup
locstrs = map(lambda x:"_".join(map(str,x)),
[loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
# Generate main, based on template
if not self.BeremizRoot.getDisable_Extensions():
- plc_main_code = targets.GetCode("plc_common_main") % {
+ plc_main_code = targets.GetCode("plc_main_head") % { "calls_prototypes":"\n".join([(
"int __init_%(s)s(int argc,char **argv);\n"+
"void __cleanup_%(s)s(void);\n"+
"void __retrieve_%(s)s(void);\n"+
"void __publish_%(s)s(void);")%{'s':locstr} for locstr in locstrs]),
"retrieve_calls":"\n ".join([
- "__retrieve_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
+ "__retrieve_%s();"%locstr for locstr in locstrs]), "publish_calls":"\n ".join([ #Call publish in reverse order
- "__publish_%s();"%locstr for locstr in locstrs]),
+ "__publish_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]), "init_calls":"\n ".join([
"if((res = __init_%s(argc,argv))){"%locstr +
@@ -808,7 +831,7 @@
"__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
- plc_main_code = targets.GetCode("plc_common_main") % {
+ plc_main_code = targets.GetCode("plc_main_head") % { @@ -816,6 +839,7 @@
plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent()["name"])
+ plc_main_code += targets.GetCode("plc_main_tail") @@ -890,13 +914,16 @@
# Now we can forget ExtraFiles (will close files object)
+ # Header file for extensions + 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
for generator, filename, name in [
(self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
# init/cleanup/retrieve/publish, run and align code
- (self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]:
+ (self.Generate_plc_main,"plc_main.c","Common runtime")]: @@ -966,7 +993,7 @@
if self._IECCodeView is None:
plc_file = self._getIECcodepath()
- self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", None, None, instancepath=name)
+ self._IECCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, None, instancepath=name) self._IECCodeView.SetTextSyntax("ALL")
self._IECCodeView.SetKeywords(IEC_KEYWORDS)
@@ -986,7 +1013,7 @@
if self._IECRawCodeView is None:
controler = MiniTextControler(self._getIECrawcodepath(), self)
- self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", None, controler, instancepath=name)
+ self._IECRawCodeView = IECCodeViewer(self.AppFrame.TabsOpened, "", self.AppFrame, controler, instancepath=name) self._IECRawCodeView.SetTextSyntax("ALL")
self._IECRawCodeView.SetKeywords(IEC_KEYWORDS)
self._IECRawCodeView.RefreshView()
@@ -1077,36 +1104,10 @@
self.CompareLocalAndRemotePLC()
def UpdatePLCLog(self, log_count):
- for level, count, prev in zip(xrange(LogLevelsCount), log_count,self.previous_log_count):
- if count is not None and prev != count:
- # XXX replace dump to console with dedicated log panel.
- dump_end = max( # request message sent after the last one we already got
- prev - 1 if prev is not None else -1,
- count - 100) # 100 is purely arbitrary number
- # dedicated panel should only ask for a small range,
- # depending on how user navigate in the panel
- # and only ask for last one in follow mode
- for msgidx in xrange(count-1, dump_end,-1):
- answer = self._connector.GetLogMessage(level, msgidx)
- if answer is not None :
- msg, tick, tv_sec, tv_nsec = answer
- str(datetime.fromtimestamp(tv_sec)),
- self.previous_log_count[level] = count
- self.logger.write("\n".join(zip(*to_console)[1]+('',)))
+ if self.AppFrame is not None: + self.AppFrame.LogViewer.SetLogCounters(log_count) def UpdateMethodsFromPLCStatus(self):
if self._connector is not None:
@@ -1115,7 +1116,7 @@
status, log_count = PLCstatus
self.UpdatePLCLog(log_count)
+ self._SetConnector(None, False) if(self.previous_plcstate != status):
@@ -1133,16 +1134,18 @@
- {"Broken": self.logger.write_error,
- None: lambda x: None}.get(
- status, self.logger.write)(_("PLC state is \"%s\"\n")%_(status))
self.previous_plcstate = status
if self.AppFrame is not None:
self.AppFrame.RefreshStatusToolBar()
+ if status == "Disconnected": + self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 1) + self.AppFrame.ConnectionStatusBar.SetStatusText('', 2) + self.AppFrame.ConnectionStatusBar.SetStatusText( + _("Connected to URI: %s") % self.BeremizRoot.getURI_location().strip(), 1) + self.AppFrame.ConnectionStatusBar.SetStatusText(_(status), 2) def PullPLCStatusProc(self, event):
- if self._connector is None:
- self.StatusTimer.Stop()
self.UpdateMethodsFromPLCStatus()
def RegisterDebugVarToConnector(self):
@@ -1179,16 +1182,23 @@
self._connector.SetTraceVariablesList([])
self.IECdebug_lock.release()
+ def IsPLCStarted(self): + return self.previous_plcstate == "Started" def ReArmDebugRegisterTimer(self):
if self.DebugTimer is not None:
- # Timer to prevent rapid-fire when registering many variables
- # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
- self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
- # Rearm anti-rapid-fire timer
- self.DebugTimer.start()
+ # Prevent to call RegisterDebugVarToConnector when PLC is not started + # If an output location var is forced it's leads to segmentation fault in runtime + # Links between PLC located variables and real variables are not ready + 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]) + # Rearm anti-rapid-fire timer + self.DebugTimer.start() def GetDebugIECVariableType(self, IECPath):
Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
@@ -1227,13 +1237,15 @@
IECdebug_data = self.IECdebug_datas.get(IECPath, None)
if IECdebug_data is not None:
IECdebug_data[0].pop(callableobj,None)
+ if len(IECdebug_data[0]) == 0: + self.IECdebug_datas.pop(IECPath) self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
def UnsubscribeAllDebugIECVariable(self):
self.IECdebug_lock.acquire()
+ self.IECdebug_datas = {} self.IECdebug_lock.release()
self.ReArmDebugRegisterTimer()
@@ -1303,6 +1315,7 @@
+ #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()] if plc_status == "Started":
self.IECdebug_lock.acquire()
if len(debug_vars) == len(self.TracedIECPath):
@@ -1341,7 +1354,6 @@
def _connect_debug(self):
self.previous_plcstate = None
- self.previous_log_count = [None]*LogLevelsCount
self.AppFrame.ResetGraphicViewers()
self.RegisterDebugVarToConnector()
@@ -1373,6 +1385,19 @@
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
+ def _SetConnector(self, connector, update_status=True): + self._connector = connector + if self.AppFrame is not None: + self.AppFrame.LogViewer.SetLogSource(connector) + if connector is not None: + # Start the status Timer + self.StatusTimer.Start(milliseconds=500, oneShot=False) + # Stop the status Timer + self.StatusTimer.Stop() + wx.CallAfter(self.UpdateMethodsFromPLCStatus) # don't accept re-connetion if already connected
if self._connector is not None:
@@ -1417,7 +1442,7 @@
- self._connector = connectors.ConnectorFactory(uri, self)
+ self._SetConnector(connectors.ConnectorFactory(uri, self)) self.logger.write_error(_("Exception while connecting %s!\n")%uri)
self.logger.write_error(traceback.format_exc())
@@ -1442,9 +1467,6 @@
#self.logger.write(_("PLC is %s\n")%status)
- # Start the status Timer
- self.StatusTimer.Start(milliseconds=500, oneShot=False)
if self.previous_plcstate in ["Started","Stopped"]:
if self.DebugAvailable() and self.GetIECProgramsAndVariables():
self.logger.write(_("Debugger ready\n"))
@@ -1477,9 +1499,7 @@
- self.StatusTimer.Stop()
- wx.CallAfter(self.UpdateMethodsFromPLCStatus)
+ self._SetConnector(None) # Get the last build PLC's
@@ -1522,8 +1542,6 @@
self.logger.write_error(_("No PLC to transfer (did build succeed ?)\n"))
- self.previous_log_count = [None]*LogLevelsCount
wx.CallAfter(self.UpdateMethodsFromPLCStatus)
--- a/editors/Viewer.py Wed Mar 13 12:34:55 2013 +0900
+++ b/editors/Viewer.py Wed Jul 31 10:45:07 2013 +0900
@@ -24,7 +24,7 @@
+from time import time as gettime from types import TupleType
from threading import Lock
@@ -35,6 +35,7 @@
+from editors.DebugViewer import DebugViewer, REFRESH_PERIOD from EditorPanel import EditorPanel
@@ -74,7 +75,11 @@
-ZOOM_FACTORS = [math.sqrt(2) ** x for x in xrange(-6, 7)]
+if wx.Platform == '__WXMSW__': +ZOOM_FACTORS = [math.sqrt(2) ** x for x in xrange(-6, MAX_ZOOMIN)] def GetVariableCreationFunction(variable_type):
def variableCreationFunction(viewer, id, specific_values):
@@ -266,6 +271,7 @@
self.ParentWindow.RefreshScrollBars()
self.ParentWindow.RefreshVisibleElements()
self.ParentWindow.RefreshVariablePanel()
+ self.ParentWindow.ParentWindow.RefreshPouInstanceVariablesPanel() self.ParentWindow.Refresh(False)
elif values[1] == "location":
if pou_type == "program":
@@ -313,6 +319,7 @@
if 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])
elif values[1] == "Constant":
self.ParentWindow.AddVariableBlock(x, y, scaling, INPUT, values[0], None)
@@ -371,7 +378,7 @@
manipulating graphic elements
-class Viewer(EditorPanel, DebugViewer, DebugDataConsumer):
+class Viewer(EditorPanel, DebugViewer): if wx.VERSION < (2, 6, 0):
def Bind(self, event, function, id = None):
@@ -433,15 +440,18 @@
(ID_ALIGN_BOTTOM, wx.ITEM_NORMAL, _(u'Bottom'), '', self.OnAlignBottomMenu)])
# Add Wire Menu items to the given menu
- def AddWireMenuItems(self, menu, delete=False):
- [ID_ADD_SEGMENT, ID_DELETE_SEGMENT] = [wx.NewId() for i in xrange(2)]
+ def AddWireMenuItems(self, menu, delete=False, replace=False): + [ID_ADD_SEGMENT, ID_DELETE_SEGMENT, ID_REPLACE_WIRE, + ] = [wx.NewId() for i in xrange(3)] self.AddMenuItems(menu, [
(ID_ADD_SEGMENT, wx.ITEM_NORMAL, _(u'Add Wire Segment'), '', self.OnAddSegmentMenu),
- (ID_DELETE_SEGMENT, wx.ITEM_NORMAL, _(u'Delete Wire Segment'), '', self.OnDeleteSegmentMenu)])
+ (ID_DELETE_SEGMENT, wx.ITEM_NORMAL, _(u'Delete Wire Segment'), '', self.OnDeleteSegmentMenu), + (ID_REPLACE_WIRE, wx.ITEM_NORMAL, _(u'Replace Wire by connections'), '', self.OnReplaceWireMenu)]) menu.Enable(ID_DELETE_SEGMENT, delete)
+ menu.Enable(ID_REPLACE_WIRE, replace) # Add Divergence Menu items to the given menu
def AddDivergenceMenuItems(self, menu, delete=False):
@@ -552,7 +562,6 @@
EditorPanel.__init__(self, parent, tagname, window, controler, debug)
DebugViewer.__init__(self, controler, debug)
- DebugDataConsumer.__init__(self)
# Adding a rubberband to Viewer
self.rubberBand = RubberBand(viewer=self)
@@ -574,6 +583,12 @@
self.InstancePath = instancepath
self.StartMousePos = None
self.StartScreenPos = None
+ # Prevent search for highlighted element to be called too often + self.LastHighlightCheckTime = gettime() + # Prevent search for element producing tooltip to be called too often + self.LastToolTipCheckTime = gettime() @@ -608,7 +623,7 @@
self.MiniTextDC.SetFont(wx.Font(faces["size"] * 0.75, wx.SWISS, wx.NORMAL, wx.NORMAL, faceName = faces["helv"]))
- self.SetScale(len(ZOOM_FACTORS) / 2, False)
+ self.SetScale(ZOOM_FACTORS.index(1.0), False) self.RefreshHighlightsTimer = wx.Timer(self, -1)
self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)
@@ -718,18 +733,6 @@
- return {"position": self.Editor.GetViewStart(),
- "zoom": self.CurrentScale}
- def SetState(self, state):
- if state.has_key("zoom"):
- self.SetScale(state["zoom"])
- if state.has_key("position"):
- self.Scroll(*state["position"])
- self.RefreshVisibleElements()
def GetLogicalDC(self, buffered=False):
bitmap = wx.EmptyBitmap(*self.Editor.GetClientSize())
@@ -748,7 +751,14 @@
self.Editor.RefreshRect(rect, eraseBackground)
+ if self.Debug and wx.Platform == '__WXMSW__': + if wx.Platform == '__WXMSW__': def GetScrollPos(self, orientation):
return self.Editor.GetScrollPos(orientation)
@@ -852,11 +862,13 @@
def GetElementIECPath(self, element):
instance_path = self.GetInstancePath(True)
- if isinstance(element, Wire) and element.EndConnected is not None:
- block = element.EndConnected.GetParentBlock()
+ if isinstance(element, (Wire, Connector)): + if isinstance(element, Wire): + element = element.EndConnected + block = element.GetParentBlock() if isinstance(block, FBD_Block):
blockname = block.GetName()
- connectorname = element.EndConnected.GetName()
+ connectorname = element.GetName() iec_path = "%s.%s.%s"%(instance_path, blockname, connectorname)
@@ -898,10 +910,10 @@
self.ToolTipElement = None
- self.DeleteDataConsumers()
+ self.UnsubscribeAllDataConsumers(tick=False) for block in self.Blocks.itervalues():
for block in self.Blocks.itervalues():
@@ -1001,7 +1013,7 @@
self.PagePen = wx.TRANSPARENT_PEN
self.RefreshVisibleElements()
+ self.Editor.Refresh(False) #-------------------------------------------------------------------------------
@@ -1053,6 +1065,10 @@
self.RefreshRect(self.GetScrolledRect(refresh_rect), False)
DebugViewer.RefreshNewData(self)
+ def SubscribeAllDataConsumers(self): + DebugViewer.SubscribeAllDataConsumers(self) # Refresh Viewer elements
def RefreshView(self, variablepanel=True, selection=None):
@@ -1062,7 +1078,7 @@
self.AddDataConsumer("%s.Q" % self.InstancePath.upper(), self)
if self.ToolTipElement is not None:
- self.ToolTipElement.ClearToolTip()
+ self.ToolTipElement.DestroyToolTip() self.ToolTipElement = None
@@ -1079,6 +1095,12 @@
instance = self.Controler.GetEditedElementInstanceInfos(self.TagName, exclude = ids, debug = self.Debug)
self.loadInstance(instance, ids, selection)
+ if (selection is not None and + isinstance(self.SelectedElement, Graphic_Group)): + self.SelectedElement.RefreshWireExclusion() + self.SelectedElement.RefreshBoundingBox() @@ -1096,14 +1118,21 @@
for block in self.Blocks.itervalues():
- iec_path = self.GetElementIECPath(block)
- if iec_path is not None:
- self.AddDataConsumer(iec_path.upper(), block)
+ if isinstance(block, FBD_Block): + for output_connector in block.GetConnectors()["outputs"]: + if len(output_connector.GetWires()) == 0: + iec_path = self.GetElementIECPath(output_connector) + if iec_path is not None: + self.AddDataConsumer(iec_path.upper(), output_connector) + iec_path = self.GetElementIECPath(block) + if iec_path is not None: + self.AddDataConsumer(iec_path.upper(), block) self.RefreshVisibleElements()
+ self.Editor.Refresh(False) def GetPreviousSteps(self, connectors):
@@ -1183,11 +1212,11 @@
if self.SelectedElement is None:
self.SelectedElement = element
elif isinstance(self.SelectedElement, Graphic_Group):
- self.SelectedElement.SelectElement(element)
+ self.SelectedElement.AddElement(element) group = Graphic_Group(self)
- group.SelectElement(self.SelectedElement)
- group.SelectElement(element)
+ group.AddElement(self.SelectedElement) + group.AddElement(element) self.SelectedElement = group
# Load instance from given informations
@@ -1245,50 +1274,81 @@
element.SetPosition(instance["x"], instance["y"])
element.SetSize(instance["width"], instance["height"])
for i, output_connector in enumerate(instance["outputs"]):
- if i < len(connectors["outputs"]):
+ if isinstance(element, FBD_Block): + connector = element.GetConnector( + wx.Point(*output_connector["position"]), + output_name = output_connector["name"]) + elif i < len(connectors["outputs"]): connector = connectors["outputs"][i]
+ if connector is not None: if output_connector.get("negated", False):
connector.SetNegated(True)
if output_connector.get("edge", "none") != "none":
connector.SetEdge(output_connector["edge"])
- connector.SetPosition(wx.Point(*output_connector["position"]))
+ if connectors["outputs"].index(connector) == i: + connector.SetPosition(wx.Point(*output_connector["position"])) for i, input_connector in enumerate(instance["inputs"]):
- if i < len(connectors["inputs"]):
+ if isinstance(element, FBD_Block): + connector = element.GetConnector( + wx.Point(*input_connector["position"]), + input_name = input_connector["name"]) + elif i < len(connectors["inputs"]): connector = connectors["inputs"][i]
- connector.SetPosition(wx.Point(*input_connector["position"]))
+ if connector is not None: + if connectors["inputs"].index(connector) == i: + connector.SetPosition(wx.Point(*input_connector["position"])) if input_connector.get("negated", False):
connector.SetNegated(True)
if input_connector.get("edge", "none") != "none":
connector.SetEdge(input_connector["edge"])
- self.CreateWires(connector, instance["id"], input_connector["links"], ids, selection)
+ if not self.CreateWires(connector, instance["id"], input_connector["links"], ids, selection): + element.RefreshConnectors() if selection is not None and selection[0].get(instance["id"], False):
self.SelectInGroup(element)
def CreateWires(self, start_connector, id, links, ids, selection=None):
refLocalId = link["refLocalId"]
- if refLocalId is not None:
- if refLocalId not in ids:
- new_instance = self.Controler.GetEditedElementInstanceInfos(self.TagName, refLocalId, debug = self.Debug)
- if new_instance is not None:
- self.loadInstance(new_instance, ids, selection)
- connected = self.FindElementById(refLocalId)
- if connected is not None:
- points = link["points"]
- end_connector = connected.GetConnector(wx.Point(points[-1][0], points[-1][1]), link["formalParameter"])
- if end_connector is not None:
- start_connector.Connect((wire, 0), False)
- end_connector.Connect((wire, -1), False)
- wire.ConnectStartPoint(None, start_connector)
- wire.ConnectEndPoint(None, end_connector)
- if selection is not None and (\
- selection[1].get((id, refLocalId), False) or \
- selection[1].get((refLocalId, id), False)):
- self.SelectInGroup(wire)
+ links_connected = False + if refLocalId not in ids: + new_instance = self.Controler.GetEditedElementInstanceInfos(self.TagName, refLocalId, debug = self.Debug) + if new_instance is not None: + self.loadInstance(new_instance, ids, selection) + connected = self.FindElementById(refLocalId) + links_connected = False + points = link["points"] + end_connector = connected.GetConnector(wx.Point(points[-1][0], points[-1][1]), link["formalParameter"]) + if end_connector is not None: + start_connector.Connect((wire, 0), False) + end_connector.Connect((wire, -1), False) + wire.ConnectStartPoint(None, start_connector) + wire.ConnectEndPoint(None, end_connector) + connected.RefreshConnectors() + if selection is not None and (\ + selection[1].get((id, refLocalId), False) or \ + selection[1].get((refLocalId, id), False)): + self.SelectInGroup(wire) + links_connected = False def IsOfType(self, type, reference):
return self.Controler.IsOfType(type, reference, self.Debug)
@@ -1356,8 +1416,7 @@
if self.SelectedElement is not None:
self.SelectedElement.SetSelected(False)
self.SelectedElement = Graphic_Group(self)
- for element in self.GetElements():
- self.SelectedElement.SelectElement(element)
+ self.SelectedElement.SetElements(self.GetElements()) self.SelectedElement.SetSelected(True)
#-------------------------------------------------------------------------------
@@ -1449,7 +1508,18 @@
def PopupWireMenu(self, delete=True):
- self.AddWireMenuItems(menu, delete)
+ # If Check that wire can be replace by connections or abort + connected = self.SelectedElement.GetConnected() + self.SelectedElement.GetEndConnected() + if self.SelectedElement.GetStartConnected() in connected + else self.SelectedElement.GetStartConnected()) + self.AddWireMenuItems(menu, delete, + start_connector.GetDirection() == EAST and + not isinstance(start_connector.GetParentBlock(), SFC_Step)) self.AddDefaultMenuItems(menu, block=True)
self.Editor.PopupMenu(menu)
@@ -1487,37 +1557,37 @@
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(ALIGN_LEFT, None)
+ self.Editor.Refresh(False) def OnAlignCenterMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(ALIGN_CENTER, None)
+ self.Editor.Refresh(False) def OnAlignRightMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(ALIGN_RIGHT, None)
+ self.Editor.Refresh(False) def OnAlignTopMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(None, ALIGN_TOP)
+ self.Editor.Refresh(False) def OnAlignMiddleMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(None, ALIGN_MIDDLE)
+ self.Editor.Refresh(False) def OnAlignBottomMenu(self, event):
if self.SelectedElement is not None and isinstance(self.SelectedElement, Graphic_Group):
self.SelectedElement.AlignElements(None, ALIGN_BOTTOM)
+ self.Editor.Refresh(False) def OnNoModifierMenu(self, event):
if self.SelectedElement is not None and self.IsBlock(self.SelectedElement):
@@ -1552,7 +1622,111 @@
if self.SelectedElement is not None and self.IsWire(self.SelectedElement):
self.SelectedElement.DeleteSegment()
self.SelectedElement.Refresh()
+ 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)): + # Get wire redraw bbox to erase it from screen + wire = self.SelectedElement + redraw_rect = wire.GetRedrawRect() + # Get connector at both ends of wire + connected = wire.GetConnected() + if wire.GetStartConnected() in connected: + start_connector = wire.GetEndConnected() + end_connector = wire.GetStartConnected() + wire.UnConnectStartPoint() + start_connector = wire.GetStartConnected() + end_connector = wire.GetEndConnected() + wire.UnConnectEndPoint() + # Get a new default connection name + connection_name = self.Controler.GenerateNewName( + self.TagName, None, "Connection%d", 0) + # Create a connector to connect to wire + connection = FBD_Connector(self, CONNECTOR, connection_name, id) + connection.SetSize(*self.GetScaledSize(*connection.GetMinSize())) + # Calculate position of connector at the right of start connector + connector = connection.GetConnectors()["inputs"][0] + rel_pos = connector.GetRelPosition() + direction = connector.GetDirection() + start_point = start_connector.GetPosition(False) + end_point = (start_point[0] + LD_WIRE_SIZE, start_point[1]) + connection.SetPosition(end_point[0] - rel_pos[0], + end_point[1] - rel_pos[1]) + # Connect connector to wire + connector.Connect((wire, point_to_connect)) + if point_to_connect == 0: + wire.SetPoints([end_point, start_point]) + wire.SetPoints([start_point, end_point]) + # Update redraw bbox with new wire trace so that it will be redraw + redraw_rect.Union(wire.GetRedrawRect()) + # Add connector to Viewer and model + self.AddBlock(connection) + self.Controler.AddEditedElementConnection(self.TagName, id, + connection.RefreshModel() + # Update redraw bbox with new connector bbox so that it will be + redraw_rect.Union(connection.GetRedrawRect()) + connection = FBD_Connector(self, CONTINUATION, connection_name, id) + connection.SetSize(*self.GetScaledSize(*connection.GetMinSize())) + # Calculate position of connection at the left of end connector + connector = connection.GetConnectors()["outputs"][0] + rel_pos = connector.GetRelPosition() + direction = connector.GetDirection() + end_point = end_connector.GetPosition(False) + start_point = (end_point[0] - LD_WIRE_SIZE, end_point[1]) + connection.SetPosition(start_point[0] - rel_pos[0], + start_point[1] - rel_pos[1]) + # Add Wire to Viewer and connect it to blocks + [wx.Point(*start_point), connector.GetDirection()], + [wx.Point(*end_point), end_connector.GetDirection()]) + connector.Connect((new_wire, 0), False) + end_connector.Connect((new_wire, -1), False) + new_wire.ConnectStartPoint(None, connector) + new_wire.ConnectEndPoint(None, end_connector) + # Update redraw bbox with new wire bbox so that it will be drawn on + redraw_rect.Union(new_wire.GetRedrawRect()) + # Add connection to Viewer and model + self.AddBlock(connection) + self.Controler.AddEditedElementConnection(self.TagName, id, + connection.RefreshModel() + # Update redraw bbox with new connection bbox so that it will be + redraw_rect.Union(connection.GetRedrawRect()) + # Refresh model for new wire + end_connector.RefreshParentBlock() + self.RefreshScrollBars() + self.RefreshVisibleElements() + self.RefreshRect(self.GetScrolledRect(redraw_rect), False) def OnAddBranchMenu(self, event):
if self.SelectedElement is not None and self.IsBlock(self.SelectedElement):
self.AddDivergenceBranch(self.SelectedElement)
@@ -1577,7 +1751,7 @@
self.SelectedElement.Delete()
self.SelectedElement = None
+ self.Editor.Refresh(False) def OnClearExecutionOrderMenu(self, event):
self.Controler.ClearEditedElementExecutionOrder(self.TagName)
@@ -1594,6 +1768,12 @@
wx.CallAfter(func, self.rubberBand.GetCurrentExtent(), *args)
+ def GetAddToWireMenuCallBack(self, func, *args): + args += (self.SelectedElement,) + def AddToWireMenuCallBack(event): + func(wx.Rect(0, 0, 0, 0), *args) + return AddToWireMenuCallBack def GetClipboardCallBack(self, func):
def ClipboardCallback(event):
@@ -1604,23 +1784,32 @@
#-------------------------------------------------------------------------------
def OnViewerMouseEvent(self, event):
- if not event.Entering():
+ if event.Leaving() and self.ToolTipElement is not None: + self.ToolTipElement.DestroyToolTip() + elif (not event.Entering() and + gettime() - self.LastToolTipCheckTime > REFRESH_PERIOD): + self.LastToolTipCheckTime = gettime() if not event.Leaving() and not event.LeftUp() and not event.LeftDClick():
- element = self.FindElement(event, True, False)
+ dc = self.GetLogicalDC() + pos = event.GetLogicalPosition(dc) + element = self.FindBlockConnector(pos) + if element is None or len(element.GetWires()) > 0: + element = self.FindElement(event, True, False) if self.ToolTipElement is not None:
- self.ToolTipElement.ClearToolTip()
+ self.ToolTipElement.DestroyToolTip() self.ToolTipElement = element
if self.ToolTipElement is not None:
tooltip_pos = self.Editor.ClientToScreen(event.GetPosition())
- self.ToolTipElement.CreateToolTip(tooltip_pos)
+ self.ToolTipElement.DisplayToolTip(tooltip_pos) def OnViewerLeftDown(self, event):
self.Editor.CaptureMouse()
+ self.StartMousePos = event.GetPosition() if self.Mode == MODE_SELECTION:
pos = event.GetLogicalPosition(dc)
@@ -1674,10 +1863,15 @@
elif not self.Debug and connector is not None and not event.ControlDown():
scaled_pos = GetScaledEventPosition(event, dc, self.Scaling)
- if (connector.GetDirection() == EAST):
- wire = Wire(self, [wx.Point(pos.x, pos.y), EAST], [wx.Point(scaled_pos.x, scaled_pos.y), WEST])
- wire = Wire(self, [wx.Point(pos.x, pos.y), WEST], [wx.Point(scaled_pos.x, scaled_pos.y), EAST])
+ SOUTH: [SOUTH, NORTH]}[connector.GetDirection()] + wire = Wire(self, *map(list, zip( + [wx.Point(pos.x, pos.y), + wx.Point(scaled_pos.x, scaled_pos.y)], wire.Handle = (HANDLE_POINT, 0)
wire.ProcessDragging(0, 0, event, None)
@@ -1691,6 +1885,7 @@
self.HighlightedElement = wire
self.RefreshVisibleElements()
self.SelectedElement.SetHighlighted(True)
+ self.SelectedElement.StartConnected.HighlightParentBlock(True) if self.SelectedElement is not None and self.SelectedElement != element:
self.SelectedElement.SetSelected(False)
@@ -1698,7 +1893,6 @@
self.SelectedElement = element
- self.StartMousePos = event.GetPosition()
Graphic_Element.OnLeftDown(self.SelectedElement, event, dc, self.Scaling)
self.SelectedElement.OnLeftDown(event, dc, self.Scaling)
@@ -1712,7 +1906,6 @@
self.rubberBand.OnLeftDown(event, self.GetLogicalDC(), self.Scaling)
elif self.Mode == MODE_MOTION:
- self.StartMousePos = event.GetPosition()
self.StartScreenPos = self.GetScrollPos(wx.HORIZONTAL), self.GetScrollPos(wx.VERTICAL)
@@ -1783,14 +1976,72 @@
self.SelectedElement.HighlightPoint(pos)
elif connector is None or self.SelectedElement.GetDragging():
- self.DrawingWire = False
- rect = self.SelectedElement.GetRedrawRect()
- wire = self.SelectedElement
- self.SelectedElement = self.SelectedElement.StartConnected.GetParentBlock()
- self.SelectedElement.SetSelected(True)
- rect.Union(self.SelectedElement.GetRedrawRect())
- self.RefreshRect(self.GetScrolledRect(rect), False)
+ start_connector = self.SelectedElement.GetStartConnected() + start_direction = start_connector.GetDirection() + if self.CurrentLanguage == "SFC" and start_direction == SOUTH: + (_(u'Initial Step'), self.GetAddToWireMenuCallBack(self.AddNewStep, True)), + (_(u'Step'), self.GetAddToWireMenuCallBack(self.AddNewStep, False)), + (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, False)), + (_(u'Divergence'), self.GetAddToWireMenuCallBack(self.AddNewDivergence)), + (_(u'Jump'), self.GetAddToWireMenuCallBack(self.AddNewJump)), + elif start_direction == EAST: + if isinstance(start_connector.GetParentBlock(), SFC_Step): + (_(u'Action Block'), self.GetAddToWireMenuCallBack(self.AddNewActionBlock)) + (_(u'Block'), self.GetAddToWireMenuCallBack(self.AddNewBlock)), + (_(u'Variable'), self.GetAddToWireMenuCallBack(self.AddNewVariable, True)), + (_(u'Connection'), self.GetAddToWireMenuCallBack(self.AddNewConnection)), + if self.CurrentLanguage != "FBD": + (_(u'Contact'), self.GetAddToWireMenuCallBack(self.AddNewContact)) + if self.CurrentLanguage == "LD": + (_(u'Coil'), self.GetAddToWireMenuCallBack(self.AddNewCoil)), + (_(u'Power Rail'), self.GetAddToWireMenuCallBack(self.AddNewPowerRail)), + if self.CurrentLanguage == "SFC": + (_(u'Transition'), self.GetAddToWireMenuCallBack(self.AddNewTransition, True)) + if self.Editor.HasCapture(): + self.Editor.ReleaseMouse() + # Popup contextual menu + self.AddMenuItems(menu, + [(wx.NewId(), wx.ITEM_NORMAL, text, '', callback) + for text, callback in items]) + self.SelectedElement.StartConnected.HighlightParentBlock(False) + self.DrawingWire = False + rect = self.SelectedElement.GetRedrawRect() + wire = self.SelectedElement + self.SelectedElement = self.SelectedElement.StartConnected.GetParentBlock() + self.SelectedElement.SetSelected(True) + rect.Union(self.SelectedElement.GetRedrawRect()) + self.RefreshRect(self.GetScrolledRect(rect), False) + self.SelectedElement.SetSelected(True) + if not self.SelectedElement.IsConnectedCompatible(): + self.SelectedElement.SetValid(False) Graphic_Element.OnLeftUp(self.SelectedElement, event, dc, self.Scaling)
@@ -1798,7 +2049,6 @@
self.SelectedElement.OnLeftUp(event, dc, self.Scaling)
wx.CallAfter(self.SetCurrentCursor, 0)
elif self.Mode == MODE_MOTION:
- self.StartMousePos = None
self.StartScreenPos = None
if self.Mode != MODE_SELECTION and not self.SavedMode:
wx.CallAfter(self.ParentWindow.ResetCurrentMode)
@@ -1853,7 +2103,7 @@
def OnViewerLeftDClick(self, event):
- element = self.FindElement(event, connectors=False)
+ element = self.FindElement(event) if self.Mode == MODE_SELECTION and element is not None:
if self.SelectedElement is not None and self.SelectedElement != element:
self.SelectedElement.SetSelected(False)
@@ -1866,15 +2116,24 @@
if isinstance(self.SelectedElement, FBD_Block):
- instance_type = self.SelectedElement.GetType()
- "program": ITEM_PROGRAM,
- "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.Controler.ComputePouName(instance_type))
+ dc = self.GetLogicalDC() + pos = event.GetLogicalPosition(dc) + connector = self.SelectedElement.TestConnector(pos, EAST) + if connector is not None and len(connector.GetWires()) == 0: + iec_path = self.GetElementIECPath(connector) + if iec_path is not None: + self.ParentWindow.OpenDebugViewer( + ITEM_VAR_LOCAL, iec_path, connector.GetType()) + instance_type = self.SelectedElement.GetType() + "program": ITEM_PROGRAM, + "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.Controler.ComputePouName(instance_type)) iec_path = self.GetElementIECPath(self.SelectedElement)
@@ -1925,13 +2184,15 @@
self.RefreshVisibleElements()
- if not event.Dragging():
+ 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:
self.HighlightedElement.SetHighlighted(False)
self.HighlightedElement = None
if highlighted is not None:
- if isinstance(highlighted, (Wire, Graphic_Group)):
+ if not self.Debug and isinstance(highlighted, (Wire, Graphic_Group)): highlighted.HighlightPoint(pos)
if self.HighlightedElement != highlighted:
highlighted.SetHighlighted(True)
@@ -1947,16 +2208,25 @@
self.SelectedElement.GeneratePoints()
if movex != 0 or movey != 0:
self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)), False)
self.SelectedElement.HighlightPoint(pos)
movex, movey = self.SelectedElement.OnMotion(event, dc, self.Scaling)
if movex != 0 or movey != 0:
self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)), False)
+ self.RefreshVisibleElements() elif self.Debug and self.StartMousePos is not None and event.Dragging():
pos = event.GetPosition()
if abs(self.StartMousePos.x - pos.x) > 5 or abs(self.StartMousePos.y - pos.y) > 5:
- iec_path = self.GetElementIECPath(self.SelectedElement)
+ element = self.SelectedElement + if isinstance(self.SelectedElement, FBD_Block): + dc = self.GetLogicalDC() + connector = self.SelectedElement.TestConnector( + wx.Point(dc.DeviceToLogicalX(self.StartMousePos.x), + dc.DeviceToLogicalY(self.StartMousePos.y))) + if connector is not None: + iec_path = self.GetElementIECPath(element) self.StartMousePos = None
if self.HighlightedElement is not None:
@@ -1973,8 +2243,6 @@
def OnLeaveViewer(self, event):
- if self.StartScreenPos is None:
- self.StartMousePos = None
if self.SelectedElement is not None and self.SelectedElement.GetDragging():
elif self.HighlightedElement is not None:
@@ -2053,6 +2321,7 @@
self.SelectedElement.RefreshModel()
+ self.RefreshVisibleElements() self.RefreshRect(self.GetScrolledRect(self.SelectedElement.GetRedrawRect(movex, movey)), False)
elif not self.Debug and keycode == wx.WXK_SPACE and self.SelectedElement is not None and self.SelectedElement.Dragging:
if self.IsBlock(self.SelectedElement) or self.IsComment(self.SelectedElement):
@@ -2099,7 +2368,7 @@
self.RefreshVisibleElements()
+ self.Editor.Refresh(False) #-------------------------------------------------------------------------------
@@ -2111,13 +2380,39 @@
height = round(float(height) / float(self.Scaling[1]) + 0.4) * self.Scaling[1]
- def AddNewBlock(self, bbox):
- dialog = FBDBlockDialog(self.ParentWindow, self.Controler)
+ def AddNewElement(self, element, bbox, wire=None, connector=None): + min_width, min_height = (element.GetMinSize(True) + if isinstance(element, (LD_PowerRail, + else element.GetMinSize()) + element.SetSize(*self.GetScaledSize( + max(bbox.width, min_width), max(bbox.height, min_height))) + connector = element.GetConnectors()["inputs"][0] + point = wire.GetPoint(-1) + rel_pos = connector.GetRelPosition() + direction = connector.GetDirection() + point[0] - rel_pos[0] - direction[0] * CONNECTOR_SIZE, + point[1] - rel_pos[1] - direction[1] * CONNECTOR_SIZE, + connector.Connect((wire, -1)) + self.DrawingWire = False + element.SetPosition(bbox.x, bbox.y) + self.RefreshScrollBars() + self.RefreshVisibleElements() + def AddNewBlock(self, bbox, wire=None): + dialog = FBDBlockDialog(self.ParentWindow, self.Controler, self.TagName) dialog.SetPreviewFont(self.GetFont())
- dialog.SetBlockList(self.Controler.GetBlockTypes(self.TagName, self.Debug))
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- dialog.SetPouElementNames(self.Controler.GetEditedElementVariables(self.TagName, self.Debug))
- dialog.SetMinBlockSize((bbox.width, bbox.height))
+ dialog.SetMinElementSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
@@ -2126,78 +2421,54 @@
values["extension"], values["inputs"],
executionControl = values["executionControl"],
executionOrder = values["executionOrder"])
- block.SetPosition(bbox.x, bbox.y)
- block.SetSize(*self.GetScaledSize(values["width"], values["height"]))
self.Controler.AddEditedElementBlock(self.TagName, id, values["type"], values.get("name", None))
- self.RefreshBlockModel(block)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
- self.RefreshVariablePanel()
- self.ParentWindow.RefreshPouInstanceVariablesPanel()
+ for input_connector in block.GetConnectors()["inputs"]: + if input_connector.IsCompatible( + wire.GetStartConnectedType()): + connector = input_connector + self.AddNewElement(block, bbox, wire, connector) - def AddNewVariable(self, bbox):
- words = self.TagName.split("::")
- dialog = FBDVariableDialog(self.ParentWindow, self.Controler, words[2])
- dialog = FBDVariableDialog(self.ParentWindow, self.Controler)
+ def AddNewVariable(self, bbox, exclude_input=False, wire=None): + dialog = FBDVariableDialog(self.ParentWindow, self.Controler, self.TagName, exclude_input) dialog.SetPreviewFont(self.GetFont())
- dialog.SetMinVariableSize((bbox.width, bbox.height))
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- varlist.append((var["Name"], var["Class"], var["Type"]))
- returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
- varlist.append((self.Controler.GetEditedElementName(self.TagName), "Output", returntype))
- dialog.SetVariables(varlist)
+ dialog.SetMinElementSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
- variable = FBD_Variable(self, values["type"], values["name"], values["value_type"], id)
- variable.SetPosition(bbox.x, bbox.y)
- variable.SetSize(*self.GetScaledSize(values["width"], values["height"]))
- self.AddBlock(variable)
- self.Controler.AddEditedElementVariable(self.TagName, id, values["type"])
- self.RefreshVariableModel(variable)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ variable = FBD_Variable(self, values["class"], values["expression"], values["var_type"], id) + variable.SetExecutionOrder(values["executionOrder"]) + self.Controler.AddEditedElementVariable(self.TagName, id, values["class"]) + self.AddNewElement(variable, bbox, wire) - def AddNewConnection(self, bbox):
- dialog = ConnectionDialog(self.ParentWindow, self.Controler)
- dialog.SetPreviewFont(self.GetFont())
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- dialog.SetPouElementNames(self.Controler.GetEditedElementVariables(self.TagName, self.Debug))
- dialog.SetMinConnectionSize((bbox.width, bbox.height))
- if dialog.ShowModal() == wx.ID_OK:
+ def AddNewConnection(self, bbox, wire=None): + "name": self.Controler.GenerateNewName( + self.TagName, None, "Connection%d", 0)} + dialog = ConnectionDialog(self.ParentWindow, self.Controler, self.TagName) + dialog.SetPreviewFont(self.GetFont()) + dialog.SetMinElementSize((bbox.width, bbox.height)) + values = (dialog.GetValues() + if dialog.ShowModal() == wx.ID_OK - values = dialog.GetValues()
connection = FBD_Connector(self, values["type"], values["name"], id)
- connection.SetPosition(bbox.x, bbox.y)
- connection.SetSize(*self.GetScaledSize(values["width"], values["height"]))
- self.AddBlock(connection)
self.Controler.AddEditedElementConnection(self.TagName, id, values["type"])
- self.RefreshConnectionModel(connection)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ self.AddNewElement(connection, bbox, wire) def AddNewComment(self, bbox):
- if wx.VERSION >= (2, 5, 0):
- dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), "", wx.OK|wx.CANCEL|wx.TE_MULTILINE)
- dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), "", wx.OK|wx.CANCEL)
+ dialog = wx.TextEntryDialog(self.ParentWindow, + _("Please enter comment text"), + "", wx.OK|wx.CANCEL|wx.TE_MULTILINE) dialog.SetClientSize(wx.Size(400, 200))
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
@@ -2215,158 +2486,112 @@
- def AddNewContact(self, bbox):
- dialog = LDElementDialog(self.ParentWindow, self.Controler, "contact")
+ def AddNewContact(self, bbox, wire=None): + dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "contact") dialog.SetPreviewFont(self.GetFont())
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- if var["Type"] == "BOOL":
- varlist.append(var["Name"])
- dialog.SetVariables(varlist)
- dialog.SetValues({"name":"","type":CONTACT_NORMAL})
- dialog.SetElementSize((bbox.width, bbox.height))
+ dialog.SetMinElementSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
- contact = LD_Contact(self, values["type"], values["name"], id)
- contact.SetPosition(bbox.x, bbox.y)
- contact.SetSize(*self.GetScaledSize(values["width"], values["height"]))
+ contact = LD_Contact(self, values["modifier"], values["variable"], id) self.Controler.AddEditedElementContact(self.TagName, id)
- self.RefreshContactModel(contact)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ self.AddNewElement(contact, bbox, wire) - def AddNewCoil(self, bbox):
- dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
+ def AddNewCoil(self, bbox, wire=None): + dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "coil") dialog.SetPreviewFont(self.GetFont())
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- if var["Class"] != "Input" and var["Type"] == "BOOL":
- varlist.append(var["Name"])
- returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
- if returntype == "BOOL":
- varlist.append(self.Controler.GetEditedElementName(self.TagName))
- dialog.SetVariables(varlist)
- dialog.SetValues({"name":"","type":COIL_NORMAL})
- dialog.SetElementSize((bbox.width, bbox.height))
- if dialog.ShowModal() == wx.ID_OK:
- values = dialog.GetValues()
- coil = LD_Coil(self, values["type"], values["name"], id)
- coil.SetPosition(bbox.x, bbox.y)
- coil.SetSize(*self.GetScaledSize(values["width"], values["height"]))
- self.Controler.AddEditedElementCoil(self.TagName, id)
- self.RefreshCoilModel(coil)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
- def AddNewPowerRail(self, bbox):
- dialog = LDPowerRailDialog(self.ParentWindow, self.Controler)
- dialog.SetPreviewFont(self.GetFont())
- dialog.SetMinSize((bbox.width, bbox.height))
+ dialog.SetMinElementSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
- powerrail = LD_PowerRail(self, values["type"], id, values["number"])
- powerrail.SetPosition(bbox.x, bbox.y)
- powerrail.SetSize(*self.GetScaledSize(values["width"], values["height"]))
- self.AddBlock(powerrail)
- self.Controler.AddEditedElementPowerRail(self.TagName, id, values["type"])
- self.RefreshPowerRailModel(powerrail)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ coil = LD_Coil(self, values["modifier"], values["variable"], id) + self.Controler.AddEditedElementCoil(self.TagName, id) + self.AddNewElement(coil, bbox, wire) - def AddNewStep(self, bbox, initial = False):
- dialog = SFCStepDialog(self.ParentWindow, self.Controler, initial)
- dialog.SetPreviewFont(self.GetFont())
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug))
- dialog.SetStepNames([block.GetName() for block in self.Blocks.itervalues() if isinstance(block, SFC_Step)])
- dialog.SetMinStepSize((bbox.width, bbox.height))
- if dialog.ShowModal() == wx.ID_OK:
+ def AddNewPowerRail(self, bbox, wire=None): + dialog = LDPowerRailDialog(self.ParentWindow, self.Controler, self.TagName) + dialog.SetPreviewFont(self.GetFont()) + dialog.SetMinElementSize((bbox.width, bbox.height)) + values = (dialog.GetValues() + if dialog.ShowModal() == wx.ID_OK - values = dialog.GetValues()
+ powerrail = LD_PowerRail(self, values["type"], id, values["pin_number"]) + self.Controler.AddEditedElementPowerRail(self.TagName, id, values["type"]) + self.AddNewElement(powerrail, bbox, wire) + def AddNewStep(self, bbox, initial=False, wire=None): + "name": self.Controler.GenerateNewName( + self.TagName, None, "Step%d", 0), + dialog = SFCStepDialog(self.ParentWindow, self.Controler, self.TagName, initial) + dialog.SetPreviewFont(self.GetFont()) + dialog.SetMinElementSize((bbox.width, bbox.height)) + values = (dialog.GetValues() + if dialog.ShowModal() == wx.ID_OK step = SFC_Step(self, values["name"], initial, id)
- step.SetPosition(bbox.x, bbox.y)
- min_width, min_height = step.GetMinSize()
- step.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
self.Controler.AddEditedElementStep(self.TagName, id)
- self.RefreshStepModel(step)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
- def AddNewTransition(self, bbox):
- dialog = SFCTransitionDialog(self.ParentWindow, self.Controler, self.GetDrawingMode() == FREEDRAWING_MODE)
- dialog.SetPreviewFont(self.GetFont())
- dialog.SetTransitions(self.Controler.GetEditedElementTransitions(self.TagName, self.Debug))
- if dialog.ShowModal() == wx.ID_OK:
+ for connector in ["input", "output", "action"]: + else "Remove") + connector.capitalize())() + self.AddNewElement(step, bbox, wire) + def AddNewTransition(self, bbox, connection=False, wire=None): + if wire is not None and connection: + dialog = SFCTransitionDialog(self.ParentWindow, self.Controler, self.TagName, self.GetDrawingMode() == FREEDRAWING_MODE) + dialog.SetPreviewFont(self.GetFont()) + dialog.SetMinElementSize((bbox.width, bbox.height)) + values = (dialog.GetValues() + if dialog.ShowModal() == wx.ID_OK - values = dialog.GetValues()
transition = SFC_Transition(self, values["type"], values["value"], values["priority"], id)
- transition.SetPosition(bbox.x, bbox.y)
- min_width, min_height = transition.GetMinSize()
- transition.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
- self.AddBlock(transition)
self.Controler.AddEditedElementTransition(self.TagName, id)
- self.RefreshTransitionModel(transition)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
- def AddNewDivergence(self, bbox):
- dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler)
+ connector = transition.GetConditionConnector() + connector = transition.GetConnectors()["inputs"][0] + self.AddNewElement(transition, bbox, wire, connector) + def AddNewDivergence(self, bbox, wire=None): + dialog = SFCDivergenceDialog(self.ParentWindow, self.Controler, self.TagName) dialog.SetPreviewFont(self.GetFont())
- dialog.SetMinSize((bbox.width, bbox.height))
+ dialog.SetMinElementSize((bbox.width, bbox.height)) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
divergence = SFC_Divergence(self, values["type"], values["number"], id)
- divergence.SetPosition(bbox.x, bbox.y)
- min_width, min_height = divergence.GetMinSize(True)
- divergence.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
- self.AddBlock(divergence)
self.Controler.AddEditedElementDivergence(self.TagName, id, values["type"])
- self.RefreshDivergenceModel(divergence)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ self.AddNewElement(divergence, bbox, wire) - def AddNewJump(self, bbox):
+ def AddNewJump(self, bbox, wire=None): for block in self.Blocks.itervalues():
if isinstance(block, SFC_Step):
@@ -2376,39 +2601,21 @@
choices, wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
- value = dialog.GetStringSelection()
- jump = SFC_Jump(self, value, id)
- jump.SetPosition(bbox.x, bbox.y)
- min_width, min_height = jump.GetMinSize()
- jump.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
+ jump = SFC_Jump(self, dialog.GetStringSelection(), id) self.Controler.AddEditedElementJump(self.TagName, id)
- self.RefreshJumpModel(jump)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ self.AddNewElement(jump, bbox, wire) - def AddNewActionBlock(self, bbox):
+ def AddNewActionBlock(self, bbox, wire=None): dialog = ActionBlockDialog(self.ParentWindow)
dialog.SetQualifierList(self.Controler.GetQualifierTypes())
dialog.SetActionList(self.Controler.GetEditedElementActions(self.TagName, self.Debug))
dialog.SetVariableList(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug))
if dialog.ShowModal() == wx.ID_OK:
- actions = dialog.GetValues()
- actionblock = SFC_ActionBlock(self, actions, id)
- actionblock.SetPosition(bbox.x, bbox.y)
- min_width, min_height = actionblock.GetMinSize()
- actionblock.SetSize(*self.GetScaledSize(max(bbox.width, min_width), max(bbox.height, min_height)))
- self.AddBlock(actionblock)
+ actionblock = SFC_ActionBlock(self, dialog.GetValues(), id) self.Controler.AddEditedElementActionBlock(self.TagName, id)
- self.RefreshActionBlockModel(actionblock)
- self.RefreshScrollBars()
- self.RefreshVisibleElements()
+ self.AddNewElement(actionblock, bbox, wire) #-------------------------------------------------------------------------------
@@ -2416,15 +2623,9 @@
#-------------------------------------------------------------------------------
def EditBlockContent(self, block):
- dialog = FBDBlockDialog(self.ParentWindow, self.Controler)
+ dialog = FBDBlockDialog(self.ParentWindow, self.Controler, self.TagName) dialog.SetPreviewFont(self.GetFont())
- dialog.SetBlockList(self.Controler.GetBlockTypes(self.TagName, self.Debug))
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- variable_names = self.Controler.GetEditedElementVariables(self.TagName, self.Debug)
- if block.GetName() != "":
- variable_names.remove(block.GetName())
- dialog.SetPouElementNames(variable_names)
- dialog.SetMinBlockSize(block.GetSize())
+ dialog.SetMinElementSize(block.GetSize()) old_values = {"name" : block.GetName(),
"type" : block.GetType(),
"extension" : block.GetExtension(),
@@ -2456,38 +2657,24 @@
def EditVariableContent(self, variable):
- words = self.TagName.split("::")
- dialog = FBDVariableDialog(self.ParentWindow, self.Controler, words[2])
- dialog = FBDVariableDialog(self.ParentWindow, self.Controler)
+ dialog = FBDVariableDialog(self.ParentWindow, self.Controler, self.TagName) dialog.SetPreviewFont(self.GetFont())
- dialog.SetMinVariableSize(variable.GetSize())
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- varlist.append((var["Name"], var["Class"], var["Type"]))
- returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
- varlist.append((self.Controler.GetEditedElementName(self.TagName), "Output", returntype))
- dialog.SetVariables(varlist)
- old_values = {"name" : variable.GetName(), "type" : variable.GetType(),
- "executionOrder" : variable.GetExecutionOrder()}
+ dialog.SetMinElementSize(variable.GetSize()) + 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()
rect = variable.GetRedrawRect(1, 1)
- variable.SetName(new_values["name"])
- variable.SetType(new_values["type"], new_values["value_type"])
+ variable.SetName(new_values["expression"]) + variable.SetType(new_values["class"], new_values["var_type"]) variable.SetSize(*self.GetScaledSize(new_values["width"], new_values["height"]))
variable.SetExecutionOrder(new_values["executionOrder"])
rect = rect.Union(variable.GetRedrawRect())
- if old_values["type"] != new_values["type"]:
+ if old_values["class"] != new_values["class"]: self.Controler.RemoveEditedElementInstance(self.TagName, id)
- self.Controler.AddEditedElementVariable(self.TagName, id, new_values["type"])
+ self.Controler.AddEditedElementVariable(self.TagName, id, new_values["class"]) self.RefreshVariableModel(variable)
if old_values["executionOrder"] != new_values["executionOrder"]:
@@ -2499,11 +2686,9 @@
def EditConnectionContent(self, connection):
- dialog = ConnectionDialog(self.ParentWindow, self.Controler, True)
+ dialog = ConnectionDialog(self.ParentWindow, self.Controler, self.TagName, True) dialog.SetPreviewFont(self.GetFont())
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- dialog.SetPouElementNames(self.Controler.GetEditedElementVariables(self.TagName, self.Debug))
- dialog.SetMinConnectionSize(connection.GetSize())
+ dialog.SetMinElementSize(connection.GetSize()) values = {"name" : connection.GetName(), "type" : connection.GetType()}
result = dialog.ShowModal()
@@ -2533,23 +2718,16 @@
def EditContactContent(self, contact):
- dialog = LDElementDialog(self.ParentWindow, self.Controler, "contact")
+ dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "contact") dialog.SetPreviewFont(self.GetFont())
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- if var["Type"] == "BOOL":
- varlist.append(var["Name"])
- dialog.SetVariables(varlist)
- values = {"name" : contact.GetName(), "type" : contact.GetType()}
- dialog.SetValues(values)
- dialog.SetElementSize(contact.GetSize())
+ dialog.SetMinElementSize(contact.GetSize()) + dialog.SetValues({"variable" : contact.GetName(), + "modifier" : contact.GetType()}) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = contact.GetRedrawRect(1, 1)
- contact.SetName(values["name"])
- contact.SetType(values["type"])
+ contact.SetName(values["variable"]) + contact.SetType(values["modifier"]) contact.SetSize(*self.GetScaledSize(values["width"], values["height"]))
rect = rect.Union(contact.GetRedrawRect())
self.RefreshContactModel(contact)
@@ -2560,26 +2738,16 @@
def EditCoilContent(self, coil):
- dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
+ dialog = LDElementDialog(self.ParentWindow, self.Controler, self.TagName, "coil") dialog.SetPreviewFont(self.GetFont())
- vars = self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)
- if var["Class"] != "Input" and var["Type"] == "BOOL":
- varlist.append(var["Name"])
- returntype = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
- if returntype == "BOOL":
- varlist.append(self.Controler.GetEditedElementName(self.TagName))
- dialog.SetVariables(varlist)
- values = {"name" : coil.GetName(), "type" : coil.GetType()}
- dialog.SetValues(values)
- dialog.SetElementSize(coil.GetSize())
+ dialog.SetMinElementSize(coil.GetSize()) + dialog.SetValues({"variable" : coil.GetName(), + "modifier" : coil.GetType()}) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = coil.GetRedrawRect(1, 1)
- coil.SetName(values["name"])
- coil.SetType(values["type"])
+ coil.SetName(values["variable"]) + coil.SetType(values["modifier"]) coil.SetSize(*self.GetScaledSize(values["width"], values["height"]))
rect = rect.Union(coil.GetRedrawRect())
self.RefreshCoilModel(coil)
@@ -2590,23 +2758,21 @@
def EditPowerRailContent(self, powerrail):
- connectors = powerrail.GetConnectors()
- type = powerrail.GetType()
- pin_number = len(connectors["outputs"])
- pin_number = len(connectors["inputs"])
- dialog = LDPowerRailDialog(self.ParentWindow, self.Controler, type, pin_number)
+ dialog = LDPowerRailDialog(self.ParentWindow, self.Controler, self.TagName) dialog.SetPreviewFont(self.GetFont())
- dialog.SetMinSize(powerrail.GetSize())
+ dialog.SetMinElementSize(powerrail.GetSize()) + powerrail_type = powerrail.GetType() + "type": powerrail.GetType(), + "pin_number": len(powerrail.GetConnectors()[ + ("outputs" if powerrail_type == LEFTRAIL else "inputs")])}) if dialog.ShowModal() == wx.ID_OK:
- old_type = powerrail.GetType()
values = dialog.GetValues()
rect = powerrail.GetRedrawRect(1, 1)
- powerrail.SetType(values["type"], values["number"])
+ powerrail.SetType(values["type"], values["pin_number"]) powerrail.SetSize(*self.GetScaledSize(values["width"], values["height"]))
rect = rect.Union(powerrail.GetRedrawRect())
- if old_type != values["type"]:
+ if powerrail_type != values["type"]: self.Controler.RemoveEditedElementInstance(self.TagName, id)
self.Controler.AddEditedElementPowerRail(self.TagName, id, values["type"])
@@ -2618,18 +2784,15 @@
def EditStepContent(self, step):
- dialog = SFCStepDialog(self.ParentWindow, self.Controler, step.GetInitial())
+ dialog = SFCStepDialog(self.ParentWindow, self.Controler, self.TagName, step.GetInitial()) dialog.SetPreviewFont(self.GetFont())
- dialog.SetPouNames(self.Controler.GetProjectPouNames(self.Debug))
- dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug))
- dialog.SetStepNames([block.GetName() for block in self.Blocks.itervalues() if isinstance(block, SFC_Step) and block.GetName() != step.GetName()])
- dialog.SetMinStepSize(step.GetSize())
- values = {"name" : step.GetName()}
+ dialog.SetMinElementSize(step.GetSize()) connectors = step.GetConnectors()
- values["input"] = len(connectors["inputs"]) > 0
- values["output"] = len(connectors["outputs"]) > 0
- values["action"] = step.GetActionConnector() != None
- dialog.SetValues(values)
+ "name" : step.GetName(), + "input": len(connectors["inputs"]) > 0, + "output": len(connectors["outputs"]) > 0, + "action": step.GetActionConnector() != None}) if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = step.GetRedrawRect(1, 1)
@@ -2655,11 +2818,10 @@
def EditTransitionContent(self, transition):
- dialog = SFCTransitionDialog(self.ParentWindow, self.Controler, self.GetDrawingMode() == FREEDRAWING_MODE)
+ dialog = SFCTransitionDialog(self.ParentWindow, self.Controler, self.TagName, self.GetDrawingMode() == FREEDRAWING_MODE) dialog.SetPreviewFont(self.GetFont())
- dialog.SetTransitions(self.Controler.GetEditedElementTransitions(self.TagName, self.Debug))
+ dialog.SetMinElementSize(transition.GetSize()) dialog.SetValues({"type":transition.GetType(),"value":transition.GetCondition(), "priority":transition.GetPriority()})
- dialog.SetElementSize(transition.GetSize())
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
rect = transition.GetRedrawRect(1, 1)
@@ -2714,10 +2876,11 @@
def EditCommentContent(self, comment):
- if wx.VERSION >= (2, 5, 0):
- dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), comment.GetContent(), wx.OK|wx.CANCEL|wx.TE_MULTILINE)
- dialog = wx.TextEntryDialog(self.ParentWindow, _("Edit comment"), _("Please enter comment text"), comment.GetContent(), wx.OK|wx.CANCEL)
+ dialog = wx.TextEntryDialog(self.ParentWindow, + _("Please enter comment text"), + wx.OK|wx.CANCEL|wx.TE_MULTILINE) dialog.SetClientSize(wx.Size(400, 200))
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
@@ -3091,7 +3254,11 @@
format = "%s%%d" % blocktype
- return self.Controler.GenerateNewName(self.TagName, None, format, exclude, self.Debug)
+ return self.Controler.GenerateNewName(self.TagName, def IsNamedElement(self, element):
return isinstance(element, FBD_Block) and element.GetName() != "" or isinstance(element, SFC_Step)
@@ -3178,6 +3345,7 @@
blocks.append((block, (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT)))
self.SearchResults.extend([infos for block, infos in blocks])
+ self.CurrentFindHighlight = None if len(self.SearchResults) > 0:
if self.CurrentFindHighlight is not None:
@@ -3245,15 +3413,27 @@
#-------------------------------------------------------------------------------
def OnScrollWindow(self, event):
- if self.Editor.HasCapture() and self.StartMousePos:
+ if self.Editor.HasCapture() and self.StartMousePos is not None: if wx.Platform == '__WXMSW__':
wx.CallAfter(self.RefreshVisibleElements)
+ wx.CallAfter(self.Editor.Thaw) elif event.GetOrientation() == wx.HORIZONTAL:
self.RefreshVisibleElements(xp = event.GetPosition())
self.RefreshVisibleElements(yp = event.GetPosition())
+ # Handle scroll in debug to fully redraw area and ensuring + # instance path is fully draw without flickering + if self.Debug and wx.Platform != '__WXMSW__': + x, y = self.GetViewStart() + if event.GetOrientation() == wx.HORIZONTAL: + self.Scroll(event.GetPosition(), y) + self.Scroll(x, event.GetPosition()) def OnScrollStop(self, event):
@@ -3276,7 +3456,7 @@
yp = max(0, min(y - rotation * 3, self.Editor.GetVirtualSize()[1] / self.Editor.GetScrollPixelsPerUnit()[1]))
self.RefreshVisibleElements(yp = yp)
def OnMoveWindow(self, event):
self.RefreshVisibleElements()
@@ -3334,21 +3514,28 @@
+ scalex, scaley = dc.GetUserScale() is_action = self.TagName.split("::")[0] == "A"
text = _("Debug: %s") % self.InstancePath
if is_action and self.Value is not None:
- dc.DrawText(text, 2, 2)
+ text_offset_x, text_offset_y = self.CalcUnscrolledPosition(2, 2) + dc.DrawText(text, text_offset_x, text_offset_y) if is_action and self.Value is not None:
value_text = self.VALUE_TRANSLATION[self.Value]
tw, th = dc.GetTextExtent(text)
dc.SetTextForeground(wx.GREEN)
- dc.DrawText(value_text, tw + 2, 2)
+ dc.DrawText(value_text, text_offset_x + tw, text_offset_y) dc.SetTextForeground(wx.BLACK)
vw, vh = dc.GetTextExtent(value_text)
- dc.DrawText(")", tw + vw + 4, 2)
+ dc.DrawText(")", text_offset_x + tw + vw + 2, text_offset_y) + dc.SetUserScale(scalex, scaley) if self.rubberBand.IsShown():
--- a/i18n/Beremiz_fr_FR.po Wed Mar 13 12:34:55 2013 +0900
+++ b/i18n/Beremiz_fr_FR.po Wed Jul 31 10:45:07 2013 +0900
@@ -7,8 +7,8 @@
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-09-07 01:17+0200\n"
-"PO-Revision-Date: 2012-09-07 01:31+0100\n"
+"POT-Creation-Date: 2013-03-26 22:55+0100\n" +"PO-Revision-Date: 2013-03-26 23:08+0100\n" "Last-Translator: Laurent BESSARD <laurent.bessard@gmail.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,7 +16,7 @@
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../PLCOpenEditor.py:520
+#: ../PLCOpenEditor.py:405 "An error has occurred.\n"
@@ -38,7 +38,7 @@
@@ -87,7 +87,7 @@
-#: ../PLCOpenEditor.py:530
+#: ../PLCOpenEditor.py:415 @@ -99,7 +99,7 @@
-#: ../ProjectController.py:890
+#: ../ProjectController.py:917 msgid " generation failed !\n"
msgstr "la construction a échouée !\n"
@@ -123,8 +123,8 @@
msgid "\"%s\" can't use itself!"
msgstr "\"%s\" ne peut pas s'utiliser lui-même !"
msgid "\"%s\" config already exists!"
msgstr "La configuration \"%s\" existe déjà !"
@@ -134,46 +134,46 @@
msgid "\"%s\" configuration already exists !!!"
msgstr "La configuration \"%s\" existe déjà !!!"
msgid "\"%s\" data type already exists!"
msgstr "Le type de données \"%s\" existe déjà !"
-#: ../PLCControler.py:2040
-#: ../PLCControler.py:2044
+#: ../PLCControler.py:2165 +#: ../PLCControler.py:2169 msgid "\"%s\" element can't be pasted here!!!"
msgstr "L'élément \"%s\" ne peut être collé ici !!!"
-#: ../editors/TextViewer.py:305
-#: ../editors/TextViewer.py:325
-#: ../editors/Viewer.py:252
+#: ../editors/TextViewer.py:298 +#: ../editors/TextViewer.py:318 +#: ../editors/Viewer.py:250 #: ../dialogs/PouTransitionDialog.py:105
-#: ../dialogs/ConnectionDialog.py:150
+#: ../dialogs/ConnectionDialog.py:157 #: ../dialogs/PouActionDialog.py:102
#: ../dialogs/FBDBlockDialog.py:162
msgid "\"%s\" element for this pou already exists!"
msgstr "Un élément \"%s\" existe déjà dans ce POU !"
msgid "\"%s\" folder is not a valid Beremiz project\n"
msgstr "Le dossier \"%s\" ne contient pas de projet Beremiz valide\n"
-#: ../plcopen/structures.py:106
+#: ../plcopen/structures.py:105 msgid "\"%s\" function cancelled in \"%s\" POU: No input connected"
msgstr "L'appel à la fonction \"%s\" dans le POU \"%s\" a été abandonné : aucune entrée connectée"
-#: ../controls/VariablePanel.py:656
-#: ../editors/DataTypeEditor.py:548
-#: ../editors/DataTypeEditor.py:577
+#: ../controls/VariablePanel.py:659 +#: ../editors/DataTypeEditor.py:554 +#: ../editors/DataTypeEditor.py:583 #: ../dialogs/PouNameDialog.py:49
#: ../dialogs/PouTransitionDialog.py:101
#: ../dialogs/SFCStepNameDialog.py:51
-#: ../dialogs/ConnectionDialog.py:146
+#: ../dialogs/ConnectionDialog.py:153 #: ../dialogs/FBDVariableDialog.py:199
#: ../dialogs/PouActionDialog.py:98
#: ../dialogs/PouDialog.py:118
@@ -183,29 +183,29 @@
msgid "\"%s\" is a keyword. It can't be used!"
msgstr "\"%s\" est un mot réservé. Il ne peut être utilisé !"
-#: ../editors/Viewer.py:240
+#: ../editors/Viewer.py:238 msgid "\"%s\" is already used by \"%s\"!"
msgstr "\"%s\" est déjà utilisé par \"%s\" !"
-#: ../plcopen/plcopen.py:2786
+#: ../plcopen/plcopen.py:2836 msgid "\"%s\" is an invalid value!"
msgstr "\"%s\" n'est pas une valeur valide !"
-#: ../PLCOpenEditor.py:362
-#: ../PLCOpenEditor.py:399
+#: ../PLCOpenEditor.py:341 +#: ../PLCOpenEditor.py:378 msgid "\"%s\" is not a valid folder!"
msgstr "\"%s\" n'est pas un répertoire valide !"
-#: ../controls/VariablePanel.py:654
-#: ../editors/DataTypeEditor.py:572
+#: ../controls/VariablePanel.py:657 +#: ../editors/DataTypeEditor.py:578 #: ../dialogs/PouNameDialog.py:47
#: ../dialogs/PouTransitionDialog.py:99
#: ../dialogs/SFCStepNameDialog.py:49
-#: ../dialogs/ConnectionDialog.py:144
+#: ../dialogs/ConnectionDialog.py:151 #: ../dialogs/PouActionDialog.py:96
#: ../dialogs/PouDialog.py:116
#: ../dialogs/SFCStepDialog.py:120
@@ -214,22 +214,22 @@
msgid "\"%s\" is not a valid identifier!"
msgstr "\"%s\" n'est pas un identifiant valide !"
msgid "\"%s\" is used by one or more POUs. It can't be removed!"
msgstr "Le POU \"%s\" est utilisé par un ou plusieurs POUs. Il ne peut être supprimé !"
-#: ../controls/VariablePanel.py:311
-#: ../editors/TextViewer.py:303
-#: ../editors/TextViewer.py:323
-#: ../editors/TextViewer.py:360
-#: ../editors/Viewer.py:250
-#: ../editors/Viewer.py:295
-#: ../editors/Viewer.py:312
-#: ../dialogs/ConnectionDialog.py:148
+#: ../controls/VariablePanel.py:313 +#: ../editors/TextViewer.py:296 +#: ../editors/TextViewer.py:316 +#: ../editors/TextViewer.py:353 +#: ../editors/Viewer.py:248 +#: ../editors/Viewer.py:293 +#: ../editors/Viewer.py:311 +#: ../dialogs/ConnectionDialog.py:155 #: ../dialogs/PouDialog.py:120
#: ../dialogs/FBDBlockDialog.py:160
@@ -252,18 +252,18 @@
msgid "\"%s\" step already exists!"
msgstr "L'étape \"%s\" existe déjà !"
-#: ../editors/DataTypeEditor.py:543
+#: ../editors/DataTypeEditor.py:549 msgid "\"%s\" value already defined!"
msgstr "La valeur \"%s\" est déjà définie !"
-#: ../editors/DataTypeEditor.py:719
+#: ../editors/DataTypeEditor.py:744 #: ../dialogs/ArrayTypeDialog.py:97
msgid "\"%s\" value isn't a valid array dimension!"
msgstr "\"%s\" n'est pas une dimension de tableau valide !"
-#: ../editors/DataTypeEditor.py:726
+#: ../editors/DataTypeEditor.py:751 #: ../dialogs/ArrayTypeDialog.py:103
@@ -273,12 +273,12 @@
"\"%s\" n'est pas une dimension de tableau valide !\n"
"La valeur de droite doit être supérieur à celle de gauche."
-#: ../PLCControler.py:793
+#: ../PLCControler.py:847 msgid "%s \"%s\" can't be pasted as a %s."
msgstr "Le %s \"%s\" ne peut être collé en tant que %s."
-#: ../PLCControler.py:1422
+#: ../PLCControler.py:1476 msgstr "Types de données de %s"
@@ -288,90 +288,90 @@
-#: ../PLCControler.py:1417
+#: ../PLCControler.py:1471 -#: ../canfestival/SlaveEditor.py:42
-#: ../canfestival/NetworkEditor.py:72
+#: ../canfestival/SlaveEditor.py:46 +#: ../canfestival/NetworkEditor.py:67 -#: ../plcopen/plcopen.py:1780
#: ../plcopen/plcopen.py:1790
#: ../plcopen/plcopen.py:1800
#: ../plcopen/plcopen.py:1810
-#: ../plcopen/plcopen.py:1819
+#: ../plcopen/plcopen.py:1820 +#: ../plcopen/plcopen.py:1829 msgid "%s body don't have instances!"
msgstr "Le code d'un %s n'a pas d'instances !"
-#: ../plcopen/plcopen.py:1842
-#: ../plcopen/plcopen.py:1849
+#: ../plcopen/plcopen.py:1852 +#: ../plcopen/plcopen.py:1859 msgid "%s body don't have text!"
msgstr "Le code d'un %s n'a pas de texte !"
msgstr "&Ajouter un élément"
msgstr "&Type de donnée"
-#: ../PLCOpenEditor.py:148
+#: ../PLCOpenEditor.py:129
msgstr "Projets &récent"
-#: ../controls/SearchResultPanel.py:237
+#: ../controls/SearchResultPanel.py:252 msgid "'%s' - %d match in project"
msgstr "'%s' - %d correspondance dans le projet"
-#: ../controls/SearchResultPanel.py:239
+#: ../controls/SearchResultPanel.py:254 msgid "'%s' - %d matches in project"
msgstr "'%s' - %d correspondances dans le projet"
@@ -381,14 +381,14 @@
msgid "'%s' is located at %s\n"
msgstr "'%s' is disponible à l'adresse %s\n"
-#: ../controls/SearchResultPanel.py:289
+#: ../controls/SearchResultPanel.py:304 msgstr "(%d correspondances)"
-#: ../PLCOpenEditor.py:508
-#: ../PLCOpenEditor.py:510
-#: ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:393 +#: ../PLCOpenEditor.py:395 +#: ../PLCOpenEditor.py:396 @@ -400,25 +400,25 @@
-#: ../PLCOpenEditor.py:506
+#: ../PLCOpenEditor.py:391 -#: ../ProjectController.py:1268
+#: ../ProjectController.py:1294 msgid "... debugger recovered\n"
msgstr "... déboggueur operationel\n"
#: ../dialogs/PouDialog.py:122
msgid "A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?"
msgstr "Un POU a un élément nommé \"%s\". Cela peut générer des conflits. Voulez-vous continuer ?"
-#: ../controls/VariablePanel.py:658
+#: ../controls/VariablePanel.py:661 #: ../dialogs/PouNameDialog.py:51
#: ../dialogs/PouTransitionDialog.py:103
#: ../dialogs/SFCStepNameDialog.py:53
@@ -428,34 +428,34 @@
msgid "A POU named \"%s\" already exists!"
msgstr "Un POU nommé \"%s\" existe déjà !"
-#: ../ConfigTreeNode.py:371
+#: ../ConfigTreeNode.py:388 msgid "A child named \"%s\" already exist -> \"%s\"\n"
msgstr "Un noeud enfant nommé \"%s\" existe déjà -> \"%s\"\n"
-#: ../dialogs/BrowseLocationsDialog.py:175
+#: ../dialogs/BrowseLocationsDialog.py:212 msgid "A location must be selected!"
msgstr "Une adresse doit être sélectionné !"
-#: ../controls/VariablePanel.py:660
+#: ../controls/VariablePanel.py:663 #: ../dialogs/SFCStepNameDialog.py:55
#: ../dialogs/SFCStepDialog.py:126
msgid "A variable with \"%s\" as name already exists in this pou!"
msgstr "Une variable nommée \"%s\" existe déjà dans ce POU !"
-#: ../PLCOpenEditor.py:181
+#: ../PLCOpenEditor.py:162
msgstr "A propos de Beremiz"
-#: ../PLCOpenEditor.py:376
+#: ../PLCOpenEditor.py:355 msgid "About PLCOpenEditor"
msgstr "A propos de PLCOpenEditor"
@@ -468,7 +468,7 @@
-#: ../editors/Viewer.py:495
+#: ../editors/Viewer.py:494 msgstr "Ajouter un bloc fonctionnel"
@@ -480,7 +480,7 @@
msgstr "Nom de l'action :"
-#: ../plcopen/plcopen.py:1480
+#: ../plcopen/plcopen.py:1490 msgid "Action with name %s doesn't exist!"
msgstr "L'action nommée %s n'existe pas !"
@@ -493,30 +493,35 @@
-#: ../canfestival/SlaveEditor.py:54
-#: ../canfestival/NetworkEditor.py:84
+#: ../editors/Viewer.py:999 +#: ../canfestival/SlaveEditor.py:57 +#: ../canfestival/NetworkEditor.py:78 #: ../editors/Viewer.py:527
msgstr "Ajouter une action"
msgid "Add C code accessing located variables synchronously"
msgstr "Ajoute un code C ayant accès à des variables localisées de façon synchrone"
msgid "Add Configuration"
msgstr "Ajouter une configuration"
msgstr "Ajouter un type de donnée"
-#: ../editors/Viewer.py:453
+#: ../editors/Viewer.py:452 msgid "Add Divergence Branch"
msgstr "Ajouter une branche à la divergence"
@@ -524,25 +529,25 @@
msgid "Add Python code executed asynchronously"
msgstr "Ajoute un code Python executé de façon asynchone"
msgstr "Ajouter une resource"
msgstr "Ajouter une transition"
-#: ../editors/Viewer.py:442
+#: ../editors/Viewer.py:441 msgstr "Ajouter un segment au fil"
@@ -550,7 +555,7 @@
msgid "Add a new initial step"
msgstr "Ajouter une nouvelle étape initiale"
-#: ../editors/Viewer.py:2289
+#: ../editors/Viewer.py:2363 #: ../editors/SFCViewer.py:696
msgstr "Ajouter un nouveau renvoi"
@@ -559,7 +564,7 @@
msgstr "Ajouter une nouvelle étape"
msgid "Add a simple WxGlade based GUI."
msgstr "Ajoute une interface simple utilisant WxGlade"
@@ -567,23 +572,24 @@
msgstr "Ajouter une action"
-#: ../editors/DataTypeEditor.py:345
+#: ../editors/DataTypeEditor.py:351 msgstr "Ajouter un élément"
-#: ../editors/ResourceEditor.py:251
+#: ../editors/ResourceEditor.py:259 msgstr "Ajouter une instance"
-#: ../canfestival/NetworkEditor.py:86
+#: ../canfestival/NetworkEditor.py:80 msgstr "Ajouter un esclave"
-#: ../editors/ResourceEditor.py:222
+#: ../editors/ResourceEditor.py:230 msgstr "Ajouter une tâche"
-#: ../controls/VariablePanel.py:378
+#: ../controls/VariablePanel.py:380 +#: ../c_ext/CFileEditor.py:517 msgstr "Ajouter une variable"
@@ -591,33 +597,43 @@
-#: ../plcopen/structures.py:250
+#: ../plcopen/structures.py:249 msgid "Additional function blocks"
msgstr "Blocs fonctionnels additionnels"
-#: ../editors/Viewer.py:1395
+#: ../editors/Viewer.py:510 +msgid "Adjust Block Size" +msgstr "Ajuster la taille des blocs" +#: ../editors/Viewer.py:1458 #: ../controls/VariablePanel.py:75
-#: ../dialogs/BrowseLocationsDialog.py:35
-#: ../dialogs/BrowseLocationsDialog.py:116
+#: ../dialogs/BrowseLocationsDialog.py:34 +#: ../dialogs/BrowseLocationsDialog.py:43 +#: ../dialogs/BrowseLocationsDialog.py:136 +#: ../dialogs/BrowseLocationsDialog.py:139
#: ../editors/FileManagementPanel.py:35
msgid "All files (*.*)|*.*|CSV files (*.csv)|*.csv"
msgstr "Tous les fichiers|*.*|Fichiers CSV (*.csv)|*.csv"
-#: ../ProjectController.py:1335
+#: ../ProjectController.py:1373 msgid "Already connected. Please disconnect\n"
msgstr "Déjà connecté. Veuillez déconnecter\n"
-#: ../editors/DataTypeEditor.py:587
+#: ../editors/DataTypeEditor.py:593 msgid "An element named \"%s\" already exists in this structure!"
msgstr "Un élément nommé \"%s\" existe déjà dans la structure !"
+#: ../dialogs/ConnectionDialog.py:98 +msgid "Apply name modification to all continuations with the same name" +msgstr "Appliquer la modification de nom à toutes les prolongements portant ce même nom" #: ../plcopen/iec_std.csv:31
@@ -634,8 +650,9 @@
-#: ../controls/VariablePanel.py:729
-#: ../editors/DataTypeEditor.py:52
+#: ../controls/VariablePanel.py:732 +#: ../editors/DataTypeEditor.py:54 +#: ../editors/DataTypeEditor.py:634 @@ -673,19 +690,19 @@
msgid "Bad location size : %s"
msgstr "Mauvaise taille d'adresse : %s"
-#: ../editors/DataTypeEditor.py:168
-#: ../editors/DataTypeEditor.py:198
-#: ../editors/DataTypeEditor.py:290
+#: ../editors/DataTypeEditor.py:174 +#: ../editors/DataTypeEditor.py:204 +#: ../editors/DataTypeEditor.py:296 #: ../dialogs/ArrayTypeDialog.py:55
-#: ../controls/VariablePanel.py:699
-#: ../editors/DataTypeEditor.py:617
+#: ../controls/VariablePanel.py:702 +#: ../editors/DataTypeEditor.py:624
@@ -717,7 +734,7 @@
msgid "Bitwise inverting"
msgstr "Inversion bit à bit"
-#: ../editors/Viewer.py:465
+#: ../editors/Viewer.py:464 @@ -725,7 +742,7 @@
msgstr "Propriétés du bloc"
-#: ../editors/Viewer.py:434
+#: ../editors/Viewer.py:433 @@ -734,31 +751,35 @@
msgid "Browse %s values library"
msgstr "Explorer la liste des valeurs du paramètre '%s'"
-#: ../dialogs/BrowseLocationsDialog.py:55
+#: ../dialogs/BrowseLocationsDialog.py:61 msgstr "Naviger dans les adresses"
-#: ../ProjectController.py:1484
+#: ../ProjectController.py:1519 -#: ../ProjectController.py:1051
+#: ../ProjectController.py:1079 msgid "Build directory already clean\n"
msgstr "Le répertoire de compilation est déjà nettoyé\n"
-#: ../ProjectController.py:1485
+#: ../ProjectController.py:1520 msgid "Build project into build folder"
msgstr "Compiler le projet dans le répertoire ce compilation"
-#: ../ProjectController.py:910
+#: ../ProjectController.py:937 msgid "C Build crashed !\n"
msgstr "La compilation du C a mal fonctionné !\n"
-#: ../ProjectController.py:907
+#: ../ProjectController.py:934 msgid "C Build failed.\n"
msgstr "La compilation du C a échouée !\n"
-#: ../ProjectController.py:895
+#: ../c_ext/CFileEditor.py:731 +#: ../ProjectController.py:922 msgid "C code generated successfully.\n"
msgstr "Code C généré avec succès.\n"
@@ -767,18 +788,26 @@
msgid "C compilation of %s failed.\n"
msgstr "La compilation C de %s a échouée.\n"
+#: ../canfestival/NetworkEditor.py:29 +msgstr "Réseau CANOpen" +#: ../canfestival/SlaveEditor.py:21 +msgstr "Esclave CANOpen" -#: ../plcopen/plcopen.py:1722
-#: ../plcopen/plcopen.py:1736
-#: ../plcopen/plcopen.py:1757
-#: ../plcopen/plcopen.py:1773
+#: ../plcopen/plcopen.py:1732 +#: ../plcopen/plcopen.py:1746 +#: ../plcopen/plcopen.py:1767 +#: ../plcopen/plcopen.py:1783 msgid "Can only generate execution order on FBD networks!"
msgstr "L'ordre d'exécution ne peut être généré que dans les FBD !"
@@ -786,7 +815,7 @@
msgid "Can only give a location to local or global variables"
msgstr "Une adresse ne peut être affecté qu'à des variables locales ou globales"
-#: ../PLCOpenEditor.py:357
+#: ../PLCOpenEditor.py:336 msgid "Can't generate program to file %s!"
msgstr "Le programme n'a pu être généré dans le fichier \"%s\" !"
@@ -795,21 +824,21 @@
msgid "Can't give a location to a function block instance"
msgstr "Une adresse ne peut être affectée à une instance de Function Block"
-#: ../PLCOpenEditor.py:397
+#: ../PLCOpenEditor.py:376 msgid "Can't save project to file %s!"
msgstr "Le projet n'a pu être sauvé dans le fichier \"%s\" !"
-#: ../controls/VariablePanel.py:298
+#: ../controls/VariablePanel.py:300 msgid "Can't set an initial value to a function block instance"
msgstr "Une valeur initiale ne peut être affectée une instance de Function Block"
-#: ../ConfigTreeNode.py:470
+#: ../ConfigTreeNode.py:490 msgid "Cannot create child %s of type %s "
msgstr "Impossible d'ajouter un élément \"%s\" de type \"%s\""
-#: ../ConfigTreeNode.py:400
+#: ../ConfigTreeNode.py:417 msgid "Cannot find lower free IEC channel than %d\n"
msgstr "Impossible de trouver un numéro IEC inférieur à %d libre\n"
@@ -818,7 +847,7 @@
msgid "Cannot get PLC status - connection failed.\n"
msgstr "Impossible d'obtenir le statut de l'automate - la connexion a échoué.\n"
-#: ../ProjectController.py:715
+#: ../ProjectController.py:737 msgid "Cannot open/parse VARIABLES.csv!\n"
msgstr "Impossible d'ouvrir ou d'analyser le fichier VARIABLES.csv !\n"
@@ -832,27 +861,27 @@
msgstr "Respecter la casse"
-#: ../editors/Viewer.py:429
+#: ../editors/Viewer.py:428 -#: ../Beremiz_service.py:322
+#: ../Beremiz_service.py:326 msgid "Change IP of interface to bind"
msgstr "Changer l'adresse IP de l'interface à lier"
-#: ../Beremiz_service.py:321
+#: ../Beremiz_service.py:325
msgid "Change POU Type To"
msgstr "Changer le type du POU pour"
-#: ../Beremiz_service.py:325
+#: ../Beremiz_service.py:327 msgid "Change Port Number"
msgstr "Changer le numéro de port"
-#: ../Beremiz_service.py:327
+#: ../Beremiz_service.py:328 msgid "Change working directory"
msgstr "Changer le dossier de travail"
@@ -864,19 +893,19 @@
msgid "Choose a SVG file"
msgstr "Choisissez un fichier SVG"
-#: ../ProjectController.py:353
+#: ../ProjectController.py:364 msgid "Choose a directory to save project"
msgstr "Choisissez un dossier où enregistrer le projet"
-#: ../canfestival/canfestival.py:118
-#: ../PLCOpenEditor.py:313
-#: ../PLCOpenEditor.py:347
-#: ../PLCOpenEditor.py:391
+#: ../canfestival/canfestival.py:136 +#: ../PLCOpenEditor.py:294 +#: ../PLCOpenEditor.py:326 +#: ../PLCOpenEditor.py:370 msgstr "Choisissez un fichier"
msgstr "Choisissez un projet"
@@ -885,15 +914,15 @@
msgid "Choose a value for %s:"
msgstr "Choisissez une valeur pour le paramètre %s :"
-#: ../Beremiz_service.py:373
+#: ../Beremiz_service.py:378 msgid "Choose a working directory "
msgstr "Choisissez un dossier de travail"
-#: ../ProjectController.py:281
+#: ../ProjectController.py:288 msgid "Chosen folder doesn't contain a program. It's not a valid project!"
msgstr "Le répertoire ne contient pas de programme. Ce n'est pas un projet valide !"
-#: ../ProjectController.py:247
+#: ../ProjectController.py:255 msgid "Chosen folder isn't empty. You can't use it for a new project!"
msgstr "Le répertoire n'est pas vide. Vous ne pouvez pas l'utiliser pour créer un nouveau projet !"
@@ -902,7 +931,7 @@
-#: ../controls/VariablePanel.py:369
+#: ../controls/VariablePanel.py:371 msgstr "Filtre de classe :"
@@ -910,19 +939,19 @@
-#: ../ProjectController.py:1488
+#: ../ProjectController.py:1523 -#: ../ProjectController.py:1490
+#: ../ProjectController.py:1525 msgid "Clean project build folder"
msgstr "Nettoyer le répertoire de compilation"
-#: ../ProjectController.py:1048
+#: ../ProjectController.py:1076 msgid "Cleaning the build directory\n"
msgstr "Répertoire de compilation en cours de nettoyage\n"
msgstr "Effacer les erreurs"
@@ -934,29 +963,29 @@
msgid "Clear the graph values"
msgstr "Vider les valeurs du graphique"
-#: ../PLCOpenEditor.py:221
+#: ../PLCOpenEditor.py:202 msgid "Close Application"
msgstr "Fermer l'application"
-#: ../PLCOpenEditor.py:131
+#: ../PLCOpenEditor.py:112 msgstr "Fermer le projet"
-#: ../PLCOpenEditor.py:129
+#: ../PLCOpenEditor.py:110 -#: ../editors/Viewer.py:481
+#: ../editors/Viewer.py:480 -#: ../editors/Viewer.py:501
-#: ../editors/LDViewer.py:503
+#: ../editors/Viewer.py:500 +#: ../editors/LDViewer.py:506 @@ -972,7 +1001,7 @@
-#: ../ProjectController.py:538
+#: ../ProjectController.py:552 msgid "Compiling IEC Program into C code...\n"
msgstr "Compilation du program en IEC vers du code C en cours...\n"
@@ -980,6 +1009,14 @@
+#: ../editors/ConfTreeNodeEditor.py:249 +#: ../editors/ProjectNodeEditor.py:13 +msgid "Config variables" +msgstr "Variables de configuration" #: ../dialogs/SearchInProjectDialog.py:47
@@ -988,20 +1025,25 @@
-#: ../ProjectController.py:1503
+#: ../ProjectController.py:1538 -#: ../ProjectController.py:1504
+#: ../ProjectController.py:1539 msgid "Connect to the target PLC"
msgstr "Connecter à l'automate cible"
+#: ../ProjectController.py:1125 +msgid "Connected to URI: %s" +msgstr "Connecté à l'URI : %s" #: ../connectors/PYRO/__init__.py:40
msgid "Connecting to URI : %s\n"
msgstr "Connection à l'URI %s en cours...\n"
-#: ../editors/Viewer.py:467
+#: ../editors/Viewer.py:466 #: ../dialogs/SFCTransitionDialog.py:76
@@ -1010,11 +1052,11 @@
msgid "Connection Properties"
msgstr "Propriétés de la connexion"
-#: ../ProjectController.py:1359
+#: ../ProjectController.py:1397 msgid "Connection canceled!\n"
msgstr "La connection a été abandonnée !\n"
-#: ../ProjectController.py:1384
+#: ../ProjectController.py:1422 msgid "Connection failed to %s!\n"
msgstr "La connection à \"%s\" a échouée !\n"
@@ -1024,6 +1066,7 @@
msgid "Connection to '%s' failed.\n"
msgstr "La connexion à l'adresse '%s' a échouée.\n"
+#: ../editors/Viewer.py:1426 #: ../dialogs/ConnectionDialog.py:56
@@ -1032,11 +1075,15 @@
#: ../controls/VariablePanel.py:65
-#: ../editors/Viewer.py:477
+#: ../editors/Viewer.py:476 @@ -1044,6 +1091,7 @@
msgid "Content Description (optional):"
msgstr "Description du contenu (optionel) :"
+#: ../editors/Viewer.py:1427 #: ../dialogs/ConnectionDialog.py:61
@@ -1064,21 +1112,21 @@
msgid "Conversion to time-of-day"
msgstr "Conversion en heure de la journée"
#: ../editors/Viewer.py:536
-#: ../editors/FileManagementPanel.py:283
+#: ../editors/FileManagementPanel.py:65 msgid "Copy file from left folder to right"
msgstr "Copier un fichier du dossier de gauche vers celui de droite"
-#: ../editors/FileManagementPanel.py:282
+#: ../editors/FileManagementPanel.py:64 msgid "Copy file from right folder to left"
msgstr "Copier un fichier du dossier de droite vers celui de gauche"
@@ -1086,7 +1134,7 @@
-#: ../ConfigTreeNode.py:582
+#: ../ConfigTreeNode.py:602 "Could not add child \"%s\", type %s :\n"
@@ -1095,7 +1143,7 @@
"Impossible d'ajouter le noeud enfant \"%s\", de type %s :\n"
-#: ../ConfigTreeNode.py:559
+#: ../ConfigTreeNode.py:579 "Couldn't load confnode base parameters %s :\n"
@@ -1104,7 +1152,7 @@
"Impossible de charger les paramètres de base du plugin %s :\n"
-#: ../ConfigTreeNode.py:570
+#: ../ConfigTreeNode.py:590 "Couldn't load confnode parameters %s :\n"
@@ -1113,20 +1161,20 @@
"Impossible de charger les paramètres du plugin %s :\n"
-#: ../PLCControler.py:765
-#: ../PLCControler.py:802
+#: ../PLCControler.py:819 +#: ../PLCControler.py:856 msgid "Couldn't paste non-POU object."
msgstr "Impossible de coller autre chose qu'un POU."
-#: ../ProjectController.py:1317
+#: ../ProjectController.py:1344 msgid "Couldn't start PLC !\n"
msgstr "Impossible de démarrer l'automate !\n"
-#: ../ProjectController.py:1325
+#: ../ProjectController.py:1352 msgid "Couldn't stop PLC !\n"
msgstr "Impossible d'arrêter l'automate !\n"
-#: ../ProjectController.py:1295
+#: ../ProjectController.py:1321 msgid "Couldn't stop debugger.\n"
msgstr "Impossible d'arrêter le débogage de l'automate !\n"
@@ -1142,42 +1190,42 @@
msgid "Create a new action"
msgstr "Créer une nouvelle action"
msgid "Create a new action block"
msgstr "Créer un nouveau bloc d'actions"
msgid "Create a new block"
msgstr "Créer un nouveau bloc"
msgid "Create a new branch"
msgstr "Créer une nouvelle branche"
msgid "Create a new coil"
msgstr "Créer un nouveau relai"
msgid "Create a new comment"
msgstr "Créer un nouveau copmmentaire"
msgid "Create a new connection"
msgstr "Créer une nouvelle connexion"
msgid "Create a new contact"
msgstr "Créer un nouveau contact"
msgid "Create a new divergence"
msgstr "Créer une nouvelle divergence"
@@ -1185,45 +1233,45 @@
msgid "Create a new divergence or convergence"
msgstr "Créer une nouvelle divergence ou convergence"
msgid "Create a new initial step"
msgstr "Créer une nouvelle étape initiale"
msgid "Create a new jump"
msgstr "Créer un nouveau renvoi"
msgid "Create a new power rail"
msgstr "Créer une nouvelle barre d'alimentation"
msgid "Create a new rung"
msgstr "Créer un nouvel échelon"
msgid "Create a new step"
msgstr "Créer une nouvelle étape"
#: ../dialogs/PouTransitionDialog.py:42
msgid "Create a new transition"
msgstr "Créer une nouvelle transition"
msgid "Create a new variable"
msgstr "Créer une nouvelle variable"
#: ../editors/Viewer.py:535
-#: ../editors/ResourceEditor.py:71
+#: ../editors/ResourceEditor.py:72 @@ -1239,13 +1287,13 @@
-#: ../canfestival/SlaveEditor.py:50
-#: ../canfestival/NetworkEditor.py:80
+#: ../canfestival/SlaveEditor.py:53 +#: ../canfestival/NetworkEditor.py:74 -#: ../canfestival/SlaveEditor.py:51
-#: ../canfestival/NetworkEditor.py:81
+#: ../canfestival/SlaveEditor.py:54 +#: ../canfestival/NetworkEditor.py:75 @@ -1282,60 +1330,61 @@
-#: ../ProjectController.py:1405
-msgid "Debug connect matching running PLC\n"
-msgstr "L'automate connecté correspond au project ouvert.\n"
-#: ../ProjectController.py:1408
-msgid "Debug do not match PLC - stop/transfert/start to re-enable\n"
-msgstr "L'automate connecté ne correspond pas au project ouvert - Arrêter/transférez/démarrer pour pouvoir débogguer.\n"
-#: ../controls/PouInstanceVariablesPanel.py:52
+#: ../ProjectController.py:1444 +msgid "Debug does not match PLC - stop/transfert/start to re-enable\n" +msgstr "Les informations de débogage ne correspond pas l'automate connecté - Arrêter/transférez/démarrer pour pouvoir débogguer.\n" +#: ../controls/PouInstanceVariablesPanel.py:59 msgstr "Déboguer l'instance"
-#: ../editors/Viewer.py:3222
+#: ../editors/Viewer.py:1016 +#: ../editors/Viewer.py:3326 -msgstr "Déboggage : %s"
-#: ../ProjectController.py:1122
+#: ../ProjectController.py:1153 msgid "Debug: Unknown variable '%s'\n"
msgstr "Débogage : Variable '%s' inconnue\n"
-#: ../ProjectController.py:1120
+#: ../ProjectController.py:1151 msgid "Debug: Unsupported type to debug '%s'\n"
msgstr "Débogage : Type non supporté dans le débogage '%'\n"
-#: ../ProjectController.py:1285
+#: ../ProjectController.py:1311 msgid "Debugger disabled\n"
msgstr "Débogueur désactivé\n"
-#: ../ProjectController.py:1297
+#: ../ProjectController.py:1441 +msgid "Debugger ready\n" +#: ../ProjectController.py:1323 msgid "Debugger stopped.\n"
msgstr "Débogueur désactivé\n"
#: ../editors/Viewer.py:511
-#: ../editors/Viewer.py:454
+#: ../editors/Viewer.py:453 msgid "Delete Divergence Branch"
msgstr "Supprimer une branche de divergence"
-#: ../editors/FileManagementPanel.py:371
+#: ../editors/FileManagementPanel.py:153 msgstr "Supprimer un fichier"
-#: ../editors/Viewer.py:443
+#: ../editors/Viewer.py:442 msgid "Delete Wire Segment"
msgstr "Supprimer un segment de fil"
@@ -1347,11 +1396,11 @@
msgid "Deletion (within)"
msgstr "Suppression (au milieu)"
-#: ../editors/DataTypeEditor.py:146
+#: ../editors/DataTypeEditor.py:152 msgstr "Type de dérivation :"
-#: ../plcopen/structures.py:264
+#: ../plcopen/structures.py:263 "The derivative function block produces an output XOUT proportional to the rate of change of the input XIN."
@@ -1359,11 +1408,11 @@
"Le Function Block derivative produit une sortie XOUT proportionnelle au rapport de changement de l'entrée XIN."
-#: ../controls/VariablePanel.py:360
+#: ../controls/VariablePanel.py:362 -#: ../editors/DataTypeEditor.py:314
+#: ../editors/DataTypeEditor.py:320 #: ../dialogs/ArrayTypeDialog.py:61
@@ -1372,23 +1421,23 @@
-#: ../dialogs/BrowseLocationsDialog.py:78
+#: ../dialogs/BrowseLocationsDialog.py:86 -#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 -#: ../ProjectController.py:1512
+#: ../ProjectController.py:1547 -#: ../ProjectController.py:1514
+#: ../ProjectController.py:1549 msgid "Disconnect from PLC"
msgstr "Déconnecter l'automate"
-#: ../editors/Viewer.py:496
+#: ../editors/Viewer.py:495 @@ -1396,7 +1445,7 @@
-#: ../editors/FileManagementPanel.py:370
+#: ../editors/FileManagementPanel.py:152 msgid "Do you really want to delete the file '%s'?"
msgstr "Êtes-vous sûr de vouloir supprimer le fichier '%s' ?"
@@ -1406,11 +1455,11 @@
-#: ../PLCOpenEditor.py:351
+#: ../PLCOpenEditor.py:330 -#: ../plcopen/structures.py:227
+#: ../plcopen/structures.py:226 "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value."
@@ -1422,11 +1471,11 @@
-#: ../canfestival/canfestival.py:118
+#: ../canfestival/canfestival.py:139 msgid "EDS files (*.eds)|*.eds|All files|*.*"
msgstr "Fichiers EDS (*.eds)|*.eds|Tous les fichiers|*.*"
-#: ../editors/Viewer.py:510
+#: ../editors/Viewer.py:509 @@ -1458,14 +1507,14 @@
msgid "Edit array type properties"
msgstr "Editer les propriétés d'un type de données tableau"
-#: ../editors/Viewer.py:2112
-#: ../editors/Viewer.py:2114
-#: ../editors/Viewer.py:2630
-#: ../editors/Viewer.py:2632
+#: ../editors/Viewer.py:2186 +#: ../editors/Viewer.py:2188 +#: ../editors/Viewer.py:2706 +#: ../editors/Viewer.py:2708 msgstr "Editer le commentaire"
-#: ../editors/FileManagementPanel.py:284
+#: ../editors/FileManagementPanel.py:66 msgstr "Editer un fichier"
@@ -1473,11 +1522,11 @@
msgstr "Editer l'élément"
-#: ../editors/Viewer.py:2594
+#: ../editors/Viewer.py:2670 msgstr "Editer la cible du renvoi"
-#: ../ProjectController.py:1526
+#: ../ProjectController.py:1561 msgid "Edit raw IEC code added to code generated by PLCGenerator"
msgstr "Editer le code IEC ajouté au code généré par PLCGenerator"
@@ -1489,35 +1538,35 @@
msgstr "Editer la transition"
msgstr "Barre d'outils d'édition"
-#: ../ProjectController.py:1013
+#: ../ProjectController.py:1039 msgstr "Selection d'un éditeur"
-#: ../editors/DataTypeEditor.py:341
+#: ../editors/DataTypeEditor.py:347
msgstr "Activer Défaire/Refaire"
-#: ../Beremiz_service.py:380
+#: ../Beremiz_service.py:385 msgstr "Saisissez un nom"
-#: ../Beremiz_service.py:365
+#: ../Beremiz_service.py:370 msgid "Enter a port number "
msgstr "Saisissez un numéro de port"
-#: ../Beremiz_service.py:355
+#: ../Beremiz_service.py:360 msgid "Enter the IP of the interface to bind"
msgstr "Saisissez l'adresse IP de l'interface à lier"
-#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 @@ -1525,43 +1574,41 @@
-#: ../Beremiz_service.py:270
-#: ../Beremiz_service.py:394
-#: ../controls/VariablePanel.py:330
-#: ../controls/VariablePanel.py:678
-#: ../controls/DebugVariablePanel.py:164
-#: ../PLCOpenEditor.py:358
-#: ../PLCOpenEditor.py:363
-#: ../PLCOpenEditor.py:531
-#: ../PLCOpenEditor.py:541
-#: ../editors/TextViewer.py:376
-#: ../editors/DataTypeEditor.py:543
-#: ../editors/DataTypeEditor.py:548
-#: ../editors/DataTypeEditor.py:572
-#: ../editors/DataTypeEditor.py:577
-#: ../editors/DataTypeEditor.py:587
-#: ../editors/DataTypeEditor.py:719
-#: ../editors/DataTypeEditor.py:726
-#: ../editors/Viewer.py:366
-#: ../editors/LDViewer.py:663
-#: ../editors/LDViewer.py:879
-#: ../editors/LDViewer.py:883
-#: ../editors/FileManagementPanel.py:210
-#: ../ProjectController.py:221
+#: ../Beremiz_service.py:271 +#: ../controls/VariablePanel.py:332 +#: ../controls/VariablePanel.py:681 +#: ../controls/DebugVariablePanel.py:379 +#: ../PLCOpenEditor.py:337 +#: ../PLCOpenEditor.py:342 +#: ../PLCOpenEditor.py:416 +#: ../PLCOpenEditor.py:426 +#: ../editors/TextViewer.py:369 +#: ../editors/DataTypeEditor.py:549 +#: ../editors/DataTypeEditor.py:554 +#: ../editors/DataTypeEditor.py:578 +#: ../editors/DataTypeEditor.py:583 +#: ../editors/DataTypeEditor.py:593 +#: ../editors/DataTypeEditor.py:744 +#: ../editors/DataTypeEditor.py:751 +#: ../editors/Viewer.py:365 +#: ../editors/LDViewer.py:666 +#: ../editors/LDViewer.py:882 +#: ../editors/LDViewer.py:886 +#: ../ProjectController.py:225 #: ../dialogs/PouNameDialog.py:53
#: ../dialogs/PouTransitionDialog.py:107
-#: ../dialogs/BrowseLocationsDialog.py:175
+#: ../dialogs/BrowseLocationsDialog.py:212 #: ../dialogs/ProjectDialog.py:71
#: ../dialogs/SFCStepNameDialog.py:59
-#: ../dialogs/ConnectionDialog.py:152
+#: ../dialogs/ConnectionDialog.py:159 #: ../dialogs/FBDVariableDialog.py:201
#: ../dialogs/PouActionDialog.py:104
#: ../dialogs/BrowseValuesLibraryDialog.py:83
@@ -1574,20 +1621,20 @@
#: ../dialogs/ArrayTypeDialog.py:97
#: ../dialogs/ArrayTypeDialog.py:103
#: ../dialogs/FBDBlockDialog.py:164
-#: ../dialogs/ForceVariableDialog.py:169
+#: ../dialogs/ForceVariableDialog.py:179 -#: ../ProjectController.py:587
+#: ../ProjectController.py:601 msgid "Error : At least one configuration and one resource must be declared in PLC !\n"
msgstr "Erreur : Au moins une configuration ou une ressource doit être déclarée dans l'automate !\n"
-#: ../ProjectController.py:579
+#: ../ProjectController.py:593 msgid "Error : IEC to C compiler returned %d\n"
msgstr "Erreur : Le compilateur d'IEC en C a retourné %d\n"
-#: ../ProjectController.py:520
+#: ../ProjectController.py:534 "Error in ST/IL/SFC code generator :\n"
@@ -1596,24 +1643,24 @@
"Erreur dans le générateur de code ST/IL/SFC :\n"
-#: ../ConfigTreeNode.py:182
+#: ../ConfigTreeNode.py:183 msgid "Error while saving \"%s\"\n"
msgstr "Erreur lors de l'enregistrement de \"%s\"\n"
-#: ../canfestival/canfestival.py:122
+#: ../canfestival/canfestival.py:144 msgid "Error: Export slave failed\n"
msgstr "Erreur : L'export de l'esclave a échoué\n"
-#: ../canfestival/canfestival.py:270
+#: ../canfestival/canfestival.py:345 msgid "Error: No Master generated\n"
msgstr "Erreur : Aucun maître généré\n"
-#: ../canfestival/canfestival.py:265
+#: ../canfestival/canfestival.py:340 msgid "Error: No PLC built\n"
msgstr "Erreur : Aucun automate compilé\n"
-#: ../ProjectController.py:1378
+#: ../ProjectController.py:1416 msgid "Exception while connecting %s!\n"
msgstr "Une exception est apparu au cours de la connexion %s !\n"
@@ -1627,7 +1674,7 @@
msgstr "Ordre d'exécution :"
msgid "Experimental web based HMI"
msgstr "IHM expérimentale utilisant les technologies web"
@@ -1639,15 +1686,16 @@
-#: ../canfestival/canfestival.py:128
+#: ../canfestival/canfestival.py:150 msgid "Export CanOpen slave to EDS file"
msgstr "Exporter un esclave CANopen sous la forme d'un fichier EDS"
+#: ../controls/DebugVariablePanel.py:1472 #: ../editors/GraphicViewer.py:144
msgid "Export graph values to clipboard"
msgstr "Exporter les valeurs du graphique vers le presse-papier"
-#: ../canfestival/canfestival.py:127
+#: ../canfestival/canfestival.py:149 msgstr "Exporter un esclave"
@@ -1659,7 +1707,7 @@
-#: ../ProjectController.py:591
+#: ../ProjectController.py:605 msgid "Extracting Located Variables...\n"
msgstr "Extraction des variables adressées en cours...\n"
@@ -1670,16 +1718,16 @@
-#: ../ProjectController.py:1445
+#: ../ProjectController.py:1480 msgid "Failed : Must build before transfer.\n"
msgstr "Echec : Le projet doit être compilé avant d'être transféré.\n"
-#: ../editors/Viewer.py:405
+#: ../editors/Viewer.py:404 #: ../dialogs/LDElementDialog.py:84
msgstr "Front descendant"
-#: ../plcopen/structures.py:217
+#: ../plcopen/structures.py:216 "Falling edge detector\n"
"The output produces a single pulse when a falling edge is detected."
@@ -1687,7 +1735,7 @@
"Détecteur de front descendant\n"
"La sortie produit une impulsion unique lorsqu'un front descendant est détecté."
-#: ../ProjectController.py:900
+#: ../ProjectController.py:927 msgid "Fatal : cannot get builder.\n"
msgstr "Erreur fatale : impossible de trouver un compilateur.\n"
@@ -1701,22 +1749,17 @@
msgid "Fields %s haven't a valid value!"
msgstr "Les champs %s n'ont pas une valeur valide !"
-#: ../editors/FileManagementPanel.py:209
-msgid "File '%s' already exists!"
-msgstr "Le fichier '%s' existe déjà !"
#: ../dialogs/FindInPouDialog.py:30
#: ../dialogs/FindInPouDialog.py:99
msgstr "Recherche suivante"
msgstr "Recherche précédente"
@@ -1732,12 +1775,12 @@
msgid "Force runtime reload\n"
msgstr "Redémarrage du runtime forcé\n"
-#: ../controls/DebugVariablePanel.py:295
-#: ../editors/Viewer.py:1353
+#: ../controls/DebugVariablePanel.py:1934 +#: ../editors/Viewer.py:1385 msgstr "Forcer la valeur"
-#: ../dialogs/ForceVariableDialog.py:152
+#: ../dialogs/ForceVariableDialog.py:162 msgid "Forcing Variable Value"
msgstr "Forcer la valeur de la variable"
@@ -1750,7 +1793,7 @@
msgid "Form isn't complete. %s must be filled!"
msgstr "Le formulaire est incomplet. %s doit être complété !"
-#: ../dialogs/ConnectionDialog.py:142
+#: ../dialogs/ConnectionDialog.py:149 #: ../dialogs/FBDBlockDialog.py:154
msgid "Form isn't complete. Name must be filled!"
msgstr "Le formulaire est incomplet. Le nom doit être complété !"
@@ -1771,16 +1814,16 @@
msgstr "&Bloc Fonctionnel"
#: ../dialogs/SearchInProjectDialog.py:45
msgstr "Bloc fonctionnel"
-#: ../controls/VariablePanel.py:741
+#: ../controls/VariablePanel.py:744 msgid "Function Block Types"
msgstr "Types de blocs fonctionnels"
@@ -1792,11 +1835,7 @@
msgid "Function Blocks can't be used in Functions!"
msgstr "Les blocs fonctionnels ne peuvent être utilisés dans des functions !"
-#: ../editors/Viewer.py:238
-msgid "Function Blocks can't be used in Transitions!"
-msgstr "Les blocs fonctionnels ne peuvent être utilisés dans des transitions"
-#: ../PLCControler.py:2055
+#: ../PLCControler.py:2180 msgid "FunctionBlock \"%s\" can't be pasted in a Function!!!"
msgstr "Le bloc fonctionnel \"%s\" ne peuvent être collés dans une function !"
@@ -1805,11 +1844,11 @@
-#: ../PLCOpenEditor.py:138
+#: ../PLCOpenEditor.py:119 msgstr "Générer le program"
-#: ../ProjectController.py:510
+#: ../ProjectController.py:524 msgid "Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"
msgstr "Création du code ST/IL/SFC de l'automate IEC-61131 en cours...\n"
@@ -1817,6 +1856,7 @@
+#: ../controls/DebugVariablePanel.py:1471 #: ../editors/GraphicViewer.py:131
msgid "Go to current value"
msgstr "Aller à la valeur actuelle"
@@ -1841,7 +1881,7 @@
-#: ../editors/FileManagementPanel.py:303
+#: ../editors/FileManagementPanel.py:85 msgstr "Répertoire utilisateur :"
@@ -1853,7 +1893,7 @@
-#: ../plcopen/structures.py:279
+#: ../plcopen/structures.py:278 "The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."
@@ -1861,7 +1901,7 @@
"Le bloc functionnel hystérésis fourni un booléen en sortie suivant une courbe d'hystérésis entre les deux entrées réelles (REAL) XIN1 et XIN2."
-#: ../ProjectController.py:827
+#: ../ProjectController.py:851 msgid "IEC-61131-3 code generation failed !\n"
msgstr "La création du code IEC-61131-3 a échouée !\n"
@@ -1871,8 +1911,8 @@
-#: ../Beremiz_service.py:356
-#: ../Beremiz_service.py:357
+#: ../Beremiz_service.py:361 +#: ../Beremiz_service.py:362 msgstr "l'IP est invalide !"
@@ -1882,11 +1922,16 @@
#: ../controls/VariablePanel.py:76
+#: ../editors/Viewer.py:1412 #: ../dialogs/FBDVariableDialog.py:34
-#: ../controls/VariablePanel.py:263
+#: ../editors/Viewer.py:999 +#: ../controls/VariablePanel.py:265 msgid "Incompatible data types between \"%s\" and \"%s\""
msgstr "Types de donnée imcompatible entre \"%s\" et \"%s\""
@@ -1905,20 +1950,20 @@
-#: ../editors/Viewer.py:492
+#: ../editors/Viewer.py:491 #: ../controls/VariablePanel.py:58
#: ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48
+#: ../editors/DataTypeEditor.py:50 -#: ../editors/DataTypeEditor.py:178
-#: ../editors/DataTypeEditor.py:209
-#: ../editors/DataTypeEditor.py:265
-#: ../editors/DataTypeEditor.py:303
+#: ../editors/DataTypeEditor.py:184 +#: ../editors/DataTypeEditor.py:215 +#: ../editors/DataTypeEditor.py:271 +#: ../editors/DataTypeEditor.py:309 msgstr "Valeur initiale :"
@@ -1933,7 +1978,8 @@
#: ../controls/VariablePanel.py:76
-#: ../dialogs/BrowseLocationsDialog.py:36
+#: ../editors/Viewer.py:1410 +#: ../dialogs/BrowseLocationsDialog.py:35 #: ../dialogs/FBDVariableDialog.py:33
#: ../dialogs/SFCStepDialog.py:61
@@ -1947,16 +1993,16 @@
msgstr "Insertion (au milieu)"
-#: ../plcopen/plcopen.py:1833
+#: ../plcopen/plcopen.py:1843 msgid "Instance with id %d doesn't exist!"
msgstr "L'instance dont l'id est %d n'existe pas !"
-#: ../editors/ResourceEditor.py:247
+#: ../editors/ResourceEditor.py:255 -#: ../plcopen/structures.py:259
+#: ../plcopen/structures.py:258 "The integral function block integrates the value of input XIN over time."
@@ -1968,16 +2014,16 @@
-#: ../editors/ResourceEditor.py:71
+#: ../editors/ResourceEditor.py:72 -#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 -#: ../PLCControler.py:2032
-#: ../PLCControler.py:2070
+#: ../PLCControler.py:2157 +#: ../PLCControler.py:2195 msgid "Invalid plcopen element(s)!!!"
msgstr "Les éléments plcopen ne sont pas valides !!! "
@@ -1987,13 +2033,13 @@
msgid "Invalid type \"%s\"-> %d != %d for location\"%s\""
msgstr "Type invalide \"%s\"-> %d != %d pour cette adresse \"%s\""
-#: ../dialogs/ForceVariableDialog.py:167
+#: ../dialogs/ForceVariableDialog.py:177 msgid "Invalid value \"%s\" for \"%s\" variable!"
msgstr "Valeur \"%s\" invalide pour une variable de type \"%s\" !"
-#: ../controls/DebugVariablePanel.py:153
-#: ../controls/DebugVariablePanel.py:156
+#: ../controls/DebugVariablePanel.py:319 +#: ../controls/DebugVariablePanel.py:322 msgid "Invalid value \"%s\" for debug variable"
msgstr "Chemin de variable à déboguer \"%s\" invalide"
@@ -2018,7 +2064,7 @@
"Vous devez rentrer une valeur numérique."
-#: ../editors/Viewer.py:497
+#: ../editors/Viewer.py:496 @@ -2051,19 +2097,19 @@
-#: ../ProjectController.py:1451
+#: ../ProjectController.py:1486 msgid "Latest build already matches current target. Transfering anyway...\n"
msgstr "La dernière compilation correspond à la cible actuelle...\n"
-#: ../Beremiz_service.py:324
+#: ../Beremiz_service.py:331 msgid "Launch WX GUI inspector"
msgstr "Lancer un inspecteur d'IHM WX"
-#: ../Beremiz_service.py:323
+#: ../Beremiz_service.py:330 msgid "Launch a live Python shell"
msgstr "Lancer une console Python"
-#: ../editors/Viewer.py:428
+#: ../editors/Viewer.py:427 @@ -2083,7 +2129,7 @@
msgid "Less than or equal to"
msgstr "Inférieur ou égal à "
@@ -2100,7 +2146,11 @@
-#: ../ProjectController.py:1353
+#: ../canfestival/canfestival.py:322 +msgstr "Entrées locales" +#: ../ProjectController.py:1391 msgid "Local service discovery failed!\n"
msgstr "Echec de la sélection d'un service!\n"
@@ -2108,14 +2158,10 @@
-#: ../dialogs/BrowseLocationsDialog.py:61
+#: ../dialogs/BrowseLocationsDialog.py:68 msgid "Locations available:"
msgstr "Adresses disponibles :"
#: ../plcopen/iec_std.csv:25
msgid "Logarithm to base 10"
msgstr "Logarithme de base 10"
@@ -2125,20 +2171,20 @@
msgid "MDNS resolution failure for '%s'\n"
msgstr "Echec de la résolution MDNS pour '%s'\n"
-#: ../canfestival/SlaveEditor.py:37
-#: ../canfestival/NetworkEditor.py:67
+#: ../canfestival/SlaveEditor.py:41 +#: ../canfestival/NetworkEditor.py:62 msgstr "Variable mappable"
msgid "Map located variables over CANopen"
msgstr "Mappe des variables localisées sur un bus CANopen"
-#: ../canfestival/NetworkEditor.py:89
+#: ../canfestival/NetworkEditor.py:83 -#: ../ConfigTreeNode.py:480
+#: ../ConfigTreeNode.py:500 msgid "Max count (%d) reached for this confnode of type %s "
msgstr "Nombre limite(%d) atteint pour les plugin de type %s"
@@ -2147,15 +2193,15 @@
-#: ../editors/DataTypeEditor.py:232
+#: ../editors/DataTypeEditor.py:238 -#: ../dialogs/BrowseLocationsDialog.py:38
+#: ../dialogs/BrowseLocationsDialog.py:37
msgstr "Barre d'outils du menu principal"
@@ -2163,7 +2209,7 @@
-#: ../editors/Viewer.py:433
+#: ../editors/Viewer.py:432 @@ -2175,7 +2221,7 @@
-#: ../editors/DataTypeEditor.py:219
+#: ../editors/DataTypeEditor.py:225 @@ -2191,8 +2237,8 @@
-#: ../PLCGenerator.py:703
-#: ../PLCGenerator.py:936
+#: ../PLCGenerator.py:732 +#: ../PLCGenerator.py:975 msgid "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU"
msgstr "Plusieurs connecteurs trouvés pour le prolongement \"%s\" dans le POU \"%s\""
@@ -2205,11 +2251,11 @@
msgstr "Déplacer une action vers le haut"
-#: ../controls/DebugVariablePanel.py:185
+#: ../controls/DebugVariablePanel.py:1532 msgid "Move debug variable down"
msgstr "Déplacer une variable à déboguer vers le bas"
-#: ../controls/DebugVariablePanel.py:184
+#: ../controls/DebugVariablePanel.py:1531 msgid "Move debug variable up"
msgstr "Déplacer une variable à déboguer vers le haut"
@@ -2217,34 +2263,34 @@
msgstr "Déplacer vers le haut"
-#: ../editors/DataTypeEditor.py:348
+#: ../editors/DataTypeEditor.py:354 msgid "Move element down"
msgstr "Déplcer un élément vers le bas"
-#: ../editors/DataTypeEditor.py:347
+#: ../editors/DataTypeEditor.py:353 msgstr "Déplacer un élément vers le haut"
-#: ../editors/ResourceEditor.py:254
+#: ../editors/ResourceEditor.py:262 msgid "Move instance down"
msgstr "Déplacer une instance vers le bas"
-#: ../editors/ResourceEditor.py:253
+#: ../editors/ResourceEditor.py:261 msgstr "Déplacer une instance vers le haut"
-#: ../editors/ResourceEditor.py:225
+#: ../editors/ResourceEditor.py:233 msgstr "Déplcer une tâche vers le bas"
-#: ../editors/ResourceEditor.py:224
+#: ../editors/ResourceEditor.py:232 msgstr "Déplacer une tâche vers le haut"
msgstr "Déplacer la vue"
@@ -2252,11 +2298,13 @@
msgstr "Déplacer vers le bas"
-#: ../controls/VariablePanel.py:381
+#: ../controls/VariablePanel.py:383 +#: ../c_ext/CFileEditor.py:520 msgid "Move variable down"
msgstr "Déplacer une variable vers le bas"
-#: ../controls/VariablePanel.py:380
+#: ../controls/VariablePanel.py:382 +#: ../c_ext/CFileEditor.py:519 msgstr "Déplacer une variable vers le haut"
@@ -2268,19 +2316,19 @@
-#: ../editors/FileManagementPanel.py:301
+#: ../editors/FileManagementPanel.py:83 msgstr "Poste de travail :"
#: ../controls/VariablePanel.py:58
#: ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48
-#: ../editors/ResourceEditor.py:67
-#: ../editors/ResourceEditor.py:76
+#: ../editors/DataTypeEditor.py:50 +#: ../editors/ResourceEditor.py:68 +#: ../editors/ResourceEditor.py:77 -#: ../Beremiz_service.py:381
+#: ../Beremiz_service.py:386 msgid "Name must not be null!"
msgstr "Le nom ne doit pas être vide !"
@@ -2296,15 +2344,15 @@
msgid "Natural logarithm"
msgstr "Logarithme népérien"
-#: ../editors/Viewer.py:403
+#: ../editors/Viewer.py:402 #: ../dialogs/LDElementDialog.py:67
-#: ../PLCOpenEditor.py:125
-#: ../PLCOpenEditor.py:167
+#: ../PLCOpenEditor.py:106 +#: ../PLCOpenEditor.py:148 @@ -2312,30 +2360,30 @@
msgstr "Nouvel élément"
-#: ../editors/Viewer.py:402
+#: ../editors/Viewer.py:401 msgstr "Pas de modificateur"
-#: ../PLCControler.py:2929
+#: ../PLCControler.py:3054 msgid "No PLC project found"
msgstr "Pas de projet d'automate trouvé"
-#: ../ProjectController.py:1478
+#: ../ProjectController.py:1513 msgid "No PLC to transfer (did build succeed ?)\n"
msgstr "Aucun automate à transférer (la compilation a-t-elle réussi ?)\n"
-#: ../PLCGenerator.py:1321
+#: ../PLCGenerator.py:1360 msgid "No body defined in \"%s\" POU"
msgstr "Pas de code défini dans le POU \"%s\""
-#: ../PLCGenerator.py:722
-#: ../PLCGenerator.py:945
+#: ../PLCGenerator.py:751 +#: ../PLCGenerator.py:984 msgid "No connector found corresponding to \"%s\" continuation in \"%s\" POU"
msgstr "Pas de connecteur trouvé pour le prolongement \"%s\" dans le POU \"%s\""
-#: ../PLCOpenEditor.py:370
+#: ../PLCOpenEditor.py:349 "No documentation available.\n"
@@ -2343,19 +2391,15 @@
"Pas de documentation.\n"
-#: ../PLCGenerator.py:744
+#: ../PLCGenerator.py:773 msgid "No informations found for \"%s\" block"
msgstr "Aucune information trouvée pour le block \"%s\""
-#: ../plcopen/structures.py:167
+#: ../plcopen/structures.py:166 msgid "No output variable found"
msgstr "Pas de variable de sortie trouvée."
-#: ../Beremiz_service.py:394
-msgstr "Aucun automate en cours d'exécution"
#: ../controls/SearchResultPanel.py:169
msgid "No search results available."
msgstr "Pas de résultat de recherche disponible."
@@ -2379,16 +2423,11 @@
msgid "No valid value selected!"
msgstr "Aucune valeur valide sélectionnée !"
-#: ../PLCGenerator.py:1319
+#: ../PLCGenerator.py:1358 msgid "No variable defined in \"%s\" POU"
msgstr "Pas de varaibles définies dans le POU \"%s\""
-#: ../canfestival/SlaveEditor.py:49
-#: ../canfestival/NetworkEditor.py:79
-msgstr "Propriétés du noeud"
#: ../canfestival/config_utils.py:354
msgid "Non existing node ID : %d (variable %s)"
@@ -2419,7 +2458,7 @@
-#: ../plcopen/structures.py:247
+#: ../plcopen/structures.py:246 "The off-delay timer can be used to delay setting an output false, for fixed period after input goes false."
@@ -2427,7 +2466,7 @@
"Temporisation avec retard à l'extinction\n"
"La temporisation avec retard à l'extinction peut être utilisé pour retarder le passage de la sortie à l'état faux, d'une période fixe après le passage de l'entrée à l'état faux"
-#: ../plcopen/structures.py:242
+#: ../plcopen/structures.py:241 "The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."
@@ -2439,10 +2478,10 @@
msgstr "Uniquement les éléments"
-#: ../PLCOpenEditor.py:127
-#: ../PLCOpenEditor.py:168
+#: ../PLCOpenEditor.py:108 +#: ../PLCOpenEditor.py:149 @@ -2450,7 +2489,7 @@
msgstr "Ouverture de Inkscape"
-#: ../ProjectController.py:1530
+#: ../ProjectController.py:1565 msgid "Open a file explorer to manage project files"
msgstr "Ouvrir un explorateur de fichier pour gérer les fichiers de projet"
@@ -2471,29 +2510,30 @@
msgid "Organization (optional):"
msgstr "Groupe (optionnel) :"
-#: ../canfestival/SlaveEditor.py:47
-#: ../canfestival/NetworkEditor.py:77
+#: ../canfestival/SlaveEditor.py:51 +#: ../canfestival/NetworkEditor.py:72 #: ../controls/VariablePanel.py:76
-#: ../dialogs/BrowseLocationsDialog.py:37
+#: ../editors/Viewer.py:1411 +#: ../dialogs/BrowseLocationsDialog.py:36 #: ../dialogs/FBDVariableDialog.py:35
#: ../dialogs/SFCStepDialog.py:65
-#: ../canfestival/SlaveEditor.py:36
-#: ../canfestival/NetworkEditor.py:66
+#: ../canfestival/SlaveEditor.py:40 +#: ../canfestival/NetworkEditor.py:61 -#: ../canfestival/SlaveEditor.py:35
-#: ../canfestival/NetworkEditor.py:65
+#: ../canfestival/SlaveEditor.py:39 +#: ../canfestival/NetworkEditor.py:60 -#: ../plcopen/structures.py:269
+#: ../plcopen/structures.py:268 "The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."
@@ -2505,19 +2545,17 @@
-#: ../ProjectController.py:1096
-#: ../ProjectController.py:1398
-msgstr "L'automate est dans l'état %s\n"
-#: ../PLCOpenEditor.py:313
-#: ../PLCOpenEditor.py:391
+msgstr "Log de l'automate" +#: ../PLCOpenEditor.py:294 +#: ../PLCOpenEditor.py:370 msgid "PLCOpen files (*.xml)|*.xml|All files|*.*"
msgstr "Fichiers PLCOpen (*.xml)|*.xml|Tous les fichiers|*.*"
-#: ../PLCOpenEditor.py:175
-#: ../PLCOpenEditor.py:231
+#: ../PLCOpenEditor.py:156 +#: ../PLCOpenEditor.py:212 @@ -2537,8 +2575,8 @@
-#: ../PLCOpenEditor.py:141
+#: ../PLCOpenEditor.py:122 @@ -2546,22 +2584,22 @@
msgid "Page Size (optional):"
msgstr "Taille de la page (optionnel) :"
-#: ../PLCOpenEditor.py:476
-#: ../controls/PouInstanceVariablesPanel.py:41
+#: ../controls/PouInstanceVariablesPanel.py:48
#: ../editors/Viewer.py:537
@@ -2573,16 +2611,16 @@
msgstr "Nombre de pattes :"
-#: ../editors/Viewer.py:2289
-#: ../editors/Viewer.py:2594
+#: ../editors/Viewer.py:2363 +#: ../editors/Viewer.py:2670 #: ../editors/SFCViewer.py:696
msgid "Please choose a target"
msgstr "Choisissez une cible"
-#: ../editors/Viewer.py:2112
-#: ../editors/Viewer.py:2114
-#: ../editors/Viewer.py:2630
-#: ../editors/Viewer.py:2632
+#: ../editors/Viewer.py:2186 +#: ../editors/Viewer.py:2188 +#: ../editors/Viewer.py:2706 +#: ../editors/Viewer.py:2708 msgid "Please enter comment text"
msgstr "Saisissez le texte du commentaire"
@@ -2592,16 +2630,16 @@
msgid "Please enter step name"
msgstr "Saisissez le nom de l'étape"
-#: ../dialogs/ForceVariableDialog.py:153
+#: ../dialogs/ForceVariableDialog.py:163 msgid "Please enter value for a \"%s\" variable:"
msgstr "Veuillez entrer la valeur pour une variable de type \"%s\" :"
-#: ../Beremiz_service.py:366
+#: ../Beremiz_service.py:371 msgid "Port number must be 0 <= port <= 65535!"
msgstr "Le numéro de port doit être compris entre 0 et 65535 !"
-#: ../Beremiz_service.py:366
+#: ../Beremiz_service.py:371 msgid "Port number must be an integer!"
msgstr "Le numéro de port doit être un entier !"
@@ -2609,7 +2647,7 @@
-#: ../editors/Viewer.py:476
+#: ../editors/Viewer.py:475 msgstr "Barre d'alimentation"
@@ -2617,8 +2655,8 @@
msgid "Power Rail Properties"
msgstr "Propriétés de la barre d'alimentation"
-#: ../PLCOpenEditor.py:143
+#: ../PLCOpenEditor.py:124 msgstr "Aperçu avant impression"
@@ -2633,18 +2671,18 @@
-#: ../PLCOpenEditor.py:145
-#: ../PLCOpenEditor.py:171
+#: ../PLCOpenEditor.py:126 +#: ../PLCOpenEditor.py:152
msgstr "Aperçu avant impression"
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 @@ -2652,6 +2690,11 @@
+#: ../runtime/PLCObject.py:318 +msgid "Problem starting PLC : error %d" +msgstr "Problème au démarrage du PLC : erreur %d" #: ../controls/ProjectPropertiesPanel.py:80
msgid "Product Name (required):"
msgstr "Nom du produit (obligatoire) :"
@@ -2664,12 +2707,12 @@
msgid "Product Version (required):"
msgstr "Version du produit (obligatoire) :"
#: ../dialogs/SearchInProjectDialog.py:46
-#: ../PLCOpenEditor.py:360
+#: ../PLCOpenEditor.py:339 msgid "Program was successfully generated!"
msgstr "Le programme a été généré avec succès !"
@@ -2682,7 +2725,7 @@
msgstr "Les programmes ne peuvent être utilisés par les autres POUs !"
#: ../controls/ProjectPropertiesPanel.py:84
@@ -2691,7 +2734,7 @@
-#: ../ProjectController.py:1529
+#: ../ProjectController.py:1564 msgstr "Fichiers de projet"
@@ -2703,7 +2746,7 @@
msgid "Project Version (optional):"
msgstr "Version du projet (optionnel) :"
-#: ../PLCControler.py:2916
+#: ../PLCControler.py:3041 "Project file syntax error:\n"
@@ -2711,20 +2754,25 @@
"Erreur de syntaxe dans le fichier du projet :\n"
+#: ../editors/ProjectNodeEditor.py:14 #: ../dialogs/ProjectDialog.py:32
msgid "Project properties"
msgstr "Propriétés du projet"
-#: ../ConfigTreeNode.py:506
+#: ../ConfigTreeNode.py:526 msgid "Project tree layout do not match confnode.xml %s!=%s "
msgstr "L'organisation du projet ne correspond pas à plugin.xml %s!=%s"
+#: ../dialogs/ConnectionDialog.py:96 +msgstr "Propager le nom" -#: ../plcopen/structures.py:237
+#: ../plcopen/structures.py:236 "The pulse timer can be used to generate output pulses of a given time duration."
@@ -2732,7 +2780,11 @@
"Temporisation à impulsion\n"
"La temporisation à impulsion peut être utilisée pour générer sur la sortie des impulsions d'une durée déterminée."
+#: ../py_ext/PythonEditor.py:61 @@ -2740,13 +2792,13 @@
-#: ../Beremiz_service.py:328
-#: ../PLCOpenEditor.py:151
+#: ../Beremiz_service.py:333 +#: ../PLCOpenEditor.py:132 -#: ../plcopen/structures.py:202
+#: ../plcopen/structures.py:201 "The RS bistable is a latch where the Reset dominates."
@@ -2754,7 +2806,7 @@
"La bascule RS est une bascule où le Reset est dominant."
-#: ../plcopen/structures.py:274
+#: ../plcopen/structures.py:273 "The RAMP function block is modelled on example given in the standard."
@@ -2762,15 +2814,16 @@
"Le bloc fonctionnel RAMP est basé sur l'exemple du standard."
+#: ../controls/DebugVariablePanel.py:1462 #: ../editors/GraphicViewer.py:89
-#: ../ProjectController.py:1525
+#: ../ProjectController.py:1560 -#: ../plcopen/structures.py:254
+#: ../plcopen/structures.py:253 "The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on."
@@ -2778,13 +2831,13 @@
"L'horloge temps réel est utilisée dans de nombreux cas tels que l'horodatage, la définition des dates et heures dans des rapports de commandes, dans des messages d'alarme et bien d'autres."
msgid "Really delete node '%s'?"
msgstr "Êtes-vous sûr de vouloir supprimer le noeud '%s' ?"
@@ -2793,7 +2846,7 @@
#: ../dialogs/DiscoveryDialog.py:105
@@ -2806,8 +2859,8 @@
msgid "Regular expressions"
msgstr "Expressions régulières"
-#: ../controls/DebugVariablePanel.py:299
-#: ../editors/Viewer.py:1356
+#: ../controls/DebugVariablePanel.py:1938 +#: ../editors/Viewer.py:1388 msgstr "Relacher la valeur"
@@ -2815,7 +2868,7 @@
msgid "Remainder (modulo)"
msgstr "Enlever un noeud %s"
@@ -2824,39 +2877,40 @@
msgstr "Supprimer une action"
-#: ../controls/DebugVariablePanel.py:183
+#: ../controls/DebugVariablePanel.py:1530 msgid "Remove debug variable"
msgstr "Supprimer une variable à déboguer"
-#: ../editors/DataTypeEditor.py:346
+#: ../editors/DataTypeEditor.py:352 msgstr "Supprimer un élément"
-#: ../editors/FileManagementPanel.py:281
+#: ../editors/FileManagementPanel.py:63 msgid "Remove file from left folder"
msgstr "Supprimer un fichier du dossier de gauche"
-#: ../editors/ResourceEditor.py:252
+#: ../editors/ResourceEditor.py:260 msgstr "Supprimer une instance"
-#: ../canfestival/NetworkEditor.py:87
+#: ../canfestival/NetworkEditor.py:81 msgstr "Enlever l'esclave"
-#: ../editors/ResourceEditor.py:223
+#: ../editors/ResourceEditor.py:231 msgstr "Supprimer la tâche"
-#: ../controls/VariablePanel.py:379
+#: ../controls/VariablePanel.py:381 +#: ../c_ext/CFileEditor.py:518 msgstr "Supprimer une variable"
-#: ../editors/FileManagementPanel.py:399
+#: ../editors/FileManagementPanel.py:181 msgstr "Remplacer un fichier"
@@ -2872,7 +2926,7 @@
msgid "Reset Execution Order"
msgstr "Réinitialiser l'order d'exécution"
msgid "Reset Perspective"
msgstr "Réinitialiser l'interface"
@@ -2892,11 +2946,11 @@
-#: ../controls/VariablePanel.py:352
+#: ../controls/VariablePanel.py:354 msgstr "Type de retour :"
-#: ../editors/Viewer.py:430
+#: ../editors/Viewer.py:429 @@ -2904,12 +2958,12 @@
msgstr "Barre d'alimentation à droite"
-#: ../editors/Viewer.py:404
+#: ../editors/Viewer.py:403 #: ../dialogs/LDElementDialog.py:80
-#: ../plcopen/structures.py:212
+#: ../plcopen/structures.py:211 "The output produces a single pulse when a rising edge is detected."
@@ -2929,22 +2983,22 @@
-#: ../ProjectController.py:1493
+#: ../ProjectController.py:1528 -#: ../ProjectController.py:841
-#: ../ProjectController.py:850
+#: ../ProjectController.py:865 +#: ../ProjectController.py:874 msgid "Runtime extensions C code generation failed !\n"
msgstr "La génération du code des plugins a échoué !\n"
-#: ../canfestival/SlaveEditor.py:34
-#: ../canfestival/NetworkEditor.py:64
+#: ../canfestival/SlaveEditor.py:38 +#: ../canfestival/NetworkEditor.py:59 -#: ../canfestival/SlaveEditor.py:33
-#: ../canfestival/NetworkEditor.py:63
+#: ../canfestival/SlaveEditor.py:37 +#: ../canfestival/NetworkEditor.py:58 @@ -2953,7 +3007,7 @@
-#: ../plcopen/structures.py:197
+#: ../plcopen/structures.py:196 "The SR bistable is a latch where the Set dominates."
@@ -2967,7 +3021,7 @@
-#: ../PLCOpenEditor.py:347
+#: ../PLCOpenEditor.py:326 msgid "ST files (*.st)|*.st|All files|*.*"
msgstr "Fichiers ST (*.st)|*.st|Tous les fichiers|*.*"
@@ -2975,24 +3029,24 @@
msgid "SVG files (*.svg)|*.svg|All files|*.*"
msgstr "Fichiers SVG (*.svg)|*.svg|Tous les fichiers|*.*"
-#: ../PLCOpenEditor.py:134
-#: ../PLCOpenEditor.py:169
+#: ../PLCOpenEditor.py:115 +#: ../PLCOpenEditor.py:150
-#: ../PLCOpenEditor.py:136
-#: ../PLCOpenEditor.py:170
+#: ../PLCOpenEditor.py:117 +#: ../PLCOpenEditor.py:151 msgstr "Enregistrer sous..."
msgstr "Enregistrer sous..."
@@ -3000,13 +3054,13 @@
#: ../dialogs/SearchInProjectDialog.py:105
#: ../dialogs/SearchInProjectDialog.py:52
msgid "Search in Project"
msgstr "Rechercher dans le projet"
@@ -3015,25 +3069,26 @@
msgstr "Tout sélectionner"
+#: ../controls/LocationCellEditor.py:97 #: ../controls/VariablePanel.py:277
-#: ../editors/TextViewer.py:330
-#: ../editors/Viewer.py:277
+#: ../editors/TextViewer.py:323 +#: ../editors/Viewer.py:275 msgid "Select a variable class:"
msgstr "Sélectionner une direction pour la variable :"
-#: ../ProjectController.py:1013
+#: ../ProjectController.py:1039 msgid "Select an editor:"
msgstr "Sélectionner un éditeur :"
-#: ../controls/PouInstanceVariablesPanel.py:197
+#: ../controls/PouInstanceVariablesPanel.py:209 msgid "Select an instance"
msgstr "Sélectionnez une instance"
msgstr "Sélectionner un objet"
@@ -3049,7 +3104,7 @@
msgid "Selection Divergence"
msgstr "Divergence simple"
-#: ../plcopen/structures.py:207
+#: ../plcopen/structures.py:206 "The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."
@@ -3073,19 +3128,19 @@
msgstr "Décalage à droite"
-#: ../ProjectController.py:1519
+#: ../ProjectController.py:1554 msgid "Show IEC code generated by PLCGenerator"
msgstr "Afficher le code IEC généré par PLCGenerator"
-#: ../canfestival/canfestival.py:288
+#: ../canfestival/canfestival.py:363 msgstr "Afficher le maître"
-#: ../canfestival/canfestival.py:289
+#: ../canfestival/canfestival.py:364 msgid "Show Master generated by config_utils"
msgstr "Afficher le maître généré par config_utils"
-#: ../ProjectController.py:1517
+#: ../ProjectController.py:1552 msgstr "Afficher le code"
@@ -3101,7 +3156,7 @@
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 @@ -3109,53 +3164,53 @@
msgid "Square root (base 2)"
msgstr "Racine carré (base 2)"
-#: ../plcopen/structures.py:193
+#: ../plcopen/structures.py:192 msgid "Standard function blocks"
msgstr "Blocs fonctionnels standards"
-#: ../Beremiz_service.py:319
-#: ../ProjectController.py:1495
+#: ../Beremiz_service.py:321 +#: ../ProjectController.py:1530 msgstr "Démarrer l'automate"
-#: ../ProjectController.py:819
+#: ../ProjectController.py:843 msgid "Start build in %s\n"
msgstr "Début de la compilation dans %s\n"
-#: ../ProjectController.py:1314
+#: ../ProjectController.py:1341 msgstr "Démarrer l'automate\n"
msgstr "Barre d'outils de statut"
-#: ../editors/Viewer.py:493
+#: ../editors/Viewer.py:492 -#: ../ProjectController.py:1498
+#: ../ProjectController.py:1533 -#: ../Beremiz_service.py:320
+#: ../Beremiz_service.py:322 msgstr "Arrêter l'automate"
-#: ../ProjectController.py:1500
+#: ../ProjectController.py:1535 msgstr "Arrêter l'automate en cours d'exécution"
-#: ../ProjectController.py:1292
+#: ../ProjectController.py:1318 msgid "Stopping debugger...\n"
msgstr "Arrêt du débogage en cours\n"
-#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 -#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 @@ -3163,7 +3218,7 @@
-#: ../ProjectController.py:915
+#: ../ProjectController.py:942 msgid "Successfully built.\n"
msgstr "Compilé avec succès.\n"
@@ -3175,11 +3230,11 @@
-#: ../editors/ResourceEditor.py:76
+#: ../editors/ResourceEditor.py:77 -#: ../editors/ResourceEditor.py:218
+#: ../editors/ResourceEditor.py:226 @@ -3187,7 +3242,7 @@
-#: ../editors/FileManagementPanel.py:398
+#: ../editors/FileManagementPanel.py:180 "The file '%s' already exist.\n"
@@ -3196,22 +3251,22 @@
"Le fichier '%s' existe déjà .\n"
"Voulez-vous le remplacer ?"
-#: ../editors/LDViewer.py:879
+#: ../editors/LDViewer.py:882 msgid "The group of block must be coherent!"
msgstr "Le groupe de blocs doit être cohérent !"
msgid "There are changes, do you want to save?"
msgstr "Le projet a été modifié. Voulez-vous l'enregistrer ?"
msgid "There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?"
msgstr "Un POU a pour nom \"%s\". Cela peut générer des conflits. Voulez-vous continuer ?"
"There was a problem printing.\n"
"Perhaps your current printer is not set correctly?"
@@ -3219,7 +3274,7 @@
"Un problème est apparu lors de l'impression.\n"
"Peut-être que votre imprimante n'est pas correctement configurée ?"
-#: ../editors/LDViewer.py:888
+#: ../editors/LDViewer.py:891 msgid "This option isn't available yet!"
msgstr "Cette option n'a pas encore disponible"
@@ -3267,31 +3322,31 @@
msgid "Time-of-day subtraction"
msgstr "Soustraction d'horodatage"
-#: ../editors/Viewer.py:432
+#: ../editors/Viewer.py:431 -#: ../ProjectController.py:1507
+#: ../ProjectController.py:1542 -#: ../ProjectController.py:1509
+#: ../ProjectController.py:1544 msgstr "Transférer l'automate"
-#: ../ProjectController.py:1474
+#: ../ProjectController.py:1509 msgid "Transfer completed successfully.\n"
msgstr "Transfert effectué avec succès.\n"
-#: ../ProjectController.py:1476
+#: ../ProjectController.py:1511 msgid "Transfer failed\n"
msgstr "Le transfert a échoué\n"
-#: ../editors/Viewer.py:494
+#: ../editors/Viewer.py:493 -#: ../PLCGenerator.py:1212
+#: ../PLCGenerator.py:1252 msgid "Transition \"%s\" body must contain an output variable or coil referring to its name"
msgstr "Le code de la transition \"%s\" doit contenir une variable de sortie ou un relai dont la référence est son nom"
@@ -3304,17 +3359,17 @@
msgstr "Nom de la transition :"
-#: ../PLCGenerator.py:1301
+#: ../PLCGenerator.py:1340 msgid "Transition with content \"%s\" not connected to a next step in \"%s\" POU"
msgstr "La transition contenant \"%s\" n'est pas connectée à une étape en sortie dans le POU \"%s\" !"
-#: ../PLCGenerator.py:1292
+#: ../PLCGenerator.py:1331 msgid "Transition with content \"%s\" not connected to a previous step in \"%s\" POU"
msgstr "La transition contenant \"%s\" n'est pas connectée à une étape en entrée dans le POU \"%s\" !"
-#: ../plcopen/plcopen.py:1442
+#: ../plcopen/plcopen.py:1447 msgid "Transition with name %s doesn't exist!"
msgstr "La transition nommée %s n'existe pas !"
@@ -3323,18 +3378,22 @@
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 #: ../controls/VariablePanel.py:58
#: ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48
-#: ../editors/ResourceEditor.py:76
+#: ../editors/DataTypeEditor.py:50 +#: ../editors/ResourceEditor.py:77 #: ../dialogs/ActionBlockDialog.py:37
+#: ../dialogs/BrowseLocationsDialog.py:44 +msgid "Type and derivated" +msgstr "Type et ses dérivés" #: ../canfestival/config_utils.py:335
#: ../canfestival/config_utils.py:617
@@ -3345,12 +3404,17 @@
msgstr "Conversion de type"
-#: ../editors/DataTypeEditor.py:155
+#: ../editors/DataTypeEditor.py:161 msgstr "Propriétés du type :"
+#: ../dialogs/BrowseLocationsDialog.py:45 +msgstr "Type uniquement" #: ../dialogs/SFCDivergenceDialog.py:51
#: ../dialogs/LDPowerRailDialog.py:51
+#: ../dialogs/BrowseLocationsDialog.py:95 #: ../dialogs/ConnectionDialog.py:52
#: ../dialogs/SFCTransitionDialog.py:53
#: ../dialogs/FBDBlockDialog.py:48
@@ -3368,33 +3432,33 @@
msgid "Unable to get Xenomai's %s \n"
msgstr "Unable to get Xenomai's %s \n"
-#: ../PLCGenerator.py:865
-#: ../PLCGenerator.py:924
+#: ../PLCGenerator.py:904 +#: ../PLCGenerator.py:963 msgid "Undefined block type \"%s\" in \"%s\" POU"
msgstr "Type de block \"%s\" indéfini dans le POU \"%s\""
-#: ../PLCGenerator.py:240
+#: ../PLCGenerator.py:252 msgid "Undefined pou type \"%s\""
msgstr "Type de POU \"%s\" indéterminé !"
-#: ../ProjectController.py:254
+#: ../ProjectController.py:262 -#: ../editors/Viewer.py:336
+#: ../editors/Viewer.py:335 msgid "Unknown variable \"%s\" for this POU!"
msgstr "Variable \"%s\" inconnue dans ce POU !"
-#: ../ProjectController.py:251
-#: ../ProjectController.py:252
+#: ../ProjectController.py:259 +#: ../ProjectController.py:260 @@ -3408,7 +3472,7 @@
msgid "Unrecognized data size \"%s\""
msgstr "Taille de donnée \"%s\" non identifié !"
-#: ../plcopen/structures.py:222
+#: ../plcopen/structures.py:221 "The up-counter can be used to signal when a count has reached a maximum value."
@@ -3416,7 +3480,7 @@
"Compteur incrémental\n"
"Le compteur incrémental peut être utilisé pour signaler lorsque le compteur a atteint la valeur maximale."
-#: ../plcopen/structures.py:232
+#: ../plcopen/structures.py:231 "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other."
@@ -3424,13 +3488,13 @@
"Compteur bidirectionnel\n"
"Le compteur bidirectionnel a deux entrées CU et CD. Il peut être utilisé pour compter de façon incrémentale ou décrémentale sur l'une ou l'autre des entrées."
-#: ../controls/VariablePanel.py:709
-#: ../editors/DataTypeEditor.py:623
+#: ../controls/VariablePanel.py:712 +#: ../editors/DataTypeEditor.py:631 msgstr "Types de donnée du projet"
-#: ../canfestival/SlaveEditor.py:38
-#: ../canfestival/NetworkEditor.py:68
+#: ../canfestival/SlaveEditor.py:42 +#: ../canfestival/NetworkEditor.py:63 msgstr "Type utilisateur"
@@ -3438,7 +3502,7 @@
msgid "User-defined POUs"
-#: ../controls/DebugVariablePanel.py:40
+#: ../controls/DebugVariablePanel.py:58 #: ../dialogs/ActionBlockDialog.py:37
@@ -3447,12 +3511,12 @@
-#: ../editors/DataTypeEditor.py:252
+#: ../editors/DataTypeEditor.py:258 -#: ../controls/DebugVariablePanel.py:40
-#: ../editors/Viewer.py:466
+#: ../controls/DebugVariablePanel.py:58 +#: ../editors/Viewer.py:465 #: ../dialogs/ActionBlockDialog.py:41
@@ -3461,14 +3525,15 @@
msgid "Variable Properties"
msgstr "Propriétés de la variable"
+#: ../controls/LocationCellEditor.py:97 #: ../controls/VariablePanel.py:277
-#: ../editors/TextViewer.py:330
-#: ../editors/Viewer.py:277
+#: ../editors/TextViewer.py:323 +#: ../editors/Viewer.py:275 msgstr "Direction de la variable"
-#: ../editors/TextViewer.py:374
-#: ../editors/Viewer.py:338
+#: ../editors/TextViewer.py:367 +#: ../editors/Viewer.py:337 msgid "Variable don't belong to this POU!"
msgstr "La variable n'appartient pas à ce POU !"
@@ -3484,16 +3549,16 @@
-#: ../ProjectController.py:1276
+#: ../ProjectController.py:1302 msgid "Waiting debugger to recover...\n"
msgstr "En attente de la mise en route du déboggueur...\n"
-#: ../editors/LDViewer.py:888
+#: ../editors/LDViewer.py:891 #: ../dialogs/PouDialog.py:126
-#: ../ProjectController.py:515
+#: ../ProjectController.py:529 msgid "Warnings in ST/IL/SFC code generator :\n"
msgstr "Mises en garde du generateur de code ST/IL/SFC :\n"
@@ -3509,7 +3574,7 @@
msgstr "Interface WxGlade"
@@ -3529,7 +3594,7 @@
"Vous n'avez pas les permissions d'écriture.\n"
"Ouvrir wxGlade tout de même ?"
-#: ../ProjectController.py:220
+#: ../ProjectController.py:224 "You must have permission to work on the project\n"
"Work on a project copy ?"
@@ -3537,11 +3602,11 @@
"Vous n'avez pas la permission de travailler sur le projet.\n"
"Travailler sur une copie du projet ?"
-#: ../editors/LDViewer.py:883
+#: ../editors/LDViewer.py:886 msgid "You must select the block or group of blocks around which a branch should be added!"
msgstr "Vous devez sélectionné le bloc ou le group autour duquel un ebranche doit être ajoutée !"
-#: ../editors/LDViewer.py:663
+#: ../editors/LDViewer.py:666 msgid "You must select the wire where a contact should be added!"
msgstr "Vous devez sélectionner le fil sur lequel le contact doit être ajouté !"
@@ -3551,11 +3616,11 @@
msgid "You must type a name!"
msgstr "Vous devez saisir un nom !"
-#: ../dialogs/ForceVariableDialog.py:165
+#: ../dialogs/ForceVariableDialog.py:175 msgid "You must type a value!"
msgstr "Vous devez saisir une valeur !"
@@ -3563,7 +3628,7 @@
-#: ../PLCOpenEditor.py:356
+#: ../PLCOpenEditor.py:335 @@ -3573,8 +3638,8 @@
msgid "exited with status %s (pid %s)\n"
msgstr "a quitté avec le status %s (pid %s)\n"
-#: ../PLCOpenEditor.py:508
-#: ../PLCOpenEditor.py:510
+#: ../PLCOpenEditor.py:393 +#: ../PLCOpenEditor.py:395 @@ -3582,7 +3647,7 @@
-#: ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:396 @@ -3590,7 +3655,7 @@
msgstr "Bloc fonctionnel"
-#: ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:396 @@ -3610,7 +3675,7 @@
msgstr "Caractères à droite de"
-#: ../PLCOpenEditor.py:354
+#: ../PLCOpenEditor.py:333 @@ -3646,9 +3711,6 @@
-msgstr "Mode de débogage"
@@ -3700,6 +3762,28 @@
msgid "Disable_Extensions"
msgstr "Disable_Extensions"
+#~ msgid "Debug connect matching running PLC\n" +#~ msgstr "L'automate connecté correspond au project ouvert.\n" +#~ msgid "File '%s' already exists!" +#~ msgstr "Le fichier '%s' existe déjà !" +#~ msgid "Function Blocks can't be used in Transitions!" +#~ "Les blocs fonctionnels ne peuvent être utilisés dans des transitions" +#~ msgid "No running PLC" +#~ msgstr "Aucun automate en cours d'exécution" +#~ msgstr "Propriétés du noeud" +#~ msgstr "L'automate est dans l'état %s\n" +#~ msgstr "Mode de débogage" #~ msgid "Close Project\tCTRL+SHIFT+W"
@@ -3814,9 +3898,6 @@
#~ msgstr "Types de blocs"
#~ msgstr "Supprimer une tâche"
@@ -3844,9 +3925,6 @@
#~ msgid "Create a new POU from"
#~ msgstr "Créer un nouveau POU à partir de"
--- a/i18n/messages.pot Wed Mar 13 12:34:55 2013 +0900
+++ b/i18n/messages.pot Wed Jul 31 10:45:07 2013 +0900
@@ -8,7 +8,7 @@
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2012-09-07 01:17+0200\n"
+"POT-Creation-Date: 2013-03-26 22:55+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,7 +17,7 @@
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../PLCOpenEditor.py:520
+#: ../PLCOpenEditor.py:405 "An error has occurred.\n"
@@ -30,7 +30,7 @@
@@ -69,7 +69,7 @@
-#: ../PLCOpenEditor.py:530
+#: ../PLCOpenEditor.py:415 @@ -79,7 +79,7 @@
-#: ../ProjectController.py:890
+#: ../ProjectController.py:917 msgid " generation failed !\n"
@@ -103,7 +103,7 @@
msgid "\"%s\" can't use itself!"
-#: ../IDEFrame.py:1706 ../IDEFrame.py:1725
+#: ../IDEFrame.py:1587 ../IDEFrame.py:1606 msgid "\"%s\" config already exists!"
@@ -113,38 +113,38 @@
msgid "\"%s\" configuration already exists !!!"
msgid "\"%s\" data type already exists!"
-#: ../PLCControler.py:2040 ../PLCControler.py:2044
+#: ../PLCControler.py:2165 ../PLCControler.py:2169 msgid "\"%s\" element can't be pasted here!!!"
-#: ../editors/TextViewer.py:305 ../editors/TextViewer.py:325
-#: ../editors/Viewer.py:252 ../dialogs/PouTransitionDialog.py:105
-#: ../dialogs/ConnectionDialog.py:150 ../dialogs/PouActionDialog.py:102
+#: ../editors/TextViewer.py:298 ../editors/TextViewer.py:318 +#: ../editors/Viewer.py:250 ../dialogs/PouTransitionDialog.py:105 +#: ../dialogs/ConnectionDialog.py:157 ../dialogs/PouActionDialog.py:102 #: ../dialogs/FBDBlockDialog.py:162
msgid "\"%s\" element for this pou already exists!"
msgid "\"%s\" folder is not a valid Beremiz project\n"
-#: ../plcopen/structures.py:106
+#: ../plcopen/structures.py:105 msgid "\"%s\" function cancelled in \"%s\" POU: No input connected"
-#: ../controls/VariablePanel.py:656 ../IDEFrame.py:1651
-#: ../editors/DataTypeEditor.py:548 ../editors/DataTypeEditor.py:577
+#: ../controls/VariablePanel.py:659 ../IDEFrame.py:1532 +#: ../editors/DataTypeEditor.py:554 ../editors/DataTypeEditor.py:583 #: ../dialogs/PouNameDialog.py:49 ../dialogs/PouTransitionDialog.py:101
-#: ../dialogs/SFCStepNameDialog.py:51 ../dialogs/ConnectionDialog.py:146
+#: ../dialogs/SFCStepNameDialog.py:51 ../dialogs/ConnectionDialog.py:153 #: ../dialogs/FBDVariableDialog.py:199 ../dialogs/PouActionDialog.py:98
#: ../dialogs/PouDialog.py:118 ../dialogs/SFCStepDialog.py:122
#: ../dialogs/FBDBlockDialog.py:158
@@ -152,41 +152,41 @@
msgid "\"%s\" is a keyword. It can't be used!"
-#: ../editors/Viewer.py:240
+#: ../editors/Viewer.py:238 msgid "\"%s\" is already used by \"%s\"!"
-#: ../plcopen/plcopen.py:2786
+#: ../plcopen/plcopen.py:2836 msgid "\"%s\" is an invalid value!"
-#: ../PLCOpenEditor.py:362 ../PLCOpenEditor.py:399
+#: ../PLCOpenEditor.py:341 ../PLCOpenEditor.py:378 msgid "\"%s\" is not a valid folder!"
-#: ../controls/VariablePanel.py:654 ../IDEFrame.py:1649
-#: ../editors/DataTypeEditor.py:572 ../dialogs/PouNameDialog.py:47
+#: ../controls/VariablePanel.py:657 ../IDEFrame.py:1530 +#: ../editors/DataTypeEditor.py:578 ../dialogs/PouNameDialog.py:47 #: ../dialogs/PouTransitionDialog.py:99 ../dialogs/SFCStepNameDialog.py:49
-#: ../dialogs/ConnectionDialog.py:144 ../dialogs/PouActionDialog.py:96
+#: ../dialogs/ConnectionDialog.py:151 ../dialogs/PouActionDialog.py:96 #: ../dialogs/PouDialog.py:116 ../dialogs/SFCStepDialog.py:120
#: ../dialogs/FBDBlockDialog.py:156
msgid "\"%s\" is not a valid identifier!"
-#: ../IDEFrame.py:214 ../IDEFrame.py:2445 ../IDEFrame.py:2464
+#: ../IDEFrame.py:221 ../IDEFrame.py:2313 ../IDEFrame.py:2332 msgid "\"%s\" is used by one or more POUs. It can't be removed!"
-#: ../controls/VariablePanel.py:311 ../IDEFrame.py:1669
-#: ../editors/TextViewer.py:303 ../editors/TextViewer.py:323
-#: ../editors/TextViewer.py:360 ../editors/Viewer.py:250
-#: ../editors/Viewer.py:295 ../editors/Viewer.py:312
-#: ../dialogs/ConnectionDialog.py:148 ../dialogs/PouDialog.py:120
+#: ../controls/VariablePanel.py:313 ../IDEFrame.py:1550 +#: ../editors/TextViewer.py:296 ../editors/TextViewer.py:316 +#: ../editors/TextViewer.py:353 ../editors/Viewer.py:248 +#: ../editors/Viewer.py:293 ../editors/Viewer.py:311 +#: ../dialogs/ConnectionDialog.py:155 ../dialogs/PouDialog.py:120 #: ../dialogs/FBDBlockDialog.py:160
msgid "\"%s\" pou already exists!"
@@ -207,29 +207,29 @@
msgid "\"%s\" step already exists!"
-#: ../editors/DataTypeEditor.py:543
+#: ../editors/DataTypeEditor.py:549 msgid "\"%s\" value already defined!"
-#: ../editors/DataTypeEditor.py:719 ../dialogs/ArrayTypeDialog.py:97
+#: ../editors/DataTypeEditor.py:744 ../dialogs/ArrayTypeDialog.py:97 msgid "\"%s\" value isn't a valid array dimension!"
-#: ../editors/DataTypeEditor.py:726 ../dialogs/ArrayTypeDialog.py:103
+#: ../editors/DataTypeEditor.py:751 ../dialogs/ArrayTypeDialog.py:103 "\"%s\" value isn't a valid array dimension!\n"
"Right value must be greater than left value."
-#: ../PLCControler.py:793
+#: ../PLCControler.py:847 msgid "%s \"%s\" can't be pasted as a %s."
-#: ../PLCControler.py:1422
+#: ../PLCControler.py:1476 @@ -239,86 +239,86 @@
-#: ../PLCControler.py:1417
+#: ../PLCControler.py:1471 -#: ../canfestival/SlaveEditor.py:42 ../canfestival/NetworkEditor.py:72
+#: ../canfestival/SlaveEditor.py:46 ../canfestival/NetworkEditor.py:67 -#: ../plcopen/plcopen.py:1780 ../plcopen/plcopen.py:1790
-#: ../plcopen/plcopen.py:1800 ../plcopen/plcopen.py:1810
-#: ../plcopen/plcopen.py:1819
+#: ../plcopen/plcopen.py:1790 ../plcopen/plcopen.py:1800 +#: ../plcopen/plcopen.py:1810 ../plcopen/plcopen.py:1820 +#: ../plcopen/plcopen.py:1829 msgid "%s body don't have instances!"
-#: ../plcopen/plcopen.py:1842 ../plcopen/plcopen.py:1849
+#: ../plcopen/plcopen.py:1852 ../plcopen/plcopen.py:1859 msgid "%s body don't have text!"
-#: ../PLCOpenEditor.py:148
+#: ../PLCOpenEditor.py:129
-#: ../controls/SearchResultPanel.py:237
+#: ../controls/SearchResultPanel.py:252 msgid "'%s' - %d match in project"
-#: ../controls/SearchResultPanel.py:239
+#: ../controls/SearchResultPanel.py:254 msgid "'%s' - %d matches in project"
@@ -328,12 +328,12 @@
msgid "'%s' is located at %s\n"
-#: ../controls/SearchResultPanel.py:289
+#: ../controls/SearchResultPanel.py:304 -#: ../PLCOpenEditor.py:508 ../PLCOpenEditor.py:510 ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:393 ../PLCOpenEditor.py:395 ../PLCOpenEditor.py:396 @@ -343,21 +343,21 @@
-#: ../PLCOpenEditor.py:506
+#: ../PLCOpenEditor.py:391 -#: ../ProjectController.py:1268
+#: ../ProjectController.py:1294 msgid "... debugger recovered\n"
-#: ../IDEFrame.py:1672 ../IDEFrame.py:1714 ../IDEFrame.py:1733
+#: ../IDEFrame.py:1553 ../IDEFrame.py:1595 ../IDEFrame.py:1614 #: ../dialogs/PouDialog.py:122
msgid "A POU has an element named \"%s\". This could cause a conflict. Do you wish to continue?"
-#: ../controls/VariablePanel.py:658 ../IDEFrame.py:1684 ../IDEFrame.py:1695
+#: ../controls/VariablePanel.py:661 ../IDEFrame.py:1565 ../IDEFrame.py:1576 #: ../dialogs/PouNameDialog.py:51 ../dialogs/PouTransitionDialog.py:103
#: ../dialogs/SFCStepNameDialog.py:53 ../dialogs/PouActionDialog.py:100
#: ../dialogs/SFCStepDialog.py:124
@@ -365,30 +365,30 @@
msgid "A POU named \"%s\" already exists!"
-#: ../ConfigTreeNode.py:371
+#: ../ConfigTreeNode.py:388 msgid "A child named \"%s\" already exist -> \"%s\"\n"
-#: ../dialogs/BrowseLocationsDialog.py:175
+#: ../dialogs/BrowseLocationsDialog.py:212 msgid "A location must be selected!"
-#: ../controls/VariablePanel.py:660 ../IDEFrame.py:1686 ../IDEFrame.py:1697
+#: ../controls/VariablePanel.py:663 ../IDEFrame.py:1567 ../IDEFrame.py:1578 #: ../dialogs/SFCStepNameDialog.py:55 ../dialogs/SFCStepDialog.py:126
msgid "A variable with \"%s\" as name already exists in this pou!"
-#: ../Beremiz.py:362 ../PLCOpenEditor.py:181
+#: ../Beremiz.py:364 ../PLCOpenEditor.py:162
-#: ../PLCOpenEditor.py:376
+#: ../PLCOpenEditor.py:355 msgid "About PLCOpenEditor"
@@ -400,7 +400,7 @@
-#: ../editors/Viewer.py:495
+#: ../editors/Viewer.py:494 @@ -412,7 +412,7 @@
-#: ../plcopen/plcopen.py:1480
+#: ../plcopen/plcopen.py:1490 msgid "Action with name %s doesn't exist!"
@@ -425,28 +425,32 @@
-#: ../canfestival/SlaveEditor.py:54 ../canfestival/NetworkEditor.py:84
-#: ../editors/Viewer.py:527
+#: ../editors/Viewer.py:999 +#: ../canfestival/SlaveEditor.py:57 ../canfestival/NetworkEditor.py:78 +#: ../Beremiz.py:987 ../editors/Viewer.py:527 -#: ../IDEFrame.py:1925 ../IDEFrame.py:1956
+#: ../IDEFrame.py:1801 ../IDEFrame.py:1832
msgid "Add C code accessing located variables synchronously"
msgid "Add Configuration"
-#: ../editors/Viewer.py:453
+#: ../editors/Viewer.py:452 msgid "Add Divergence Branch"
@@ -454,23 +458,23 @@
msgid "Add Python code executed asynchronously"
-#: ../IDEFrame.py:1936 ../IDEFrame.py:1982
+#: ../IDEFrame.py:1812 ../IDEFrame.py:1858 -#: ../IDEFrame.py:1914 ../IDEFrame.py:1953
+#: ../IDEFrame.py:1790 ../IDEFrame.py:1829 -#: ../editors/Viewer.py:442
+#: ../editors/Viewer.py:441 @@ -478,7 +482,7 @@
msgid "Add a new initial step"
-#: ../editors/Viewer.py:2289 ../editors/SFCViewer.py:696
+#: ../editors/Viewer.py:2363 ../editors/SFCViewer.py:696 @@ -486,7 +490,7 @@
msgid "Add a simple WxGlade based GUI."
@@ -494,23 +498,23 @@
-#: ../editors/DataTypeEditor.py:345
+#: ../editors/DataTypeEditor.py:351 -#: ../editors/ResourceEditor.py:251
+#: ../editors/ResourceEditor.py:259 -#: ../canfestival/NetworkEditor.py:86
+#: ../canfestival/NetworkEditor.py:80 -#: ../editors/ResourceEditor.py:222
+#: ../editors/ResourceEditor.py:230 -#: ../controls/VariablePanel.py:378
+#: ../controls/VariablePanel.py:380 ../c_ext/CFileEditor.py:517 @@ -518,16 +522,22 @@
-#: ../plcopen/structures.py:250
+#: ../plcopen/structures.py:249 msgid "Additional function blocks"
-#: ../editors/Viewer.py:1395
+#: ../editors/Viewer.py:510 +msgid "Adjust Block Size" +#: ../editors/Viewer.py:1458 -#: ../controls/VariablePanel.py:75 ../dialogs/BrowseLocationsDialog.py:35
-#: ../dialogs/BrowseLocationsDialog.py:116
+#: ../controls/VariablePanel.py:75 ../dialogs/BrowseLocationsDialog.py:34 +#: ../dialogs/BrowseLocationsDialog.py:43 +#: ../dialogs/BrowseLocationsDialog.py:136 +#: ../dialogs/BrowseLocationsDialog.py:139 @@ -535,15 +545,19 @@
msgid "All files (*.*)|*.*|CSV files (*.csv)|*.csv"
-#: ../ProjectController.py:1335
+#: ../ProjectController.py:1373 msgid "Already connected. Please disconnect\n"
-#: ../editors/DataTypeEditor.py:587
+#: ../editors/DataTypeEditor.py:593 msgid "An element named \"%s\" already exists in this structure!"
+#: ../dialogs/ConnectionDialog.py:98 +msgid "Apply name modification to all continuations with the same name" #: ../plcopen/iec_std.csv:31
@@ -560,7 +574,8 @@
-#: ../controls/VariablePanel.py:729 ../editors/DataTypeEditor.py:52
+#: ../controls/VariablePanel.py:732 ../editors/DataTypeEditor.py:54 +#: ../editors/DataTypeEditor.py:634 @@ -597,16 +612,16 @@
msgid "Bad location size : %s"
-#: ../editors/DataTypeEditor.py:168 ../editors/DataTypeEditor.py:198
-#: ../editors/DataTypeEditor.py:290 ../dialogs/ArrayTypeDialog.py:55
+#: ../editors/DataTypeEditor.py:174 ../editors/DataTypeEditor.py:204 +#: ../editors/DataTypeEditor.py:296 ../dialogs/ArrayTypeDialog.py:55 -#: ../controls/VariablePanel.py:699 ../editors/DataTypeEditor.py:617
+#: ../controls/VariablePanel.py:702 ../editors/DataTypeEditor.py:624
@@ -638,7 +653,7 @@
msgid "Bitwise inverting"
-#: ../editors/Viewer.py:465
+#: ../editors/Viewer.py:464 @@ -646,7 +661,7 @@
-#: ../editors/Viewer.py:434
+#: ../editors/Viewer.py:433 @@ -655,31 +670,35 @@
msgid "Browse %s values library"
-#: ../dialogs/BrowseLocationsDialog.py:55
+#: ../dialogs/BrowseLocationsDialog.py:61 -#: ../ProjectController.py:1484
+#: ../ProjectController.py:1519 -#: ../ProjectController.py:1051
+#: ../ProjectController.py:1079 msgid "Build directory already clean\n"
-#: ../ProjectController.py:1485
+#: ../ProjectController.py:1520 msgid "Build project into build folder"
-#: ../ProjectController.py:910
+#: ../ProjectController.py:937 msgid "C Build crashed !\n"
-#: ../ProjectController.py:907
+#: ../ProjectController.py:934 msgid "C Build failed.\n"
-#: ../ProjectController.py:895
+#: ../c_ext/CFileEditor.py:731 +#: ../ProjectController.py:922 msgid "C code generated successfully.\n"
@@ -688,16 +707,24 @@
msgid "C compilation of %s failed.\n"
+#: ../canfestival/NetworkEditor.py:29 +#: ../canfestival/SlaveEditor.py:21 -#: ../plcopen/plcopen.py:1722 ../plcopen/plcopen.py:1736
-#: ../plcopen/plcopen.py:1757 ../plcopen/plcopen.py:1773
+#: ../plcopen/plcopen.py:1732 ../plcopen/plcopen.py:1746 +#: ../plcopen/plcopen.py:1767 ../plcopen/plcopen.py:1783 msgid "Can only generate execution order on FBD networks!"
@@ -705,7 +732,7 @@
msgid "Can only give a location to local or global variables"
-#: ../PLCOpenEditor.py:357
+#: ../PLCOpenEditor.py:336 msgid "Can't generate program to file %s!"
@@ -714,21 +741,21 @@
msgid "Can't give a location to a function block instance"
-#: ../PLCOpenEditor.py:397
+#: ../PLCOpenEditor.py:376 msgid "Can't save project to file %s!"
-#: ../controls/VariablePanel.py:298
+#: ../controls/VariablePanel.py:300 msgid "Can't set an initial value to a function block instance"
-#: ../ConfigTreeNode.py:470
+#: ../ConfigTreeNode.py:490 msgid "Cannot create child %s of type %s "
-#: ../ConfigTreeNode.py:400
+#: ../ConfigTreeNode.py:417 msgid "Cannot find lower free IEC channel than %d\n"
@@ -737,7 +764,7 @@
msgid "Cannot get PLC status - connection failed.\n"
-#: ../ProjectController.py:715
+#: ../ProjectController.py:737 msgid "Cannot open/parse VARIABLES.csv!\n"
@@ -750,27 +777,27 @@
-#: ../editors/Viewer.py:429
+#: ../editors/Viewer.py:428 -#: ../Beremiz_service.py:322
+#: ../Beremiz_service.py:326 msgid "Change IP of interface to bind"
-#: ../Beremiz_service.py:321
-msgid "Change POU Type To"
#: ../Beremiz_service.py:325
-msgid "Change Port Number"
+msgid "Change POU Type To" #: ../Beremiz_service.py:327
+msgid "Change Port Number" +#: ../Beremiz_service.py:328 msgid "Change working directory"
@@ -782,16 +809,16 @@
msgid "Choose a SVG file"
-#: ../ProjectController.py:353
+#: ../ProjectController.py:364 msgid "Choose a directory to save project"
-#: ../canfestival/canfestival.py:118 ../PLCOpenEditor.py:313
-#: ../PLCOpenEditor.py:347 ../PLCOpenEditor.py:391
+#: ../canfestival/canfestival.py:136 ../PLCOpenEditor.py:294 +#: ../PLCOpenEditor.py:326 ../PLCOpenEditor.py:370 -#: ../Beremiz.py:831 ../Beremiz.py:866
+#: ../Beremiz.py:858 ../Beremiz.py:893 @@ -800,15 +827,15 @@
msgid "Choose a value for %s:"
-#: ../Beremiz_service.py:373
+#: ../Beremiz_service.py:378 msgid "Choose a working directory "
-#: ../ProjectController.py:281
+#: ../ProjectController.py:288 msgid "Chosen folder doesn't contain a program. It's not a valid project!"
-#: ../ProjectController.py:247
+#: ../ProjectController.py:255 msgid "Chosen folder isn't empty. You can't use it for a new project!"
@@ -816,7 +843,7 @@
-#: ../controls/VariablePanel.py:369
+#: ../controls/VariablePanel.py:371 @@ -824,19 +851,19 @@
-#: ../ProjectController.py:1488
+#: ../ProjectController.py:1523 -#: ../ProjectController.py:1490
+#: ../ProjectController.py:1525 msgid "Clean project build folder"
-#: ../ProjectController.py:1048
+#: ../ProjectController.py:1076 msgid "Cleaning the build directory\n"
@@ -848,24 +875,24 @@
msgid "Clear the graph values"
-#: ../Beremiz.py:598 ../PLCOpenEditor.py:221
+#: ../Beremiz.py:633 ../PLCOpenEditor.py:202 msgid "Close Application"
-#: ../IDEFrame.py:1089 ../Beremiz.py:319 ../Beremiz.py:552
-#: ../PLCOpenEditor.py:131
+#: ../IDEFrame.py:972 ../Beremiz.py:321 ../Beremiz.py:587 +#: ../PLCOpenEditor.py:112 -#: ../Beremiz.py:317 ../PLCOpenEditor.py:129
+#: ../Beremiz.py:319 ../PLCOpenEditor.py:110 -#: ../editors/Viewer.py:481
+#: ../editors/Viewer.py:480 -#: ../editors/Viewer.py:501 ../editors/LDViewer.py:503
+#: ../editors/Viewer.py:500 ../editors/LDViewer.py:506 @@ -881,7 +908,7 @@
-#: ../ProjectController.py:538
+#: ../ProjectController.py:552 msgid "Compiling IEC Program into C code...\n"
@@ -889,6 +916,14 @@
+#: ../editors/ConfTreeNodeEditor.py:249 +#: ../editors/ProjectNodeEditor.py:13 +msgid "Config variables" #: ../dialogs/SearchInProjectDialog.py:47
@@ -897,20 +932,25 @@
-#: ../ProjectController.py:1503
+#: ../ProjectController.py:1538 -#: ../ProjectController.py:1504
+#: ../ProjectController.py:1539 msgid "Connect to the target PLC"
+#: ../ProjectController.py:1125 +msgid "Connected to URI: %s" #: ../connectors/PYRO/__init__.py:40
msgid "Connecting to URI : %s\n"
-#: ../editors/Viewer.py:467 ../dialogs/SFCTransitionDialog.py:76
+#: ../editors/Viewer.py:466 ../dialogs/SFCTransitionDialog.py:76 @@ -918,11 +958,11 @@
msgid "Connection Properties"
-#: ../ProjectController.py:1359
+#: ../ProjectController.py:1397 msgid "Connection canceled!\n"
-#: ../ProjectController.py:1384
+#: ../ProjectController.py:1422 msgid "Connection failed to %s!\n"
@@ -932,7 +972,7 @@
msgid "Connection to '%s' failed.\n"
-#: ../dialogs/ConnectionDialog.py:56
+#: ../editors/Viewer.py:1426 ../dialogs/ConnectionDialog.py:56 @@ -940,11 +980,15 @@
#: ../controls/VariablePanel.py:65
-#: ../editors/Viewer.py:477
+#: ../editors/Viewer.py:476 @@ -952,7 +996,7 @@
msgid "Content Description (optional):"
-#: ../dialogs/ConnectionDialog.py:61
+#: ../editors/Viewer.py:1427 ../dialogs/ConnectionDialog.py:61 @@ -972,19 +1016,19 @@
msgid "Conversion to time-of-day"
-#: ../IDEFrame.py:348 ../IDEFrame.py:401 ../editors/Viewer.py:536
+#: ../IDEFrame.py:353 ../IDEFrame.py:406 ../editors/Viewer.py:536
-#: ../editors/FileManagementPanel.py:283
+#: ../editors/FileManagementPanel.py:65 msgid "Copy file from left folder to right"
-#: ../editors/FileManagementPanel.py:282
+#: ../editors/FileManagementPanel.py:64 msgid "Copy file from right folder to left"
@@ -992,40 +1036,40 @@
-#: ../ConfigTreeNode.py:582
+#: ../ConfigTreeNode.py:602 "Could not add child \"%s\", type %s :\n"
-#: ../ConfigTreeNode.py:559
+#: ../ConfigTreeNode.py:579 "Couldn't load confnode base parameters %s :\n"
-#: ../ConfigTreeNode.py:570
+#: ../ConfigTreeNode.py:590 "Couldn't load confnode parameters %s :\n"
-#: ../PLCControler.py:765 ../PLCControler.py:802
+#: ../PLCControler.py:819 ../PLCControler.py:856 msgid "Couldn't paste non-POU object."
-#: ../ProjectController.py:1317
+#: ../ProjectController.py:1344 msgid "Couldn't start PLC !\n"
-#: ../ProjectController.py:1325
+#: ../ProjectController.py:1352 msgid "Couldn't stop PLC !\n"
-#: ../ProjectController.py:1295
+#: ../ProjectController.py:1321 msgid "Couldn't stop debugger.\n"
@@ -1041,35 +1085,35 @@
msgid "Create a new action"
msgid "Create a new action block"
-#: ../IDEFrame.py:84 ../IDEFrame.py:114 ../IDEFrame.py:147
+#: ../IDEFrame.py:91 ../IDEFrame.py:121 ../IDEFrame.py:154 msgid "Create a new block"
msgid "Create a new branch"
msgid "Create a new coil"
-#: ../IDEFrame.py:78 ../IDEFrame.py:93 ../IDEFrame.py:123
+#: ../IDEFrame.py:85 ../IDEFrame.py:100 ../IDEFrame.py:130 msgid "Create a new comment"
-#: ../IDEFrame.py:87 ../IDEFrame.py:117 ../IDEFrame.py:150
+#: ../IDEFrame.py:94 ../IDEFrame.py:124 ../IDEFrame.py:157 msgid "Create a new connection"
-#: ../IDEFrame.py:105 ../IDEFrame.py:156
+#: ../IDEFrame.py:112 ../IDEFrame.py:163 msgid "Create a new contact"
msgid "Create a new divergence"
@@ -1077,39 +1121,39 @@
msgid "Create a new divergence or convergence"
msgid "Create a new initial step"
msgid "Create a new jump"
-#: ../IDEFrame.py:96 ../IDEFrame.py:153
+#: ../IDEFrame.py:103 ../IDEFrame.py:160 msgid "Create a new power rail"
msgid "Create a new rung"
msgid "Create a new step"
-#: ../IDEFrame.py:132 ../dialogs/PouTransitionDialog.py:42
+#: ../IDEFrame.py:139 ../dialogs/PouTransitionDialog.py:42 msgid "Create a new transition"
-#: ../IDEFrame.py:81 ../IDEFrame.py:111 ../IDEFrame.py:144
+#: ../IDEFrame.py:88 ../IDEFrame.py:118 ../IDEFrame.py:151 msgid "Create a new variable"
-#: ../IDEFrame.py:346 ../IDEFrame.py:400 ../editors/Viewer.py:535
+#: ../IDEFrame.py:351 ../IDEFrame.py:405 ../editors/Viewer.py:535 -#: ../editors/ResourceEditor.py:71
+#: ../editors/ResourceEditor.py:72 @@ -1121,11 +1165,11 @@
-#: ../canfestival/SlaveEditor.py:50 ../canfestival/NetworkEditor.py:80
+#: ../canfestival/SlaveEditor.py:53 ../canfestival/NetworkEditor.py:74 -#: ../canfestival/SlaveEditor.py:51 ../canfestival/NetworkEditor.py:81
+#: ../canfestival/SlaveEditor.py:54 ../canfestival/NetworkEditor.py:75 @@ -1158,58 +1202,58 @@
-#: ../ProjectController.py:1405
-msgid "Debug connect matching running PLC\n"
-#: ../ProjectController.py:1408
-msgid "Debug do not match PLC - stop/transfert/start to re-enable\n"
-#: ../controls/PouInstanceVariablesPanel.py:52
+#: ../ProjectController.py:1444 +msgid "Debug does not match PLC - stop/transfert/start to re-enable\n" +#: ../controls/PouInstanceVariablesPanel.py:59 -#: ../editors/Viewer.py:3222
+#: ../editors/Viewer.py:1016 ../editors/Viewer.py:3326 -#: ../ProjectController.py:1122
+#: ../ProjectController.py:1153 msgid "Debug: Unknown variable '%s'\n"
-#: ../ProjectController.py:1120
+#: ../ProjectController.py:1151 msgid "Debug: Unsupported type to debug '%s'\n"
-#: ../ProjectController.py:1285
+#: ../ProjectController.py:1311 msgid "Debugger disabled\n"
-#: ../ProjectController.py:1297
+#: ../ProjectController.py:1441 +msgid "Debugger ready\n" +#: ../ProjectController.py:1323 msgid "Debugger stopped.\n"
-#: ../IDEFrame.py:1990 ../Beremiz.py:958 ../editors/Viewer.py:511
+#: ../IDEFrame.py:1866 ../Beremiz.py:991 ../editors/Viewer.py:511 -#: ../editors/Viewer.py:454
+#: ../editors/Viewer.py:453 msgid "Delete Divergence Branch"
-#: ../editors/FileManagementPanel.py:371
+#: ../editors/FileManagementPanel.py:153 -#: ../editors/Viewer.py:443
+#: ../editors/Viewer.py:442 msgid "Delete Wire Segment"
@@ -1221,21 +1265,21 @@
msgid "Deletion (within)"
-#: ../editors/DataTypeEditor.py:146
+#: ../editors/DataTypeEditor.py:152 -#: ../plcopen/structures.py:264
+#: ../plcopen/structures.py:263 "The derivative function block produces an output XOUT proportional to the rate of change of the input XIN."
-#: ../controls/VariablePanel.py:360
+#: ../controls/VariablePanel.py:362 -#: ../editors/DataTypeEditor.py:314 ../dialogs/ArrayTypeDialog.py:61
+#: ../editors/DataTypeEditor.py:320 ../dialogs/ArrayTypeDialog.py:61 @@ -1243,23 +1287,23 @@
-#: ../dialogs/BrowseLocationsDialog.py:78
+#: ../dialogs/BrowseLocationsDialog.py:86 -#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 -#: ../ProjectController.py:1512
+#: ../ProjectController.py:1547 -#: ../ProjectController.py:1514
+#: ../ProjectController.py:1549 msgid "Disconnect from PLC"
-#: ../editors/Viewer.py:496
+#: ../editors/Viewer.py:495 @@ -1267,7 +1311,7 @@
-#: ../editors/FileManagementPanel.py:370
+#: ../editors/FileManagementPanel.py:152 msgid "Do you really want to delete the file '%s'?"
@@ -1276,11 +1320,11 @@
-#: ../PLCOpenEditor.py:351
+#: ../PLCOpenEditor.py:330 -#: ../plcopen/structures.py:227
+#: ../plcopen/structures.py:226 "The down-counter can be used to signal when a count has reached zero, on counting down from a preset value."
@@ -1290,11 +1334,11 @@
-#: ../canfestival/canfestival.py:118
+#: ../canfestival/canfestival.py:139 msgid "EDS files (*.eds)|*.eds|All files|*.*"
-#: ../editors/Viewer.py:510
+#: ../editors/Viewer.py:509 @@ -1326,12 +1370,12 @@
msgid "Edit array type properties"
-#: ../editors/Viewer.py:2112 ../editors/Viewer.py:2114
-#: ../editors/Viewer.py:2630 ../editors/Viewer.py:2632
+#: ../editors/Viewer.py:2186 ../editors/Viewer.py:2188 +#: ../editors/Viewer.py:2706 ../editors/Viewer.py:2708 -#: ../editors/FileManagementPanel.py:284
+#: ../editors/FileManagementPanel.py:66 @@ -1339,11 +1383,11 @@
-#: ../editors/Viewer.py:2594
+#: ../editors/Viewer.py:2670 -#: ../ProjectController.py:1526
+#: ../ProjectController.py:1561 msgid "Edit raw IEC code added to code generated by PLCGenerator"
@@ -1355,35 +1399,35 @@
-#: ../ProjectController.py:1013
+#: ../ProjectController.py:1039 -#: ../editors/DataTypeEditor.py:341
+#: ../editors/DataTypeEditor.py:347
-#: ../Beremiz_service.py:380
+#: ../Beremiz_service.py:385 -#: ../Beremiz_service.py:365
+#: ../Beremiz_service.py:370 msgid "Enter a port number "
-#: ../Beremiz_service.py:355
+#: ../Beremiz_service.py:360 msgid "Enter the IP of the interface to bind"
-#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 @@ -1391,23 +1435,22 @@
-#: ../Beremiz_service.py:270 ../Beremiz_service.py:394
-#: ../controls/VariablePanel.py:330 ../controls/VariablePanel.py:678
-#: ../controls/DebugVariablePanel.py:164 ../IDEFrame.py:1083
-#: ../IDEFrame.py:1672 ../IDEFrame.py:1709 ../IDEFrame.py:1714
-#: ../IDEFrame.py:1728 ../IDEFrame.py:1733 ../IDEFrame.py:2422
-#: ../Beremiz.py:1083 ../PLCOpenEditor.py:358 ../PLCOpenEditor.py:363
-#: ../PLCOpenEditor.py:531 ../PLCOpenEditor.py:541
-#: ../editors/TextViewer.py:376 ../editors/DataTypeEditor.py:543
-#: ../editors/DataTypeEditor.py:548 ../editors/DataTypeEditor.py:572
-#: ../editors/DataTypeEditor.py:577 ../editors/DataTypeEditor.py:587
-#: ../editors/DataTypeEditor.py:719 ../editors/DataTypeEditor.py:726
-#: ../editors/Viewer.py:366 ../editors/LDViewer.py:663
-#: ../editors/LDViewer.py:879 ../editors/LDViewer.py:883
-#: ../editors/FileManagementPanel.py:210 ../ProjectController.py:221
-#: ../dialogs/PouNameDialog.py:53 ../dialogs/PouTransitionDialog.py:107
-#: ../dialogs/BrowseLocationsDialog.py:175 ../dialogs/ProjectDialog.py:71
-#: ../dialogs/SFCStepNameDialog.py:59 ../dialogs/ConnectionDialog.py:152
+#: ../Beremiz_service.py:271 ../controls/VariablePanel.py:332 +#: ../controls/VariablePanel.py:681 ../controls/DebugVariablePanel.py:379 +#: ../IDEFrame.py:966 ../IDEFrame.py:1553 ../IDEFrame.py:1590 +#: ../IDEFrame.py:1595 ../IDEFrame.py:1609 ../IDEFrame.py:1614 +#: ../IDEFrame.py:2290 ../Beremiz.py:1131 ../PLCOpenEditor.py:337 +#: ../PLCOpenEditor.py:342 ../PLCOpenEditor.py:416 ../PLCOpenEditor.py:426 +#: ../editors/TextViewer.py:369 ../editors/DataTypeEditor.py:549 +#: ../editors/DataTypeEditor.py:554 ../editors/DataTypeEditor.py:578 +#: ../editors/DataTypeEditor.py:583 ../editors/DataTypeEditor.py:593 +#: ../editors/DataTypeEditor.py:744 ../editors/DataTypeEditor.py:751 +#: ../editors/Viewer.py:365 ../editors/LDViewer.py:666 +#: ../editors/LDViewer.py:882 ../editors/LDViewer.py:886 +#: ../ProjectController.py:225 ../dialogs/PouNameDialog.py:53 +#: ../dialogs/PouTransitionDialog.py:107 +#: ../dialogs/BrowseLocationsDialog.py:212 ../dialogs/ProjectDialog.py:71 +#: ../dialogs/SFCStepNameDialog.py:59 ../dialogs/ConnectionDialog.py:159 #: ../dialogs/FBDVariableDialog.py:201 ../dialogs/PouActionDialog.py:104
#: ../dialogs/BrowseValuesLibraryDialog.py:83 ../dialogs/PouDialog.py:132
#: ../dialogs/SFCTransitionDialog.py:147
@@ -1415,44 +1458,44 @@
#: ../dialogs/DurationEditorDialog.py:163
#: ../dialogs/SearchInProjectDialog.py:157 ../dialogs/SFCStepDialog.py:130
#: ../dialogs/ArrayTypeDialog.py:97 ../dialogs/ArrayTypeDialog.py:103
-#: ../dialogs/FBDBlockDialog.py:164 ../dialogs/ForceVariableDialog.py:169
+#: ../dialogs/FBDBlockDialog.py:164 ../dialogs/ForceVariableDialog.py:179 -#: ../ProjectController.py:587
+#: ../ProjectController.py:601 msgid "Error : At least one configuration and one resource must be declared in PLC !\n"
-#: ../ProjectController.py:579
+#: ../ProjectController.py:593 msgid "Error : IEC to C compiler returned %d\n"
-#: ../ProjectController.py:520
+#: ../ProjectController.py:534 "Error in ST/IL/SFC code generator :\n"
-#: ../ConfigTreeNode.py:182
+#: ../ConfigTreeNode.py:183 msgid "Error while saving \"%s\"\n"
-#: ../canfestival/canfestival.py:122
+#: ../canfestival/canfestival.py:144 msgid "Error: Export slave failed\n"
-#: ../canfestival/canfestival.py:270
+#: ../canfestival/canfestival.py:345 msgid "Error: No Master generated\n"
-#: ../canfestival/canfestival.py:265
+#: ../canfestival/canfestival.py:340 msgid "Error: No PLC built\n"
-#: ../ProjectController.py:1378
+#: ../ProjectController.py:1416 msgid "Exception while connecting %s!\n"
@@ -1465,7 +1508,7 @@
msgid "Experimental web based HMI"
@@ -1477,15 +1520,15 @@
-#: ../canfestival/canfestival.py:128
+#: ../canfestival/canfestival.py:150 msgid "Export CanOpen slave to EDS file"
-#: ../editors/GraphicViewer.py:144
+#: ../controls/DebugVariablePanel.py:1472 ../editors/GraphicViewer.py:144 msgid "Export graph values to clipboard"
-#: ../canfestival/canfestival.py:127
+#: ../canfestival/canfestival.py:149 @@ -1497,7 +1540,7 @@
-#: ../ProjectController.py:591
+#: ../ProjectController.py:605 msgid "Extracting Located Variables...\n"
@@ -1507,21 +1550,21 @@
-#: ../ProjectController.py:1445
+#: ../ProjectController.py:1480 msgid "Failed : Must build before transfer.\n"
-#: ../editors/Viewer.py:405 ../dialogs/LDElementDialog.py:84
+#: ../editors/Viewer.py:404 ../dialogs/LDElementDialog.py:84 -#: ../plcopen/structures.py:217
+#: ../plcopen/structures.py:216 "Falling edge detector\n"
"The output produces a single pulse when a falling edge is detected."
-#: ../ProjectController.py:900
+#: ../ProjectController.py:927 msgid "Fatal : cannot get builder.\n"
@@ -1535,21 +1578,16 @@
msgid "Fields %s haven't a valid value!"
-#: ../editors/FileManagementPanel.py:209
-msgid "File '%s' already exists!"
-#: ../IDEFrame.py:353 ../dialogs/FindInPouDialog.py:30
+#: ../IDEFrame.py:358 ../dialogs/FindInPouDialog.py:30 #: ../dialogs/FindInPouDialog.py:99
@@ -1565,11 +1603,11 @@
msgid "Force runtime reload\n"
-#: ../controls/DebugVariablePanel.py:295 ../editors/Viewer.py:1353
+#: ../controls/DebugVariablePanel.py:1934 ../editors/Viewer.py:1385 -#: ../dialogs/ForceVariableDialog.py:152
+#: ../dialogs/ForceVariableDialog.py:162 msgid "Forcing Variable Value"
@@ -1580,7 +1618,7 @@
msgid "Form isn't complete. %s must be filled!"
-#: ../dialogs/ConnectionDialog.py:142 ../dialogs/FBDBlockDialog.py:154
+#: ../dialogs/ConnectionDialog.py:149 ../dialogs/FBDBlockDialog.py:154 msgid "Form isn't complete. Name must be filled!"
@@ -1600,15 +1638,15 @@
-#: ../IDEFrame.py:1969 ../dialogs/SearchInProjectDialog.py:45
+#: ../IDEFrame.py:1845 ../dialogs/SearchInProjectDialog.py:45 -#: ../controls/VariablePanel.py:741
+#: ../controls/VariablePanel.py:744 msgid "Function Block Types"
@@ -1620,11 +1658,7 @@
msgid "Function Blocks can't be used in Functions!"
-#: ../editors/Viewer.py:238
-msgid "Function Blocks can't be used in Transitions!"
-#: ../PLCControler.py:2055
+#: ../PLCControler.py:2180 msgid "FunctionBlock \"%s\" can't be pasted in a Function!!!"
@@ -1633,11 +1667,11 @@
-#: ../PLCOpenEditor.py:138
+#: ../PLCOpenEditor.py:119 -#: ../ProjectController.py:510
+#: ../ProjectController.py:524 msgid "Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"
@@ -1645,7 +1679,7 @@
-#: ../editors/GraphicViewer.py:131
+#: ../controls/DebugVariablePanel.py:1471 ../editors/GraphicViewer.py:131 msgid "Go to current value"
@@ -1669,7 +1703,7 @@
-#: ../editors/FileManagementPanel.py:303
+#: ../editors/FileManagementPanel.py:85 @@ -1681,13 +1715,13 @@
-#: ../plcopen/structures.py:279
+#: ../plcopen/structures.py:278 "The hysteresis function block provides a hysteresis boolean output driven by the difference of two floating point (REAL) inputs XIN1 and XIN2."
-#: ../ProjectController.py:827
+#: ../ProjectController.py:851 msgid "IEC-61131-3 code generation failed !\n"
@@ -1696,7 +1730,7 @@
-#: ../Beremiz_service.py:356 ../Beremiz_service.py:357
+#: ../Beremiz_service.py:361 ../Beremiz_service.py:362 @@ -1704,11 +1738,16 @@
-#: ../controls/VariablePanel.py:76 ../dialogs/FBDVariableDialog.py:34
+#: ../controls/VariablePanel.py:76 ../editors/Viewer.py:1412 +#: ../dialogs/FBDVariableDialog.py:34 -#: ../controls/VariablePanel.py:263
+#: ../editors/Viewer.py:999 +#: ../controls/VariablePanel.py:265 msgid "Incompatible data types between \"%s\" and \"%s\""
@@ -1727,17 +1766,17 @@
-#: ../editors/Viewer.py:492
+#: ../editors/Viewer.py:491 #: ../controls/VariablePanel.py:58 ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48
+#: ../editors/DataTypeEditor.py:50 -#: ../editors/DataTypeEditor.py:178 ../editors/DataTypeEditor.py:209
-#: ../editors/DataTypeEditor.py:265 ../editors/DataTypeEditor.py:303
+#: ../editors/DataTypeEditor.py:184 ../editors/DataTypeEditor.py:215 +#: ../editors/DataTypeEditor.py:271 ../editors/DataTypeEditor.py:309 @@ -1750,8 +1789,9 @@
-#: ../controls/VariablePanel.py:76 ../dialogs/BrowseLocationsDialog.py:36
-#: ../dialogs/FBDVariableDialog.py:33 ../dialogs/SFCStepDialog.py:61
+#: ../controls/VariablePanel.py:76 ../editors/Viewer.py:1410 +#: ../dialogs/BrowseLocationsDialog.py:35 ../dialogs/FBDVariableDialog.py:33 +#: ../dialogs/SFCStepDialog.py:61 @@ -1763,16 +1803,16 @@
-#: ../plcopen/plcopen.py:1833
+#: ../plcopen/plcopen.py:1843 msgid "Instance with id %d doesn't exist!"
-#: ../editors/ResourceEditor.py:247
+#: ../editors/ResourceEditor.py:255 -#: ../plcopen/structures.py:259
+#: ../plcopen/structures.py:258 "The integral function block integrates the value of input XIN over time."
@@ -1782,15 +1822,15 @@
-#: ../editors/ResourceEditor.py:71
+#: ../editors/ResourceEditor.py:72 -#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 -#: ../PLCControler.py:2032 ../PLCControler.py:2070
+#: ../PLCControler.py:2157 ../PLCControler.py:2195 msgid "Invalid plcopen element(s)!!!"
@@ -1799,12 +1839,12 @@
msgid "Invalid type \"%s\"-> %d != %d for location\"%s\""
-#: ../dialogs/ForceVariableDialog.py:167
+#: ../dialogs/ForceVariableDialog.py:177 msgid "Invalid value \"%s\" for \"%s\" variable!"
-#: ../controls/DebugVariablePanel.py:153 ../controls/DebugVariablePanel.py:156
+#: ../controls/DebugVariablePanel.py:319 ../controls/DebugVariablePanel.py:322 msgid "Invalid value \"%s\" for debug variable"
@@ -1825,7 +1865,7 @@
"You must fill a numeric value."
-#: ../editors/Viewer.py:497
+#: ../editors/Viewer.py:496 @@ -1854,19 +1894,19 @@
-#: ../ProjectController.py:1451
+#: ../ProjectController.py:1486 msgid "Latest build already matches current target. Transfering anyway...\n"
-#: ../Beremiz_service.py:324
+#: ../Beremiz_service.py:331 msgid "Launch WX GUI inspector"
-#: ../Beremiz_service.py:323
+#: ../Beremiz_service.py:330 msgid "Launch a live Python shell"
-#: ../editors/Viewer.py:428
+#: ../editors/Viewer.py:427 @@ -1886,7 +1926,7 @@
msgid "Less than or equal to"
@@ -1902,7 +1942,11 @@
-#: ../ProjectController.py:1353
+#: ../canfestival/canfestival.py:322 +#: ../ProjectController.py:1391 msgid "Local service discovery failed!\n"
@@ -1910,14 +1954,10 @@
-#: ../dialogs/BrowseLocationsDialog.py:61
+#: ../dialogs/BrowseLocationsDialog.py:68 msgid "Locations available:"
#: ../plcopen/iec_std.csv:25
msgid "Logarithm to base 10"
@@ -1927,19 +1967,19 @@
msgid "MDNS resolution failure for '%s'\n"
-#: ../canfestival/SlaveEditor.py:37 ../canfestival/NetworkEditor.py:67
+#: ../canfestival/SlaveEditor.py:41 ../canfestival/NetworkEditor.py:62
msgid "Map located variables over CANopen"
-#: ../canfestival/NetworkEditor.py:89
+#: ../canfestival/NetworkEditor.py:83 -#: ../ConfigTreeNode.py:480
+#: ../ConfigTreeNode.py:500 msgid "Max count (%d) reached for this confnode of type %s "
@@ -1948,15 +1988,15 @@
-#: ../editors/DataTypeEditor.py:232
+#: ../editors/DataTypeEditor.py:238 -#: ../dialogs/BrowseLocationsDialog.py:38
+#: ../dialogs/BrowseLocationsDialog.py:37
@@ -1964,7 +2004,7 @@
-#: ../editors/Viewer.py:433
+#: ../editors/Viewer.py:432 @@ -1976,7 +2016,7 @@
-#: ../editors/DataTypeEditor.py:219
+#: ../editors/DataTypeEditor.py:225 @@ -1992,7 +2032,7 @@
-#: ../PLCGenerator.py:703 ../PLCGenerator.py:936
+#: ../PLCGenerator.py:732 ../PLCGenerator.py:975 msgid "More than one connector found corresponding to \"%s\" continuation in \"%s\" POU"
@@ -2005,11 +2045,11 @@
-#: ../controls/DebugVariablePanel.py:185
+#: ../controls/DebugVariablePanel.py:1532 msgid "Move debug variable down"
-#: ../controls/DebugVariablePanel.py:184
+#: ../controls/DebugVariablePanel.py:1531 msgid "Move debug variable up"
@@ -2017,31 +2057,31 @@
-#: ../editors/DataTypeEditor.py:348
+#: ../editors/DataTypeEditor.py:354 msgid "Move element down"
-#: ../editors/DataTypeEditor.py:347
+#: ../editors/DataTypeEditor.py:353 -#: ../editors/ResourceEditor.py:254
+#: ../editors/ResourceEditor.py:262 msgid "Move instance down"
-#: ../editors/ResourceEditor.py:253
+#: ../editors/ResourceEditor.py:261 -#: ../editors/ResourceEditor.py:225
+#: ../editors/ResourceEditor.py:233 -#: ../editors/ResourceEditor.py:224
+#: ../editors/ResourceEditor.py:232 -#: ../IDEFrame.py:75 ../IDEFrame.py:90 ../IDEFrame.py:120 ../IDEFrame.py:161
+#: ../IDEFrame.py:82 ../IDEFrame.py:97 ../IDEFrame.py:127 ../IDEFrame.py:168 @@ -2049,11 +2089,11 @@
-#: ../controls/VariablePanel.py:381
+#: ../controls/VariablePanel.py:383 ../c_ext/CFileEditor.py:520 msgid "Move variable down"
-#: ../controls/VariablePanel.py:380
+#: ../controls/VariablePanel.py:382 ../c_ext/CFileEditor.py:519 @@ -2065,17 +2105,17 @@
-#: ../editors/FileManagementPanel.py:301
+#: ../editors/FileManagementPanel.py:83 #: ../controls/VariablePanel.py:58 ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48 ../editors/ResourceEditor.py:67
-#: ../editors/ResourceEditor.py:76
+#: ../editors/DataTypeEditor.py:50 ../editors/ResourceEditor.py:68 +#: ../editors/ResourceEditor.py:77 -#: ../Beremiz_service.py:381
+#: ../Beremiz_service.py:386 msgid "Name must not be null!"
@@ -2089,12 +2129,12 @@
msgid "Natural logarithm"
-#: ../editors/Viewer.py:403 ../dialogs/LDElementDialog.py:67
+#: ../editors/Viewer.py:402 ../dialogs/LDElementDialog.py:67 -#: ../Beremiz.py:307 ../Beremiz.py:342 ../PLCOpenEditor.py:125
-#: ../PLCOpenEditor.py:167
+#: ../Beremiz.py:309 ../Beremiz.py:344 ../PLCOpenEditor.py:106 +#: ../PLCOpenEditor.py:148 @@ -2102,47 +2142,43 @@
-#: ../editors/Viewer.py:402
+#: ../editors/Viewer.py:401 -#: ../PLCControler.py:2929
+#: ../PLCControler.py:3054 msgid "No PLC project found"
-#: ../ProjectController.py:1478
+#: ../ProjectController.py:1513 msgid "No PLC to transfer (did build succeed ?)\n"
-#: ../PLCGenerator.py:1321
+#: ../PLCGenerator.py:1360 msgid "No body defined in \"%s\" POU"
-#: ../PLCGenerator.py:722 ../PLCGenerator.py:945
+#: ../PLCGenerator.py:751 ../PLCGenerator.py:984 msgid "No connector found corresponding to \"%s\" continuation in \"%s\" POU"
-#: ../PLCOpenEditor.py:370
+#: ../PLCOpenEditor.py:349 "No documentation available.\n"
-#: ../PLCGenerator.py:744
+#: ../PLCGenerator.py:773 msgid "No informations found for \"%s\" block"
-#: ../plcopen/structures.py:167
+#: ../plcopen/structures.py:166 msgid "No output variable found"
-#: ../Beremiz_service.py:394
#: ../controls/SearchResultPanel.py:169
msgid "No search results available."
@@ -2166,15 +2202,11 @@
msgid "No valid value selected!"
-#: ../PLCGenerator.py:1319
+#: ../PLCGenerator.py:1358 msgid "No variable defined in \"%s\" POU"
-#: ../canfestival/SlaveEditor.py:49 ../canfestival/NetworkEditor.py:79
#: ../canfestival/config_utils.py:354
msgid "Non existing node ID : %d (variable %s)"
@@ -2205,13 +2237,13 @@
-#: ../plcopen/structures.py:247
+#: ../plcopen/structures.py:246 "The off-delay timer can be used to delay setting an output false, for fixed period after input goes false."
-#: ../plcopen/structures.py:242
+#: ../plcopen/structures.py:241 "The on-delay timer can be used to delay setting an output true, for fixed period after an input becomes true."
@@ -2221,8 +2253,8 @@
-#: ../Beremiz.py:309 ../Beremiz.py:343 ../PLCOpenEditor.py:127
-#: ../PLCOpenEditor.py:168
+#: ../Beremiz.py:311 ../Beremiz.py:345 ../PLCOpenEditor.py:108 +#: ../PLCOpenEditor.py:149 @@ -2230,7 +2262,7 @@
-#: ../ProjectController.py:1530
+#: ../ProjectController.py:1565 msgid "Open a file explorer to manage project files"
@@ -2250,24 +2282,25 @@
msgid "Organization (optional):"
-#: ../canfestival/SlaveEditor.py:47 ../canfestival/NetworkEditor.py:77
+#: ../canfestival/SlaveEditor.py:51 ../canfestival/NetworkEditor.py:72 -#: ../controls/VariablePanel.py:76 ../dialogs/BrowseLocationsDialog.py:37
-#: ../dialogs/FBDVariableDialog.py:35 ../dialogs/SFCStepDialog.py:65
+#: ../controls/VariablePanel.py:76 ../editors/Viewer.py:1411 +#: ../dialogs/BrowseLocationsDialog.py:36 ../dialogs/FBDVariableDialog.py:35 +#: ../dialogs/SFCStepDialog.py:65 -#: ../canfestival/SlaveEditor.py:36 ../canfestival/NetworkEditor.py:66
+#: ../canfestival/SlaveEditor.py:40 ../canfestival/NetworkEditor.py:61 -#: ../canfestival/SlaveEditor.py:35 ../canfestival/NetworkEditor.py:65
+#: ../canfestival/SlaveEditor.py:39 ../canfestival/NetworkEditor.py:60 -#: ../plcopen/structures.py:269
+#: ../plcopen/structures.py:268 "The PID (proportional, Integral, Derivative) function block provides the classical three term controller for closed loop control."
@@ -2277,16 +2310,15 @@
-#: ../ProjectController.py:1096 ../ProjectController.py:1398
-#: ../PLCOpenEditor.py:313 ../PLCOpenEditor.py:391
+#: ../PLCOpenEditor.py:294 ../PLCOpenEditor.py:370 msgid "PLCOpen files (*.xml)|*.xml|All files|*.*"
-#: ../PLCOpenEditor.py:175 ../PLCOpenEditor.py:231
+#: ../PLCOpenEditor.py:156 ../PLCOpenEditor.py:212 @@ -2306,7 +2338,7 @@
-#: ../Beremiz.py:322 ../PLCOpenEditor.py:141
+#: ../Beremiz.py:324 ../PLCOpenEditor.py:122 @@ -2314,20 +2346,20 @@
msgid "Page Size (optional):"
-#: ../PLCOpenEditor.py:476
-#: ../controls/PouInstanceVariablesPanel.py:41
+#: ../controls/PouInstanceVariablesPanel.py:48 -#: ../IDEFrame.py:350 ../IDEFrame.py:402 ../editors/Viewer.py:537
+#: ../IDEFrame.py:355 ../IDEFrame.py:407 ../editors/Viewer.py:537
@@ -2339,13 +2371,13 @@
-#: ../editors/Viewer.py:2289 ../editors/Viewer.py:2594
+#: ../editors/Viewer.py:2363 ../editors/Viewer.py:2670 #: ../editors/SFCViewer.py:696
msgid "Please choose a target"
-#: ../editors/Viewer.py:2112 ../editors/Viewer.py:2114
-#: ../editors/Viewer.py:2630 ../editors/Viewer.py:2632
+#: ../editors/Viewer.py:2186 ../editors/Viewer.py:2188 +#: ../editors/Viewer.py:2706 ../editors/Viewer.py:2708 msgid "Please enter comment text"
@@ -2354,16 +2386,16 @@
msgid "Please enter step name"
-#: ../dialogs/ForceVariableDialog.py:153
+#: ../dialogs/ForceVariableDialog.py:163 msgid "Please enter value for a \"%s\" variable:"
-#: ../Beremiz_service.py:366
+#: ../Beremiz_service.py:371 msgid "Port number must be 0 <= port <= 65535!"
-#: ../Beremiz_service.py:366
+#: ../Beremiz_service.py:371 msgid "Port number must be an integer!"
@@ -2371,7 +2403,7 @@
-#: ../editors/Viewer.py:476
+#: ../editors/Viewer.py:475 @@ -2379,7 +2411,7 @@
msgid "Power Rail Properties"
-#: ../Beremiz.py:324 ../PLCOpenEditor.py:143
+#: ../Beremiz.py:326 ../PLCOpenEditor.py:124 @@ -2390,16 +2422,16 @@
-#: ../Beremiz.py:326 ../Beremiz.py:346 ../PLCOpenEditor.py:145
-#: ../PLCOpenEditor.py:171
+#: ../Beremiz.py:328 ../Beremiz.py:348 ../PLCOpenEditor.py:126 +#: ../PLCOpenEditor.py:152
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 @@ -2407,6 +2439,11 @@
+#: ../runtime/PLCObject.py:318 +msgid "Problem starting PLC : error %d" #: ../controls/ProjectPropertiesPanel.py:80
msgid "Product Name (required):"
@@ -2419,11 +2456,11 @@
msgid "Product Version (required):"
-#: ../IDEFrame.py:1972 ../dialogs/SearchInProjectDialog.py:46
+#: ../IDEFrame.py:1848 ../dialogs/SearchInProjectDialog.py:46 -#: ../PLCOpenEditor.py:360
+#: ../PLCOpenEditor.py:339 msgid "Program was successfully generated!"
@@ -2435,7 +2472,7 @@
msgid "Programs can't be used by other POUs!"
-#: ../controls/ProjectPropertiesPanel.py:84 ../IDEFrame.py:553
+#: ../controls/ProjectPropertiesPanel.py:84 ../IDEFrame.py:557 @@ -2444,7 +2481,7 @@
-#: ../ProjectController.py:1529
+#: ../ProjectController.py:1564 @@ -2456,32 +2493,40 @@
msgid "Project Version (optional):"
-#: ../PLCControler.py:2916
+#: ../PLCControler.py:3041 "Project file syntax error:\n"
-#: ../dialogs/ProjectDialog.py:32
+#: ../editors/ProjectNodeEditor.py:14 ../dialogs/ProjectDialog.py:32 msgid "Project properties"
-#: ../ConfigTreeNode.py:506
+#: ../ConfigTreeNode.py:526 msgid "Project tree layout do not match confnode.xml %s!=%s "
+#: ../dialogs/ConnectionDialog.py:96 -#: ../plcopen/structures.py:237
+#: ../plcopen/structures.py:236 "The pulse timer can be used to generate output pulses of a given time duration."
+#: ../py_ext/PythonEditor.py:61 @@ -2489,42 +2534,42 @@
-#: ../Beremiz_service.py:328 ../Beremiz.py:329 ../PLCOpenEditor.py:151
+#: ../Beremiz_service.py:333 ../Beremiz.py:331 ../PLCOpenEditor.py:132 -#: ../plcopen/structures.py:202
+#: ../plcopen/structures.py:201 "The RS bistable is a latch where the Reset dominates."
-#: ../plcopen/structures.py:274
+#: ../plcopen/structures.py:273 "The RAMP function block is modelled on example given in the standard."
-#: ../editors/GraphicViewer.py:89
+#: ../controls/DebugVariablePanel.py:1462 ../editors/GraphicViewer.py:89 -#: ../ProjectController.py:1525
+#: ../ProjectController.py:1560 -#: ../plcopen/structures.py:254
+#: ../plcopen/structures.py:253 "The real time clock has many uses including time stamping, setting dates and times of day in batch reports, in alarm messages and so on."
msgid "Really delete node '%s'?"
-#: ../IDEFrame.py:340 ../IDEFrame.py:398
+#: ../IDEFrame.py:345 ../IDEFrame.py:403 @@ -2532,7 +2577,7 @@
-#: ../IDEFrame.py:408 ../dialogs/DiscoveryDialog.py:105
+#: ../IDEFrame.py:413 ../dialogs/DiscoveryDialog.py:105 @@ -2544,7 +2589,7 @@
msgid "Regular expressions"
-#: ../controls/DebugVariablePanel.py:299 ../editors/Viewer.py:1356
+#: ../controls/DebugVariablePanel.py:1938 ../editors/Viewer.py:1388 @@ -2552,7 +2597,7 @@
msgid "Remainder (modulo)"
@@ -2561,39 +2606,39 @@
-#: ../controls/DebugVariablePanel.py:183
+#: ../controls/DebugVariablePanel.py:1530 msgid "Remove debug variable"
-#: ../editors/DataTypeEditor.py:346
+#: ../editors/DataTypeEditor.py:352 -#: ../editors/FileManagementPanel.py:281
+#: ../editors/FileManagementPanel.py:63 msgid "Remove file from left folder"
-#: ../editors/ResourceEditor.py:252
+#: ../editors/ResourceEditor.py:260 -#: ../canfestival/NetworkEditor.py:87
+#: ../canfestival/NetworkEditor.py:81 -#: ../editors/ResourceEditor.py:223
+#: ../editors/ResourceEditor.py:231 -#: ../controls/VariablePanel.py:379
+#: ../controls/VariablePanel.py:381 ../c_ext/CFileEditor.py:518
-#: ../editors/FileManagementPanel.py:399
+#: ../editors/FileManagementPanel.py:181 @@ -2609,7 +2654,7 @@
msgid "Reset Execution Order"
msgid "Reset Perspective"
@@ -2629,11 +2674,11 @@
-#: ../controls/VariablePanel.py:352
+#: ../controls/VariablePanel.py:354 -#: ../editors/Viewer.py:430
+#: ../editors/Viewer.py:429 @@ -2641,11 +2686,11 @@
-#: ../editors/Viewer.py:404 ../dialogs/LDElementDialog.py:80
+#: ../editors/Viewer.py:403 ../dialogs/LDElementDialog.py:80 -#: ../plcopen/structures.py:212
+#: ../plcopen/structures.py:211 "The output produces a single pulse when a rising edge is detected."
@@ -2663,19 +2708,19 @@
-#: ../ProjectController.py:1493
+#: ../ProjectController.py:1528 -#: ../ProjectController.py:841 ../ProjectController.py:850
+#: ../ProjectController.py:865 ../ProjectController.py:874 msgid "Runtime extensions C code generation failed !\n"
-#: ../canfestival/SlaveEditor.py:34 ../canfestival/NetworkEditor.py:64
+#: ../canfestival/SlaveEditor.py:38 ../canfestival/NetworkEditor.py:59 -#: ../canfestival/SlaveEditor.py:33 ../canfestival/NetworkEditor.py:63
+#: ../canfestival/SlaveEditor.py:37 ../canfestival/NetworkEditor.py:58 @@ -2683,7 +2728,7 @@
-#: ../plcopen/structures.py:197
+#: ../plcopen/structures.py:196 "The SR bistable is a latch where the Set dominates."
@@ -2694,7 +2739,7 @@
-#: ../PLCOpenEditor.py:347
+#: ../PLCOpenEditor.py:326 msgid "ST files (*.st)|*.st|All files|*.*"
@@ -2702,20 +2747,20 @@
msgid "SVG files (*.svg)|*.svg|All files|*.*"
-#: ../Beremiz.py:313 ../Beremiz.py:344 ../PLCOpenEditor.py:134
-#: ../PLCOpenEditor.py:169
+#: ../Beremiz.py:315 ../Beremiz.py:346 ../PLCOpenEditor.py:115 +#: ../PLCOpenEditor.py:150 -#: ../Beremiz.py:345 ../PLCOpenEditor.py:136 ../PLCOpenEditor.py:170
+#: ../Beremiz.py:347 ../PLCOpenEditor.py:117 ../PLCOpenEditor.py:151
@@ -2723,11 +2768,11 @@
-#: ../IDEFrame.py:592 ../dialogs/SearchInProjectDialog.py:105
+#: ../IDEFrame.py:596 ../dialogs/SearchInProjectDialog.py:105 -#: ../IDEFrame.py:360 ../IDEFrame.py:404
+#: ../IDEFrame.py:365 ../IDEFrame.py:409 #: ../dialogs/SearchInProjectDialog.py:52
msgid "Search in Project"
@@ -2736,24 +2781,24 @@
-#: ../controls/VariablePanel.py:277 ../editors/TextViewer.py:330
-#: ../editors/Viewer.py:277
+#: ../controls/LocationCellEditor.py:97 ../controls/VariablePanel.py:277 +#: ../editors/TextViewer.py:323 ../editors/Viewer.py:275 msgid "Select a variable class:"
-#: ../ProjectController.py:1013
+#: ../ProjectController.py:1039 msgid "Select an editor:"
-#: ../controls/PouInstanceVariablesPanel.py:197
+#: ../controls/PouInstanceVariablesPanel.py:209 msgid "Select an instance"
@@ -2769,7 +2814,7 @@
msgid "Selection Divergence"
-#: ../plcopen/structures.py:207
+#: ../plcopen/structures.py:206 "The semaphore provides a mechanism to allow software elements mutually exclusive access to certain ressources."
@@ -2791,19 +2836,19 @@
-#: ../ProjectController.py:1519
+#: ../ProjectController.py:1554 msgid "Show IEC code generated by PLCGenerator"
-#: ../canfestival/canfestival.py:288
+#: ../canfestival/canfestival.py:363 -#: ../canfestival/canfestival.py:289
+#: ../canfestival/canfestival.py:364 msgid "Show Master generated by config_utils"
-#: ../ProjectController.py:1517
+#: ../ProjectController.py:1552 @@ -2819,7 +2864,7 @@
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 @@ -2827,52 +2872,52 @@
msgid "Square root (base 2)"
-#: ../plcopen/structures.py:193
+#: ../plcopen/structures.py:192 msgid "Standard function blocks"
-#: ../Beremiz_service.py:319 ../ProjectController.py:1495
+#: ../Beremiz_service.py:321 ../ProjectController.py:1530 -#: ../ProjectController.py:819
+#: ../ProjectController.py:843 msgid "Start build in %s\n"
-#: ../ProjectController.py:1314
+#: ../ProjectController.py:1341
-#: ../editors/Viewer.py:493
+#: ../editors/Viewer.py:492 -#: ../ProjectController.py:1498
+#: ../ProjectController.py:1533 -#: ../Beremiz_service.py:320
+#: ../Beremiz_service.py:322 -#: ../ProjectController.py:1500
+#: ../ProjectController.py:1535 -#: ../ProjectController.py:1292
+#: ../ProjectController.py:1318 msgid "Stopping debugger...\n"
-#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 -#: ../editors/DataTypeEditor.py:52
+#: ../editors/DataTypeEditor.py:54 @@ -2880,7 +2925,7 @@
-#: ../ProjectController.py:915
+#: ../ProjectController.py:942 msgid "Successfully built.\n"
@@ -2892,11 +2937,11 @@
-#: ../editors/ResourceEditor.py:76
+#: ../editors/ResourceEditor.py:77 -#: ../editors/ResourceEditor.py:218
+#: ../editors/ResourceEditor.py:226 @@ -2904,33 +2949,33 @@
-#: ../editors/FileManagementPanel.py:398
+#: ../editors/FileManagementPanel.py:180 "The file '%s' already exist.\n"
"Do you want to replace it?"
-#: ../editors/LDViewer.py:879
+#: ../editors/LDViewer.py:882 msgid "The group of block must be coherent!"
-#: ../IDEFrame.py:1091 ../Beremiz.py:555
+#: ../IDEFrame.py:974 ../Beremiz.py:590 msgid "There are changes, do you want to save?"
-#: ../IDEFrame.py:1709 ../IDEFrame.py:1728
+#: ../IDEFrame.py:1590 ../IDEFrame.py:1609 msgid "There is a POU named \"%s\". This could cause a conflict. Do you wish to continue?"
"There was a problem printing.\n"
"Perhaps your current printer is not set correctly?"
-#: ../editors/LDViewer.py:888
+#: ../editors/LDViewer.py:891 msgid "This option isn't available yet!"
@@ -2971,31 +3016,31 @@
msgid "Time-of-day subtraction"
-#: ../editors/Viewer.py:432
+#: ../editors/Viewer.py:431 -#: ../ProjectController.py:1507
+#: ../ProjectController.py:1542 +#: ../ProjectController.py:1544 #: ../ProjectController.py:1509
-#: ../ProjectController.py:1474
msgid "Transfer completed successfully.\n"
-#: ../ProjectController.py:1476
+#: ../ProjectController.py:1511 msgid "Transfer failed\n"
-#: ../editors/Viewer.py:494
+#: ../editors/Viewer.py:493 -#: ../PLCGenerator.py:1212
+#: ../PLCGenerator.py:1252 msgid "Transition \"%s\" body must contain an output variable or coil referring to its name"
@@ -3008,17 +3053,17 @@
-#: ../PLCGenerator.py:1301
+#: ../PLCGenerator.py:1340 msgid "Transition with content \"%s\" not connected to a next step in \"%s\" POU"
-#: ../PLCGenerator.py:1292
+#: ../PLCGenerator.py:1331 msgid "Transition with content \"%s\" not connected to a previous step in \"%s\" POU"
-#: ../plcopen/plcopen.py:1442
+#: ../plcopen/plcopen.py:1447 msgid "Transition with name %s doesn't exist!"
@@ -3027,16 +3072,20 @@
-#: ../editors/ResourceEditor.py:67
+#: ../editors/ResourceEditor.py:68 #: ../controls/VariablePanel.py:58 ../controls/VariablePanel.py:59
-#: ../editors/DataTypeEditor.py:48 ../editors/ResourceEditor.py:76
+#: ../editors/DataTypeEditor.py:50 ../editors/ResourceEditor.py:77 #: ../dialogs/ActionBlockDialog.py:37
+#: ../dialogs/BrowseLocationsDialog.py:44 +msgid "Type and derivated" #: ../canfestival/config_utils.py:335 ../canfestival/config_utils.py:617
msgid "Type conflict for location \"%s\""
@@ -3046,13 +3095,17 @@
-#: ../editors/DataTypeEditor.py:155
+#: ../editors/DataTypeEditor.py:161 +#: ../dialogs/BrowseLocationsDialog.py:45 #: ../dialogs/SFCDivergenceDialog.py:51 ../dialogs/LDPowerRailDialog.py:51
-#: ../dialogs/ConnectionDialog.py:52 ../dialogs/SFCTransitionDialog.py:53
-#: ../dialogs/FBDBlockDialog.py:48
+#: ../dialogs/BrowseLocationsDialog.py:95 ../dialogs/ConnectionDialog.py:52 +#: ../dialogs/SFCTransitionDialog.py:53 ../dialogs/FBDBlockDialog.py:48 @@ -3066,30 +3119,30 @@
msgid "Unable to get Xenomai's %s \n"
-#: ../PLCGenerator.py:865 ../PLCGenerator.py:924
+#: ../PLCGenerator.py:904 ../PLCGenerator.py:963 msgid "Undefined block type \"%s\" in \"%s\" POU"
-#: ../PLCGenerator.py:240
+#: ../PLCGenerator.py:252 msgid "Undefined pou type \"%s\""
-#: ../IDEFrame.py:338 ../IDEFrame.py:397
+#: ../IDEFrame.py:343 ../IDEFrame.py:402 -#: ../ProjectController.py:254
+#: ../ProjectController.py:262 -#: ../editors/Viewer.py:336
+#: ../editors/Viewer.py:335 msgid "Unknown variable \"%s\" for this POU!"
-#: ../ProjectController.py:251 ../ProjectController.py:252
+#: ../ProjectController.py:259 ../ProjectController.py:260 @@ -3103,23 +3156,23 @@
msgid "Unrecognized data size \"%s\""
-#: ../plcopen/structures.py:222
+#: ../plcopen/structures.py:221 "The up-counter can be used to signal when a count has reached a maximum value."
-#: ../plcopen/structures.py:232
+#: ../plcopen/structures.py:231 "The up-down counter has two inputs CU and CD. It can be used to both count up on one input and down on the other."
-#: ../controls/VariablePanel.py:709 ../editors/DataTypeEditor.py:623
+#: ../controls/VariablePanel.py:712 ../editors/DataTypeEditor.py:631 -#: ../canfestival/SlaveEditor.py:38 ../canfestival/NetworkEditor.py:68
+#: ../canfestival/SlaveEditor.py:42 ../canfestival/NetworkEditor.py:63 @@ -3127,7 +3180,7 @@
msgid "User-defined POUs"
-#: ../controls/DebugVariablePanel.py:40 ../dialogs/ActionBlockDialog.py:37
+#: ../controls/DebugVariablePanel.py:58 ../dialogs/ActionBlockDialog.py:37 @@ -3135,11 +3188,11 @@
-#: ../editors/DataTypeEditor.py:252
+#: ../editors/DataTypeEditor.py:258 -#: ../controls/DebugVariablePanel.py:40 ../editors/Viewer.py:466
+#: ../controls/DebugVariablePanel.py:58 ../editors/Viewer.py:465 #: ../dialogs/ActionBlockDialog.py:41
@@ -3148,12 +3201,12 @@
msgid "Variable Properties"
-#: ../controls/VariablePanel.py:277 ../editors/TextViewer.py:330
-#: ../editors/Viewer.py:277
+#: ../controls/LocationCellEditor.py:97 ../controls/VariablePanel.py:277 +#: ../editors/TextViewer.py:323 ../editors/Viewer.py:275 -#: ../editors/TextViewer.py:374 ../editors/Viewer.py:338
+#: ../editors/TextViewer.py:367 ../editors/Viewer.py:337 msgid "Variable don't belong to this POU!"
@@ -3169,15 +3222,15 @@
-#: ../ProjectController.py:1276
+#: ../ProjectController.py:1302 msgid "Waiting debugger to recover...\n"
-#: ../editors/LDViewer.py:888 ../dialogs/PouDialog.py:126
+#: ../editors/LDViewer.py:891 ../dialogs/PouDialog.py:126 -#: ../ProjectController.py:515
+#: ../ProjectController.py:529 msgid "Warnings in ST/IL/SFC code generator :\n"
@@ -3193,7 +3246,7 @@
@@ -3209,17 +3262,17 @@
-#: ../ProjectController.py:220
+#: ../ProjectController.py:224 "You must have permission to work on the project\n"
"Work on a project copy ?"
-#: ../editors/LDViewer.py:883
+#: ../editors/LDViewer.py:886 msgid "You must select the block or group of blocks around which a branch should be added!"
-#: ../editors/LDViewer.py:663
+#: ../editors/LDViewer.py:666 msgid "You must select the wire where a contact should be added!"
@@ -3228,11 +3281,11 @@
msgid "You must type a name!"
-#: ../dialogs/ForceVariableDialog.py:165
+#: ../dialogs/ForceVariableDialog.py:175 msgid "You must type a value!"
@@ -3240,7 +3293,7 @@
-#: ../PLCOpenEditor.py:356
+#: ../PLCOpenEditor.py:335 @@ -3250,7 +3303,7 @@
msgid "exited with status %s (pid %s)\n"
-#: ../PLCOpenEditor.py:508 ../PLCOpenEditor.py:510
+#: ../PLCOpenEditor.py:393 ../PLCOpenEditor.py:395 @@ -3258,7 +3311,7 @@
-#: ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:396 @@ -3266,7 +3319,7 @@
-#: ../PLCOpenEditor.py:511
+#: ../PLCOpenEditor.py:396 @@ -3286,7 +3339,7 @@
-#: ../PLCOpenEditor.py:354
+#: ../PLCOpenEditor.py:333 @@ -3323,9 +3376,6 @@