# HG changeset patch # User Edouard Tisserant # Date 1654068127 -7200 # Node ID e87a2daace80705b24d702fabd486935ec2d11c9 # Parent ca312be569294eda8870ce6b8ad71a7d4c865a92# Parent a88ac1760faf2f2d7eadc135de5324c2dbe57225 merged diff -r ca312be56929 -r e87a2daace80 ProjectController.py --- a/ProjectController.py Wed Jun 01 09:15:26 2022 +0200 +++ b/ProjectController.py Wed Jun 01 09:22:07 2022 +0200 @@ -601,11 +601,11 @@ else: path = os.getenv("HOME") dirdialog = wx.DirDialog( - self.AppFrame, _("Choose a directory to save project"), path, wx.DD_NEW_DIR_BUTTON) + self.AppFrame, _("Create or choose an empty directory to save project"), path, wx.DD_NEW_DIR_BUTTON) answer = dirdialog.ShowModal() + newprojectpath = dirdialog.GetPath() dirdialog.Destroy() if answer == wx.ID_OK: - newprojectpath = dirdialog.GetPath() if os.path.isdir(newprojectpath): if self.CheckNewProjectPath(self.ProjectPath, newprojectpath): self.ProjectPath, old_project_path = newprojectpath, self.ProjectPath @@ -1722,10 +1722,16 @@ for weakcallable, buffer_list in WeakCallableDict.iteritems(): function = getattr(weakcallable, function_name, None) if function is not None: - if buffer_list: - function(*cargs) - else: - function(*tuple([lst[-1] for lst in cargs])) + # FIXME: apparently, despite of weak ref objects, + # some dead C/C++ wx object are still reachable from here + # leading to RuntimeError exception + try: + if buffer_list: + function(*cargs) + else: + function(*tuple([lst[-1] for lst in cargs])) + except RuntimeError: + pass def GetTicktime(self): return self._Ticktime diff -r ca312be56929 -r e87a2daace80 docutil/docsvg.py --- a/docutil/docsvg.py Wed Jun 01 09:15:26 2022 +0200 +++ b/docutil/docsvg.py Wed Jun 01 09:22:07 2022 +0200 @@ -27,21 +27,26 @@ import wx import subprocess -def get_inkscape_path(): + +def _get_inkscape_path(): """ Return the Inkscape binary path """ if wx.Platform == '__WXMSW__': from six.moves import winreg inkcmd = None - try: - inkcmd = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, - 'Software\\Classes\\svgfile\\shell\\Inkscape\\command') - except OSError: + tries = [(winreg.HKEY_LOCAL_MACHINE, 'Software\\Classes\\svgfile\\shell\\Inkscape\\command'), + (winreg.HKEY_LOCAL_MACHINE, 'Software\\Classes\\inkscape.svg\\shell\\open\\command'), + (winreg.HKEY_CURRENT_USER, 'Software\\Classes\\inkscape.svg\\shell\\open\\command')] + + for subreg, key in tries: try: - inkcmd = winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, - 'Software\\Classes\\inkscape.svg\\shell\\open\\command') + inkcmd = winreg.QueryValue(subreg, key) + break; except OSError: - return None + pass + + if inkcmd is None: + return None return inkcmd.replace('"%1"', '').strip().replace('"', '') @@ -51,6 +56,36 @@ except subprocess.CalledProcessError: return None +_inkscape_path = None +def get_inkscape_path(): + """ Return the Inkscape binary path """ + + global _inkscape_path + + if _inkscape_path is not None: + return _inkscape_path + + _inkscape_path = _get_inkscape_path() + return _inkscape_path + + +def _get_inkscape_version(): + inkpath = get_inkscape_path() + if inkpath is None: + return None + return map(int, + subprocess.check_output([inkpath,"--version"]).split()[1].split('.')) + +_inkscape_version = None +def get_inkscape_version(): + global _inkscape_version + + if _inkscape_version is not None: + return _inkscape_version + + _inkscape_version = _get_inkscape_version() + return _inkscape_version + def open_svg(svgfile): """ Generic function to open SVG file """ diff -r ca312be56929 -r e87a2daace80 exemples/svghmi_traffic_light/svghmi_0@svghmi/confnode.xml --- a/exemples/svghmi_traffic_light/svghmi_0@svghmi/confnode.xml Wed Jun 01 09:15:26 2022 +0200 +++ b/exemples/svghmi_traffic_light/svghmi_0@svghmi/confnode.xml Wed Jun 01 09:22:07 2022 +0200 @@ -1,2 +1,2 @@ - + diff -r ca312be56929 -r e87a2daace80 svghmi/analyse_widget.xslt --- a/svghmi/analyse_widget.xslt Wed Jun 01 09:15:26 2022 +0200 +++ b/svghmi/analyse_widget.xslt Wed Jun 01 09:22:07 2022 +0200 @@ -925,8 +925,8 @@ value - - buffer size + + X axis range expressed either in samples or duration. format string for X label @@ -934,12 +934,6 @@ format string for Y label - - minimum value foe X axis - - - maximum value for X axis - diff -r ca312be56929 -r e87a2daace80 svghmi/gen_index_xhtml.xslt --- a/svghmi/gen_index_xhtml.xslt Wed Jun 01 09:15:26 2022 +0200 +++ b/svghmi/gen_index_xhtml.xslt Wed Jun 01 09:22:07 2022 +0200 @@ -1556,15 +1556,15 @@ if(typeof(init) == "function"){ - // try { + try { init.call(this); - // } catch(err) { - - // console.log(err); - - // } + } catch(err) { + + console.log(err); + + } } @@ -7780,7 +7780,7 @@ activate(val) { - let [active, inactive] = val ? ["none",""] : ["", "none"]; + let [active, inactive] = val ? ["","none"] : ["none", ""]; if (this.active_elt) @@ -7865,8 +7865,8 @@ value - - buffer size + + X axis range expressed either in samples or duration. format string for X label @@ -7874,12 +7874,6 @@ format string for Y label - - minimum value foe X axis - - - maximum value for X axis - class diff -r ca312be56929 -r e87a2daace80 svghmi/svghmi.py --- a/svghmi/svghmi.py Wed Jun 01 09:15:26 2022 +0200 +++ b/svghmi/svghmi.py Wed Jun 01 09:22:07 2022 +0200 @@ -282,6 +282,10 @@ CONFNODEEDITOR_TABS = [ (_("HMI Tree"), "CreateSVGHMI_UI")] + def __init__(self, parent, controler, window): + ConfTreeNodeEditor.__init__(self, parent, controler, window) + self.Controler = controler + def CreateSVGHMI_UI(self, parent): global hmi_tree_root @@ -292,25 +296,29 @@ hmitree_backup_file = open(hmitree_backup_path, 'rb') hmi_tree_root = HMITreeNode.from_etree(etree.parse(hmitree_backup_file).getroot()) - ret = SVGHMI_UI(parent, Register_SVGHMI_UI_for_HMI_tree_updates) + ret = SVGHMI_UI(parent, self.Controler, Register_SVGHMI_UI_for_HMI_tree_updates) on_hmitree_update(hmi_tree_root) return ret if wx.Platform == '__WXMSW__': - browser_launch_cmd="cmd.exe /c 'start msedge {url}'" + default_cmds={ + "launch":"cmd.exe /c 'start msedge {url}'", + "watchdog":"cmd.exe /k 'echo watchdog for {url} !'"} else: - browser_launch_cmd="chromium {url}" + default_cmds={ + "launch":"chromium {url}", + "watchdog":"echo Watchdog for {name} !"} class SVGHMI(object): XSD = """ - + - + @@ -342,7 +350,7 @@ - """%browser_launch_cmd + """%default_cmds EditorType = SVGHMIEditor @@ -399,9 +407,13 @@ if from_project_path is not None: shutil.copyfile(self._getSVGpath(from_project_path), self._getSVGpath()) - shutil.copyfile(self._getPOTpath(from_project_path), - self._getPOTpath()) - # XXX TODO copy .PO files + + potpath = self._getPOTpath(from_project_path) + if os.path.isfile(potpath): + shutil.copyfile(potpath, self._getPOTpath()) + # copy .PO files + for _name, pofile in GetPoFiles(from_project_path): + shutil.copy(pofile, self.CTNPath()) return True def GetSVGGeometry(self): diff -r ca312be56929 -r e87a2daace80 svghmi/ui.py --- a/svghmi/ui.py Wed Jun 01 09:15:26 2022 +0200 +++ b/svghmi/ui.py Wed Jun 01 09:22:07 2022 +0200 @@ -11,6 +11,7 @@ import hashlib import weakref import re +import tempfile from threading import Thread, Lock from functools import reduce from itertools import izip @@ -26,7 +27,7 @@ import util.paths as paths from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath -from docutil import get_inkscape_path +from docutil import get_inkscape_path, get_inkscape_version from util.ProcessLogger import ProcessLogger @@ -276,8 +277,10 @@ _conf_key = "SVGHMIWidgetLib" _preview_height = 200 _preview_margin = 5 +thumbnail_temp_path = None + class WidgetLibBrowser(wx.SplitterWindow): - def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + def __init__(self, parent, controler, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize): wx.SplitterWindow.__init__(self, parent, @@ -287,6 +290,7 @@ self.msg = None self.hmitree_nodes = [] self.selected_SVG = None + self.Controler = controler self.Config = wx.ConfigBase.Get() self.libdir = self.RecallLibDir() @@ -455,10 +459,14 @@ if inkpath is None: self.msg = _("Inkscape is not installed.") return False + + export_opt = "-o" if get_inkscape_version()[0] > 0 else "-e" + # TODO: spawn a thread, to decouple thumbnail gen status, result, _err_result = ProcessLogger( - None, - '"' + inkpath + '" "' + svgpath + '" -e "' + thumbpath + + self.Controler.GetCTRoot().logger, + '"' + inkpath + '" "' + svgpath + '" ' + + export_opt + ' "' + thumbpath + '" -D -h ' + str(_preview_height)).spin() if status != 0: self.msg = _("Inkscape couldn't generate thumbnail.") @@ -470,10 +478,28 @@ Called when tree item is selected @param event: wx.TreeEvent """ + global thumbnail_temp_path + event.Skip() item_pydata = self.widgetpicker.GetPyData(event.GetItem()) if item_pydata is not None: svgpath = item_pydata - dname = os.path.dirname(svgpath) + + if thumbnail_temp_path is None: + try: + dname = os.path.dirname(svgpath) + thumbdir = os.path.join(dname, ".svghmithumbs") + if not os.path.exists(thumbdir): + os.mkdir(thumbdir) + except Exception : + # library not writable : use temp dir + thumbnail_temp_path = os.path.join( + tempfile.gettempdir(), "svghmithumbs") + thumbdir = thumbnail_temp_path + if not os.path.exists(thumbdir): + os.mkdir(thumbdir) + else: + thumbdir = thumbnail_temp_path + fname = os.path.basename(svgpath) hasher = hashlib.new('md5') with open(svgpath, 'rb') as afile: @@ -485,30 +511,24 @@ break digest = hasher.hexdigest() thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" - thumbdir = os.path.join(dname, ".svghmithumbs") thumbpath = os.path.join(thumbdir, thumbfname) have_thumb = os.path.exists(thumbpath) - try: - if not have_thumb: - if not os.path.exists(thumbdir): - os.mkdir(thumbdir) - have_thumb = self.GenThumbnail(svgpath, thumbpath) - - self.bmp = wx.Bitmap(thumbpath) if have_thumb else None - - self.selected_SVG = svgpath if have_thumb else None - - self.AnalyseWidgetAndUpdateUI(fname) - - self.SetMessage(self.msg) - - except IOError: - self.msg = _("Widget library must be writable") + if not have_thumb: + self.Controler.GetCTRoot().logger.write( + "Rendering preview of " + fname + " widget.\n") + have_thumb = self.GenThumbnail(svgpath, thumbpath) + + self.bmp = wx.Bitmap(thumbpath) if have_thumb else None + + self.selected_SVG = svgpath if have_thumb else None + + self.AnalyseWidgetAndUpdateUI(fname) + + self.SetMessage(self.msg) self.Refresh() - event.Skip() def OnHMITreeNodeSelection(self, hmitree_nodes): self.hmitree_nodes = hmitree_nodes @@ -687,12 +707,12 @@ class SVGHMI_UI(wx.SplitterWindow): - def __init__(self, parent, register_for_HMI_tree_updates): + def __init__(self, parent, controler, register_for_HMI_tree_updates): wx.SplitterWindow.__init__(self, parent, style=wx.SUNKEN_BORDER | wx.SP_3D) self.SelectionTree = HMITreeSelector(self) - self.Staging = WidgetLibBrowser(self) + self.Staging = WidgetLibBrowser(self, controler) self.SplitVertically(self.SelectionTree, self.Staging, 300) register_for_HMI_tree_updates(weakref.ref(self)) diff -r ca312be56929 -r e87a2daace80 svghmi/widget_tooglebutton.ysl2 --- a/svghmi/widget_tooglebutton.ysl2 Wed Jun 01 09:15:26 2022 +0200 +++ b/svghmi/widget_tooglebutton.ysl2 Wed Jun 01 09:22:07 2022 +0200 @@ -38,7 +38,7 @@ } activate(val) { - let [active, inactive] = val ? ["none",""] : ["", "none"]; + let [active, inactive] = val ? ["","none"] : ["none", ""]; if (this.active_elt) this.active_elt.style.display = active; if (this.inactive_elt) diff -r ca312be56929 -r e87a2daace80 util/ProcessLogger.py --- a/util/ProcessLogger.py Wed Jun 01 09:15:26 2022 +0200 +++ b/util/ProcessLogger.py Wed Jun 01 09:22:07 2022 +0200 @@ -139,7 +139,7 @@ else: self.timeout = None - if _debug: + if _debug and self.logger: self.logger.write("(DEBUG) launching:\n" + self.Command_str + "\n") self.Proc = subprocess.Popen(self.Command, **popenargs) diff -r ca312be56929 -r e87a2daace80 util/misc.py --- a/util/misc.py Wed Jun 01 09:15:26 2022 +0200 +++ b/util/misc.py Wed Jun 01 09:22:07 2022 +0200 @@ -28,7 +28,8 @@ from __future__ import absolute_import -import os +import os,sys +import random from functools import reduce from util.BitmapLibrary import AddBitmapFolder @@ -42,8 +43,19 @@ for root, dirs, files in os.walk(path): files = [f for f in files if not f[0] == '.'] dirs[:] = [d for d in dirs if not d[0] == '.'] + if sys.platform.startswith('win'): + try: + testdirpath = os.path.join(root, "testdir_" + str(random.randint(0, 4294967296))) + os.mkdir(testdirpath) + os.rmdir(testdirpath) + except: + return False + else: + if os.access(root, os.W_OK) is not True: + return False + for name in files: - if os.access(root, os.W_OK) is not True or os.access(os.path.join(root, name), os.W_OK) is not True: + if os.access(os.path.join(root, name), os.W_OK) is not True: return False return True