commit 6f79bf845415a3c96de2a88a22c5b53f56e7ed65
Author: Koji Yokota <[email protected]>
Date:   Sun Feb 22 21:23:54 2026 +0900

    Add support for draw.io as an external template as promised
    
    Please let me know if additional work is required esp. related to file 
format
    
    https://lists.lyx.org/pipermail/lyx-devel/2025-July/thread.html#14905
---
 lib/Makefile.am                  |   1 +
 lib/configure.py                 | 101 +++++++++++++++++++++++++++++++++++++--
 lib/xtemplates/draw.io.xtemplate |  69 ++++++++++++++++++++++++++
 3 files changed, 167 insertions(+), 4 deletions(-)

diff --git a/lib/Makefile.am b/lib/Makefile.am
index c71e0d6fd3..401c937f06 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -3407,6 +3407,7 @@ xtemplatesdir = $(pkgdatadir)/xtemplates
 dist_xtemplates_DATA = \
        xtemplates/chess.xtemplate \
        xtemplates/dia.xtemplate \
+       xtemplates/draw.io.xtemplate \
        xtemplates/gnumeric.xtemplate \
        xtemplates/inkscape.xtemplate \
        xtemplates/lilypond.xtemplate \
diff --git a/lib/configure.py b/lib/configure.py
index 5f1ea0fdc1..914812a48e 100644
--- a/lib/configure.py
+++ b/lib/configure.py
@@ -342,17 +342,47 @@ def check_java():
 
 
 def checkMacOSappInstalled(prog):
+    result = checkMacOSapp(prog)
+    if result != False:
+        return result != ''
+    else:
+        return result
+
+
+def checkMacOSapp(prog, retarderKeys = False):
     '''
         Use metadata lookup to search for an "installed" macOS application 
bundle.
+        It returns full path of only one program among those found.
+        If retarderKeys == False, the path of first-found program is returned.
+        If retarderKeys is specified, programs that contains one of 
retarderKeys
+        in their path name will have lower priority to be reported.
     '''
     if sys.platform == 'darwin' and len(prog) >= 1:
         command = r'mdfind "kMDItemContentTypeTree == 
\"com.apple.application\"c && kMDItemFSName == \"%s\""' % prog
-        result = cmdOutput(command)
+        # Take the one found first (outcome of cmdOutput is multiple lines if
+        # it finds more than one)
+        results = cmdOutput(command).split('\n')
+        if retarderKeys != False:
+            retarder = []
+            priority = []
+            isRetarder = False
+            for idx in range(len(results)):
+                path_components = results[idx].split(os.sep)
+                for com in path_components:
+                    if com in retarderKeys:
+                        retarder.append(results[idx])
+                        isRetarder = True
+                        break
+                if not isRetarder:
+                    priority.append(results[idx])
+                else:
+                    isRetarder = False
+            results = priority + retarder
+        result = results[0]
         logger.debug(command + ": " + result)
-        return result != ''
+        return result
     return False
 
