]> git.lyx.org Git - lyx.git/blobdiff - lib/lyx2lyx/lyx_2_2.py
When cleaning up before quitting, take care of exceptions
[lyx.git] / lib / lyx2lyx / lyx_2_2.py
index 8571c5cdcc2fa0d5ad1d6bb2143ca82e122cb6cb..996c22684ef1be04a76505f5d69c940e3f7fe249 100644 (file)
@@ -1,6 +1,5 @@
 # -*- coding: utf-8 -*-
 # This file is part of lyx2lyx
-# -*- coding: utf-8 -*-
 # Copyright (C) 2015 The LyX team
 #
 # This program is free software; you can redistribute it and/or
@@ -31,7 +30,7 @@ import sys, os
 #  del_token, check_token, get_option_value
 
 from lyx2lyx_tools import add_to_preamble, put_cmd_in_ert, get_ert, lyx2latex, \
-  lyx2verbatim, length_in_bp
+  lyx2verbatim, length_in_bp, convert_info_insets
 #  insert_to_preamble, latex_length, revert_flex_inset, \
 #  revert_font_attrs, hex2ratio, str2bool
 
@@ -78,7 +77,7 @@ def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment,
             if nolastopt == False:
               document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}{")
             else:
-              document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}") 
+              document.body[endInset - 2 : endInset + 1] = put_cmd_in_ert("}")
             del(document.body[lineArg : beginPlain + 1])
             wasOpt = False
           else:
