198 "8LszMRweXLr7kWB35oMdCAT+1jRt0cqVK6Otra2+hvoGGuobWPLEEsoXzkbPkLhvR4CBRwJY" |
198 "8LszMRweXLr7kWB35oMdCAT+1jRt0cqVK6Otra2+hvoGGuobWPLEEsoXzkbPkLhvR4CBRwJY" |
199 "Xq/3SGVlZbq7u7utsrJyxDTNz06cOJHZ0tRCS1MLAKuRwNQT9v8AyV27dn1fXl7eqmlae11d" |
199 "Xq/3SGVlZbq7u7utsrJyxDTNz06cOJHZ0tRCS1MLAKuRwNQT9v8AyV27dn1fXl7eqmlae11d" |
200 "XXLfvn0/+Xy+l6LR6Gu2befFYjFfzrk2FzeHp7mK7jdxz2/LffGamhpvc3NzyLKsbFd3z1PG" |
200 "XXLfvn0/+Xy+l6LR6Gu2befFYjFfzrk2FzeHp7mK7jdxz2/LffGamhpvc3NzyLKsbFd3z1PG" |
201 "aHyBTKdjum0POGzbFAp7qo0xVOtJZdf/C/wRDnL5FYGSAAAAAElFTkSuQmCC") |
201 "aHyBTKdjum0POGzbFAp7qo0xVOtJZdf/C/wRDnL5FYGSAAAAAElFTkSuQmCC") |
202 |
202 |
203 class ParamsEntryDialog(wx.TextEntryDialog): |
203 class ParamsEntryDialog(wx.TextEntryDialog): |
204 if wx.VERSION < (2, 6, 0): |
204 if wx.VERSION < (2, 6, 0): |
205 def Bind(self, event, function, id = None): |
205 def Bind(self, event, function, id = None): |
206 if id is not None: |
206 if id is not None: |
207 event(self, id, function) |
207 event(self, id, function) |
|
208 else: |
|
209 event(self, function) |
|
210 |
|
211 |
|
212 def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", |
|
213 style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): |
|
214 wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) |
|
215 |
|
216 self.Tests = [] |
|
217 if wx.VERSION >= (2, 8, 0): |
|
218 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) |
|
219 elif wx.VERSION >= (2, 6, 0): |
|
220 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) |
208 else: |
221 else: |
209 event(self, function) |
222 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) |
210 |
223 |
211 |
224 def OnOK(self, event): |
212 def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", |
225 value = self.GetValue() |
213 style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): |
226 texts = {"value" : value} |
214 wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) |
227 for function, message in self.Tests: |
215 |
228 if not function(value): |
216 self.Tests = [] |
229 message = wx.MessageDialog(self, message%texts, "Error", wx.OK|wx.ICON_ERROR) |
217 if wx.VERSION >= (2, 8, 0): |
230 message.ShowModal() |
218 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) |
231 message.Destroy() |
219 elif wx.VERSION >= (2, 6, 0): |
232 return |
220 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) |
233 self.EndModal(wx.ID_OK) |
221 else: |
234 event.Skip() |
222 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) |
235 |
223 |
236 def GetValue(self): |
224 def OnOK(self, event): |
237 return self.GetSizer().GetItem(1).GetWindow().GetValue() |
225 value = self.GetValue() |
238 |
226 texts = {"value" : value} |
239 def SetTests(self, tests): |
227 for function, message in self.Tests: |
240 self.Tests = tests |
228 if not function(value): |
241 |
229 message = wx.MessageDialog(self, message%texts, "Error", wx.OK|wx.ICON_ERROR) |
242 class BeremizTaskBarIcon(wx.TaskBarIcon): |
230 message.ShowModal() |
243 TBMENU_START = wx.NewId() |
231 message.Destroy() |
244 TBMENU_STOP = wx.NewId() |
232 return |
245 TBMENU_CHANGE_NAME = wx.NewId() |
233 self.EndModal(wx.ID_OK) |
246 TBMENU_CHANGE_PORT = wx.NewId() |
234 event.Skip() |
247 TBMENU_CHANGE_INTERFACE = wx.NewId() |
235 |
248 TBMENU_LIVE_SHELL = wx.NewId() |
236 def GetValue(self): |
249 TBMENU_WXINSPECTOR = wx.NewId() |
237 return self.GetSizer().GetItem(1).GetWindow().GetValue() |
250 TBMENU_CHANGE_WD = wx.NewId() |
238 |
251 TBMENU_QUIT = wx.NewId() |
239 def SetTests(self, tests): |
252 |
240 self.Tests = tests |
253 def __init__(self, pyroserver): |
241 |
254 wx.TaskBarIcon.__init__(self) |
242 class BeremizTaskBarIcon(wx.TaskBarIcon): |
255 self.pyroserver = pyroserver |
243 TBMENU_START = wx.NewId() |
256 # Set the image |
244 TBMENU_STOP = wx.NewId() |
257 self.UpdateIcon(None) |
245 TBMENU_CHANGE_NAME = wx.NewId() |
|
246 TBMENU_CHANGE_PORT = wx.NewId() |
|
247 TBMENU_CHANGE_INTERFACE = wx.NewId() |
|
248 TBMENU_LIVE_SHELL = wx.NewId() |
|
249 TBMENU_WXINSPECTOR = wx.NewId() |
|
250 TBMENU_CHANGE_WD = wx.NewId() |
|
251 TBMENU_QUIT = wx.NewId() |
|
252 |
|
253 def __init__(self, pyroserver): |
|
254 wx.TaskBarIcon.__init__(self) |
|
255 self.pyroserver = pyroserver |
|
256 # Set the image |
|
257 self.UpdateIcon(None) |
|
258 |
|
259 # bind some events |
|
260 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
|
261 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
|
262 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
|
263 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE) |
|
264 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL) |
|
265 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR) |
|
266 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT) |
|
267 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD) |
|
268 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT) |
|
269 |
|
270 def CreatePopupMenu(self): |
|
271 """ |
|
272 This method is called by the base class when it needs to popup |
|
273 the menu for the default EVT_RIGHT_DOWN event. Just create |
|
274 the menu how you want it and return it from this function, |
|
275 the base class takes care of the rest. |
|
276 """ |
|
277 menu = wx.Menu() |
|
278 menu.Append(self.TBMENU_START, "Start PLC") |
|
279 menu.Append(self.TBMENU_STOP, "Stop PLC") |
|
280 menu.Append(self.TBMENU_CHANGE_NAME, "Change Name") |
|
281 menu.Append(self.TBMENU_CHANGE_INTERFACE, "Change IP of interface to bind") |
|
282 menu.Append(self.TBMENU_LIVE_SHELL, "Launch a live Python shell") |
|
283 menu.Append(self.TBMENU_WXINSPECTOR, "Launch WX GUI inspector") |
|
284 menu.Append(self.TBMENU_CHANGE_PORT, "Change Port Number") |
|
285 menu.AppendSeparator() |
|
286 menu.Append(self.TBMENU_CHANGE_WD, "Change working directory") |
|
287 menu.Append(self.TBMENU_QUIT, "Quit") |
|
288 return menu |
|
289 |
|
290 def MakeIcon(self, img): |
|
291 """ |
|
292 The various platforms have different requirements for the |
|
293 icon size... |
|
294 """ |
|
295 if "wxMSW" in wx.PlatformInfo: |
|
296 img = img.Scale(16, 16) |
|
297 elif "wxGTK" in wx.PlatformInfo: |
|
298 img = img.Scale(22, 22) |
|
299 # wxMac can be any size upto 128x128, so leave the source img alone.... |
|
300 icon = wx.IconFromBitmap(img.ConvertToBitmap() ) |
|
301 return icon |
|
302 |
|
303 def OnTaskBarStartPLC(self, evt): |
|
304 if self.pyroserver.plcobj is not None: |
|
305 self.pyroserver.plcobj.StartPLC() |
|
306 evt.Skip() |
|
307 |
|
308 def OnTaskBarStopPLC(self, evt): |
|
309 if self.pyroserver.plcobj is not None: |
|
310 self.pyroserver.plcobj.StopPLC() |
|
311 evt.Skip() |
|
312 |
|
313 def OnTaskBarChangeInterface(self, evt): |
|
314 dlg = ParamsEntryDialog(None, "Enter the ip of the interface to bind", defaultValue=self.pyroserver.ip) |
|
315 dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, "Ip is not valid!"), |
|
316 ( lambda ip :len([x for x in ip.split(".") if 0 <= int(x) <= 255]) == 4, "Ip is not valid!") |
|
317 ]) |
|
318 if dlg.ShowModal() == wx.ID_OK: |
|
319 self.pyroserver.ip = dlg.GetValue() |
|
320 self.pyroserver.Stop() |
|
321 evt.Skip() |
|
322 |
258 |
323 def OnTaskBarChangePort(self, evt): |
259 # bind some events |
324 dlg = ParamsEntryDialog(None, "Enter a port number ", defaultValue=str(self.pyroserver.port)) |
260 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
325 dlg.SetTests([(UnicodeType.isdigit, "Port number must be an integer!"), (lambda port : 0 <= int(port) <= 65535 , "Port number must be 0 <= port <= 65535!")]) |
261 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
326 if dlg.ShowModal() == wx.ID_OK: |
262 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
327 self.pyroserver.port = int(dlg.GetValue()) |
263 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE) |
328 self.pyroserver.Stop() |
264 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL) |
329 evt.Skip() |
265 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR) |
330 |
266 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT) |
331 def OnTaskBarChangeWorkingDir(self, evt): |
267 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD) |
332 dlg = wx.DirDialog(None, "Choose a working directory ", self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON) |
268 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT) |
333 if dlg.ShowModal() == wx.ID_OK: |
269 |
334 self.pyroserver.workdir = dlg.GetPath() |
270 def CreatePopupMenu(self): |
335 self.pyroserver.Stop() |
271 """ |
336 evt.Skip() |
272 This method is called by the base class when it needs to popup |
|
273 the menu for the default EVT_RIGHT_DOWN event. Just create |
|
274 the menu how you want it and return it from this function, |
|
275 the base class takes care of the rest. |
|
276 """ |
|
277 menu = wx.Menu() |
|
278 menu.Append(self.TBMENU_START, "Start PLC") |
|
279 menu.Append(self.TBMENU_STOP, "Stop PLC") |
|
280 menu.Append(self.TBMENU_CHANGE_NAME, "Change Name") |
|
281 menu.Append(self.TBMENU_CHANGE_INTERFACE, "Change IP of interface to bind") |
|
282 menu.Append(self.TBMENU_LIVE_SHELL, "Launch a live Python shell") |
|
283 menu.Append(self.TBMENU_WXINSPECTOR, "Launch WX GUI inspector") |
|
284 menu.Append(self.TBMENU_CHANGE_PORT, "Change Port Number") |
|
285 menu.AppendSeparator() |
|
286 menu.Append(self.TBMENU_CHANGE_WD, "Change working directory") |
|
287 menu.Append(self.TBMENU_QUIT, "Quit") |
|
288 return menu |
|
289 |
|
290 def MakeIcon(self, img): |
|
291 """ |
|
292 The various platforms have different requirements for the |
|
293 icon size... |
|
294 """ |
|
295 if "wxMSW" in wx.PlatformInfo: |
|
296 img = img.Scale(16, 16) |
|
297 elif "wxGTK" in wx.PlatformInfo: |
|
298 img = img.Scale(22, 22) |
|
299 # wxMac can be any size upto 128x128, so leave the source img alone.... |
|
300 icon = wx.IconFromBitmap(img.ConvertToBitmap() ) |
|
301 return icon |
|
302 |
|
303 def OnTaskBarStartPLC(self, evt): |
|
304 if self.pyroserver.plcobj is not None: |
|
305 self.pyroserver.plcobj.StartPLC() |
|
306 evt.Skip() |
|
307 |
|
308 def OnTaskBarStopPLC(self, evt): |
|
309 if self.pyroserver.plcobj is not None: |
|
310 self.pyroserver.plcobj.StopPLC() |
|
311 evt.Skip() |
|
312 |
|
313 def OnTaskBarChangeInterface(self, evt): |
|
314 dlg = ParamsEntryDialog(None, "Enter the ip of the interface to bind", defaultValue=self.pyroserver.ip) |
|
315 dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, "Ip is not valid!"), |
|
316 ( lambda ip :len([x for x in ip.split(".") if 0 <= int(x) <= 255]) == 4, "Ip is not valid!") |
|
317 ]) |
|
318 if dlg.ShowModal() == wx.ID_OK: |
|
319 self.pyroserver.ip = dlg.GetValue() |
|
320 self.pyroserver.Stop() |
|
321 evt.Skip() |
|
322 |
|
323 def OnTaskBarChangePort(self, evt): |
|
324 dlg = ParamsEntryDialog(None, "Enter a port number ", defaultValue=str(self.pyroserver.port)) |
|
325 dlg.SetTests([(UnicodeType.isdigit, "Port number must be an integer!"), (lambda port : 0 <= int(port) <= 65535 , "Port number must be 0 <= port <= 65535!")]) |
|
326 if dlg.ShowModal() == wx.ID_OK: |
|
327 self.pyroserver.port = int(dlg.GetValue()) |
|
328 self.pyroserver.Stop() |
|
329 evt.Skip() |
|
330 |
|
331 def OnTaskBarChangeWorkingDir(self, evt): |
|
332 dlg = wx.DirDialog(None, "Choose a working directory ", self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON) |
|
333 if dlg.ShowModal() == wx.ID_OK: |
|
334 self.pyroserver.workdir = dlg.GetPath() |
|
335 self.pyroserver.Stop() |
|
336 evt.Skip() |
|
337 |
|
338 def OnTaskBarChangeName(self, evt): |
|
339 dlg = ParamsEntryDialog(None, "Enter a name ", defaultValue=self.pyroserver.name) |
|
340 dlg.SetTests([(lambda name : len(name) is not 0 , "Name must not be null!")]) |
|
341 if dlg.ShowModal() == wx.ID_OK: |
|
342 self.pyroserver.name = dlg.GetValue() |
|
343 self.pyroserver.Restart() |
|
344 evt.Skip() |
|
345 |
|
346 def OnTaskBarLiveShell(self, evt): |
|
347 if self.pyroserver.plcobj is not None and self.pyroserver.plcobj.python_threads_vars is not None: |
|
348 from wx import py |
|
349 #frame = py.shell.ShellFrame(locals=self.pyroserver.plcobj.python_threads_vars) |
|
350 frame = py.crust.CrustFrame(locals=self.pyroserver.plcobj.python_threads_vars) |
|
351 frame.Show() |
|
352 else: |
|
353 wx.MessageBox("No runnning PLC","Error") |
|
354 evt.Skip() |
|
355 |
|
356 def OnTaskBarWXInspector(self, evt): |
|
357 # Activate the widget inspection tool |
|
358 from wx.lib.inspection import InspectionTool |
|
359 if not InspectionTool().initialized: |
|
360 InspectionTool().Init(locals=self.pyroserver.plcobj.python_threads_vars) |
337 |
361 |
338 def OnTaskBarChangeName(self, evt): |
362 # Find a widget to be selected in the tree. Use either the |
339 dlg = ParamsEntryDialog(None, "Enter a name ", defaultValue=self.pyroserver.name) |
363 # one under the cursor, if any, or this frame. |
340 dlg.SetTests([(lambda name : len(name) is not 0 , "Name must not be null!")]) |
364 wnd = wx.FindWindowAtPointer() |
341 if dlg.ShowModal() == wx.ID_OK: |
365 if not wnd: |
342 self.pyroserver.name = dlg.GetValue() |
366 wnd = wx.GetApp() |
343 self.pyroserver.Restart() |
367 InspectionTool().Show(wnd, True) |
344 evt.Skip() |
368 evt.Skip() |
345 |
369 |
346 def OnTaskBarLiveShell(self, evt): |
370 def OnTaskBarQuit(self, evt): |
347 if self.pyroserver.plcobj is not None and self.pyroserver.plcobj.python_threads_vars is not None: |
371 self.pyroserver.Quit() |
348 from wx import py |
372 self.RemoveIcon() |
349 #frame = py.shell.ShellFrame(locals=self.pyroserver.plcobj.python_threads_vars) |
373 wx.CallAfter(wx.GetApp().Exit) |
350 frame = py.crust.CrustFrame(locals=self.pyroserver.plcobj.python_threads_vars) |
374 evt.Skip() |
351 frame.Show() |
375 |
352 else: |
376 def UpdateIcon(self, plcstatus): |
353 wx.MessageBox("No runnning PLC","Error") |
377 if plcstatus is "Started" : |
354 evt.Skip() |
378 currenticon = self.MakeIcon(starticon.GetImage()) |
355 |
379 elif plcstatus is "Stopped": |
356 def OnTaskBarWXInspector(self, evt): |
380 currenticon = self.MakeIcon(stopicon.GetImage()) |
357 # Activate the widget inspection tool |
381 else: |
358 from wx.lib.inspection import InspectionTool |
382 currenticon = self.MakeIcon(defaulticon.GetImage()) |
359 if not InspectionTool().initialized: |
383 self.SetIcon(currenticon, "Beremiz Service") |
360 InspectionTool().Init(locals=self.pyroserver.plcobj.python_threads_vars) |
384 |
361 |
385 from runtime import PLCObject, PLCprint, ServicePublisher |
362 # Find a widget to be selected in the tree. Use either the |
|
363 # one under the cursor, if any, or this frame. |
|
364 wnd = wx.FindWindowAtPointer() |
|
365 if not wnd: |
|
366 wnd = wx.GetApp() |
|
367 InspectionTool().Show(wnd, True) |
|
368 evt.Skip() |
|
369 |
|
370 def OnTaskBarQuit(self, evt): |
|
371 self.pyroserver.Quit() |
|
372 self.RemoveIcon() |
|
373 wx.CallAfter(wx.GetApp().Exit) |
|
374 evt.Skip() |
|
375 |
|
376 def UpdateIcon(self, plcstatus): |
|
377 if plcstatus is "Started" : |
|
378 currenticon = self.MakeIcon(starticon.GetImage()) |
|
379 elif plcstatus is "Stopped": |
|
380 currenticon = self.MakeIcon(stopicon.GetImage()) |
|
381 else: |
|
382 currenticon = self.MakeIcon(defaulticon.GetImage()) |
|
383 self.SetIcon(currenticon, "Beremiz Service") |
|
384 |
|
385 from runtime import PLCObject, ServicePublisher |
|
386 import Pyro.core as pyro |
386 import Pyro.core as pyro |
387 |
387 |
388 if not os.path.isdir(WorkingDir): |
388 if not os.path.isdir(WorkingDir): |
389 os.mkdir(WorkingDir) |
389 os.mkdir(WorkingDir) |
390 |
390 |