]> git.lyx.org Git - lyx.git/blobdiff - lib/lyx2lyx/lyx_1_2.py
fix bug 2026 and bug 2088
[lyx.git] / lib / lyx2lyx / lyx_1_2.py
index 6849c2573539490f12a0b1d5028bd6fefcaa5584..46b7797a8bd78a08fc3d46c023027e58d953e2b1 100644 (file)
@@ -23,7 +23,7 @@ import re
 from parser_tools import find_token, find_token_backwards, get_next_paragraph,\
                          find_tokens, find_end_of_inset, find_re, \
                          is_nonempty_line, get_paragraph, find_nonempty_line, \
-                         get_value, get_tabular_lines, check_token
+                         get_value, get_tabular_lines, check_token, get_layout
 
 floats = {
     "footnote": ["\\begin_inset Foot",
@@ -71,7 +71,8 @@ def get_width(mo):
 #
 # Change \begin_float .. \end_float into \begin_inset Float .. \end_inset
 #
-def remove_oldfloat(lines, opt):
+def remove_oldfloat(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_float", i)
@@ -82,7 +83,7 @@ def remove_oldfloat(lines, opt):
 
        floattype = string.split(lines[i])[1]
        if not floats.has_key(floattype):
-           opt.warning("Error! Unknown float type " + floattype)
+           file.warning("Error! Unknown float type " + floattype)
            floattype = "fig"
 
        # skip \end_deeper tokens
@@ -90,7 +91,7 @@ def remove_oldfloat(lines, opt):
        while check_token(lines[i2], "\\end_deeper"):
            i2 = i2+1
        if i2 > i+1:
-           j2 = get_next_paragraph(lines, j+1)
+           j2 = get_next_paragraph(lines, j + 1, file.format + 1)
            lines[j2:j2] = ["\\end_deeper "]*(i2-(i+1))
 
        new = floats[floattype]+[""]
@@ -115,7 +116,7 @@ def remove_oldfloat(lines, opt):
        # as extra '\foo default' commands are ignored.
        # In fact, it might be safer to output '\foo default' for all
        # font attributes.
-       k = get_paragraph(lines, i)
+       k = get_paragraph(lines, i, file.format + 1)
        flag = 0
        for token in font_tokens:
            if find_token(lines, token, k, i) != -1:
@@ -125,7 +126,7 @@ def remove_oldfloat(lines, opt):
                    flag = 1
                    new.append("")
                if token == "\\lang":
-                   new.append(token+" "+ opt.language)
+                   new.append(token+" "+ file.language)
                else:
                    new.append(token+" default ")
 
@@ -135,8 +136,10 @@ def remove_oldfloat(lines, opt):
 
 pextra_type2_rexp = re.compile(r".*\\pextra_type\s+[12]")
 pextra_type2_rexp2 = re.compile(r".*(\\layout|\\pextra_type\s+2)")
+pextra_widthp = re.compile(r"\\pextra_widthp")
 
-def remove_pextra(lines):
+def remove_pextra(file):
+    lines = file.body
     i = 0
     flag = 0
     while 1:
@@ -144,6 +147,12 @@ def remove_pextra(lines):
        if i == -1:
            break
 
+        # Sometimes the \pextra_widthp argument comes in it own
+        # line. If that happens insert it back in this line.
+        if pextra_widthp.search(lines[i+1]):
+            lines[i] = lines[i] + ' ' + lines[i+1]
+            del lines[i+1]
+
        mo = pextra_rexp.search(lines[i])
         width = get_width(mo)
 
@@ -170,10 +179,10 @@ def remove_pextra(lines):
            if hfill:
                start = ["","\hfill",""]+start
        else:
-           start = ["\\layout Standard"] + start
+           start = ['\\layout %s' % file.default_layout,''] + start
 
        j0 = find_token_backwards(lines,"\\layout", i-1)
-       j = get_next_paragraph(lines, i)
+       j = get_next_paragraph(lines, i, file.format + 1)
 
        count = 0
        while 1:
@@ -207,13 +216,15 @@ def is_empty(lines):
 move_rexp =  re.compile(r"\\(family|series|shape|size|emph|numeric|bar|noun|end_deeper)")
 ert_rexp = re.compile(r"\\begin_inset|\\hfill|.*\\SpecialChar")
 spchar_rexp = re.compile(r"(.*)(\\SpecialChar.*)")
-ert_begin = ["\\begin_inset ERT",
-            "status Collapsed",
-            "",
-            "\\layout Standard"]
 
 
-def remove_oldert(lines):
+def remove_oldert(file):
+    ert_begin = ["\\begin_inset ERT",
+                 "status Collapsed",
+                 "",
+                 '\\layout %s' % file.default_layout,
+                 ""]
+    lines = file.body
     i = 0
     while 1:
        i = find_tokens(lines, ["\\latex latex", "\\layout LaTeX"], i)
@@ -238,8 +249,7 @@ def remove_oldert(lines):
        new = []
        new2 = []
        if check_token(lines[i], "\\layout LaTeX"):
-           new = ["\layout Standard", "", ""]
-           # We have a problem with classes in which Standard is not the default layout!
+           new = ['\layout %s' % file.default_layout, "", ""]
 
        k = i+1
        while 1:
@@ -292,7 +302,7 @@ def remove_oldert(lines):
                    k = k+1
                    new.append("")
             elif hfill:
-                new = new+["\hfill", ""]
+                new = new + ["\\hfill", ""]
                 k = k2
            elif specialchar:
                if new == []:
@@ -322,7 +332,8 @@ def remove_oldert(lines):
 
 
 # ERT insert are hidden feature of lyx 1.1.6. This might be removed in the future.
-def remove_oldertinset(lines):
+def remove_oldertinset(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_inset ERT", i)
@@ -330,7 +341,7 @@ def remove_oldertinset(lines):
            break
        j = find_end_of_inset(lines, i)
        k = find_token(lines, "\\layout", i+1)
-       l = get_paragraph(lines, i)
+       l = get_paragraph(lines, i, file.format + 1)
        if lines[k] == lines[l]: # same layout
            k = k+1
        new = lines[k:j]
@@ -338,8 +349,11 @@ def remove_oldertinset(lines):
        i = i+1
 
 
-def is_ert_paragraph(lines, i):
-    if not check_token(lines[i], "\\layout Standard"):
+def is_ert_paragraph(file, i):
+    lines = file.body
+    if not check_token(lines[i], "\\layout"):
+        return 0
+    if not file.is_default_layout(get_layout(lines[i], file.default_layout)):
         return 0
 
     i = find_nonempty_line(lines, i+1)
@@ -351,16 +365,17 @@ def is_ert_paragraph(lines, i):
     return check_token(lines[k], "\\layout")
 
 
-def combine_ert(lines):
+def combine_ert(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_inset ERT", i)
        if i == -1:
            break
-       j = get_paragraph(lines, i)
+       j = get_paragraph(lines, i, file.format + 1)
        count = 0
        text = []
-       while is_ert_paragraph(lines, j):
+       while is_ert_paragraph(file, j):
 
            count = count+1
            i2 = find_token(lines, "\\layout", j+1)
@@ -392,7 +407,8 @@ def write_attribute(x, token, value):
        x.append("\t"+token+" "+value)
 
 
-def remove_figinset(lines):
+def remove_figinset(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_inset Figure", i)
@@ -456,17 +472,22 @@ def remove_figinset(lines):
        write_attribute(new, "lyxsize_type", "1")
        write_attribute(new, "lyxwidth", lyxwidth)
        write_attribute(new, "lyxheight", lyxheight)
-       new = new + ["\end_inset"]
+       new = new + ["\\end_inset"]
        lines[i:j+1] = new
 
 
+##
+# Convert tabular format 2 to 3
+#
 attr_re = re.compile(r' \w*="(false|0|)"')
 line_re = re.compile(r'<(features|column|row|cell)')
 
-def update_tabular(lines):
+def update_tabular(file):
+    regexp = re.compile(r'^\\begin_inset\s+Tabular')
+    lines = file.body
     i = 0
     while 1:
-        i = find_token(lines, '\\begin_inset  Tabular', i)
+        i = find_re(lines, regexp, i)
         if i == -1:
             break
 
@@ -482,8 +503,186 @@ def update_tabular(lines):
        i = i+1
 
 
+##
+# Convert tabular format 2 to 3
+#
+# compatibility read for old longtable options. Now we can make any
+# row part of the header/footer type we want before it was strict
+# sequential from the first row down (as LaTeX does it!). So now when
+# we find a header/footer line we have to go up the rows and set it
+# on all preceding rows till the first or one with already a h/f option
+# set. If we find a firstheader on the same line as a header or a
+# lastfooter on the same line as a footer then this should be set empty.
+# (Jug 20011220)
+
+# just for compatibility with old python versions
+# python >= 2.3 has real booleans (False and True)
+false = 0
+true = 1
+
+# simple data structure to deal with long table info
+class row:
+    def __init__(self):
+        self.endhead = false           # header row
+        self.endfirsthead = false      # first header row
+        self.endfoot = false           # footer row
+        self.endlastfoot = false       # last footer row
+
+
+def haveLTFoot(row_info):
+    for row_ in row_info:
+        if row_.endfoot:
+            return true
+    return false
+
+
+def setHeaderFooterRows(hr, fhr, fr, lfr, rows_, row_info):
+    endfirsthead_empty = false
+    endlastfoot_empty = false
+    # set header info
+    while (hr > 0):
+        hr = hr - 1
+        row_info[hr].endhead = true
+
+    # set firstheader info
+    if fhr and fhr < rows_:
+        if row_info[fhr].endhead:
+            while fhr > 0:
+                fhr = fhr - 1
+                row_info[fhr].endfirsthead = true
+                row_info[fhr].endhead = false
+        elif row_info[fhr - 1].endhead:
+            endfirsthead_empty = true
+        else:
+            while fhr > 0 and not row_info[fhr - 1].endhead:
+                fhr = fhr - 1
+                row_info[fhr].endfirsthead = true
+
+    # set footer info
+    if fr and fr < rows_:
+        if row_info[fr].endhead and row_info[fr - 1].endhead:
+            while fr > 0 and not row_info[fr - 1].endhead:
+                fr = fr - 1
+                row_info[fr].endfoot = true
+                row_info[fr].endhead = false
+        elif row_info[fr].endfirsthead and row_info[fr - 1].endfirsthead:
+            while fr > 0 and not row_info[fr - 1].endfirsthead:
+                fr = fr - 1
+                row_info[fr].endfoot = true
+                row_info[fr].endfirsthead = false
+        elif not row_info[fr - 1].endhead and not row_info[fr - 1].endfirsthead:
+            while fr > 0 and not row_info[fr - 1].endhead and not row_info[fr - 1].endfirsthead:
+                fr = fr - 1
+                row_info[fr].endfoot = true
+
+    # set lastfooter info
+    if lfr and lfr < rows_:
+        if row_info[lfr].endhead and row_info[lfr - 1].endhead:
+            while lfr > 0 and not row_info[lfr - 1].endhead:
+                lfr = lfr - 1
+                row_info[lfr].endlastfoot = true
+                row_info[lfr].endhead = false
+        elif row_info[lfr].endfirsthead and row_info[lfr - 1].endfirsthead:
+            while lfr > 0 and not row_info[lfr - 1].endfirsthead:
+                lfr = lfr - 1
+                row_info[lfr].endlastfoot = true
+                row_info[lfr].endfirsthead = false
+        elif row_info[lfr].endfoot and row_info[lfr - 1].endfoot:
+            while lfr > 0 and not row_info[lfr - 1].endfoot:
+                lfr = lfr - 1
+                row_info[lfr].endlastfoot = true
+                row_info[lfr].endfoot = false
+        elif not row_info[fr - 1].endhead and not row_info[fr - 1].endfirsthead and not row_info[fr - 1].endfoot:
+            while lfr > 0 and not row_info[lfr - 1].endhead and not row_info[lfr - 1].endfirsthead and not row_info[lfr - 1].endfoot:
+                lfr = lfr - 1
+                row_info[lfr].endlastfoot = true
+        elif haveLTFoot(row_info):
+            endlastfoot_empty = true
+
+    return endfirsthead_empty, endlastfoot_empty
+
+
+def insert_attribute(lines, i, attribute):
+    last = string.find(lines[i],'>')
+    lines[i] = lines[i][:last] + ' ' + attribute + lines[i][last:]
+
+
+rows_re = re.compile(r'rows="(\d*)"')
+longtable_re = re.compile(r'islongtable="(\w)"')
+ltvalues_re = re.compile(r'endhead="(-?\d*)" endfirsthead="(-?\d*)" endfoot="(-?\d*)" endlastfoot="(-?\d*)"')
+lt_features_re = re.compile(r'(endhead="-?\d*" endfirsthead="-?\d*" endfoot="-?\d*" endlastfoot="-?\d*")')
+def update_longtables(file):
+    regexp = re.compile(r'^\\begin_inset\s+Tabular')
+    body = file.body
+    i = 0
+    while 1:
+        i = find_re(body, regexp, i)
+        if i == -1:
+            break
+        i = i + 1
+        i = find_token(body, "<lyxtabular", i)
+        if i == -1:
+            break
+
+        # get number of rows in the table
+        rows = int(rows_re.search(body[i]).group(1))
+
+        i = i + 1
+        i = find_token(body, '<features', i)
+        if i == -1:
+            break
+
+        # is this a longtable?
+        longtable = longtable_re.search(body[i])
+
+        if not longtable:
+            # islongtable is missing add it
+            body[i] = body[i][:10] + 'islongtable="false" ' + body[i][10:]
+
+        if not longtable or longtable.group(1) != "true":
+            # remove longtable elements from features
+            features = lt_features_re.search(body[i])
+            if features:
+                body[i] = string.replace(body[i], features.group(1), "")
+            continue
+
+        row_info = row() * rows
+        res = ltvalues_re.search(body[i])
+        if not res:
+            continue
+
+        endfirsthead_empty, endlastfoot_empty = setHeaderFooterRows(res.group(1), res.group(2), res.group(3), res.group(4), rows, row_info)
+
+        if endfirsthead_empty:
+            insert_attribute(body, i, 'firstHeadEmpty="true"')
+
+        if endfirsthead_empty:
+            insert_attribute(body, i, 'lastFootEmpty="true"')
+
+        i = i + 1
+        for j in range(rows):
+            i = find_token(body, '<row', i)
+
+            self.endfoot = false               # footer row
+            self.endlastfoot = false   # last footer row
+            if row_info[j].endhead:
+                insert_attribute(body, i, 'endhead="true"')
+
+            if row_info[j].endfirsthead:
+                insert_attribute(body, i, 'endfirsthead="true"')
+
+            if row_info[j].endfoot:
+                insert_attribute(body, i, 'endfoot="true"')
+
+            if row_info[j].endlastfoot:
+                insert_attribute(body, i, 'endlastfoot="true"')
+
+            i = i + 1
+
+
 # Figure insert are hidden feature of lyx 1.1.6. This might be removed in the future.
-def fix_oldfloatinset(lines):
+def fix_oldfloatinset(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_inset Float ", i)
@@ -495,7 +694,8 @@ def fix_oldfloatinset(lines):
         i = i+1
 
 
-def change_listof(lines):
+def change_listof(file):
+    lines = file.body
     i = 0
     while 1:
        i = find_token(lines, "\\begin_inset LatexCommand \\listof", i)
@@ -506,7 +706,8 @@ def change_listof(lines):
         i = i+1
 
 
-def change_infoinset(lines):
+def change_infoinset(file):
+    lines = file.body
     i = 0
     while 1:
         i = find_token(lines, "\\begin_inset Info", i)
@@ -523,7 +724,7 @@ def change_infoinset(lines):
             note_lines = [txt]+note_lines
 
         for line in note_lines:
-            new = new + ["\layout Standard", ""]
+            new = new + ['\layout %s' % file.default_layout, ""]
             tmp = string.split(line, '\\')
             new = new + [tmp[0]]
             for x in tmp[1:]:
@@ -532,7 +733,8 @@ def change_infoinset(lines):
         i = i+5
 
 
-def change_preamble(lines):
+def change_header(file):
+    lines = file.header
     i = find_token(lines, "\\use_amsmath", 0)
     if i == -1:
        return
@@ -540,23 +742,11 @@ def change_preamble(lines):
                      "\use_numerical_citations 0"]
 
 
-def convert(header, body, opt):
-    change_preamble(header)
-    change_listof(body)
-    fix_oldfloatinset(body)
-    update_tabular(body)
-    remove_pextra(body)
-    remove_oldfloat(body, opt)
-    remove_figinset(body)
-    remove_oldertinset(body)
-    remove_oldert(body)
-    combine_ert(body)
-    change_infoinset(body)
-    opt.format = 220
-
-
-def revert(header, body, opt):
-    opt.error("The convertion to an older format (%s) is not implemented." % opt.format)
+convert = [[220, [change_header, change_listof, fix_oldfloatinset,
+                  update_tabular, update_longtables, remove_pextra,
+                  remove_oldfloat, remove_figinset, remove_oldertinset,
+                  remove_oldert, combine_ert, change_infoinset]]]
+revert  = []
 
 
 if __name__ == "__main__":