@@ -104,6 +103,36 @@ def revert_Argument_to_TeX_brace(document, line, endline, n, nmax, environment,
 ###
 ###############################################################################
 
+def convert_longtable_label_internal(document, forward):
+    """
+    Convert reference to "LongTableNoNumber" into "Unnumbered" if forward is True
+    else revert it.
+    """
+    old_reference = "\\begin_inset Caption LongTableNoNumber"
+    new_reference = "\\begin_inset Caption Unnumbered"
+
+    # if the purpose is to revert swap the strings roles
+    if not forward:
+        old_reference, new_reference = new_reference, old_reference
+
+    i = 0
+    while True:
+        i = find_token(document.body, old_reference, i)
+
+        if i == -1:
+            return
+
+        document.body[i] = new_reference
+
+
+def convert_longtable_label(document):
+    convert_longtable_label_internal(document, True)
+
+
+def revert_longtable_label(document):
+    convert_longtable_label_internal(document, False)
+
+
 def convert_separator(document):
     """
     Convert layout separators to separator insets and add (LaTeX) paragraph
@@ -123,7 +152,7 @@ def convert_separator(document):
         }
 
     i = 0
-    while 1:
+    while True:
         i = find_token(document.body, "\\begin_deeper", i)
         if i == -1:
             break
@@ -145,7 +174,7 @@ def convert_separator(document):
             i = i + 1
 
     i = 0
-    while 1:
+    while True:
         i = find_token(document.body, "\\align", i)
         if i == -1:
             break
@@ -178,7 +207,7 @@ def convert_separator(document):
     regexp = re.compile(r'^\\begin_layout (?:(-*)|(\s*))(Separator|EndOfSlide)(?:(-*)|(\s*))$', re.IGNORECASE)
 
     i = 0
-    while 1:
+    while True:
         i = find_re(document.body, regexp, i)
         if i == -1:
             return
@@ -219,7 +248,7 @@ def revert_separator(document):
               "", "\\end_inset", ""]
 
     i = 0
-    while 1:
+    while True:
         i = find_token(document.body, "\\begin_inset Separator", i)
         if i == -1:
             return
@@ -304,6 +333,46 @@ def revert_separator(document):
         i = i + 1
 
 
+def convert_parbreak(document):
+    """
+    Convert parbreak separators not specifically used to separate
+    environments to latexpar separators.
+    """
+    parbreakinset = "\\begin_inset Separator parbreak"
+    i = 0
+    while True:
+        i = find_token(document.body, parbreakinset, i)
+        if i == -1:
+            return
+        lay = get_containing_layout(document.body, i)
+        if lay == False:
+            document.warning("Malformed LyX document: Can't convert separator inset at line " + str(i))
+            i += 1
+            continue
+        if lay[0] == "Standard":
+            # Convert only if not alone in the paragraph
+            k1 = find_nonempty_line(document.body, lay[1] + 1, i + 1)
+            k2 = find_nonempty_line(document.body, i + 1, lay[2])
+            if (k1 < i) or (k2 > i + 1) or not check_token(document.body[i], parbreakinset):
+                document.body[i] = document.body[i].replace("parbreak", "latexpar")
+        else:
+            document.body[i] = document.body[i].replace("parbreak", "latexpar")
+        i += 1
+
+
+def revert_parbreak(document):
+    """
+    Revert latexpar separators to parbreak separators.
+    """
+    i = 0
+    while True:
+        i = find_token(document.body, "\\begin_inset Separator latexpar", i)
+        if i == -1:
+            return
+        document.body[i] = document.body[i].replace("latexpar", "parbreak")
+        i += 1
+
+
 def revert_smash(document):
     " Set amsmath to on if smash commands are used "
 
@@ -550,7 +619,7 @@ def convert_dashes(document):
     while i < len(document.body):
         words = document.body[i].split()
         if len(words) > 1 and words[0] == "\\begin_inset" and \
-           words[1] in ["CommandInset", "ERT", "External", "Formula", "Graphics", "IPA", "listings"]:
+           words[1] in ["CommandInset", "ERT", "External", "Formula", "FormulaMacro", "Graphics", "IPA", "listings"]:
             # must not replace anything in insets that store LaTeX contents in .lyx files
             # (math and command insets withut overridden read() and write() methods
             # filtering out IPA makes Text::readParToken() more simple
@@ -562,6 +631,10 @@ def convert_dashes(document):
             else:
                 i = j
             continue
+        if len(words) > 0 and words[0] in ["\\leftindent", "\\paragraph_spacing", "\\align", "\\labelwidthstring"]:
+            # skip paragraph parameters (bug 10243)
+            i += 1
+            continue
         while True:
             j = document.body[i].find("--")
             if j == -1:
@@ -726,7 +799,7 @@ def convert_specialchar_internal(document, forward):
             else:
                 i = j
             continue
-        for key, value in specialchars.iteritems():
+        for key, value in specialchars.items():
             if forward:
                 document.body[i] = document.body[i].replace("\\SpecialChar " + key, "\\SpecialChar " + value)
                 document.body[i] = document.body[i].replace("\\SpecialCharNoPassThru " + key, "\\SpecialCharNoPassThru " + value)
@@ -922,17 +995,26 @@ def revert_newgloss(document):
     for glosse in glosses:
         i = 0
         while True:
-            i = find_token(document.body, "\\begin_inset ERT", i)
+            i = find_token(document.body, glosse, i)
             if i == -1:
-                return
+                break
             j = find_end_of_inset(document.body, i)
             if j == -1:
-                document.warning("Malformed LyX document: Can't find end of ERT inset")
+                document.warning("Malformed LyX document: Can't find end of Glosse inset")
                 i += 1
                 continue
-            ert = get_ert(document.body, i, True)
-            document.body[i:j+1] = [ert]
-            i = i + 1
+            while True:
+                ert = find_token(document.body, "\\begin_inset ERT", i, j)
+                if ert == -1:
+                    break
+                ertend = find_end_of_inset(document.body, ert)
+                if ertend == -1:
+                    document.warning("Malformed LyX document: Can't find end of ERT inset")
+                    ert += 1
+                    continue
+                ertcontent = get_ert(document.body, ert, True)
+                document.body[ert : ertend + 1] = [ertcontent]
+            i += 1
 
 
 def convert_newgloss(document):
@@ -1006,43 +1088,59 @@ def revert_BoxFeatures(document):
     defaultThick = "0.4pt"
     defaultShadow = "4pt"
     while True:
-        i = find_token(document.body, "height_special", i)
+        i = find_token(document.body, "thickness", i)
         if i == -1:
             return
+        binset = find_token(document.body, "\\begin_inset Box", i - 11)
+        if binset == -1 or binset != i - 11:
+            i = i + 1
+            continue # then "thickness" is is just a word in the text
+        einset = find_end_of_inset(document.body, binset)
+        if einset == -1:
+            document.warning("Malformed LyX document: Can't find end of box inset!")
+            i = i + 1
+            continue
         # read out the values
+        beg = document.body[i].find('"');
+        end = document.body[i].rfind('"');
+        thickness = document.body[i][beg+1:end];
         beg = document.body[i+1].find('"');
         end = document.body[i+1].rfind('"');
-        thickness = document.body[i+1][beg+1:end];
+        separation = document.body[i+1][beg+1:end];
         beg = document.body[i+2].find('"');
         end = document.body[i+2].rfind('"');
-        separation = document.body[i+2][beg+1:end];
-        beg = document.body[i+3].find('"');
-        end = document.body[i+3].rfind('"');
-        shadowsize = document.body[i+3][beg+1:end];
+        shadowsize = document.body[i+2][beg+1:end];
         # delete the specification
-        del document.body[i+1:i+4]
+        del document.body[i:i+3]
         # output ERT
         # first output the closing brace
         if shadowsize != defaultShadow or separation != defaultSep or thickness != defaultThick:
-            document.body[i + 10 : i + 10] = put_cmd_in_ert("}")
+            document.body[einset -1 : einset - 1] = put_cmd_in_ert("}")
+        # we have now the problem that if there is already \(f)colorbox in ERT around the inset
+        # the ERT from this routine must be around it
+        regexp = re.compile(r'^.*colorbox{.*$')
+        pos = find_re(document.body, regexp, binset - 4)
+        if pos != -1 and pos == binset - 4:
+            pos = i - 11 - 10
+        else:
+            pos = i - 11
         # now output the lengths
         if shadowsize != defaultShadow or separation != defaultSep or thickness != defaultThick:
-            document.body[i - 10 : i - 10] = put_cmd_in_ert("{")
+            document.body[pos : pos] = put_cmd_in_ert("{")
         if thickness != defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxrule " + thickness]
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness]
         if separation != defaultSep and thickness == defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxsep " + separation]
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxsep " + separation]
         if separation != defaultSep and thickness != defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation]
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation]
         if shadowsize != defaultShadow and separation == defaultSep and thickness == defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash shadowsize " + shadowsize]
+            document.body[pos + 5 : pos +6] = ["{\\backslash shadowsize " + shadowsize]
         if shadowsize != defaultShadow and separation != defaultSep and thickness == defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
         if shadowsize != defaultShadow and separation == defaultSep and thickness != defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxrule " + thickness + "\\backslash shadowsize " + shadowsize]
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash shadowsize " + shadowsize]
         if shadowsize != defaultShadow and separation != defaultSep and thickness != defaultThick:
-            document.body[i - 5 : i - 4] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
-        i = i + 11
+            document.body[pos + 5 : pos +6] = ["{\\backslash fboxrule " + thickness + "\\backslash fboxsep " + separation + "\\backslash shadowsize " + shadowsize]
 
 
 def convert_origin(document):
@@ -1052,11 +1150,11 @@ def convert_origin(document):
     if i == -1:
         document.warning("Malformed LyX document: No \\textclass!!")
         return
-    if document.dir == "":
-        origin = "stdin"
+    if document.dir == u'':
+        origin = u'stdin'
     else:
-        relpath = ''
-        if document.systemlyxdir and document.systemlyxdir != '':
+        relpath = u''
+        if document.systemlyxdir and document.systemlyxdir != u'':
             try:
                 if os.path.isabs(document.dir):
                     absdir = os.path.normpath(document.dir)
@@ -1067,16 +1165,14 @@ def convert_origin(document):
                 else:
                     abssys = os.path.normpath(os.path.abspath(document.systemlyxdir))
                 relpath = os.path.relpath(absdir, abssys)
-                if relpath.find('..') == 0:
-                    relpath = ''
+                if relpath.find(u'..') == 0:
+                    relpath = u''
             except:
-                relpath = ''
-        if relpath == '':
-            origin = document.dir.replace('\\', '/') + '/'
+                relpath = u''
+        if relpath == u'':
+            origin = document.dir.replace(u'\\', u'/') + u'/'
         else:
-            origin = os.path.join("/systemlyxdir", relpath).replace('\\', '/') + '/'
-        if os.name != 'nt':
-            origin = unicode(origin, sys.getfilesystemencoding())
+            origin = os.path.join(u"/systemlyxdir", relpath).replace(u'\\', u'/') + u'/'
     document.header[i:i] = ["\\origin " + origin]
 
 
@@ -1110,12 +1206,12 @@ def revert_textcolor(document):
                     # register that xcolor must be loaded in the preamble
                     if xcolor == False:
                         xcolor = True
-                        add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\usepackage{xcolor}}{}"])
+                        add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
                     # find the next \\color and/or the next \\end_layout
                     j = find_token(document.body, "\\color", i + 1)
                     k = find_token(document.body, "\\end_layout", i + 1)
                     if j == -1 and k != -1:
-                        j = k +1 
+                        j = k +1
                     # output TeX code
                     # first output the closing brace
                     if k < j:
@@ -1141,67 +1237,54 @@ def convert_colorbox(document):
 
 def revert_colorbox(document):
     " outputs color settings for boxes as TeX code "
-
-    binset = 0
+    
+    i = 0
     defaultframecolor = "black"
     defaultbackcolor = "none"
     while True:
-        binset = find_token(document.body, "\\begin_inset Box", binset)
+        i = find_token(document.body, "framecolor", i)
+        if i == -1:
+            return
+        binset = find_token(document.body, "\\begin_inset Box", i - 14)
         if binset == -1:
             return
-
         einset = find_end_of_inset(document.body, binset)
         if einset == -1:
             document.warning("Malformed LyX document: Can't find end of box inset!")
-            binset += 1
-            continue
-
-        blay = find_token(document.body, "\\begin_layout", binset, einset)
-        if blay == -1:
-            document.warning("Malformed LyX document: Can't find start of layout!")
-            binset = einset
             continue
-
-        # doing it this way, we make sure only to find a framecolor option
-        frame = find_token(document.body, "framecolor", binset, blay)
-        if frame == -1:
-            binset = einset
-            continue
-
-        beg = document.body[frame].find('"')
-        end = document.body[frame].rfind('"')
-        framecolor = document.body[frame][beg + 1 : end]
-
-        # this should be on the next line
-        bgcolor = frame + 1
-        beg = document.body[bgcolor].find('"')
-        end = document.body[bgcolor].rfind('"')
-        backcolor = document.body[bgcolor][beg + 1 : end]
-
-        # delete those bits
-        del document.body[frame : frame + 2]
-        # adjust end of inset
-        einset -= 2
-
-        if document.body[binset] == "\\begin_inset Box Boxed" and \
-            framecolor != defaultframecolor:
-          document.body[binset] = "\\begin_inset Box Frameless"
-
-        # output TeX code
+        # read out the values
+        beg = document.body[i].find('"');
+        end = document.body[i].rfind('"');
+        framecolor = document.body[i][beg+1:end];
+        beg = document.body[i + 1].find('"');
+        end = document.body[i + 1].rfind('"');
+        backcolor = document.body[i+1][beg+1:end];
+        # delete the specification
+        del document.body[i:i + 2]
+        # output ERT
         # first output the closing brace
-        if framecolor == defaultframecolor and backcolor == defaultbackcolor:
-            # nothing needed
-            pass
-        else:
-            # we also neeed to load xcolor in the preamble but only once
-            add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\usepackage{xcolor}}{}"])
-            document.body[einset + 1 : einset + 1] = put_cmd_in_ert("}")
-            if framecolor != defaultframecolor:
-                document.body[binset:binset] = put_cmd_in_ert("\\fcolorbox{" + framecolor + "}{" + backcolor + "}{")
-            else:
-              document.body[binset:binset] = put_cmd_in_ert("\\colorbox{" + backcolor + "}{")
-
-        binset = einset
+        if framecolor != defaultframecolor or backcolor != defaultbackcolor:
+            add_to_preamble(document, ["\\@ifundefined{rangeHsb}{\\usepackage{xcolor}}{}"])
+            document.body[einset : einset] = put_cmd_in_ert("}")
+        # determine the box type
+        isBox = find_token(document.body, "\\begin_inset Box Boxed", binset)
+        # now output the box commands
+        if (framecolor != defaultframecolor and isBox == binset) or (backcolor != defaultbackcolor and isBox == binset):
+            document.body[i - 14 : i - 14] = put_cmd_in_ert("\\fcolorbox{" + framecolor + "}{" + backcolor + "}{")
+            # in the case we must also change the box type because the ERT code adds a frame
+            document.body[i - 4] = "\\begin_inset Box Frameless"
+            # if has_inner_box 0 we must set it and use_makebox to 1
+            ibox = find_token(document.body, "has_inner_box", i - 4)
+            if ibox == -1 or ibox != i - 1:
+                document.warning("Malformed LyX document: Can't find has_inner_box statement!")
+                continue
+            # read out the value
+            innerbox = document.body[ibox][-1:];
+            if innerbox == "0":
+                document.body[ibox] = "has_inner_box 1"
+                document.body[ibox + 3] = "use_makebox 1"
+        if backcolor != defaultbackcolor and isBox != binset:
+            document.body[i - 14 : i - 14] =  put_cmd_in_ert("\\colorbox{" + backcolor + "}{")
 
 
 def revert_mathmulticol(document):
@@ -1418,7 +1501,6 @@ def revert_jss(document):
           h = find_token(document.body, "\\begin_inset Flex Code Chunk", h)
         if h != -1:
           endh = find_end_of_inset(document.body, h)
-          document.body[endh + 1 : endh] = ["\\end_layout"]
           document.body[endh : endh + 1] = put_cmd_in_ert("\\end{CodeChunk}")
           document.body[h : h + 3] = put_cmd_in_ert("\\begin{CodeChunk}")
           document.body[h - 1 : h] = ["\\begin_layout Standard"]
@@ -1617,7 +1699,7 @@ def revert_tcolorbox_1(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Subtitle", flex)
@@ -1642,7 +1724,7 @@ def revert_tcolorbox_2(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Raster Color Box", flex)
@@ -1663,7 +1745,7 @@ def revert_tcolorbox_3(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 1", flex)
@@ -1685,7 +1767,7 @@ def revert_tcolorbox_4(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 2", flex)
@@ -1707,7 +1789,7 @@ def revert_tcolorbox_5(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 3", flex)
@@ -1729,7 +1811,7 @@ def revert_tcolorbox_6(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 4", flex)
@@ -1751,7 +1833,7 @@ def revert_tcolorbox_7(document):
     i = find_token(document.header, "tcolorbox", i)
     if i == -1:
       break
-    else:    
+    else:
       flex = 0
       flexEnd = -1
       flex = find_token(document.body, "\\begin_inset Flex Custom Color Box 5", flex)
@@ -1799,7 +1881,7 @@ def revert_tcolorbox_8(document):
 
 def revert_moderncv_1(document):
   " Reverts the new inset of moderncv to TeX-code in preamble "
-  
+
   if document.textclass != "moderncv":
     return
   i = 0
@@ -1867,7 +1949,7 @@ def revert_moderncv_1(document):
 
 def revert_moderncv_2(document):
   " Reverts the phone inset of moderncv to the obsoleted mobile or fax "
-  
+
   if document.textclass != "moderncv":
     return
   i = 0
@@ -1911,77 +1993,105 @@ def revert_moderncv_2(document):
     i += 1
 
 
-def convert_moderncv(document):
-  " Convert the Fax and Mobile inset of moderncv to the new phone inset "
-  
-  if document.textclass != "moderncv":
-    return
-  i = 0
-  j = 0
-  lineArg = 0
-  while True:
-    # \mobile
-    i = find_token(document.body, "\\begin_layout Mobile", i)
-    if i == -1:
-      return
-    j = find_end_of_layout(document.body, i)
-    if j == -1:
-      document.warning("Malformed LyX document: Can't find end of Mobile layout")
-      i += 1
-      return
-    document.body[i + 1 : i + 1] = ["\\begin_inset Argument 1", "status open", "",
-                        "\\begin_layout Plain Layout", "mobile", "\\end_layout", "",
-                        "\\end_inset", ""]
-    # \fax
-    i = find_token(document.body, "\\begin_layout Fax", i)
-    if i == -1:
-      return
-    j = find_end_of_layout(document.body, i)
-    if j == -1:
-      document.warning("Malformed LyX document: Can't find end of Fax layout")
-      i += 1
-      return
-    document.body[i + 1 : i + 1] = ["\\begin_inset Argument 1", "status open", "",
-                        "\\begin_layout Plain Layout", "fax", "\\end_layout", "",
-                        "\\end_inset", ""]
-    # \firstname and \familyname
-    i1 = find_token(document.body, "\\begin_layout FirstName", 0)
-    if i1 == -1:
-      return
-    j1 = find_end_of_layout(document.body, i1)
-    if j1 == -1:
-      document.warning("Malformed LyX document: Can't find end of FirstName layout")
-      i1 += 1
-      return
-    FirstName = document.body[i1 + 1 : i1 + 2]
-    i2 = find_token(document.body, "\\begin_layout FamilyName", 0)
-    if i2 == -1:
-      return
-    j2 = find_end_of_layout(document.body, i2)
-    if j2 == -1:
-      document.warning("Malformed LyX document: Can't find end of FamilyName layout")
-      i2 += 1
-      return
-    FamilyName = document.body[i2 + 1 : i2 + 2]
-    if j1 > j2:
-      k = j1
-      l = i2
-    else:
-      k = j2
-      l = i1
-    document.body[k + 1 : k + 1] = ["\\begin_layout Name", "\\begin_inset Argument 1", "status open", "",
-                        "\\begin_layout Plain Layout", FirstName[0], "\\end_layout", "",
-                        "\\end_inset", "", FamilyName[0], "\\end_layout", ""]
-    #document.body[i2 + 1 : i2 + 1] = ["hellok: ", str(k)]
-    del(document.body[l : k])
-    i += 1
-    i1 += 1
-    i2 += 1
+def convert_moderncv_phone(document):
+    " Convert the Fax and Mobile inset of moderncv to the new phone inset "
+
+    if document.textclass != "moderncv":
+        return
+    i = 0
+    j = 0
+    lineArg = 0
+
+    phone_dict = {
+        "Mobile" : "mobile",
+        "Fax" : "fax",
+        }
+
+    rx = re.compile(r'^\\begin_layout (\S+)$')
+    while True:
+        # substitute \fax and \mobile by \phone[fax] and \phone[mobile], respectively
+        i = find_token(document.body, "\\begin_layout", i)
+        if i == -1:
+            return
+
+        m = rx.match(document.body[i])
+        val = ""
+        if m:
+            val = m.group(1)
+        if val not in list(phone_dict.keys()):
+            i += 1
+            continue
+        j = find_end_of_layout(document.body, i)
+        if j == -1:
+            document.warning("Malformed LyX document: Can't find end of Mobile layout")
+            i += 1
+            return
+
+        document.body[i : i + 1] = ["\\begin_layout Phone", "\\begin_inset Argument 1", "status open", "",
+                            "\\begin_layout Plain Layout", phone_dict[val], "\\end_layout", "",
+                            "\\end_inset", ""]
+
+
+def convert_moderncv_name(document):
+    " Convert the FirstName and LastName layout of moderncv to the general Name layout "
+
+    if document.textclass != "moderncv":
+        return
+
+    fnb = 0 # Begin of FirstName inset
+    fne = 0 # End of FirstName inset
+    lnb = 0 # Begin of LastName (FamilyName) inset
+    lne = 0 # End of LastName (FamilyName) inset
+    nb = 0 # Begin of substituting Name inset
+    ne = 0 # End of substituting Name inset
+    FirstName = [] # FirstName content
+    FamilyName = [] # LastName content
+
+    while True:
+        # locate FirstName
+        fnb = find_token(document.body, "\\begin_layout FirstName", fnb)
+        if fnb != -1:
+            fne = find_end_of_layout(document.body, fnb)
+            if fne == -1:
+                document.warning("Malformed LyX document: Can't find end of FirstName layout")
+                return
+            FirstName = document.body[fnb + 1 : fne]
+        # locate FamilyName
+        lnb = find_token(document.body, "\\begin_layout FamilyName", lnb)
+        if lnb != -1:
+            lne = find_end_of_layout(document.body, lnb)
+            if lne == -1:
+                document.warning("Malformed LyX document: Can't find end of FamilyName layout")
+                return
+            FamilyName = document.body[lnb + 1 : lne]
+        # Determine the region for the substituting Name layout
+        if fnb == -1 and lnb == -1: # Neither FirstName nor FamilyName exists -> Do nothing
+            return
+        elif fnb == -1: # Only FamilyName exists -> New Name insets replaces that
+            nb = lnb
+            ne = lne
+        elif lnb == -1: # Only FirstName exists -> New Name insets replaces that
+            nb = fnb
+            ne = fne
+        elif fne > lne: # FirstName position before FamilyName -> New Name insets spans
+            nb = lnb #     from FamilyName begin
+            ne = fne #     to FirstName end
+        else: #           FirstName position before FamilyName -> New Name insets spans
+            nb = fnb #     from FirstName begin
+            ne = lne #     to FamilyName end
+
+        # Insert the substituting layout now. If FirstName exists, use an otpional argument.
+        if FirstName == []:
+            document.body[nb : ne + 1] = ["\\begin_layout Name"] + FamilyName + ["\\end_layout", ""]
+        else:
+            document.body[nb : ne + 1] = ["\\begin_layout Name", "\\begin_inset Argument 1", "status open", "",
+                                "\\begin_layout Plain Layout"] + FirstName + ["\\end_layout", "",
+                                "\\end_inset", ""] + FamilyName + ["\\end_layout", ""]
 
 
 def revert_achemso(document):
   " Reverts the flex inset Latin to TeX code "
-  
+
   if document.textclass != "achemso":
     return
   i = 0
@@ -2148,6 +2258,35 @@ def revert_verbatim_star(document):
     revert_verbatim(document, True)
 
 
+def convert_save_props(document):
+    " Add save_transient_properties parameter. "
+    i = find_token(document.header, '\\begin_header', 0)
+    if i == -1:
+        document.warning("Malformed lyx document: Missing '\\begin_header'.")
+        return
+    document.header.insert(i + 1, '\\save_transient_properties true')
+
+
+def revert_save_props(document):
+    " Remove save_transient_properties parameter. "
+    i = find_token(document.header, "\\save_transient_properties", 0)
+    if i == -1:
+        return
+    del document.header[i]
+
+
+def convert_info_tabular_feature(document):
+    def f(arg):
+        return arg.replace("inset-modify tabular", "tabular-feature")
+    convert_info_insets(document, "shortcut(s)?|icon", f)
+
+
+def revert_info_tabular_feature(document):
+    def f(arg):
+        return arg.replace("tabular-feature", "inset-modify tabular")
+    convert_info_insets(document, "shortcut(s)?|icon", f)
+
+
 ##
 # Conversion hub
 #
@@ -2181,14 +2320,24 @@ convert = [
            [496, [convert_nounzip]],
            [497, [convert_external_bbox]],
            [498, []],
-           [499, [convert_moderncv]],
+           [499, [convert_moderncv_phone, convert_moderncv_name]],
            [500, []],
            [501, [convert_fontsettings]],
            [502, []],
-           [503, []]
+           [503, []],
+           [504, [convert_save_props]],
+           [505, []],
+           [506, [convert_info_tabular_feature]],
+           [507, [convert_longtable_label]],
+           [508, [convert_parbreak]]
           ]
 
 revert =  [
+           [507, [revert_parbreak]],
+           [506, [revert_longtable_label]],
+           [505, [revert_info_tabular_feature]],
+           [504, []],
+           [503, [revert_save_props]],
            [502, [revert_verbatim_star]],
            [501, [revert_solution]],
            [500, [revert_fontsettings]],