]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_6.py
a3c3af060b4f1c684ed5df3a2cdbffb2dc8b45d7
[lyx.git] / lib / lyx2lyx / lyx_1_6.py
1 # This file is part of lyx2lyx
2 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2008 The LyX Team <lyx-devel@lists.lyx.org>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 """ Convert files to the file format generated by lyx 1.6"""
20
21 import re
22 import unicodedata
23 import sys, os
24
25 from parser_tools import find_token, find_end_of, find_tokens, get_value, get_value_string
26
27 ####################################################################
28 # Private helper functions
29
30 def find_end_of_inset(lines, i):
31     " Find end of inset, where lines[i] is included."
32     return find_end_of(lines, i, "\\begin_inset", "\\end_inset")
33
34 # WARNING!
35 # DO NOT do this:
36 #   document.body[i] = wrap_insert_ert(...)
37 # wrap_into_ert may returns a multiline string, which should NOT appear
38 # in document.body. Insetad, do something like this:
39 #   subst = wrap_inset_ert(...)
40 #   subst = subst.split('\n')
41 #   document.body[i:i+1] = subst
42 #   i+= len(subst) - 1
43 # where the last statement resets the counter to accord with the added
44 # lines.
45 def wrap_into_ert(string, src, dst):
46     '''Within string, replace occurrences of src with dst, wrapped into ERT
47        E.g.: wrap_into_ert('sch\"on', "\\", "\\backslash") is:
48        sch<ERT>\\backslash</ERT>"on'''
49     return string.replace(src, '\n\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n'
50       + dst + '\n\\end_layout\n\\end_inset\n')
51
52 def put_cmd_in_ert(string):
53     string = string.replace('\\', "\\backslash\n")
54     string = "\\begin_inset ERT\nstatus collapsed\n\\begin_layout Standard\n" \
55       + string + "\n\\end_layout\n\\end_inset"
56     return string
57
58 def add_to_preamble(document, text):
59     """ Add text to the preamble if it is not already there.
60     Only the first line is checked!"""
61
62     if find_token(document.preamble, text[0], 0) != -1:
63         return
64
65     document.preamble.extend(text)
66
67 # Convert a LyX length into a LaTeX length
68 def convert_len(len):
69     units = {"text%":"\\backslash\ntextwidth", "col%":"\\backslash\ncolumnwidth",
70              "page%":"\\backslash\npagewidth", "line%":"\\backslash\nlinewidth",
71              "theight%":"\\backslash\ntextheight", "pheight%":"\\backslash\npageheight"}
72
73     # Convert LyX units to LaTeX units
74     for unit in units.keys():
75         if len.find(unit) != -1:
76             len = '%f' % (len2value(len) / 100)
77             len = len.strip('0') + units[unit]
78             break
79
80     return len
81
82 # Return the value of len without the unit in numerical form.
83 def len2value(len):
84     result = re.search('([+-]?[0-9.]+)', len)
85     if result:
86         return float(result.group(1))
87     # No number means 1.0
88     return 1.0
89
90 # Unfortunately, this doesn't really work, since Standard isn't always default.
91 # But it's as good as we can do right now.
92 def find_default_layout(document, start, end):
93     l = find_token(document.body, "\\begin_layout Standard", start, end)
94     if l == -1:
95         l = find_token(document.body, "\\begin_layout PlainLayout", start, end)
96     if l == -1:
97         l = find_token(document.body, "\\begin_layout Plain Layout", start, end)
98     return l
99
100 def get_option(document, m, option, default):
101     l = document.body[m].find(option)
102     val = default
103     if l != -1:
104         val = document.body[m][l:].split('"')[1]
105     return val
106
107 def remove_option(document, m, option):
108     l = document.body[m].find(option)
109     if l != -1:
110         val = document.body[m][l:].split('"')[1]
111         document.body[m] = document.body[m][:l-1] + document.body[m][l+len(option + '="' + val + '"'):]
112     return l
113
114 def set_option(document, m, option, value):
115     l = document.body[m].find(option)
116     if l != -1:
117         oldval = document.body[m][l:].split('"')[1]
118         l = l + len(option + '="')
119         document.body[m] = document.body[m][:l] + value + document.body[m][l+len(oldval):]
120     else:
121         document.body[m] = document.body[m][:-1] + ' ' + option + '="' + value + '">'
122     return l
123
124
125 def read_unicodesymbols():
126     " Read the unicodesymbols list of unicode characters and corresponding commands."
127     pathname = os.path.abspath(os.path.dirname(sys.argv[0]))
128     fp = open(os.path.join(pathname.strip('lyx2lyx'), 'unicodesymbols'))
129     spec_chars = []
130     # Two backslashes, followed by some non-word character, and then a character
131     # in brackets. The idea is to check for constructs like: \"{u}, which is how
132     # they are written in the unicodesymbols file; but they can also be written
133     # as: \"u.
134     r = re.compile(r'\\\\(\W)\{(\w)\}')
135     for line in fp.readlines():
136         if line[0] != '#' and line.strip() != "":
137             line=line.replace(' "',' ') # remove all quotation marks with spaces before
138             line=line.replace('" ',' ') # remove all quotation marks with spaces after
139             line=line.replace(r'\"','"') # replace \" by " (for characters with diaeresis)
140             try:
141                 [ucs4,command,dead] = line.split(None,2)
142                 if command[0:1] != "\\":
143                     continue
144                 spec_chars.append([command, unichr(eval(ucs4))])
145             except:
146                 continue
147             m = r.match(command)
148             if m != None:
149                 command = "\\\\"
150                 # If the character is a double-quote, then we need to escape it, too,
151                 # since it is done that way in the LyX file.
152                 if m.group(1) == "\"":
153                     command += "\\"
154                 command += m.group(1) + m.group(2)
155                 spec_chars.append([command, unichr(eval(ucs4))])
156     fp.close()
157     return spec_chars
158
159
160 def extract_argument(line):
161     'Extracts a LaTeX argument from the start of line. Returns (arg, rest).'
162
163     if not line:
164         return (None, "")
165
166     bracere = re.compile("(\s*)(.*)")
167     n = bracere.match(line)
168     whitespace = n.group(1)
169     stuff = n.group(2)
170     brace = stuff[:1]
171     if brace != "[" and brace != "{":
172         return (None, line)
173
174     # find closing brace
175     remain = stuff[1:]
176     pos = 0
177     num = 1
178     term = "}"
179     if brace == "[":
180         term = "]"
181     skip = False
182     for c in remain:
183         if skip:
184             skip = False
185         elif c == "\\":
186             skip = True
187         elif c == brace:
188             num += 1
189         elif c == term:
190             num -= 1
191         if c == 0:
192             break
193         pos += 1
194     if num != 0:
195         # We never found the matching brace
196         # So, to be on the safe side, let's just return everything
197         # which will then get wrapped as ERT
198         return (line, "")
199     return (line[:pos + 1], line[pos + 1:])
200
201
202 def latex2ert(line):
203     '''Converts LaTeX commands into ERT. line may well be a multi-line
204        string when it is returned.'''
205     if not line:
206         return line
207
208     retval = ""
209     ## FIXME Escaped \ ??
210     # This regex looks for a LaTeX command---i.e., something of the form
211     # "\alPhaStuFF", or "\X", where X is any character---where the command
212     # may also be preceded by an additional backslash, which is how it would
213     # appear (e.g.) in an InsetIndex.
214     labelre = re.compile(r'(.*?)\\?(\\(?:[a-zA-Z]+|.))(.*)')
215
216     m = labelre.match(line)
217     while m != None:
218         retval += m.group(1)
219         cmd = m.group(2)
220         end = m.group(3)
221
222         while True:
223             (arg, rest) = extract_argument(end)
224             if arg == None:
225                 break
226             cmd += arg
227             end = rest
228         # If we wanted to put labels into an InsetLabel, for example, then we
229         # would just need to test here for cmd == "label" and then take some
230         # appropriate action, i.e., to use arg to get the content and then
231         # wrap it appropriately.
232         cmd = put_cmd_in_ert(cmd)
233         retval += "\n" + cmd + "\n"
234         line = end
235         m = labelre.match(line)
236     retval += line
237     return retval
238
239
240 def latex2lyx(data):
241     '''Takes a string, possibly multi-line, and returns the result of
242     converting LaTeX constructs into LyX constructs. Returns a list of
243     lines, suitable for insertion into document.body.'''
244
245     retval = []
246
247     # Convert LaTeX to Unicode
248     reps = read_unicodesymbols()
249     # Commands of this sort need to be checked to make sure they are
250     # followed by a non-alpha character, lest we replace too much.
251     hardone = re.compile(r'^\\\\[a-zA-Z]+$')
252
253     for rep in reps:
254         if hardone.match(rep[0]):
255             pos = 0
256             while True:
257                 pos = data.find(rep[0], pos)
258                 if pos == -1:
259                     break
260                 nextpos = pos + len(rep[0])
261                 if nextpos < len(data) and data[nextpos].isalpha():
262                     # not the end of that command
263                     pos = nextpos
264                     continue
265                 data = data[:pos] + rep[1] + data[nextpos:]
266                 pos = nextpos
267         else:
268             data = data.replace(rep[0], rep[1])
269
270     # Generic, \" -> ":
271     data = wrap_into_ert(data, r'\"', '"')
272
273     # Math:
274     mathre = re.compile('^(.*?)(\$.*?\$)(.*)')
275     lines = data.split('\n')
276     for line in lines:
277         #document.warning("LINE: " + line)
278         #document.warning(str(i) + ":" + document.body[i])
279         #document.warning("LAST: " + document.body[-1])
280         g = line
281         m = mathre.match(g)
282         while m != None:
283             s = m.group(1)
284             f = m.group(2).replace('\\\\', '\\')
285             g = m.group(3)
286             if s:
287                 # this is non-math!
288                 s = latex2ert(s)
289                 subst = s.split('\n')
290                 retval += subst
291             retval.append("\\begin_inset Formula " + f)
292             retval.append("\\end_inset")
293             m = mathre.match(g)
294         # Handle whatever is left, which is just text
295         g = latex2ert(g)
296         subst = g.split('\n')
297         retval += subst
298     return retval
299
300
301 def lyx2latex(lines):
302     'Convert some LyX stuff into corresponding LaTeX stuff, as best we can.'
303     # clean up multiline stuff
304     content = ""
305     ert_end = 0
306     reps = read_unicodesymbols()
307
308     for curline in range(len(lines)):
309       line = lines[curline]
310       if line.startswith("\\begin_inset ERT"):
311           # We don't want to replace things inside ERT, so figure out
312           # where the end of the inset is.
313           ert_end = find_end_of_inset(lines, curline + 1)
314           continue
315       elif line.startswith("\\begin_inset Formula"):
316           line = line[20:]
317       elif line.startswith("\\begin_inset Quotes"):
318           # For now, we do a very basic reversion. Someone who understands
319           # quotes is welcome to fix it up.
320           qtype = line[20:].strip()
321           # lang = qtype[0]
322           side = qtype[1]
323           dbls = qtype[2]
324           if side == "l":
325               if dbls == "d":
326                   line = "``"
327               else:
328                   line = "`"
329           else:
330               if dbls == "d":
331                   line = "''"
332               else:
333                   line = "'"
334       elif line.isspace() or \
335             line.startswith("\\begin_layout") or \
336             line.startswith("\\end_layout") or \
337             line.startswith("\\begin_inset") or \
338             line.startswith("\\end_inset") or \
339             line.startswith("\\lang") or \
340             line.strip() == "status collapsed" or \
341             line.strip() == "status open":
342           #skip all that stuff
343           continue
344
345       # a lossless reversion is not possible
346       # try at least to handle some common insets and settings
347       # do not replace inside ERTs
348       if ert_end >= curline:
349           line = line.replace(r'\backslash', r'\\')
350       else:
351           # Do the LyX text --> LaTeX conversion
352           for rep in reps:
353             line = line.replace(rep[1], rep[0])
354           line = line.replace(r'\backslash', r'\textbackslash{}')
355           line = line.replace(r'\series bold', r'\bfseries{}').replace(r'\series default', r'\mdseries{}')
356           line = line.replace(r'\shape italic', r'\itshape{}').replace(r'\shape smallcaps', r'\scshape{}')
357           line = line.replace(r'\shape slanted', r'\slshape{}').replace(r'\shape default', r'\upshape{}')
358           line = line.replace(r'\emph on', r'\em{}').replace(r'\emph default', r'\em{}')
359           line = line.replace(r'\noun on', r'\scshape{}').replace(r'\noun default', r'\upshape{}')
360           line = line.replace(r'\bar under', r'\underbar{').replace(r'\bar default', r'}')
361           line = line.replace(r'\family sans', r'\sffamily{}').replace(r'\family default', r'\normalfont{}')
362           line = line.replace(r'\family typewriter', r'\ttfamily{}').replace(r'\family roman', r'\rmfamily{}')
363           line = line.replace(r'\InsetSpace ', r'').replace(r'\SpecialChar ', r'')
364       content += line
365     return content
366
367
368 ####################################################################
369
370 def convert_ltcaption(document):
371     i = 0
372     while True:
373         i = find_token(document.body, "\\begin_inset Tabular", i)
374         if i == -1:
375             return
376         j = find_end_of_inset(document.body, i + 1)
377         if j == -1:
378             document.warning("Malformed LyX document: Could not find end of tabular.")
379             continue
380
381         nrows = int(document.body[i+1].split('"')[3])
382         ncols = int(document.body[i+1].split('"')[5])
383
384         m = i + 1
385         for k in range(nrows):
386             m = find_token(document.body, "<row", m)
387             r = m
388             caption = 'false'
389             for k in range(ncols):
390                 m = find_token(document.body, "<cell", m)
391                 if (k == 0):
392                     mend = find_token(document.body, "</cell>", m + 1)
393                     # first look for caption insets
394                     mcap = find_token(document.body, "\\begin_inset Caption", m + 1, mend)
395                     # then look for ERT captions
396                     if mcap == -1:
397                         mcap = find_token(document.body, "caption", m + 1, mend)
398                         if mcap > -1:
399                             mcap = find_token(document.body, "\\backslash", mcap - 1, mcap)
400                     if mcap > -1:
401                         caption = 'true'
402                 if caption == 'true':
403                     if (k == 0):
404                         set_option(document, r, 'caption', 'true')
405                         set_option(document, m, 'multicolumn', '1')
406                         set_option(document, m, 'bottomline', 'false')
407                         set_option(document, m, 'topline', 'false')
408                         set_option(document, m, 'rightline', 'false')
409                         set_option(document, m, 'leftline', 'false')
410                         #j = find_end_of_inset(document.body, j + 1)
411                     else:
412                         set_option(document, m, 'multicolumn', '2')
413                 m = m + 1
414             m = m + 1
415
416         i = j + 1
417
418
419 #FIXME Use of wrap_into_ert can confuse lyx2lyx
420 def revert_ltcaption(document):
421     i = 0
422     while True:
423         i = find_token(document.body, "\\begin_inset Tabular", i)
424         if i == -1:
425             return
426         j = find_end_of_inset(document.body, i + 1)
427         if j == -1:
428             document.warning("Malformed LyX document: Could not find end of tabular.")
429             continue
430
431         m = i + 1
432         nrows = int(document.body[i+1].split('"')[3])
433         ncols = int(document.body[i+1].split('"')[5])
434
435         for k in range(nrows):
436             m = find_token(document.body, "<row", m)
437             caption = get_option(document, m, 'caption', 'false')
438             if caption == 'true':
439                 remove_option(document, m, 'caption')
440                 for k in range(ncols):
441                     m = find_token(document.body, "<cell", m)
442                     remove_option(document, m, 'multicolumn')
443                     if k == 0:
444                         m = find_token(document.body, "\\begin_inset Caption", m)
445                         if m == -1:
446                             return
447                         m = find_end_of_inset(document.body, m + 1)
448                         document.body[m] += wrap_into_ert("","","\\backslash\n\\backslash\n%")
449                     m = m + 1
450             m = m + 1
451         i = j + 1
452
453
454 def convert_tablines(document):
455     i = 0
456     while True:
457         i = find_token(document.body, "\\begin_inset Tabular", i)
458         if i == -1:
459             # LyX 1.3 inserted an extra space between \begin_inset
460             # and Tabular so let us try if this is the case and fix it.
461             i = find_token(document.body, "\\begin_inset  Tabular", i)
462             if i == -1:
463                 return
464             else:
465                 document.body[i] = "\\begin_inset Tabular"
466         j = find_end_of_inset(document.body, i + 1)
467         if j == -1:
468             document.warning("Malformed LyX document: Could not find end of tabular.")
469             continue
470
471         m = i + 1
472         nrows = int(document.body[i+1].split('"')[3])
473         ncols = int(document.body[i+1].split('"')[5])
474
475         col_info = []
476         for k in range(ncols):
477             m = find_token(document.body, "<column", m)
478             left = get_option(document, m, 'leftline', 'false')
479             right = get_option(document, m, 'rightline', 'false')
480             col_info.append([left, right])
481             remove_option(document, m, 'leftline')
482             remove_option(document, m, 'rightline')
483             m = m + 1
484
485         row_info = []
486         for k in range(nrows):
487             m = find_token(document.body, "<row", m)
488             top = get_option(document, m, 'topline', 'false')
489             bottom = get_option(document, m, 'bottomline', 'false')
490             row_info.append([top, bottom])
491             remove_option(document, m, 'topline')
492             remove_option(document, m, 'bottomline')
493             m = m + 1
494
495         m = i + 1
496         mc_info = []
497         for k in range(nrows*ncols):
498             m = find_token(document.body, "<cell", m)
499             mc_info.append(get_option(document, m, 'multicolumn', '0'))
500             m = m + 1
501         m = i + 1
502         for l in range(nrows):
503             for k in range(ncols):
504                 m = find_token(document.body, '<cell', m)
505                 if mc_info[l*ncols + k] == '0':
506                     r = set_option(document, m, 'topline', row_info[l][0])
507                     r = set_option(document, m, 'bottomline', row_info[l][1])
508                     r = set_option(document, m, 'leftline', col_info[k][0])
509                     r = set_option(document, m, 'rightline', col_info[k][1])
510                 elif mc_info[l*ncols + k] == '1':
511                     s = k + 1
512                     while s < ncols and mc_info[l*ncols + s] == '2':
513                         s = s + 1
514                     if s < ncols and mc_info[l*ncols + s] != '1':
515                         r = set_option(document, m, 'rightline', col_info[k][1])
516                     if k > 0 and mc_info[l*ncols + k - 1] == '0':
517                         r = set_option(document, m, 'leftline', col_info[k][0])
518                 m = m + 1
519         i = j + 1
520
521
522 def revert_tablines(document):
523     i = 0
524     while True:
525         i = find_token(document.body, "\\begin_inset Tabular", i)
526         if i == -1:
527             return
528         j = find_end_of_inset(document.body, i + 1)
529         if j == -1:
530             document.warning("Malformed LyX document: Could not find end of tabular.")
531             continue
532
533         m = i + 1
534         nrows = int(document.body[i+1].split('"')[3])
535         ncols = int(document.body[i+1].split('"')[5])
536
537         lines = []
538         for k in range(nrows*ncols):
539             m = find_token(document.body, "<cell", m)
540             top = get_option(document, m, 'topline', 'false')
541             bottom = get_option(document, m, 'bottomline', 'false')
542             left = get_option(document, m, 'leftline', 'false')
543             right = get_option(document, m, 'rightline', 'false')
544             lines.append([top, bottom, left, right])
545             m = m + 1
546
547         # we will want to ignore longtable captions
548         m = i + 1
549         caption_info = []
550         for k in range(nrows):
551             m = find_token(document.body, "<row", m)
552             caption = get_option(document, m, 'caption', 'false')
553             caption_info.append([caption])
554             m = m + 1
555
556         m = i + 1
557         col_info = []
558         for k in range(ncols):
559             m = find_token(document.body, "<column", m)
560             left = 'true'
561             for l in range(nrows):
562                 left = lines[l*ncols + k][2]
563                 if left == 'false' and caption_info[l] == 'false':
564                     break
565             set_option(document, m, 'leftline', left)
566             right = 'true'
567             for l in range(nrows):
568                 right = lines[l*ncols + k][3]
569                 if right == 'false' and caption_info[l] == 'false':
570                     break
571             set_option(document, m, 'rightline', right)
572             m = m + 1
573
574         row_info = []
575         for k in range(nrows):
576             m = find_token(document.body, "<row", m)
577             top = 'true'
578             for l in range(ncols):
579                 top = lines[k*ncols + l][0]
580                 if top == 'false':
581                     break
582             if caption_info[k] == 'false':
583                 top = 'false'
584             set_option(document, m, 'topline', top)
585             bottom = 'true'
586             for l in range(ncols):
587                 bottom = lines[k*ncols + l][1]
588                 if bottom == 'false':
589                     break
590             if caption_info[k] == 'false':
591                 bottom = 'false'
592             set_option(document, m, 'bottomline', bottom)
593             m = m + 1
594
595         i = j + 1
596
597
598 def fix_wrong_tables(document):
599     i = 0
600     while True:
601         i = find_token(document.body, "\\begin_inset Tabular", i)
602         if i == -1:
603             return
604         j = find_end_of_inset(document.body, i + 1)
605         if j == -1:
606             document.warning("Malformed LyX document: Could not find end of tabular.")
607             continue
608
609         m = i + 1
610         nrows = int(document.body[i+1].split('"')[3])
611         ncols = int(document.body[i+1].split('"')[5])
612
613         for l in range(nrows):
614             prev_multicolumn = 0
615             for k in range(ncols):
616                 m = find_token(document.body, '<cell', m)
617
618                 if document.body[m].find('multicolumn') != -1:
619                     multicol_cont = int(document.body[m].split('"')[1])
620
621                     if multicol_cont == 2 and (k == 0 or prev_multicolumn == 0):
622                         document.body[m] = document.body[m][:5] + document.body[m][21:]
623                         prev_multicolumn = 0
624                     else:
625                         prev_multicolumn = multicol_cont
626                 else:
627                     prev_multicolumn = 0
628
629         i = j + 1
630
631
632 def close_begin_deeper(document):
633     i = 0
634     depth = 0
635     while True:
636         i = find_tokens(document.body, ["\\begin_deeper", "\\end_deeper"], i)
637
638         if i == -1:
639             break
640
641         if document.body[i][:13] == "\\begin_deeper":
642             depth += 1
643         else:
644             depth -= 1
645
646         i += 1
647
648     document.body[-2:-2] = ['\\end_deeper' for i in range(depth)]
649
650
651 def long_charstyle_names(document):
652     i = 0
653     while True:
654         i = find_token(document.body, "\\begin_inset CharStyle", i)
655         if i == -1:
656             return
657         document.body[i] = document.body[i].replace("CharStyle ", "CharStyle CharStyle:")
658         i += 1
659
660 def revert_long_charstyle_names(document):
661     i = 0
662     while True:
663         i = find_token(document.body, "\\begin_inset CharStyle", i)
664         if i == -1:
665             return
666         document.body[i] = document.body[i].replace("CharStyle CharStyle:", "CharStyle ")
667         i += 1
668
669
670 def axe_show_label(document):
671     i = 0
672     while True:
673         i = find_token(document.body, "\\begin_inset CharStyle", i)
674         if i == -1:
675             return
676         if document.body[i + 1].find("show_label") != -1:
677             if document.body[i + 1].find("true") != -1:
678                 document.body[i + 1] = "status open"
679                 del document.body[ i + 2]
680             else:
681                 if document.body[i + 1].find("false") != -1:
682                     document.body[i + 1] = "status collapsed"
683                     del document.body[ i + 2]
684                 else:
685                     document.warning("Malformed LyX document: show_label neither false nor true.")
686         else:
687             document.warning("Malformed LyX document: show_label missing in CharStyle.")
688
689         i += 1
690
691
692 def revert_show_label(document):
693     i = 0
694     while True:
695         i = find_token(document.body, "\\begin_inset CharStyle", i)
696         if i == -1:
697             return
698         if document.body[i + 1].find("status open") != -1:
699             document.body.insert(i + 1, "show_label true")
700         else:
701             if document.body[i + 1].find("status collapsed") != -1:
702                 document.body.insert(i + 1, "show_label false")
703             else:
704                 document.warning("Malformed LyX document: no legal status line in CharStyle.")
705         i += 1
706
707 def revert_begin_modules(document):
708     i = 0
709     while True:
710         i = find_token(document.header, "\\begin_modules", i)
711         if i == -1:
712             return
713         j = find_end_of(document.header, i, "\\begin_modules", "\\end_modules")
714         if j == -1:
715             # this should not happen
716             break
717         document.header[i : j + 1] = []
718
719 def convert_flex(document):
720     "Convert CharStyle to Flex"
721     i = 0
722     while True:
723         i = find_token(document.body, "\\begin_inset CharStyle", i)
724         if i == -1:
725             return
726         document.body[i] = document.body[i].replace('\\begin_inset CharStyle', '\\begin_inset Flex')
727
728 def revert_flex(document):
729     "Convert Flex to CharStyle"
730     i = 0
731     while True:
732         i = find_token(document.body, "\\begin_inset Flex", i)
733         if i == -1:
734             return
735         document.body[i] = document.body[i].replace('\\begin_inset Flex', '\\begin_inset CharStyle')
736
737
738 #  Discard PDF options for hyperref
739 def revert_pdf_options(document):
740         "Revert PDF options for hyperref."
741         # store the PDF options and delete the entries from the Lyx file
742         i = 0
743         hyperref = False
744         title = ""
745         author = ""
746         subject = ""
747         keywords = ""
748         bookmarks = ""
749         bookmarksnumbered = ""
750         bookmarksopen = ""
751         bookmarksopenlevel = ""
752         breaklinks = ""
753         pdfborder = ""
754         colorlinks = ""
755         backref = ""
756         pagebackref = ""
757         pagemode = ""
758         otheroptions = ""
759         i = find_token(document.header, "\\use_hyperref", i)
760         if i != -1:
761             hyperref = get_value(document.header, "\\use_hyperref", i) == 'true'
762             del document.header[i]
763         i = find_token(document.header, "\\pdf_store_options", i)
764         if i != -1:
765             del document.header[i]
766         i = find_token(document.header, "\\pdf_title", 0)
767         if i != -1:
768             title = get_value_string(document.header, '\\pdf_title', 0, 0, True)
769             title = ' pdftitle={' + title + '}'
770             del document.header[i]
771         i = find_token(document.header, "\\pdf_author", 0)
772         if i != -1:
773             author = get_value_string(document.header, '\\pdf_author', 0, 0, True)
774             if title == "":
775                 author = ' pdfauthor={' + author + '}'
776             else:
777                 author = ',\n pdfauthor={' + author + '}'
778             del document.header[i]
779         i = find_token(document.header, "\\pdf_subject", 0)
780         if i != -1:
781             subject = get_value_string(document.header, '\\pdf_subject', 0, 0, True)
782             if title == "" and author == "":
783                 subject = ' pdfsubject={' + subject + '}'
784             else:
785                 subject = ',\n pdfsubject={' + subject + '}'
786             del document.header[i]
787         i = find_token(document.header, "\\pdf_keywords", 0)
788         if i != -1:
789             keywords = get_value_string(document.header, '\\pdf_keywords', 0, 0, True)
790             if title == "" and author == "" and subject == "":
791                 keywords = ' pdfkeywords={' + keywords + '}'
792             else:
793                 keywords = ',\n pdfkeywords={' + keywords + '}'
794             del document.header[i]
795         i = find_token(document.header, "\\pdf_bookmarks", 0)
796         if i != -1:
797             bookmarks = get_value_string(document.header, '\\pdf_bookmarks', 0)
798             bookmarks = ',\n bookmarks=' + bookmarks
799             del document.header[i]
800         i = find_token(document.header, "\\pdf_bookmarksnumbered", i)
801         if i != -1:
802             bookmarksnumbered = get_value_string(document.header, '\\pdf_bookmarksnumbered', 0)
803             bookmarksnumbered = ',\n bookmarksnumbered=' + bookmarksnumbered
804             del document.header[i]
805         i = find_token(document.header, "\\pdf_bookmarksopen", i)
806         if i != -1:
807             bookmarksopen = get_value_string(document.header, '\\pdf_bookmarksopen', 0)
808             bookmarksopen = ',\n bookmarksopen=' + bookmarksopen
809             del document.header[i]
810         i = find_token(document.header, "\\pdf_bookmarksopenlevel", i)
811         if i != -1:
812             bookmarksopenlevel = get_value_string(document.header, '\\pdf_bookmarksopenlevel', 0, 0, True)
813             bookmarksopenlevel = ',\n bookmarksopenlevel=' + bookmarksopenlevel
814             del document.header[i]
815         i = find_token(document.header, "\\pdf_breaklinks", i)
816         if i != -1:
817             breaklinks = get_value_string(document.header, '\\pdf_breaklinks', 0)
818             breaklinks = ',\n breaklinks=' + breaklinks
819             del document.header[i]
820         i = find_token(document.header, "\\pdf_pdfborder", i)
821         if i != -1:
822             pdfborder = get_value_string(document.header, '\\pdf_pdfborder', 0)
823             if pdfborder == 'true':
824                 pdfborder = ',\n pdfborder={0 0 0}'
825             else:
826                 pdfborder = ',\n pdfborder={0 0 1}'
827             del document.header[i]
828         i = find_token(document.header, "\\pdf_colorlinks", i)
829         if i != -1:
830             colorlinks = get_value_string(document.header, '\\pdf_colorlinks', 0)
831             colorlinks = ',\n colorlinks=' + colorlinks
832             del document.header[i]
833         i = find_token(document.header, "\\pdf_backref", i)
834         if i != -1:
835             backref = get_value_string(document.header, '\\pdf_backref', 0)
836             backref = ',\n backref=' + backref
837             del document.header[i]
838         i = find_token(document.header, "\\pdf_pagebackref", i)
839         if i != -1:
840             pagebackref = get_value_string(document.header, '\\pdf_pagebackref', 0)
841             pagebackref = ',\n pagebackref=' + pagebackref
842             del document.header[i]
843         i = find_token(document.header, "\\pdf_pagemode", 0)
844         if i != -1:
845             pagemode = get_value_string(document.header, '\\pdf_pagemode', 0)
846             pagemode = ',\n pdfpagemode=' + pagemode
847             del document.header[i]
848         i = find_token(document.header, "\\pdf_quoted_options", 0)
849         if i != -1:
850             otheroptions = get_value_string(document.header, '\\pdf_quoted_options', 0, 0, True)
851             if title == "" and author == "" and subject == "" and keywords == "":
852                 otheroptions = ' ' + otheroptions
853             else:
854                 otheroptions = ',\n ' + otheroptions
855             del document.header[i]
856
857         # write to the preamble when hyperref was used
858         if hyperref == True:
859             # preamble write preparations
860             # bookmark numbers are only output when they are turned on
861             if bookmarksopen == ',\n bookmarksopen=true':
862                 bookmarksopen = bookmarksopen + bookmarksopenlevel
863             if bookmarks == ',\n bookmarks=true':
864                 bookmarks = bookmarks + bookmarksnumbered + bookmarksopen
865             else:
866                 bookmarks = bookmarks
867             # hypersetup is only output when there are things to be set up
868             setupstart = '\\hypersetup{%\n'
869             setupend = ' }\n'
870             if otheroptions == "" and title == "" and  author == ""\
871                and  subject == "" and keywords == "":
872                 setupstart = ""
873                 setupend = ""
874             # write the preamble
875             add_to_preamble(document,
876                                 ['% Commands inserted by lyx2lyx for PDF properties',
877                                  '\\usepackage[unicode=true'
878                                  + bookmarks
879                                  + breaklinks
880                                  + pdfborder
881                                  + backref
882                                  + pagebackref
883                                  + colorlinks
884                                  + pagemode
885                                  + ']\n'
886                                  ' {hyperref}\n'
887                                  + setupstart
888                                  + title
889                                  + author
890                                  + subject
891                                  + keywords
892                                  + otheroptions
893                                  + setupend])
894
895
896 def remove_inzip_options(document):
897     "Remove inzipName and embed options from the Graphics inset"
898     i = 0
899     while 1:
900         i = find_token(document.body, "\\begin_inset Graphics", i)
901         if i == -1:
902             return
903         j = find_end_of_inset(document.body, i + 1)
904         if j == -1:
905             # should not happen
906             document.warning("Malformed LyX document: Could not find end of graphics inset.")
907         # If there's a inzip param, just remove that
908         k = find_token(document.body, "\tinzipName", i + 1, j)
909         if k != -1:
910             del document.body[k]
911             # embed option must follow the inzipName option
912             del document.body[k+1]
913         i = i + 1
914
915
916 def convert_inset_command(document):
917     """
918         Convert:
919             \begin_inset LatexCommand cmd
920         to
921             \begin_inset CommandInset InsetType
922             LatexCommand cmd
923     """
924     i = 0
925     while 1:
926         i = find_token(document.body, "\\begin_inset LatexCommand", i)
927         if i == -1:
928             return
929         line = document.body[i]
930         r = re.compile(r'\\begin_inset LatexCommand (.*)$')
931         m = r.match(line)
932         cmdName = m.group(1)
933         insetName = ""
934         #this is adapted from factory.cpp
935         if cmdName[0:4].lower() == "cite":
936             insetName = "citation"
937         elif cmdName == "url" or cmdName == "htmlurl":
938             insetName = "url"
939         elif cmdName[-3:] == "ref":
940             insetName = "ref"
941         elif cmdName == "tableofcontents":
942             insetName = "toc"
943         elif cmdName == "printnomenclature":
944             insetName = "nomencl_print"
945         elif cmdName == "printindex":
946             insetName = "index_print"
947         else:
948             insetName = cmdName
949         insertion = ["\\begin_inset CommandInset " + insetName, "LatexCommand " + cmdName]
950         document.body[i : i+1] = insertion
951
952
953 def revert_inset_command(document):
954     """
955         Convert:
956             \begin_inset CommandInset InsetType
957             LatexCommand cmd
958         to
959             \begin_inset LatexCommand cmd
960         Some insets may end up being converted to insets earlier versions of LyX
961         will not be able to recognize. Not sure what to do about that.
962     """
963     i = 0
964     while 1:
965         i = find_token(document.body, "\\begin_inset CommandInset", i)
966         if i == -1:
967             return
968         nextline = document.body[i+1]
969         r = re.compile(r'LatexCommand\s+(.*)$')
970         m = r.match(nextline)
971         if not m:
972             document.warning("Malformed LyX document: Missing LatexCommand in " + document.body[i] + ".")
973             continue
974         cmdName = m.group(1)
975         insertion = ["\\begin_inset LatexCommand " + cmdName]
976         document.body[i : i+2] = insertion
977
978
979 def convert_wrapfig_options(document):
980     "Convert optional options for wrap floats (wrapfig)."
981     # adds the tokens "lines", "placement", and "overhang"
982     i = 0
983     while True:
984         i = find_token(document.body, "\\begin_inset Wrap figure", i)
985         if i == -1:
986             return
987         document.body.insert(i + 1, "lines 0")
988         j = find_token(document.body, "placement", i)
989         # placement can be already set or not; if not, set it
990         if j == i+2:
991             document.body.insert(i + 3, "overhang 0col%")
992         else:
993            document.body.insert(i + 2, "placement o")
994            document.body.insert(i + 3, "overhang 0col%")
995         i = i + 1
996
997
998 def revert_wrapfig_options(document):
999     "Revert optional options for wrap floats (wrapfig)."
1000     i = 0
1001     while True:
1002         i = find_token(document.body, "\\begin_inset Wrap figure", i)
1003         if i == -1:
1004             return
1005         j = find_end_of_inset(document.body, i)
1006         if j == -1:
1007             document.warning("Can't find end of Wrap inset at line " + str(i))
1008             i += 1
1009             continue
1010         k = find_default_layout(document, i, j)
1011         if k == -1:
1012             document.warning("Can't find default layout for Wrap figure!")
1013             i = j
1014             continue
1015         # Options should be between i and k now
1016         l = find_token(document.body, "lines", i, k)
1017         if l == -1:
1018             document.warning("Can't find lines option for Wrap figure!")
1019             i = k
1020             continue
1021         m = find_token(document.body, "overhang", i + 1, k)
1022         if m == -1:
1023             document.warning("Malformed LyX document: Couldn't find overhang parameter of wrap float!")
1024             i = k
1025             continue
1026         # Do these in reverse order
1027         del document.body[m]
1028         del document.body[l]
1029         i = k
1030
1031
1032 def convert_latexcommand_index(document):
1033     "Convert from LatexCommand form to collapsable form."
1034     i = 0
1035     r1 = re.compile('name "(.*)"')
1036     while True:
1037         i = find_token(document.body, "\\begin_inset CommandInset index", i)
1038         if i == -1:
1039             return
1040         if document.body[i + 1] != "LatexCommand index": # Might also be index_print
1041             return
1042         m = r1.match(document.body[i + 2])
1043         if m == None:
1044             document.warning("Unable to match: " + document.body[i+2])
1045             i += 1
1046             continue
1047         fullcontent = m.group(1)
1048         #document.warning(fullcontent)
1049         document.body[i:i + 3] = ["\\begin_inset Index",
1050           "status collapsed",
1051           "\\begin_layout Standard"]
1052         i += 3
1053         # We are now on the blank line preceding "\end_inset"
1054         # We will write the content here, into the inset.
1055
1056         linelist = latex2lyx(fullcontent)
1057         document.body[i+1:i+1] = linelist
1058         i += len(linelist)
1059
1060         document.body.insert(i + 1, "\\end_layout")
1061         i += 1
1062
1063
1064 def revert_latexcommand_index(document):
1065     "Revert from collapsable form to LatexCommand form."
1066     i = 0
1067     while True:
1068         i = find_token(document.body, "\\begin_inset Index", i)
1069         if i == -1:
1070           return
1071         j = find_end_of_inset(document.body, i + 1)
1072         if j == -1:
1073           return
1074
1075         content = lyx2latex(document.body[i:j])
1076         # escape quotes
1077         content = content.replace('"', r'\"')
1078         document.body[i:j] = ["\\begin_inset CommandInset index", "LatexCommand index",
1079             "name " + '"' + content + '"', ""]
1080         i += 5
1081
1082
1083 def revert_wraptable(document):
1084     "Revert wrap table to wrap figure."
1085     i = 0
1086     while True:
1087         i = find_token(document.body, "\\begin_inset Wrap table", i)
1088         if i == -1:
1089             return
1090         document.body[i] = document.body[i].replace('\\begin_inset Wrap table', '\\begin_inset Wrap figure')
1091         i = i + 1
1092
1093
1094 def revert_vietnamese(document):
1095     "Set language Vietnamese to English"
1096     # Set document language from Vietnamese to English
1097     i = 0
1098     if document.language == "vietnamese":
1099         document.language = "english"
1100         i = find_token(document.header, "\\language", 0)
1101         if i != -1:
1102             document.header[i] = "\\language english"
1103     j = 0
1104     while True:
1105         j = find_token(document.body, "\\lang vietnamese", j)
1106         if j == -1:
1107             return
1108         document.body[j] = document.body[j].replace("\\lang vietnamese", "\\lang english")
1109         j = j + 1
1110
1111
1112 def convert_japanese_cjk(document):
1113     "Set language japanese to japanese-cjk"
1114     # Set document language from japanese-plain to japanese
1115     i = 0
1116     if document.language == "japanese":
1117         document.language = "japanese-cjk"
1118         i = find_token(document.header, "\\language", 0)
1119         if i != -1:
1120             document.header[i] = "\\language japanese-cjk"
1121     j = 0
1122     while True:
1123         j = find_token(document.body, "\\lang japanese", j)
1124         if j == -1:
1125             return
1126         document.body[j] = document.body[j].replace("\\lang japanese", "\\lang japanese-cjk")
1127         j = j + 1
1128
1129
1130 def revert_japanese(document):
1131     "Set language japanese-plain to japanese"
1132     # Set document language from japanese-plain to japanese
1133     i = 0
1134     if document.language == "japanese-plain":
1135         document.language = "japanese"
1136         i = find_token(document.header, "\\language", 0)
1137         if i != -1:
1138             document.header[i] = "\\language japanese"
1139     j = 0
1140     while True:
1141         j = find_token(document.body, "\\lang japanese-plain", j)
1142         if j == -1:
1143             return
1144         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
1145         j = j + 1
1146
1147
1148 def revert_japanese_cjk(document):
1149     "Set language japanese-cjk to japanese"
1150     # Set document language from japanese-plain to japanese
1151     i = 0
1152     if document.language == "japanese-cjk":
1153         document.language = "japanese"
1154         i = find_token(document.header, "\\language", 0)
1155         if i != -1:
1156             document.header[i] = "\\language japanese"
1157     j = 0
1158     while True:
1159         j = find_token(document.body, "\\lang japanese-cjk", j)
1160         if j == -1:
1161             return
1162         document.body[j] = document.body[j].replace("\\lang japanese-cjk", "\\lang japanese")
1163         j = j + 1
1164
1165
1166 def revert_japanese_encoding(document):
1167     "Set input encoding form EUC-JP-plain to EUC-JP etc."
1168     # Set input encoding form EUC-JP-plain to EUC-JP etc.
1169     i = 0
1170     i = find_token(document.header, "\\inputencoding EUC-JP-plain", 0)
1171     if i != -1:
1172         document.header[i] = "\\inputencoding EUC-JP"
1173     j = 0
1174     j = find_token(document.header, "\\inputencoding JIS-plain", 0)
1175     if j != -1:
1176         document.header[j] = "\\inputencoding JIS"
1177     k = 0
1178     k = find_token(document.header, "\\inputencoding SJIS-plain", 0)
1179     if k != -1: # convert to UTF8 since there is currently no SJIS encoding
1180         document.header[k] = "\\inputencoding UTF8"
1181
1182
1183 def revert_inset_info(document):
1184     'Replace info inset with its content'
1185     i = 0
1186     while 1:
1187         i = find_token(document.body, '\\begin_inset Info', i)
1188         if i == -1:
1189             return
1190         j = find_end_of_inset(document.body, i + 1)
1191         if j == -1:
1192             # should not happen
1193             document.warning("Malformed LyX document: Could not find end of Info inset.")
1194         type = 'unknown'
1195         arg = ''
1196         for k in range(i, j+1):
1197             if document.body[k].startswith("arg"):
1198                 arg = document.body[k][3:].strip().strip('"')
1199             if document.body[k].startswith("type"):
1200                 type = document.body[k][4:].strip().strip('"')
1201         # I think there is a newline after \\end_inset, which should be removed.
1202         if document.body[j + 1].strip() == "":
1203             document.body[i : (j + 2)] = [type + ':' + arg]
1204         else:
1205             document.body[i : (j + 1)] = [type + ':' + arg]
1206
1207
1208 def convert_pdf_options(document):
1209     # Set the pdfusetitle tag, delete the pdf_store_options,
1210     # set quotes for bookmarksopenlevel"
1211     has_hr = get_value(document.header, "\\use_hyperref", 0, default = "0")
1212     if has_hr == "1":
1213         k = find_token(document.header, "\\use_hyperref", 0)
1214         document.header.insert(k + 1, "\\pdf_pdfusetitle true")
1215     k = find_token(document.header, "\\pdf_store_options", 0)
1216     if k != -1:
1217         del document.header[k]
1218     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1219     if i == -1: return
1220     document.header[i] = document.header[i].replace('"', '')
1221
1222
1223 def revert_pdf_options_2(document):
1224     # reset the pdfusetitle tag, set quotes for bookmarksopenlevel"
1225     k = find_token(document.header, "\\use_hyperref", 0)
1226     i = find_token(document.header, "\\pdf_pdfusetitle", k)
1227     if i != -1:
1228         del document.header[i]
1229     i = find_token(document.header, "\\pdf_bookmarksopenlevel", k)
1230     if i == -1: return
1231     values = document.header[i].split()
1232     values[1] = ' "' + values[1] + '"'
1233     document.header[i] = ''.join(values)
1234
1235
1236 def convert_htmlurl(document):
1237     'Convert "htmlurl" to "href" insets for docbook'
1238     if document.backend != "docbook":
1239       return
1240     i = 0
1241     while True:
1242       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1243       if i == -1:
1244         return
1245       document.body[i] = "\\begin_inset CommandInset href"
1246       document.body[i + 1] = "LatexCommand href"
1247       i = i + 1
1248
1249
1250 def convert_url(document):
1251     'Convert url insets to url charstyles'
1252     if document.backend == "docbook":
1253       return
1254     i = 0
1255     while True:
1256       i = find_token(document.body, "\\begin_inset CommandInset url", i)
1257       if i == -1:
1258         break
1259       n = find_token(document.body, "name", i)
1260       if n == i + 2:
1261         # place the URL name in typewriter before the new URL insert
1262         # grab the name 'bla' from the e.g. the line 'name "bla"',
1263         # therefore start with the 6th character
1264         name = document.body[n][6:-1]
1265         newname = [name + " "]
1266         document.body[i:i] = newname
1267         i = i + 1
1268       j = find_token(document.body, "target", i)
1269       if j == -1:
1270         document.warning("Malformed LyX document: Can't find target for url inset")
1271         i = j
1272         continue
1273       target = document.body[j][8:-1]
1274       k = find_token(document.body, "\\end_inset", j)
1275       if k == -1:
1276         document.warning("Malformed LyX document: Can't find end of url inset")
1277         i = k
1278         continue
1279       newstuff = ["\\begin_inset Flex URL",
1280         "status collapsed", "",
1281         "\\begin_layout Standard",
1282         "",
1283         target,
1284         "\\end_layout",
1285         ""]
1286       document.body[i:k] = newstuff
1287       i = k
1288
1289 def convert_ams_classes(document):
1290   tc = document.textclass
1291   if (tc != "amsart" and tc != "amsart-plain" and
1292       tc != "amsart-seq" and tc != "amsbook"):
1293     return
1294   if tc == "amsart-plain":
1295     document.textclass = "amsart"
1296     document.set_textclass()
1297     document.add_module("Theorems (Starred)")
1298     return
1299   if tc == "amsart-seq":
1300     document.textclass = "amsart"
1301     document.set_textclass()
1302   document.add_module("Theorems (AMS)")
1303
1304   #Now we want to see if any of the environments in the extended theorems
1305   #module were used in this document. If so, we'll add that module, too.
1306   layouts = ["Criterion", "Algorithm", "Axiom", "Condition", "Note",  \
1307     "Notation", "Summary", "Acknowledgement", "Conclusion", "Fact", \
1308     "Assumption"]
1309
1310   r = re.compile(r'^\\begin_layout (.*?)\*?\s*$')
1311   i = 0
1312   while True:
1313     i = find_token(document.body, "\\begin_layout", i)
1314     if i == -1:
1315       return
1316     m = r.match(document.body[i])
1317     if m == None:
1318       # This is an empty layout
1319       # document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1320       i += 1
1321       continue
1322     m = m.group(1)
1323     if layouts.count(m) != 0:
1324       document.add_module("Theorems (AMS-Extended)")
1325       return
1326     i += 1
1327
1328 def revert_href(document):
1329     'Reverts hyperlink insets (href) to url insets (url)'
1330     i = 0
1331     while True:
1332       i = find_token(document.body, "\\begin_inset CommandInset href", i)
1333       if i == -1:
1334           return
1335       document.body[i : i + 2] = \
1336         ["\\begin_inset CommandInset url", "LatexCommand url"]
1337       i = i + 2
1338
1339 def revert_url(document):
1340     'Reverts Flex URL insets to old-style URL insets'
1341     i = 0
1342     while True:
1343         i = find_token(document.body, "\\begin_inset Flex URL", i)
1344         if i == -1:
1345             return
1346         j = find_end_of_inset(document.body, i)
1347         if j == -1:
1348             document.warning("Can't find end of inset in revert_url!")
1349             return
1350         k = find_default_layout(document, i, j)
1351         if k == -1:
1352             document.warning("Can't find default layout in revert_url!")
1353             i = j
1354             continue
1355         l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1356         if l == -1 or l >= j:
1357             document.warning("Can't find end of default layout in revert_url!")
1358             i = j
1359             continue
1360         # OK, so the inset's data is between lines k and l.
1361         data =  " ".join(document.body[k+1:l])
1362         data = data.strip()
1363         newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1364                     "", "\\end_inset"]
1365         document.body[i:j+1] = newinset
1366         i = i + len(newinset)
1367
1368
1369 def convert_include(document):
1370   'Converts include insets to new format.'
1371   i = 0
1372   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1373   while True:
1374     i = find_token(document.body, "\\begin_inset Include", i)
1375     if i == -1:
1376       return
1377     line = document.body[i]
1378     previewline = document.body[i + 1]
1379     m = r.match(line)
1380     if m == None:
1381       document.warning("Unable to match line " + str(i) + " of body!")
1382       i += 1
1383       continue
1384     cmd = m.group(1)
1385     fn  = m.group(2)
1386     opt = m.group(3)
1387     insertion = ["\\begin_inset CommandInset include",
1388        "LatexCommand " + cmd, previewline,
1389        "filename \"" + fn + "\""]
1390     newlines = 2
1391     if opt:
1392       insertion.append("lstparams " + '"' + opt + '"')
1393       newlines += 1
1394     document.body[i : i + 2] = insertion
1395     i += newlines
1396
1397
1398 def revert_include(document):
1399   'Reverts include insets to old format.'
1400   i = 0
1401   r0 = re.compile('preview.*')
1402   r1 = re.compile('LatexCommand (.+)')
1403   r2 = re.compile('filename "(.+)"')
1404   r3 = re.compile('lstparams "(.*)"')
1405   while True:
1406     i = find_token(document.body, "\\begin_inset CommandInset include", i)
1407     if i == -1:
1408       return
1409     nextline = i + 1
1410     if r0.match(document.body[nextline]):
1411       previewline = document.body[nextline]
1412       nextline += 1
1413     else:
1414       previewline = ""
1415     m = r1.match(document.body[nextline])
1416     if m == None:
1417       document.warning("Malformed LyX document: No LatexCommand line for `" +
1418         document.body[i] + "' on line " + str(i) + ".")
1419       i += 1
1420       continue
1421     cmd = m.group(1)
1422     nextline += 1
1423     m = r2.match(document.body[nextline])
1424     if m == None:
1425       document.warning("Malformed LyX document: No filename line for `" + \
1426         document.body[i] + "' on line " + str(i) + ".")
1427       i += 2
1428       continue
1429     fn = m.group(1)
1430     nextline += 1
1431     options = ""
1432     if (cmd == "lstinputlisting"):
1433       m = r3.match(document.body[nextline])
1434       if m != None:
1435         options = m.group(1)
1436         numlines = 5
1437         nextline += 1
1438     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1439     if options:
1440       newline += ("[" + options + "]")
1441     insertion = [newline]
1442     if previewline != "":
1443       insertion.append(previewline)
1444     document.body[i : nextline] = insertion
1445     i += 2
1446
1447
1448 def revert_albanian(document):
1449     "Set language Albanian to English"
1450     i = 0
1451     if document.language == "albanian":
1452         document.language = "english"
1453         i = find_token(document.header, "\\language", 0)
1454         if i != -1:
1455             document.header[i] = "\\language english"
1456     j = 0
1457     while True:
1458         j = find_token(document.body, "\\lang albanian", j)
1459         if j == -1:
1460             return
1461         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1462         j = j + 1
1463
1464
1465 def revert_lowersorbian(document):
1466     "Set language lower Sorbian to English"
1467     i = 0
1468     if document.language == "lowersorbian":
1469         document.language = "english"
1470         i = find_token(document.header, "\\language", 0)
1471         if i != -1:
1472             document.header[i] = "\\language english"
1473     j = 0
1474     while True:
1475         j = find_token(document.body, "\\lang lowersorbian", j)
1476         if j == -1:
1477             return
1478         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1479         j = j + 1
1480
1481
1482 def revert_uppersorbian(document):
1483     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1484     i = 0
1485     if document.language == "uppersorbian":
1486         document.language = "usorbian"
1487         i = find_token(document.header, "\\language", 0)
1488         if i != -1:
1489             document.header[i] = "\\language usorbian"
1490     j = 0
1491     while True:
1492         j = find_token(document.body, "\\lang uppersorbian", j)
1493         if j == -1:
1494             return
1495         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1496         j = j + 1
1497
1498
1499 def convert_usorbian(document):
1500     "Set language usorbian to uppersorbian"
1501     i = 0
1502     if document.language == "usorbian":
1503         document.language = "uppersorbian"
1504         i = find_token(document.header, "\\language", 0)
1505         if i != -1:
1506             document.header[i] = "\\language uppersorbian"
1507     j = 0
1508     while True:
1509         j = find_token(document.body, "\\lang usorbian", j)
1510         if j == -1:
1511             return
1512         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1513         j = j + 1
1514
1515
1516 def revert_macro_optional_params(document):
1517     "Convert macro definitions with optional parameters into ERTs"
1518     # Stub to convert macro definitions with one or more optional parameters
1519     # into uninterpreted ERT insets
1520
1521
1522 def revert_hyperlinktype(document):
1523     'Reverts hyperlink type'
1524     i = 0
1525     j = 0
1526     while True:
1527       i = find_token(document.body, "target", i)
1528       if i == -1:
1529           return
1530       j = find_token(document.body, "type", i)
1531       if j == -1:
1532           return
1533       if j == i + 1:
1534           del document.body[j]
1535       i = i + 1
1536
1537
1538 def revert_pagebreak(document):
1539     'Reverts pagebreak to ERT'
1540     i = 0
1541     while True:
1542       i = find_token(document.body, "\\pagebreak", i)
1543       if i == -1:
1544           return
1545       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1546       '\\begin_layout Standard\n\n\n\\backslash\n' \
1547       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1548       i = i + 1
1549
1550
1551 def revert_linebreak(document):
1552     'Reverts linebreak to ERT'
1553     i = 0
1554     while True:
1555       i = find_token(document.body, "\\linebreak", i)
1556       if i == -1:
1557           return
1558       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1559       '\\begin_layout Standard\n\n\n\\backslash\n' \
1560       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1561       i = i + 1
1562
1563
1564 def revert_latin(document):
1565     "Set language Latin to English"
1566     i = 0
1567     if document.language == "latin":
1568         document.language = "english"
1569         i = find_token(document.header, "\\language", 0)
1570         if i != -1:
1571             document.header[i] = "\\language english"
1572     j = 0
1573     while True:
1574         j = find_token(document.body, "\\lang latin", j)
1575         if j == -1:
1576             return
1577         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1578         j = j + 1
1579
1580
1581 def revert_samin(document):
1582     "Set language North Sami to English"
1583     i = 0
1584     if document.language == "samin":
1585         document.language = "english"
1586         i = find_token(document.header, "\\language", 0)
1587         if i != -1:
1588             document.header[i] = "\\language english"
1589     j = 0
1590     while True:
1591         j = find_token(document.body, "\\lang samin", j)
1592         if j == -1:
1593             return
1594         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1595         j = j + 1
1596
1597
1598 def convert_serbocroatian(document):
1599     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1600     i = 0
1601     if document.language == "serbocroatian":
1602         document.language = "croatian"
1603         i = find_token(document.header, "\\language", 0)
1604         if i != -1:
1605             document.header[i] = "\\language croatian"
1606     j = 0
1607     while True:
1608         j = find_token(document.body, "\\lang serbocroatian", j)
1609         if j == -1:
1610             return
1611         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1612         j = j + 1
1613
1614
1615 def convert_framed_notes(document):
1616     "Convert framed notes to boxes. "
1617     i = 0
1618     while 1:
1619         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1620         if i == -1:
1621             return
1622         subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1623                  'position "t"',
1624                  'hor_pos "c"',
1625                  'has_inner_box 0',
1626                  'inner_pos "t"',
1627                  'use_parbox 0',
1628                  'width "100col%"',
1629                  'special "none"',
1630                  'height "1in"',
1631                  'height_special "totalheight"']
1632         document.body[i:i+1] = subst
1633         i = i + 9
1634
1635
1636 def convert_module_names(document):
1637   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1638     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1639     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1640     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1641     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1642   modlist = document.get_module_list()
1643   if len(modlist) == 0:
1644     return
1645   newmodlist = []
1646   for mod in modlist:
1647     if modulemap.has_key(mod):
1648       newmodlist.append(modulemap[mod])
1649     else:
1650       document.warning("Can't find module %s in the module map!" % mod)
1651       newmodlist.append(mod)
1652   document.set_module_list(newmodlist)
1653
1654
1655 def revert_module_names(document):
1656   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1657     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1658     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1659     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1660     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1661   modlist = document.get_module_list()
1662   if len(modlist) == 0:
1663     return
1664   newmodlist = []
1665   for mod in modlist:
1666     if modulemap.has_key(mod):
1667       newmodlist.append(modulemap[mod])
1668     else:
1669       document.warning("Can't find module %s in the module map!" % mod)
1670       newmodlist.append(mod)
1671   document.set_module_list(newmodlist)
1672
1673
1674 def revert_colsep(document):
1675     i = find_token(document.header, "\\columnsep", 0)
1676     if i == -1:
1677         return
1678     colsepline = document.header[i]
1679     r = re.compile(r'\\columnsep (.*)')
1680     m = r.match(colsepline)
1681     if not m:
1682         document.warning("Malformed column separation line!")
1683         return
1684     colsep = m.group(1)
1685     del document.header[i]
1686     #it seems to be safe to add the package even if it is already used
1687     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1688
1689     add_to_preamble(document, pretext)
1690
1691
1692 def revert_framed_notes(document):
1693     "Revert framed boxes to notes. "
1694     i = 0
1695     while 1:
1696         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1697
1698         if i == -1:
1699             return
1700         j = find_end_of_inset(document.body, i + 1)
1701         if j == -1:
1702             # should not happen
1703             document.warning("Malformed LyX document: Could not find end of Box inset.")
1704         k = find_token(document.body, "status", i + 1, j)
1705         if k == -1:
1706             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1707             return
1708         status = document.body[k]
1709         l = find_default_layout(document, i + 1, j)
1710         if l == -1:
1711             document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1712             return
1713         m = find_token(document.body, "\\end_layout", i + 1, j)
1714         if m == -1:
1715             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1716             return
1717         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1718         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1719         if ibox == -1 and pbox == -1:
1720             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1721             del document.body[i+1:k]
1722         else:
1723             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1724             subst1 = [document.body[l],
1725                       "\\begin_inset Note Shaded",
1726                       status,
1727                       '\\begin_layout Standard']
1728             document.body[l:l + 1] = subst1
1729             subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1730             document.body[m:m + 1] = subst2
1731         i = i + 1
1732
1733
1734 def revert_slash(document):
1735     'Revert \\SpecialChar \\slash{} to ERT'
1736     r = re.compile(r'\\SpecialChar \\slash{}')
1737     i = 0
1738     while i < len(document.body):
1739         m = r.match(document.body[i])
1740         if m:
1741           subst = ['\\begin_inset ERT',
1742                    'status collapsed', '',
1743                    '\\begin_layout Standard',
1744                    '', '', '\\backslash',
1745                    'slash{}',
1746                    '\\end_layout', '',
1747                    '\\end_inset', '']
1748           document.body[i: i+1] = subst
1749           i = i + len(subst)
1750         else:
1751           i = i + 1
1752
1753
1754 def revert_nobreakdash(document):
1755     'Revert \\SpecialChar \\nobreakdash- to ERT'
1756     i = 0
1757     while i < len(document.body):
1758         line = document.body[i]
1759         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1760         m = r.match(line)
1761         if m:
1762             subst = ['\\begin_inset ERT',
1763                     'status collapsed', '',
1764                     '\\begin_layout Standard', '', '',
1765                     '\\backslash',
1766                     'nobreakdash-',
1767                     '\\end_layout', '',
1768                     '\\end_inset', '']
1769             document.body[i:i+1] = subst
1770             i = i + len(subst)
1771             j = find_token(document.header, "\\use_amsmath", 0)
1772             if j == -1:
1773                 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1774                 return
1775             document.header[j] = "\\use_amsmath 2"
1776         else:
1777             i = i + 1
1778
1779
1780 #Returns number of lines added/removed
1781 def revert_nocite_key(body, start, end):
1782     'key "..." -> \nocite{...}'
1783     r = re.compile(r'^key "(.*)"')
1784     i = start
1785     j = end
1786     while i < j:
1787         m = r.match(body[i])
1788         if m:
1789             body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1790             j += 1     # because we added a line
1791             i += 2     # skip that line
1792         else:
1793             del body[i]
1794             j -= 1     # because we deleted a line
1795             # no need to change i, since it now points to the next line
1796     return j - end
1797
1798
1799 def revert_nocite(document):
1800     "Revert LatexCommand nocite to ERT"
1801     i = 0
1802     while 1:
1803         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1804         if i == -1:
1805             return
1806         if (document.body[i+1] != "LatexCommand nocite"):
1807             # note that we already incremented i
1808             i = i + 1
1809             continue
1810         insetEnd = find_end_of_inset(document.body, i)
1811         if insetEnd == -1:
1812             #this should not happen
1813             document.warning("End of CommandInset citation not found in revert_nocite!")
1814             return
1815
1816         paramLocation = i + 2 #start of the inset's parameters
1817         addedLines = 0
1818         document.body[i:i+2] = \
1819             ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1820         # that added two lines
1821         paramLocation += 2
1822         insetEnd += 2
1823         #print insetEnd, document.body[i: insetEnd + 1]
1824         insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1825         #print insetEnd, document.body[i: insetEnd + 1]
1826         document.body.insert(insetEnd, "\\end_layout")
1827         document.body.insert(insetEnd + 1, "")
1828         i = insetEnd + 1
1829
1830
1831 def revert_btprintall(document):
1832     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1833     i = find_token(document.header, '\\use_bibtopic', 0)
1834     if i == -1:
1835         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1836         return
1837     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1838         i = 0
1839         while i < len(document.body):
1840             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1841             if i == -1:
1842                 return
1843             j = find_end_of_inset(document.body, i + 1)
1844             if j == -1:
1845                 #this should not happen
1846                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1847                 j = len(document.body)
1848             # this range isn't really right, but it should be OK, since we shouldn't
1849             # see more than one matching line in each inset
1850             addedlines = 0
1851             for k in range(i, j):
1852                 if (document.body[k] == 'btprint "btPrintAll"'):
1853                     del document.body[k]
1854                     subst = ["\\begin_inset ERT",
1855                              "status collapsed", "",
1856                              "\\begin_layout Standard", "",
1857                              "\\backslash",
1858                              "nocite{*}",
1859                              "\\end_layout",
1860                              "\\end_inset"]
1861                     document.body[i:i] = subst
1862                     addlines = addedlines + len(subst) - 1
1863             i = j + addedlines
1864
1865
1866 def revert_bahasam(document):
1867     "Set language Bahasa Malaysia to Bahasa Indonesia"
1868     i = 0
1869     if document.language == "bahasam":
1870         document.language = "bahasa"
1871         i = find_token(document.header, "\\language", 0)
1872         if i != -1:
1873             document.header[i] = "\\language bahasa"
1874     j = 0
1875     while True:
1876         j = find_token(document.body, "\\lang bahasam", j)
1877         if j == -1:
1878             return
1879         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1880         j = j + 1
1881
1882
1883 def revert_interlingua(document):
1884     "Set language Interlingua to English"
1885     i = 0
1886     if document.language == "interlingua":
1887         document.language = "english"
1888         i = find_token(document.header, "\\language", 0)
1889         if i != -1:
1890             document.header[i] = "\\language english"
1891     j = 0
1892     while True:
1893         j = find_token(document.body, "\\lang interlingua", j)
1894         if j == -1:
1895             return
1896         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1897         j = j + 1
1898
1899
1900 def revert_serbianlatin(document):
1901     "Set language Serbian-Latin to Croatian"
1902     i = 0
1903     if document.language == "serbian-latin":
1904         document.language = "croatian"
1905         i = find_token(document.header, "\\language", 0)
1906         if i != -1:
1907             document.header[i] = "\\language croatian"
1908     j = 0
1909     while True:
1910         j = find_token(document.body, "\\lang serbian-latin", j)
1911         if j == -1:
1912             return
1913         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1914         j = j + 1
1915
1916
1917 def revert_rotfloat(document):
1918     " Revert sideways custom floats. "
1919     i = 0
1920     while 1:
1921         # whitespace intended (exclude \\begin_inset FloatList)
1922         i = find_token(document.body, "\\begin_inset Float ", i)
1923         if i == -1:
1924             return
1925         line = document.body[i]
1926         r = re.compile(r'\\begin_inset Float (.*)$')
1927         m = r.match(line)
1928         if m == None:
1929             document.warning("Unable to match line " + str(i) + " of body!")
1930             i += 1
1931             continue
1932         floattype = m.group(1)
1933         if floattype == "figure" or floattype == "table":
1934             i += 1
1935             continue
1936         j = find_end_of_inset(document.body, i)
1937         if j == -1:
1938             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1939             i += 1
1940             continue
1941         addedLines = 0
1942         if get_value(document.body, 'sideways', i, j) == "false":
1943             i += 1
1944             continue
1945         l = find_default_layout(document, i + 1, j)
1946         if l == -1:
1947             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1948             return
1949         subst = ['\\begin_layout Standard',
1950                   '\\begin_inset ERT',
1951                   'status collapsed', '',
1952                   '\\begin_layout Standard', '', '',
1953                   '\\backslash', '',
1954                   'end{sideways' + floattype + '}',
1955                   '\\end_layout', '', '\\end_inset']
1956         document.body[j : j+1] = subst
1957         addedLines = len(subst) - 1
1958         del document.body[i+1 : l]
1959         addedLines -= (l-1) - (i+1)
1960         subst = ['\\begin_inset ERT', 'status collapsed', '',
1961                   '\\begin_layout Standard', '', '', '\\backslash',
1962                   'begin{sideways' + floattype + '}',
1963                   '\\end_layout', '', '\\end_inset', '',
1964                   '\\end_layout', '']
1965         document.body[i : i+1] = subst
1966         addedLines += len(subst) - 1
1967         if floattype == "algorithm":
1968             add_to_preamble(document,
1969                             ['% Commands inserted by lyx2lyx for sideways algorithm float',
1970                               '\\usepackage{rotfloat}',
1971                               '\\floatstyle{ruled}',
1972                               '\\newfloat{algorithm}{tbp}{loa}',
1973                               '\\floatname{algorithm}{Algorithm}'])
1974         else:
1975             document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1976         i += addedLines + 1
1977
1978
1979 def revert_widesideways(document):
1980     " Revert wide sideways floats. "
1981     i = 0
1982     while 1:
1983         # whitespace intended (exclude \\begin_inset FloatList)
1984         i = find_token(document.body, '\\begin_inset Float ', i)
1985         if i == -1:
1986             return
1987         line = document.body[i]
1988         r = re.compile(r'\\begin_inset Float (.*)$')
1989         m = r.match(line)
1990         if m == None:
1991             document.warning("Unable to match line " + str(i) + " of body!")
1992             i += 1
1993             continue
1994         floattype = m.group(1)
1995         if floattype != "figure" and floattype != "table":
1996             i += 1
1997             continue
1998         j = find_end_of_inset(document.body, i)
1999         if j == -1:
2000             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2001             i += 1
2002             continue
2003         if get_value(document.body, 'sideways', i, j) == "false" or \
2004            get_value(document.body, 'wide', i, j) == "false":
2005              i += 1
2006              continue
2007         l = find_default_layout(document, i + 1, j)
2008         if l == -1:
2009             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2010             return
2011         subst = ['\\begin_layout Standard', '\\begin_inset ERT',
2012                   'status collapsed', '',
2013                   '\\begin_layout Standard', '', '', '\\backslash',
2014                   'end{sideways' + floattype + '*}',
2015                   '\\end_layout', '', '\\end_inset']
2016         document.body[j : j+1] = subst
2017         addedLines = len(subst) - 1
2018         del document.body[i+1:l-1]
2019         addedLines -= (l-1) - (i+1)
2020         subst = ['\\begin_inset ERT', 'status collapsed', '',
2021                  '\\begin_layout Standard', '', '', '\\backslash',
2022                  'begin{sideways' + floattype + '*}', '\\end_layout', '',
2023                  '\\end_inset', '', '\\end_layout', '']
2024         document.body[i : i+1] = subst
2025         addedLines += len(subst) - 1
2026         add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2027         i += addedLines + 1
2028
2029
2030 def revert_inset_embedding(document, type):
2031     ' Remove embed tag from certain type of insets'
2032     i = 0
2033     while 1:
2034         i = find_token(document.body, "\\begin_inset %s" % type, i)
2035         if i == -1:
2036             return
2037         j = find_end_of_inset(document.body, i)
2038         if j == -1:
2039             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2040             i = i + 1
2041             continue
2042         k = find_token(document.body, "\tembed", i, j)
2043         if k == -1:
2044             k = find_token(document.body, "embed", i, j)
2045         if k != -1:
2046             del document.body[k]
2047         i = i + 1
2048
2049
2050 def revert_external_embedding(document):
2051     ' Remove embed tag from external inset '
2052     revert_inset_embedding(document, 'External')
2053
2054
2055 def convert_subfig(document):
2056     " Convert subfigures to subfloats. "
2057     i = 0
2058     while 1:
2059         i = find_token(document.body, '\\begin_inset Graphics', i)
2060         if i == -1:
2061             return
2062         endInset = find_end_of_inset(document.body, i)
2063         if endInset == -1:
2064             document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2065             i += 1
2066             continue
2067         k = find_token(document.body, '\tsubcaption', i, endInset)
2068         if k == -1:
2069             i = endInset
2070             continue
2071         l = find_token(document.body, '\tsubcaptionText', i, endInset)
2072         if l == -1:
2073             document.warning("Malformed lyx document: Can't find subcaptionText!")
2074             i = endInset
2075             continue
2076         caption = document.body[l][16:].strip('"')
2077         del document.body[l]
2078         del document.body[k]
2079         addedLines = -2
2080         subst = ['\\begin_inset Float figure', 'wide false', 'sideways false',
2081                  'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption',
2082                  '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2083                  [ '\\end_layout', '', '\\end_inset', '',
2084                  '\\end_layout', '', '\\begin_layout Plain Layout']
2085         document.body[i : i] = subst
2086         addedLines += len(subst)
2087         endInset += addedLines
2088         subst = ['', '\\end_inset', '', '\\end_layout']
2089         document.body[endInset : endInset] = subst
2090         addedLines += len(subst)
2091         i += addedLines + 1
2092
2093
2094 def revert_subfig(document):
2095     " Revert subfloats. "
2096     i = 0
2097     while 1:
2098         # whitespace intended (exclude \\begin_inset FloatList)
2099         i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2100         if i == -1:
2101             return
2102         j = 0
2103         addedLines = 0
2104         while j != -1:
2105             j = find_end_of_inset(document.body, i)
2106             if j == -1:
2107                 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2108                 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2109                 i += 1
2110                 continue # this will get us back to the outer loop, since j == -1
2111             # look for embedded float (= subfloat)
2112             # whitespace intended (exclude \\begin_inset FloatList)
2113             k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2114             if k == -1:
2115                 break
2116             l = find_end_of_inset(document.body, k)
2117             if l == -1:
2118                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2119                 i += 1
2120                 j == -1
2121                 continue # escape to the outer loop
2122             m = find_default_layout(document, k + 1, l)
2123             # caption?
2124             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2125             caption = ''
2126             shortcap = ''
2127             capend = cap
2128             if cap != -1:
2129                 capend = find_end_of_inset(document.body, cap)
2130                 if capend == -1:
2131                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2132                     return
2133                 # label?
2134                 label = ''
2135                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2136                 if lbl != -1:
2137                     lblend = find_end_of_inset(document.body, lbl + 1)
2138                     if lblend == -1:
2139                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2140                         return
2141                     for line in document.body[lbl:lblend + 1]:
2142                         if line.startswith('name '):
2143                             label = line.split()[1].strip('"')
2144                             break
2145                 else:
2146                     lbl = capend
2147                     lblend = capend
2148                     label = ''
2149                 # opt arg?
2150                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2151                 if opt != -1:
2152                     optend = find_end_of_inset(document.body, opt)
2153                     if optend == -1:
2154                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2155                         return
2156                     optc = find_default_layout(document, opt, optend)
2157                     if optc == -1:
2158                         document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2159                         return
2160                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2161                     for line in document.body[optc:optcend]:
2162                         if not line.startswith('\\'):
2163                             shortcap += line.strip()
2164                 else:
2165                     opt = capend
2166                     optend = capend
2167                 for line in document.body[cap:capend]:
2168                     if line in document.body[lbl:lblend]:
2169                         continue
2170                     elif line in document.body[opt:optend]:
2171                         continue
2172                     elif not line.startswith('\\'):
2173                         caption += line.strip()
2174                 if len(label) > 0:
2175                     caption += "\\backslash\nlabel{" + label + "}"
2176             subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2177                       '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
2178                       '\\end_layout\n\n\\begin_layout Plain Layout\n'
2179             subst = subst.split('\n')
2180             document.body[l : l+1] = subst
2181             addedLines = len(subst) - 1
2182             # this is before l and so is unchanged by the multiline insertion
2183             if cap != capend:
2184                 del document.body[cap:capend+1]
2185                 addedLines -= (capend + 1 - cap)
2186             del document.body[k+1:m-1]
2187             addedLines -= (m - 1 - (k + 1))
2188             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2189                         '\\begin_layout Plain Layout\n\n\\backslash\n' \
2190                         'subfloat'
2191             if len(shortcap) > 0:
2192                 insertion = insertion + "[" + shortcap + "]"
2193             if len(caption) > 0:
2194                 insertion = insertion + "[" + caption + "]"
2195             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2196             insertion = insertion.split('\n')
2197             document.body[k : k + 1] = insertion
2198             addedLines += len(insertion) - 1
2199             add_to_preamble(document, ['\\usepackage{subfig}\n'])
2200         i += addedLines + 1
2201
2202
2203 def revert_wrapplacement(document):
2204     " Revert placement options wrap floats (wrapfig). "
2205     i = 0
2206     while True:
2207         i = find_token(document.body, "\\begin_inset Wrap figure", i)
2208         if i == -1:
2209             return
2210         e = find_end_of_inset(document.body, i)
2211         j = find_token(document.body, "placement", i + 1, e)
2212         if j == -1:
2213             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2214             i += 1
2215             continue
2216         r = re.compile("placement (o|i|l|r)")
2217         m = r.match(document.body[j])
2218         if m == None:
2219             document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2220         document.body[j] = "placement " + m.group(1).lower()
2221         i = j
2222
2223
2224 def remove_extra_embedded_files(document):
2225     " Remove \extra_embedded_files from buffer params "
2226     i = find_token(document.header, '\\extra_embedded_files', 0)
2227     if i == -1:
2228         return
2229     document.header.pop(i)
2230
2231
2232 def convert_spaceinset(document):
2233     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2234     i = 0
2235     while i < len(document.body):
2236         m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2237         if m:
2238             before = m.group(1)
2239             after = m.group(2)
2240             subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2241             document.body[i: i+1] = subst
2242             i = i + len(subst)
2243         else:
2244             i = i + 1
2245
2246
2247 def revert_spaceinset(document):
2248     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2249     i = 0
2250     while True:
2251         i = find_token(document.body, "\\begin_inset Space", i)
2252         if i == -1:
2253             return
2254         j = find_end_of_inset(document.body, i)
2255         if j == -1:
2256             document.warning("Malformed LyX document: Could not find end of space inset.")
2257             continue
2258         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2259         del document.body[j]
2260
2261
2262 def convert_hfill(document):
2263     " Convert hfill to space inset "
2264     i = 0
2265     while True:
2266         i = find_token(document.body, "\\hfill", i)
2267         if i == -1:
2268             return
2269         subst = document.body[i].replace('\\hfill', \
2270                   '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2271         subst = subst.split('\n')
2272         document.body[i : i+1] = subst
2273         i += len(subst)
2274
2275
2276 def revert_hfills(document):
2277     ' Revert \\hfill commands '
2278     hfill = re.compile(r'\\hfill')
2279     dotfill = re.compile(r'\\dotfill')
2280     hrulefill = re.compile(r'\\hrulefill')
2281     i = 0
2282     while True:
2283         i = find_token(document.body, "\\InsetSpace", i)
2284         if i == -1:
2285             return
2286         if hfill.search(document.body[i]):
2287             document.body[i] = \
2288               document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2289             i += 1
2290             continue
2291         if dotfill.search(document.body[i]):
2292             subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2293               '\\begin_inset ERT\nstatus collapsed\n\n' \
2294               '\\begin_layout Standard\n\n\n\\backslash\n' \
2295               'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2296             subst = subst.split('\n')
2297             document.body[i : i+1] = subst
2298             i += len(subst)
2299             continue
2300         if hrulefill.search(document.body[i]):
2301             subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2302               '\\begin_inset ERT\nstatus collapsed\n\n' \
2303               '\\begin_layout Standard\n\n\n\\backslash\n' \
2304               'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2305             subst = subst.split('\n')
2306             document.body[i : i+1] = subst
2307             i += len(subst)
2308             continue
2309         i += 1
2310
2311 def revert_hspace(document):
2312     ' Revert \\InsetSpace \\hspace{} to ERT '
2313     i = 0
2314     hspace = re.compile(r'\\hspace{}')
2315     hstar  = re.compile(r'\\hspace\*{}')
2316     while True:
2317         i = find_token(document.body, "\\InsetSpace \\hspace", i)
2318         if i == -1:
2319             return
2320         length = get_value(document.body, '\\length', i+1)
2321         if length == '':
2322             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2323             return
2324         del document.body[i+1]
2325         addedLines = -1
2326         if hstar.search(document.body[i]):
2327             subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2328               '\\begin_inset ERT\nstatus collapsed\n\n' \
2329               '\\begin_layout Standard\n\n\n\\backslash\n' \
2330               'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2331             subst = subst.split('\n')
2332             document.body[i : i+1] = subst
2333             addedLines += len(subst) - 1
2334             i += addedLines + 1
2335             continue
2336         if hspace.search(document.body[i]):
2337             subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2338               '\\begin_inset ERT\nstatus collapsed\n\n' \
2339               '\\begin_layout Standard\n\n\n\\backslash\n' \
2340               'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2341             subst = subst.split('\n')
2342             document.body[i : i+1] = subst
2343             addedLines += len(subst) - 1
2344             i += addedLines + 1
2345             continue
2346         i += 1
2347
2348
2349 def revert_protected_hfill(document):
2350     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2351     i = 0
2352     while True:
2353         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2354         if i == -1:
2355             return
2356         j = find_end_of_inset(document.body, i)
2357         if j == -1:
2358             document.warning("Malformed LyX document: Could not find end of space inset.")
2359             continue
2360         del document.body[j]
2361         subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2362           '\\begin_inset ERT\nstatus collapsed\n\n' \
2363           '\\begin_layout Standard\n\n\n\\backslash\n' \
2364           'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2365         subst = subst.split('\n')
2366         document.body[i : i+1] = subst
2367         i += len(subst)
2368
2369
2370 def revert_leftarrowfill(document):
2371     ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2372     i = 0
2373     while True:
2374         i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2375         if i == -1:
2376             return
2377         j = find_end_of_inset(document.body, i)
2378         if j == -1:
2379             document.warning("Malformed LyX document: Could not find end of space inset.")
2380             continue
2381         del document.body[j]
2382         subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2383           '\\begin_inset ERT\nstatus collapsed\n\n' \
2384           '\\begin_layout Standard\n\n\n\\backslash\n' \
2385           'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2386         subst = subst.split('\n')
2387         document.body[i : i+1] = subst
2388         i += len(subst)
2389
2390
2391 def revert_rightarrowfill(document):
2392     ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2393     i = 0
2394     while True:
2395         i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2396         if i == -1:
2397             return
2398         j = find_end_of_inset(document.body, i)
2399         if j == -1:
2400             document.warning("Malformed LyX document: Could not find end of space inset.")
2401             continue
2402         del document.body[j]
2403         subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2404           '\\begin_inset ERT\nstatus collapsed\n\n' \
2405           '\\begin_layout Standard\n\n\n\\backslash\n' \
2406           'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2407         subst = subst.split('\n')
2408         document.body[i : i+1] = subst
2409         i += len(subst)
2410
2411
2412 def revert_upbracefill(document):
2413     ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2414     i = 0
2415     while True:
2416         i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2417         if i == -1:
2418             return
2419         j = find_end_of_inset(document.body, i)
2420         if j == -1:
2421             document.warning("Malformed LyX document: Could not find end of space inset.")
2422             continue
2423         del document.body[j]
2424         subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2425           '\\begin_inset ERT\nstatus collapsed\n\n' \
2426           '\\begin_layout Standard\n\n\n\\backslash\n' \
2427           'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2428         subst = subst.split('\n')
2429         document.body[i : i+1] = subst
2430         i += len(subst)
2431
2432
2433 def revert_downbracefill(document):
2434     ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2435     i = 0
2436     while True:
2437         i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2438         if i == -1:
2439             return
2440         j = find_end_of_inset(document.body, i)
2441         if j == -1:
2442             document.warning("Malformed LyX document: Could not find end of space inset.")
2443             continue
2444         del document.body[j]
2445         subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2446           '\\begin_inset ERT\nstatus collapsed\n\n' \
2447           '\\begin_layout Standard\n\n\n\\backslash\n' \
2448           'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2449         subst = subst.split('\n')
2450         document.body[i : i+1] = subst
2451         i += len(subst)
2452
2453
2454 def revert_local_layout(document):
2455     ' Revert local layout headers.'
2456     i = 0
2457     while True:
2458         i = find_token(document.header, "\\begin_local_layout", i)
2459         if i == -1:
2460             return
2461         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2462         if j == -1:
2463             # this should not happen
2464             break
2465         document.header[i : j + 1] = []
2466
2467
2468 def convert_pagebreaks(document):
2469     ' Convert inline Newpage insets to new format '
2470     i = 0
2471     while True:
2472         i = find_token(document.body, '\\newpage', i)
2473         if i == -1:
2474             break
2475         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2476                                 '\\end_inset']
2477     i = 0
2478     while True:
2479         i = find_token(document.body, '\\pagebreak', i)
2480         if i == -1:
2481             break
2482         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2483                                 '\\end_inset']
2484     i = 0
2485     while True:
2486         i = find_token(document.body, '\\clearpage', i)
2487         if i == -1:
2488             break
2489         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2490                                 '\\end_inset']
2491     i = 0
2492     while True:
2493         i = find_token(document.body, '\\cleardoublepage', i)
2494         if i == -1:
2495             break
2496         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2497                                 '\\end_inset']
2498
2499
2500 def revert_pagebreaks(document):
2501     ' Revert \\begin_inset Newpage to previous inline format '
2502     i = 0
2503     while True:
2504         i = find_token(document.body, '\\begin_inset Newpage', i)
2505         if i == -1:
2506             return
2507         j = find_end_of_inset(document.body, i)
2508         if j == -1:
2509             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2510             continue
2511         del document.body[j]
2512         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2513         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2514         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2515         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2516
2517
2518 def convert_linebreaks(document):
2519     ' Convert inline Newline insets to new format '
2520     i = 0
2521     while True:
2522         i = find_token(document.body, '\\newline', i)
2523         if i == -1:
2524             break
2525         document.body[i:i+1] = ['\\begin_inset Newline newline',
2526                                 '\\end_inset']
2527     i = 0
2528     while True:
2529         i = find_token(document.body, '\\linebreak', i)
2530         if i == -1:
2531             break
2532         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2533                                 '\\end_inset']
2534
2535
2536 def revert_linebreaks(document):
2537     ' Revert \\begin_inset Newline to previous inline format '
2538     i = 0
2539     while True:
2540         i = find_token(document.body, '\\begin_inset Newline', i)
2541         if i == -1:
2542             return
2543         j = find_end_of_inset(document.body, i)
2544         if j == -1:
2545             document.warning("Malformed LyX document: Could not find end of Newline inset.")
2546             continue
2547         del document.body[j]
2548         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2549         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2550
2551
2552 def convert_japanese_plain(document):
2553     ' Set language japanese-plain to japanese '
2554     i = 0
2555     if document.language == "japanese-plain":
2556         document.language = "japanese"
2557         i = find_token(document.header, "\\language", 0)
2558         if i != -1:
2559             document.header[i] = "\\language japanese"
2560     j = 0
2561     while True:
2562         j = find_token(document.body, "\\lang japanese-plain", j)
2563         if j == -1:
2564             return
2565         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2566         j = j + 1
2567
2568
2569 def revert_pdfpages(document):
2570     ' Revert pdfpages external inset to ERT '
2571     i = 0
2572     while 1:
2573         i = find_token(document.body, "\\begin_inset External", i)
2574         if i == -1:
2575             return
2576         j = find_end_of_inset(document.body, i)
2577         if j == -1:
2578             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2579             i = i + 1
2580             continue
2581         if get_value(document.body, 'template', i, j) == "PDFPages":
2582             filename = get_value(document.body, 'filename', i, j)
2583             extra = ''
2584             r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2585             for k in range(i, j):
2586                 m = r.match(document.body[k])
2587                 if m:
2588                     extra = m.group(1)
2589             angle = get_value(document.body, 'rotateAngle', i, j)
2590             width = get_value(document.body, 'width', i, j)
2591             height = get_value(document.body, 'height', i, j)
2592             scale = get_value(document.body, 'scale', i, j)
2593             keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2594             options = extra
2595             if angle != '':
2596                  if options != '':
2597                      options += ",angle=" + angle
2598                  else:
2599                      options += "angle=" + angle
2600             if width != '':
2601                  if options != '':
2602                      options += ",width=" + convert_len(width)
2603                  else:
2604                      options += "width=" + convert_len(width)
2605             if height != '':
2606                  if options != '':
2607                      options += ",height=" + convert_len(height)
2608                  else:
2609                      options += "height=" + convert_len(height)
2610             if scale != '':
2611                  if options != '':
2612                      options += ",scale=" + scale
2613                  else:
2614                      options += "scale=" + scale
2615             if keepAspectRatio != '':
2616                  if options != '':
2617                      options += ",keepaspectratio"
2618                  else:
2619                      options += "keepaspectratio"
2620             if options != '':
2621                      options = '[' + options + ']'
2622             del document.body[i+1:j+1]
2623             document.body[i:i+1] = ['\\begin_inset ERT',
2624                                 'status collapsed',
2625                                 '',
2626                                 '\\begin_layout Standard',
2627                                 '',
2628                                 '\\backslash',
2629                                 'includepdf' + options + '{' + filename + '}',
2630                                 '\\end_layout',
2631                                 '',
2632                                 '\\end_inset']
2633             add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2634             i = i + 1
2635             continue
2636         i = i + 1
2637
2638
2639 def revert_mexican(document):
2640     ' Set language Spanish(Mexico) to Spanish '
2641     i = 0
2642     if document.language == "spanish-mexico":
2643         document.language = "spanish"
2644         i = find_token(document.header, "\\language", 0)
2645         if i != -1:
2646             document.header[i] = "\\language spanish"
2647     j = 0
2648     while True:
2649         j = find_token(document.body, "\\lang spanish-mexico", j)
2650         if j == -1:
2651             return
2652         document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2653         j = j + 1
2654
2655
2656 def remove_embedding(document):
2657     ' Remove embed tag from all insets '
2658     revert_inset_embedding(document, 'Graphics')
2659     revert_inset_embedding(document, 'External')
2660     revert_inset_embedding(document, 'CommandInset include')
2661     revert_inset_embedding(document, 'CommandInset bibtex')
2662
2663
2664 def revert_master(document):
2665     ' Remove master param '
2666     i = find_token(document.header, "\\master", 0)
2667     if i != -1:
2668         del document.header[i]
2669
2670
2671 def revert_graphics_group(document):
2672     ' Revert group information from graphics insets '
2673     i = 0
2674     while 1:
2675         i = find_token(document.body, "\\begin_inset Graphics", i)
2676         if i == -1:
2677             return
2678         j = find_end_of_inset(document.body, i)
2679         if j == -1:
2680             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2681             i = i + 1
2682             continue
2683         k = find_token(document.body, " groupId", i, j)
2684         if k == -1:
2685             i = i + 1
2686             continue
2687         del document.body[k]
2688         i = i + 1
2689
2690
2691 def update_apa_styles(document):
2692     ' Replace obsolete styles '
2693
2694     if document.textclass != "apa":
2695         return
2696
2697     obsoletedby = { "Acknowledgments": "Acknowledgements",
2698                     "Section*":        "Section",
2699                     "Subsection*":     "Subsection",
2700                     "Subsubsection*":  "Subsubsection",
2701                     "Paragraph*":      "Paragraph",
2702                     "Subparagraph*":   "Subparagraph"}
2703     i = 0
2704     while 1:
2705         i = find_token(document.body, "\\begin_layout", i)
2706         if i == -1:
2707             return
2708
2709         layout = document.body[i][14:]
2710         if layout in obsoletedby:
2711             document.body[i] = "\\begin_layout " + obsoletedby[layout]
2712
2713         i += 1
2714
2715
2716 def convert_paper_sizes(document):
2717     ' exchange size options legalpaper and executivepaper to correct order '
2718     # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2719     i = 0
2720     j = 0
2721     i = find_token(document.header, "\\papersize executivepaper", 0)
2722     if i != -1:
2723         document.header[i] = "\\papersize legalpaper"
2724         return
2725     j = find_token(document.header, "\\papersize legalpaper", 0)
2726     if j != -1:
2727         document.header[j] = "\\papersize executivepaper"
2728
2729
2730 def revert_paper_sizes(document):
2731     ' exchange size options legalpaper and executivepaper to correct order '
2732     i = 0
2733     j = 0
2734     i = find_token(document.header, "\\papersize executivepaper", 0)
2735     if i != -1:
2736         document.header[i] = "\\papersize legalpaper"
2737         return
2738     j = find_token(document.header, "\\papersize legalpaper", 0)
2739     if j != -1:
2740         document.header[j] = "\\papersize executivepaper"
2741
2742
2743 def convert_InsetSpace(document):
2744     " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2745     i = 0
2746     while True:
2747         i = find_token(document.body, "\\begin_inset Space", i)
2748         if i == -1:
2749             return
2750         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2751
2752
2753 def revert_InsetSpace(document):
2754     " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2755     i = 0
2756     while True:
2757         i = find_token(document.body, "\\begin_inset space", i)
2758         if i == -1:
2759             return
2760         document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2761
2762
2763 def convert_display_enum(document):
2764     " Convert 'display foo' to 'display false/true'"
2765     i = 0
2766     while True:
2767         i = find_token(document.body, "\tdisplay", i)
2768         if i == -1:
2769             return
2770         val = get_value(document.body, 'display', i)
2771         if val == "none":
2772             document.body[i] = document.body[i].replace('none', 'false')
2773         if val == "default":
2774             document.body[i] = document.body[i].replace('default', 'true')
2775         if val == "monochrome":
2776             document.body[i] = document.body[i].replace('monochrome', 'true')
2777         if val == "grayscale":
2778             document.body[i] = document.body[i].replace('grayscale', 'true')
2779         if val == "color":
2780             document.body[i] = document.body[i].replace('color', 'true')
2781         if val == "preview":
2782             document.body[i] = document.body[i].replace('preview', 'true')
2783         i += 1
2784
2785
2786 def revert_display_enum(document):
2787     " Revert 'display false/true' to 'display none/color'"
2788     i = 0
2789     while True:
2790         i = find_token(document.body, "\tdisplay", i)
2791         if i == -1:
2792             return
2793         val = get_value(document.body, 'display', i)
2794         if val == "false":
2795             document.body[i] = document.body[i].replace('false', 'none')
2796         if val == "true":
2797             document.body[i] = document.body[i].replace('true', 'default')
2798         i += 1
2799
2800
2801 def remove_fontsCJK(document):
2802     ' Remove font_cjk param '
2803     i = find_token(document.header, "\\font_cjk", 0)
2804     if i != -1:
2805         del document.header[i]
2806
2807
2808 def convert_plain_layout(document):
2809     " Convert 'PlainLayout' to 'Plain Layout'"
2810     i = 0
2811     while True:
2812         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2813         if i == -1:
2814             return
2815         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2816           '\\begin_layout Plain Layout')
2817         i += 1
2818
2819
2820 def revert_plain_layout(document):
2821     " Convert 'PlainLayout' to 'Plain Layout'"
2822     i = 0
2823     while True:
2824         i = find_token(document.body, '\\begin_layout Plain Layout', i)
2825         if i == -1:
2826             return
2827         document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2828           '\\begin_layout PlainLayout')
2829         i += 1
2830
2831
2832 def revert_plainlayout(document):
2833     " Convert 'PlainLayout' to 'Plain Layout'"
2834     i = 0
2835     while True:
2836         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2837         if i == -1:
2838             return
2839         # This will be incorrect for some document classes, since Standard is not always
2840         # the default. But (a) it is probably the best we can do and (b) it will actually
2841         # work, in fact, since an unknown layout will be converted to default.
2842         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2843           '\\begin_layout Standard')
2844         i += 1
2845
2846
2847 def revert_polytonicgreek(document):
2848     "Set language polytonic Greek to Greek"
2849     i = 0
2850     if document.language == "polutonikogreek":
2851         document.language = "greek"
2852         i = find_token(document.header, "\\language", 0)
2853         if i != -1:
2854             document.header[i] = "\\language greek"
2855     j = 0
2856     while True:
2857         j = find_token(document.body, "\\lang polutonikogreek", j)
2858         if j == -1:
2859             return
2860         document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2861         j = j + 1
2862
2863
2864 def revert_removed_modules(document):
2865     i = 0
2866     while True:
2867         i = find_token(document.header, "\\begin_remove_modules", i)
2868         if i == -1:
2869             return
2870         j = find_end_of(document.header, i, "\\begin_remove_modules", "\\end_remove_modules")
2871         if j == -1:
2872             # this should not happen
2873             break
2874         document.header[i : j + 1] = []
2875
2876
2877 def add_plain_layout(document):
2878     i = 0
2879     while True:
2880         i = find_token(document.body, "\\begin_layout", i)
2881         if i == -1:
2882             return
2883         if len(document.body[i].split()) == 1:
2884             document.body[i] = "\\begin_layout Plain Layout"
2885         i += 1
2886
2887 ##
2888 # Conversion hub
2889 #
2890
2891 supported_versions = ["1.6.0","1.6"]
2892 convert = [[277, [fix_wrong_tables]],
2893            [278, [close_begin_deeper]],
2894            [279, [long_charstyle_names]],
2895            [280, [axe_show_label]],
2896            [281, []],
2897            [282, []],
2898            [283, [convert_flex]],
2899            [284, []],
2900            [285, []],
2901            [286, []],
2902            [287, [convert_wrapfig_options]],
2903            [288, [convert_inset_command]],
2904            [289, [convert_latexcommand_index]],
2905            [290, []],
2906            [291, []],
2907            [292, [convert_japanese_cjk]],
2908            [293, []],
2909            [294, [convert_pdf_options]],
2910            [295, [convert_htmlurl, convert_url]],
2911            [296, [convert_include]],
2912            [297, [convert_usorbian]],
2913            [298, []],
2914            [299, []],
2915            [300, []],
2916            [301, []],
2917            [302, []],
2918            [303, [convert_serbocroatian]],
2919            [304, [convert_framed_notes]],
2920            [305, []],
2921            [306, []],
2922            [307, []],
2923            [308, []],
2924            [309, []],
2925            [310, []],
2926            [311, [convert_ams_classes]],
2927            [312, []],
2928            [313, [convert_module_names]],
2929            [314, []],
2930            [315, []],
2931            [316, [convert_subfig]],
2932            [317, []],
2933            [318, []],
2934            [319, [convert_spaceinset, convert_hfill]],
2935            [320, []],
2936            [321, [convert_tablines]],
2937            [322, [convert_plain_layout]],
2938            [323, [convert_pagebreaks]],
2939            [324, [convert_linebreaks]],
2940            [325, [convert_japanese_plain]],
2941            [326, []],
2942            [327, []],
2943            [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2944            [329, []],
2945            [330, []],
2946            [331, [convert_ltcaption]],
2947            [332, []],
2948            [333, [update_apa_styles]],
2949            [334, [convert_paper_sizes]],
2950            [335, [convert_InsetSpace]],
2951            [336, []],
2952            [337, [convert_display_enum]],
2953            [338, []],
2954            [339, []],
2955            [340, [add_plain_layout]]
2956           ]
2957
2958 revert =  [[339, []],
2959            [338, [revert_removed_modules]],
2960            [337, [revert_polytonicgreek]],
2961            [336, [revert_display_enum]],
2962            [335, [remove_fontsCJK]],
2963            [334, [revert_InsetSpace]],
2964            [333, [revert_paper_sizes]],
2965            [332, []],
2966            [331, [revert_graphics_group]],
2967            [330, [revert_ltcaption]],
2968            [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2969            [328, [revert_master]],
2970            [327, []],
2971            [326, [revert_mexican]],
2972            [325, [revert_pdfpages]],
2973            [324, []],
2974            [323, [revert_linebreaks]],
2975            [322, [revert_pagebreaks]],
2976            [321, [revert_local_layout, revert_plain_layout]],
2977            [320, [revert_tablines]],
2978            [319, [revert_protected_hfill]],
2979            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2980            [317, [remove_extra_embedded_files]],
2981            [316, [revert_wrapplacement]],
2982            [315, [revert_subfig]],
2983            [314, [revert_colsep, revert_plainlayout]],
2984            [313, []],
2985            [312, [revert_module_names]],
2986            [311, [revert_rotfloat, revert_widesideways]],
2987            [310, [revert_external_embedding]],
2988            [309, [revert_btprintall]],
2989            [308, [revert_nocite]],
2990            [307, [revert_serbianlatin]],
2991            [306, [revert_slash, revert_nobreakdash]],
2992            [305, [revert_interlingua]],
2993            [304, [revert_bahasam]],
2994            [303, [revert_framed_notes]],
2995            [302, []],
2996            [301, [revert_latin, revert_samin]],
2997            [300, [revert_linebreak]],
2998            [299, [revert_pagebreak]],
2999            [298, [revert_hyperlinktype]],
3000            [297, [revert_macro_optional_params]],
3001            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
3002            [295, [revert_include]],
3003            [294, [revert_href, revert_url]],
3004            [293, [revert_pdf_options_2]],
3005            [292, [revert_inset_info]],
3006            [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
3007            [290, [revert_vietnamese]],
3008            [289, [revert_wraptable]],
3009            [288, [revert_latexcommand_index]],
3010            [287, [revert_inset_command]],
3011            [286, [revert_wrapfig_options]],
3012            [285, [revert_pdf_options]],
3013            [284, [remove_inzip_options]],
3014            [283, []],
3015            [282, [revert_flex]],
3016            [281, []],
3017            [280, [revert_begin_modules]],
3018            [279, [revert_show_label]],
3019            [278, [revert_long_charstyle_names]],
3020            [277, []],
3021            [276, []]
3022           ]
3023
3024
3025 if __name__ == "__main__":
3026     pass