-
 def checkProgAlternatives(description, progs, rc_entry=None,
                           alt_rc_entry=None, path=None, not_found=''):
     '''
@@ -373,7 +403,10 @@ def checkProgAlternatives(description, progs, 
rc_entry=None,
     logger.info('checking for ' + description + '...')
     logger.debug('(' + ','.join(progs) + ')')
     additional_path = path
-    path = os.environ["PATH"].split(os.pathsep) + additional_path
+    sys_path = os.environ["PATH"].split(os.pathsep)
+    if (isinstance(sys_path, list)):
+        sys_path = [ x for x in sys_path if x !='' ]
+    path = sys_path + additional_path
     extlist = ['']
     if "PATHEXT" in os.environ:
         extlist = extlist + os.environ["PATHEXT"].split(os.pathsep)
@@ -631,6 +664,47 @@ def checkInkscapeStable():
         return True
 
 
+def checkDrawIO(progName, WinLMkey):
+    # Returns a list of additional paths to search for binary draw.io
+    # (draw.io inside of draw.io.app contents in the case of MacOS)
+
+    # check for MacOS
+    appPath = checkMacOSapp(progName + ".app",
+                            retarderKeys = [ 'Applications (Parallels)' ])
+    if appPath != False and appPath != '':
+        progPaths = [ appPath + "/Contents/MacOS" ]
+    elif os.name == 'nt':
+        result = checkWindowsProgram(progName, WinLMkey)[0]
+        if result == None:
+            progPaths = None
+        else:
+            progPaths = result
+    else:
+        progPaths = None
+    return progPaths
+
+
+def checkWindowsProgram(progName, WinLMkey):
+    # Returns a tuple of the installed path and filename of the program
+    # named 'progName' which has registered the fullpath in the registry key
+    # 'WinLMkey' in the hive HKEY_LOCAL_MACHINE
+    if os.name != 'nt':
+      return None, None
+
+    import winreg
+    reg_hive = winreg.HKEY_LOCAL_MACHINE
+    try:
+        with winreg.OpenKey(reg_hive, WinLMkey) as reg_key:
+          binPath = winreg.QueryValue(reg_key, None).replace('"%1"', 
'').strip()
+          logger.info('investigating in Windows registry for ' + progName + ': 
found ' + binPath)
+          pathComponents = binPath.replace('\\' + progName + '.exe', '')
+
+    except OSError:
+        return None, None
+
+    return [ pathComponents ], progName + '.exe'
+
+
 def checkLatex(dtl_tools):
     ''' Check latex, return lyx_check_config '''
     path, LATEX = checkProg('a Latex2e program', ['latex $$i', 'latex2e $$i'])
@@ -712,6 +786,10 @@ def checkFormatEntries(dtl_tools):
     checkViewerEditor('a Dia viewer and editor', ['dia'],
         rc_entry = [r'\Format dia        dia     DIA                    "" 
"%%"        "%%"    "vector,zipped=native", "application/x-dia-diagram"'])
     #
+    checkViewerEditor('a draw.io viewer and editor', [ 'draw.io', 'drawio', 
'draw.io.app' ],
+        rc_entry = [r'\Format drawio     drawio  Draw.io                    "" 
"%%"    "%%"    "vector,zipped=native", "application/x-draw.io-diagram"'],
+        path = checkWindowsProgram('draw.io', "SOFTWARE\\Classes\\draw.io 
Diagram\\shell\\open\\command")[0])
+    #
     checkViewerEditor('an OpenDocument drawing viewer and editor', 
['libreoffice', 'lodraw', 'ooffice', 'oodraw', 'soffice'],
         rc_entry = [r'\Format odg        "odg, sxd" "OpenDocument drawing"   
"" "%%"   "%%"    "vector,zipped=native"  
"application/vnd.oasis.opendocument.graphics"'])
     #
@@ -1208,6 +1286,21 @@ def checkConverterEntries():
         addToRC(r'''\converter dia        png        "dia -e $$o -t png $$i"   
""
 \converter dia        eps        "dia -e $$o -t eps $$i"       ""
 \converter dia        svg        "dia -e $$o -t svg $$i"       ""''')
+    #
+    # draw.io
+    progNames = [ 'draw.io', 'drawio' ]
+    additionalPaths = checkDrawIO(progNames[0],
+                     "SOFTWARE\\Classes\\draw.io 
Diagram\\shell\\open\\command")
+    path, drawio = checkProg('a Draw.io -> Image converter', progNames,
+                             path=additionalPaths)
+    if drawio == progNames[0] or drawio == progNames[1]:
+        fullpath = os.path.join(path, drawio)
+        addToRC(r'''\converter drawio        pdf6        "\"%s\" -xf pdf -o 
$$o --crop $$i"    ""
+\converter drawio        png        "\"%s\" -xf png -o $$o $$i"        ""
+\converter drawio        jpg        "\"%s\" -xf jpg -o $$o $$i"        ""
+\converter drawio        svg        "\"%s\" -xf svg -o $$o $$i"        ""
+\converter drawio        docbook5        "\"%s\" -xf xml -o $$o $$i"   "xml"'''
+            % (fullpath, fullpath, fullpath, fullpath, fullpath))
 
     #
     # Actually, this produces EPS, but with a wrong bounding box (usually A4 
or letter).
diff --git a/lib/xtemplates/draw.io.xtemplate b/lib/xtemplates/draw.io.xtemplate
new file mode 100644
index 0000000000..6ad0e54cb1
--- /dev/null
+++ b/lib/xtemplates/draw.io.xtemplate
@@ -0,0 +1,69 @@
+#
+# Draw.io External Template
+#
+# This file is part of LyX, the document processor.
+# Licence details can be found in the file COPYING.
+#
+# author Koji Yokota
+#
+# Full author contact details are available in file CREDITS.
+
+
+Template Draw.io
+       GuiName "Draw.io diagram"
+       HelpText
+               Draw.io diagram.
+               Draw.io provided as a browser-based and also as a stand-alone 
application. This template uses a stand-alone program so please make it ready 
before using this template. Included file will be cropped to the size of the 
diagram.
+       HelpTextEnd
+       InputFormat drawio
+       FileFilter "*.drawio"
+       AutomaticProduction true
+       # LyX has hard-coded support for these transformations
+       Transform Rotate
+       Transform Resize
+       Transform Clip
+       Transform Extra
+       Preview Graphics
+       Format LaTeX
+               TransformOption Rotate RotationLatexOption
+               TransformOption Resize ResizeLatexOption
+               TransformOption Clip   ClipLatexOption
+               TransformOption Extra  ExtraOption
+               Option Arg "[$$Extra,$$Rotate,$$Resize,$$Clip]"
+               # This string is what is output to the LaTeX file.
+               Product "\\includegraphics$$Arg{$$AbsOrRelPathMaster$$Basename}"
+               UpdateFormat pdf6
+               UpdateResult "$$AbsPath$$Basename.pdf"
+               Requirement "graphicx"
+               ReferencedFile latex "$$AbsPath$$Basename.pdf"
+               ReferencedFile dvi   "$$AbsPath$$Basename.pdf"
+       FormatEnd
+       Format PDFLaTeX
+               TransformOption Rotate RotationLatexOption
+               TransformOption Resize ResizeLatexOption
+               TransformOption Clip   ClipLatexOption
+               TransformOption Extra  ExtraOption
+               Option Arg "[$$Extra,$$Rotate,$$Resize,$$Clip]"
+               Product "\\includegraphics$$Arg{$$AbsOrRelPathMaster$$Basename}"
+               UpdateFormat pdf6
+               UpdateResult "$$AbsPath$$Basename.pdf"
+               Requirement "graphicx"
+               ReferencedFile pdflatex "$$AbsPath$$Basename.pdf"
+       FormatEnd
+       Format Ascii
+               Product "[Draw.io: $$FName]"
+       FormatEnd
+       Format DocBook
+               Product "<graphic 
fileref=\"$$AbsOrRelPathMaster$$Basename.png\"></graphic>"
+               UpdateFormat eps
+               UpdateResult "$$AbsPath$$Basename.png"
+               ReferencedFile docbook     "$$AbsPath$$Basename.png"
+               ReferencedFile docbook-xml "$$AbsPath$$Basename.png"
+       FormatEnd
+       Format XHTML
+               Product "<img src=\"$$AbsOrRelPathMaster$$Basename.svg\" />"
+               UpdateFormat svg
+               UpdateResult "$$AbsPath$$Basename.svg"
+               ReferencedFile xhtml "$$AbsPath$$Basename.svg"
+       FormatEnd
+TemplateEnd
-- 
lyx-cvs mailing list
[email protected]
https://lists.lyx.org/mailman/listinfo/lyx-cvs

Reply via email to