]> git.lyx.org Git - lyx.git/blob - lib/lyx2lyx/lyx_1_6.py
Fix bug 4927 again. The latex2ert routine was geared too much toward IndexInset,...
[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       document.warning("Weirdly formed \\begin_layout at line %d of body!" % i)
1319       i += 1
1320       continue
1321     m = m.group(1)
1322     if layouts.count(m) != 0:
1323       document.add_module("Theorems (AMS-Extended)")
1324       return
1325     i += 1
1326
1327 def revert_href(document):
1328     'Reverts hyperlink insets (href) to url insets (url)'
1329     i = 0
1330     while True:
1331       i = find_token(document.body, "\\begin_inset CommandInset href", i)
1332       if i == -1:
1333           return
1334       document.body[i : i + 2] = \
1335         ["\\begin_inset CommandInset url", "LatexCommand url"]
1336       i = i + 2
1337
1338 def revert_url(document):
1339     'Reverts Flex URL insets to old-style URL insets'
1340     i = 0
1341     while True:
1342         i = find_token(document.body, "\\begin_inset Flex URL", i)
1343         if i == -1:
1344             return
1345         j = find_end_of_inset(document.body, i)
1346         if j == -1:
1347             document.warning("Can't find end of inset in revert_url!")
1348             return
1349         k = find_default_layout(document, i, j)
1350         if k == -1:
1351             document.warning("Can't find default layout in revert_url!")
1352             i = j
1353             continue
1354         l = find_end_of(document.body, k, "\\begin_layout", "\\end_layout")
1355         if l == -1 or l >= j:
1356             document.warning("Can't find end of default layout in revert_url!")
1357             i = j
1358             continue
1359         # OK, so the inset's data is between lines k and l.
1360         data =  " ".join(document.body[k+1:l])
1361         data = data.strip()
1362         newinset = ["\\begin_inset LatexCommand url", "target \"" + data + "\"",\
1363                     "", "\\end_inset"]
1364         document.body[i:j+1] = newinset
1365         i = i + len(newinset)
1366
1367
1368 def convert_include(document):
1369   'Converts include insets to new format.'
1370   i = 0
1371   r = re.compile(r'\\begin_inset Include\s+\\([^{]+){([^}]*)}(?:\[(.*)\])?')
1372   while True:
1373     i = find_token(document.body, "\\begin_inset Include", i)
1374     if i == -1:
1375       return
1376     line = document.body[i]
1377     previewline = document.body[i + 1]
1378     m = r.match(line)
1379     if m == None:
1380       document.warning("Unable to match line " + str(i) + " of body!")
1381       i += 1
1382       continue
1383     cmd = m.group(1)
1384     fn  = m.group(2)
1385     opt = m.group(3)
1386     insertion = ["\\begin_inset CommandInset include",
1387        "LatexCommand " + cmd, previewline,
1388        "filename \"" + fn + "\""]
1389     newlines = 2
1390     if opt:
1391       insertion.append("lstparams " + '"' + opt + '"')
1392       newlines += 1
1393     document.body[i : i + 2] = insertion
1394     i += newlines
1395
1396
1397 def revert_include(document):
1398   'Reverts include insets to old format.'
1399   i = 0
1400   r0 = re.compile('preview.*')
1401   r1 = re.compile('LatexCommand (.+)')
1402   r2 = re.compile('filename "(.+)"')
1403   r3 = re.compile('lstparams "(.*)"')
1404   while True:
1405     i = find_token(document.body, "\\begin_inset CommandInset include", i)
1406     if i == -1:
1407       return
1408     nextline = i + 1
1409     if r0.match(document.body[nextline]):
1410       previewline = document.body[nextline]
1411       nextline += 1
1412     else:
1413       previewline = ""
1414     m = r1.match(document.body[nextline])
1415     if m == None:
1416       document.warning("Malformed LyX document: No LatexCommand line for `" +
1417         document.body[i] + "' on line " + str(i) + ".")
1418       i += 1
1419       continue
1420     cmd = m.group(1)
1421     nextline += 1
1422     m = r2.match(document.body[nextline])
1423     if m == None:
1424       document.warning("Malformed LyX document: No filename line for `" + \
1425         document.body[i] + "' on line " + str(i) + ".")
1426       i += 2
1427       continue
1428     fn = m.group(1)
1429     nextline += 1
1430     options = ""
1431     if (cmd == "lstinputlisting"):
1432       m = r3.match(document.body[nextline])
1433       if m != None:
1434         options = m.group(1)
1435         numlines = 5
1436         nextline += 1
1437     newline = "\\begin_inset Include \\" + cmd + "{" + fn + "}"
1438     if options:
1439       newline += ("[" + options + "]")
1440     insertion = [newline]
1441     if previewline != "":
1442       insertion.append(previewline)
1443     document.body[i : nextline] = insertion
1444     i += 2
1445
1446
1447 def revert_albanian(document):
1448     "Set language Albanian to English"
1449     i = 0
1450     if document.language == "albanian":
1451         document.language = "english"
1452         i = find_token(document.header, "\\language", 0)
1453         if i != -1:
1454             document.header[i] = "\\language english"
1455     j = 0
1456     while True:
1457         j = find_token(document.body, "\\lang albanian", j)
1458         if j == -1:
1459             return
1460         document.body[j] = document.body[j].replace("\\lang albanian", "\\lang english")
1461         j = j + 1
1462
1463
1464 def revert_lowersorbian(document):
1465     "Set language lower Sorbian to English"
1466     i = 0
1467     if document.language == "lowersorbian":
1468         document.language = "english"
1469         i = find_token(document.header, "\\language", 0)
1470         if i != -1:
1471             document.header[i] = "\\language english"
1472     j = 0
1473     while True:
1474         j = find_token(document.body, "\\lang lowersorbian", j)
1475         if j == -1:
1476             return
1477         document.body[j] = document.body[j].replace("\\lang lowersorbian", "\\lang english")
1478         j = j + 1
1479
1480
1481 def revert_uppersorbian(document):
1482     "Set language uppersorbian to usorbian as this was used in LyX 1.5"
1483     i = 0
1484     if document.language == "uppersorbian":
1485         document.language = "usorbian"
1486         i = find_token(document.header, "\\language", 0)
1487         if i != -1:
1488             document.header[i] = "\\language usorbian"
1489     j = 0
1490     while True:
1491         j = find_token(document.body, "\\lang uppersorbian", j)
1492         if j == -1:
1493             return
1494         document.body[j] = document.body[j].replace("\\lang uppersorbian", "\\lang usorbian")
1495         j = j + 1
1496
1497
1498 def convert_usorbian(document):
1499     "Set language usorbian to uppersorbian"
1500     i = 0
1501     if document.language == "usorbian":
1502         document.language = "uppersorbian"
1503         i = find_token(document.header, "\\language", 0)
1504         if i != -1:
1505             document.header[i] = "\\language uppersorbian"
1506     j = 0
1507     while True:
1508         j = find_token(document.body, "\\lang usorbian", j)
1509         if j == -1:
1510             return
1511         document.body[j] = document.body[j].replace("\\lang usorbian", "\\lang uppersorbian")
1512         j = j + 1
1513
1514
1515 def revert_macro_optional_params(document):
1516     "Convert macro definitions with optional parameters into ERTs"
1517     # Stub to convert macro definitions with one or more optional parameters
1518     # into uninterpreted ERT insets
1519
1520
1521 def revert_hyperlinktype(document):
1522     'Reverts hyperlink type'
1523     i = 0
1524     j = 0
1525     while True:
1526       i = find_token(document.body, "target", i)
1527       if i == -1:
1528           return
1529       j = find_token(document.body, "type", i)
1530       if j == -1:
1531           return
1532       if j == i + 1:
1533           del document.body[j]
1534       i = i + 1
1535
1536
1537 def revert_pagebreak(document):
1538     'Reverts pagebreak to ERT'
1539     i = 0
1540     while True:
1541       i = find_token(document.body, "\\pagebreak", i)
1542       if i == -1:
1543           return
1544       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1545       '\\begin_layout Standard\n\n\n\\backslash\n' \
1546       'pagebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1547       i = i + 1
1548
1549
1550 def revert_linebreak(document):
1551     'Reverts linebreak to ERT'
1552     i = 0
1553     while True:
1554       i = find_token(document.body, "\\linebreak", i)
1555       if i == -1:
1556           return
1557       document.body[i] = '\\begin_inset ERT\nstatus collapsed\n\n' \
1558       '\\begin_layout Standard\n\n\n\\backslash\n' \
1559       'linebreak{}\n\\end_layout\n\n\\end_inset\n\n'
1560       i = i + 1
1561
1562
1563 def revert_latin(document):
1564     "Set language Latin to English"
1565     i = 0
1566     if document.language == "latin":
1567         document.language = "english"
1568         i = find_token(document.header, "\\language", 0)
1569         if i != -1:
1570             document.header[i] = "\\language english"
1571     j = 0
1572     while True:
1573         j = find_token(document.body, "\\lang latin", j)
1574         if j == -1:
1575             return
1576         document.body[j] = document.body[j].replace("\\lang latin", "\\lang english")
1577         j = j + 1
1578
1579
1580 def revert_samin(document):
1581     "Set language North Sami to English"
1582     i = 0
1583     if document.language == "samin":
1584         document.language = "english"
1585         i = find_token(document.header, "\\language", 0)
1586         if i != -1:
1587             document.header[i] = "\\language english"
1588     j = 0
1589     while True:
1590         j = find_token(document.body, "\\lang samin", j)
1591         if j == -1:
1592             return
1593         document.body[j] = document.body[j].replace("\\lang samin", "\\lang english")
1594         j = j + 1
1595
1596
1597 def convert_serbocroatian(document):
1598     "Set language Serbocroatian to Croatian as this was really Croatian in LyX 1.5"
1599     i = 0
1600     if document.language == "serbocroatian":
1601         document.language = "croatian"
1602         i = find_token(document.header, "\\language", 0)
1603         if i != -1:
1604             document.header[i] = "\\language croatian"
1605     j = 0
1606     while True:
1607         j = find_token(document.body, "\\lang serbocroatian", j)
1608         if j == -1:
1609             return
1610         document.body[j] = document.body[j].replace("\\lang serbocroatian", "\\lang croatian")
1611         j = j + 1
1612
1613
1614 def convert_framed_notes(document):
1615     "Convert framed notes to boxes. "
1616     i = 0
1617     while 1:
1618         i = find_tokens(document.body, ["\\begin_inset Note Framed", "\\begin_inset Note Shaded"], i)
1619         if i == -1:
1620             return
1621         subst = [document.body[i].replace("\\begin_inset Note", "\\begin_inset Box"),
1622                  'position "t"',
1623                  'hor_pos "c"',
1624                  'has_inner_box 0',
1625                  'inner_pos "t"', 
1626                  'use_parbox 0',
1627                  'width "100col%"',
1628                  'special "none"',
1629                  'height "1in"',
1630                  'height_special "totalheight"']
1631         document.body[i:i+1] = subst
1632         i = i + 9
1633
1634
1635 def convert_module_names(document):
1636   modulemap = { 'Braille' : 'braille', 'Endnote' : 'endnotes', 'Foot to End' : 'foottoend',\
1637     'Hanging' : 'hanging', 'Linguistics' : 'linguistics', 'Logical Markup' : 'logicalmkup', \
1638     'Theorems (AMS-Extended)' : 'theorems-ams-extended', 'Theorems (AMS)' : 'theorems-ams', \
1639     'Theorems (Order By Chapter)' : 'theorems-chap', 'Theorems (Order By Section)' : 'theorems-sec', \
1640     'Theorems (Starred)' : 'theorems-starred', 'Theorems' : 'theorems-std' }
1641   modlist = document.get_module_list()
1642   if len(modlist) == 0:
1643     return
1644   newmodlist = []
1645   for mod in modlist:
1646     if modulemap.has_key(mod):
1647       newmodlist.append(modulemap[mod])
1648     else:
1649       document.warning("Can't find module %s in the module map!" % mod)
1650       newmodlist.append(mod)
1651   document.set_module_list(newmodlist)
1652
1653
1654 def revert_module_names(document):
1655   modulemap = { 'braille' : 'Braille', 'endnotes' : 'Endnote', 'foottoend' : 'Foot to End',\
1656     'hanging' : 'Hanging', 'linguistics' : 'Linguistics', 'logicalmkup' : 'Logical Markup', \
1657     'theorems-ams-extended' : 'Theorems (AMS-Extended)', 'theorems-ams' : 'Theorems (AMS)', \
1658     'theorems-chap' : 'Theorems (Order By Chapter)', 'theorems-sec' : 'Theorems (Order By Section)', \
1659     'theorems-starred' : 'Theorems (Starred)', 'theorems-std' : 'Theorems'}
1660   modlist = document.get_module_list()
1661   if len(modlist) == 0:
1662     return
1663   newmodlist = []
1664   for mod in modlist:
1665     if modulemap.has_key(mod):
1666       newmodlist.append(modulemap[mod])
1667     else:
1668       document.warning("Can't find module %s in the module map!" % mod)
1669       newmodlist.append(mod)
1670   document.set_module_list(newmodlist)
1671
1672
1673 def revert_colsep(document):
1674     i = find_token(document.header, "\\columnsep", 0)
1675     if i == -1:
1676         return
1677     colsepline = document.header[i]
1678     r = re.compile(r'\\columnsep (.*)')
1679     m = r.match(colsepline)
1680     if not m:
1681         document.warning("Malformed column separation line!")
1682         return
1683     colsep = m.group(1)
1684     del document.header[i]
1685     #it seems to be safe to add the package even if it is already used
1686     pretext = ["\\usepackage{geometry}", "\\geometry{columnsep=" + colsep + "}"]
1687
1688     add_to_preamble(document, pretext)
1689
1690
1691 def revert_framed_notes(document):
1692     "Revert framed boxes to notes. "
1693     i = 0
1694     while 1:
1695         i = find_tokens(document.body, ["\\begin_inset Box Framed", "\\begin_inset Box Shaded"], i)
1696
1697         if i == -1:
1698             return
1699         j = find_end_of_inset(document.body, i + 1)
1700         if j == -1:
1701             # should not happen
1702             document.warning("Malformed LyX document: Could not find end of Box inset.")
1703         k = find_token(document.body, "status", i + 1, j)
1704         if k == -1:
1705             document.warning("Malformed LyX document: Missing `status' tag in Box inset.")
1706             return
1707         status = document.body[k]
1708         l = find_default_layout(document, i + 1, j)
1709         if l == -1:
1710             document.warning("Malformed LyX document: Missing `\\begin_layout' in Box inset.")
1711             return
1712         m = find_token(document.body, "\\end_layout", i + 1, j)
1713         if m == -1:
1714             document.warning("Malformed LyX document: Missing `\\end_layout' in Box inset.")
1715             return
1716         ibox = find_token(document.body, "has_inner_box 1", i + 1, k)
1717         pbox = find_token(document.body, "use_parbox 1", i + 1, k)
1718         if ibox == -1 and pbox == -1:
1719             document.body[i] = document.body[i].replace("\\begin_inset Box", "\\begin_inset Note")
1720             del document.body[i+1:k]
1721         else:
1722             document.body[i] = document.body[i].replace("\\begin_inset Box Shaded", "\\begin_inset Box Frameless")
1723             subst1 = [document.body[l],
1724                       "\\begin_inset Note Shaded",
1725                       status,
1726                       '\\begin_layout Standard']
1727             document.body[l:l + 1] = subst1
1728             subst2 = [document.body[m], "\\end_layout", "\\end_inset"]
1729             document.body[m:m + 1] = subst2
1730         i = i + 1
1731
1732
1733 def revert_slash(document):
1734     'Revert \\SpecialChar \\slash{} to ERT'
1735     r = re.compile(r'\\SpecialChar \\slash{}')
1736     i = 0
1737     while i < len(document.body):
1738         m = r.match(document.body[i])
1739         if m:
1740           subst = ['\\begin_inset ERT',
1741                    'status collapsed', '',
1742                    '\\begin_layout Standard',
1743                    '', '', '\\backslash',
1744                    'slash{}',
1745                    '\\end_layout', '',
1746                    '\\end_inset', '']
1747           document.body[i: i+1] = subst
1748           i = i + len(subst)
1749         else:
1750           i = i + 1
1751
1752
1753 def revert_nobreakdash(document):
1754     'Revert \\SpecialChar \\nobreakdash- to ERT'
1755     i = 0
1756     while i < len(document.body):
1757         line = document.body[i]
1758         r = re.compile(r'\\SpecialChar \\nobreakdash-')
1759         m = r.match(line)
1760         if m:
1761             subst = ['\\begin_inset ERT',
1762                     'status collapsed', '',
1763                     '\\begin_layout Standard', '', '',
1764                     '\\backslash',
1765                     'nobreakdash-',
1766                     '\\end_layout', '',
1767                     '\\end_inset', '']
1768             document.body[i:i+1] = subst
1769             i = i + len(subst)
1770             j = find_token(document.header, "\\use_amsmath", 0)
1771             if j == -1:
1772                 document.warning("Malformed LyX document: Missing '\\use_amsmath'.")
1773                 return
1774             document.header[j] = "\\use_amsmath 2"
1775         else:
1776             i = i + 1
1777
1778
1779 #Returns number of lines added/removed
1780 def revert_nocite_key(body, start, end):
1781     'key "..." -> \nocite{...}' 
1782     r = re.compile(r'^key "(.*)"')
1783     i = start
1784     j = end
1785     while i < j:
1786         m = r.match(body[i])
1787         if m:
1788             body[i:i+1] = ["\\backslash", "nocite{" + m.group(1) + "}"]
1789             j += 1     # because we added a line
1790             i += 2     # skip that line
1791         else:
1792             del body[i]
1793             j -= 1     # because we deleted a line
1794             # no need to change i, since it now points to the next line
1795     return j - end
1796
1797
1798 def revert_nocite(document):
1799     "Revert LatexCommand nocite to ERT"
1800     i = 0
1801     while 1:
1802         i = find_token(document.body, "\\begin_inset CommandInset citation", i)
1803         if i == -1:
1804             return
1805         if (document.body[i+1] != "LatexCommand nocite"):
1806             # note that we already incremented i
1807             i = i + 1
1808             continue
1809         insetEnd = find_end_of_inset(document.body, i)
1810         if insetEnd == -1:
1811             #this should not happen
1812             document.warning("End of CommandInset citation not found in revert_nocite!")
1813             return
1814
1815         paramLocation = i + 2 #start of the inset's parameters
1816         addedLines = 0
1817         document.body[i:i+2] = \
1818             ["\\begin_inset ERT", "status collapsed", "", "\\begin_layout Standard"]
1819         # that added two lines
1820         paramLocation += 2
1821         insetEnd += 2
1822         #print insetEnd, document.body[i: insetEnd + 1]
1823         insetEnd += revert_nocite_key(document.body, paramLocation, insetEnd)
1824         #print insetEnd, document.body[i: insetEnd + 1]
1825         document.body.insert(insetEnd, "\\end_layout")
1826         document.body.insert(insetEnd + 1, "")
1827         i = insetEnd + 1
1828
1829
1830 def revert_btprintall(document):
1831     "Revert (non-bibtopic) btPrintAll option to ERT \nocite{*}"
1832     i = find_token(document.header, '\\use_bibtopic', 0)
1833     if i == -1:
1834         document.warning("Malformed lyx document: Missing '\\use_bibtopic'.")
1835         return
1836     if get_value(document.header, '\\use_bibtopic', 0) == "false":
1837         i = 0
1838         while i < len(document.body):
1839             i = find_token(document.body, "\\begin_inset CommandInset bibtex", i)
1840             if i == -1:
1841                 return
1842             j = find_end_of_inset(document.body, i + 1)
1843             if j == -1:
1844                 #this should not happen
1845                 document.warning("End of CommandInset bibtex not found in revert_btprintall!")
1846                 j = len(document.body)
1847             # this range isn't really right, but it should be OK, since we shouldn't
1848             # see more than one matching line in each inset
1849             addedlines = 0
1850             for k in range(i, j):
1851                 if (document.body[k] == 'btprint "btPrintAll"'):
1852                     del document.body[k]
1853                     subst = ["\\begin_inset ERT",
1854                              "status collapsed", "",
1855                              "\\begin_layout Standard", "",
1856                              "\\backslash",
1857                              "nocite{*}",
1858                              "\\end_layout",
1859                              "\\end_inset"]
1860                     document.body[i:i] = subst
1861                     addlines = addedlines + len(subst) - 1
1862             i = j + addedlines
1863
1864
1865 def revert_bahasam(document):
1866     "Set language Bahasa Malaysia to Bahasa Indonesia"
1867     i = 0
1868     if document.language == "bahasam":
1869         document.language = "bahasa"
1870         i = find_token(document.header, "\\language", 0)
1871         if i != -1:
1872             document.header[i] = "\\language bahasa"
1873     j = 0
1874     while True:
1875         j = find_token(document.body, "\\lang bahasam", j)
1876         if j == -1:
1877             return
1878         document.body[j] = document.body[j].replace("\\lang bahasam", "\\lang bahasa")
1879         j = j + 1
1880
1881
1882 def revert_interlingua(document):
1883     "Set language Interlingua to English"
1884     i = 0
1885     if document.language == "interlingua":
1886         document.language = "english"
1887         i = find_token(document.header, "\\language", 0)
1888         if i != -1:
1889             document.header[i] = "\\language english"
1890     j = 0
1891     while True:
1892         j = find_token(document.body, "\\lang interlingua", j)
1893         if j == -1:
1894             return
1895         document.body[j] = document.body[j].replace("\\lang interlingua", "\\lang english")
1896         j = j + 1
1897
1898
1899 def revert_serbianlatin(document):
1900     "Set language Serbian-Latin to Croatian"
1901     i = 0
1902     if document.language == "serbian-latin":
1903         document.language = "croatian"
1904         i = find_token(document.header, "\\language", 0)
1905         if i != -1:
1906             document.header[i] = "\\language croatian"
1907     j = 0
1908     while True:
1909         j = find_token(document.body, "\\lang serbian-latin", j)
1910         if j == -1:
1911             return
1912         document.body[j] = document.body[j].replace("\\lang serbian-latin", "\\lang croatian")
1913         j = j + 1
1914
1915
1916 def revert_rotfloat(document):
1917     " Revert sideways custom floats. "
1918     i = 0
1919     while 1:
1920         # whitespace intended (exclude \\begin_inset FloatList)
1921         i = find_token(document.body, "\\begin_inset Float ", i)
1922         if i == -1:
1923             return
1924         line = document.body[i]
1925         r = re.compile(r'\\begin_inset Float (.*)$')
1926         m = r.match(line)
1927         if m == None:
1928             document.warning("Unable to match line " + str(i) + " of body!")
1929             i += 1
1930             continue
1931         floattype = m.group(1)
1932         if floattype == "figure" or floattype == "table":
1933             i += 1
1934             continue
1935         j = find_end_of_inset(document.body, i)
1936         if j == -1:
1937             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_rotfloat.")
1938             i += 1
1939             continue
1940         addedLines = 0
1941         if get_value(document.body, 'sideways', i, j) == "false":
1942             i += 1
1943             continue
1944         l = find_default_layout(document, i + 1, j)
1945         if l == -1:
1946             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
1947             return
1948         subst = ['\\begin_layout Standard',
1949                   '\\begin_inset ERT',
1950                   'status collapsed', '',
1951                   '\\begin_layout Standard', '', '', 
1952                   '\\backslash', '',
1953                   'end{sideways' + floattype + '}',
1954                   '\\end_layout', '', '\\end_inset']
1955         document.body[j : j+1] = subst
1956         addedLines = len(subst) - 1
1957         del document.body[i+1 : l]
1958         addedLines -= (l-1) - (i+1) 
1959         subst = ['\\begin_inset ERT', 'status collapsed', '',
1960                   '\\begin_layout Standard', '', '', '\\backslash', 
1961                   'begin{sideways' + floattype + '}', 
1962                   '\\end_layout', '', '\\end_inset', '',
1963                   '\\end_layout', '']
1964         document.body[i : i+1] = subst
1965         addedLines += len(subst) - 1
1966         if floattype == "algorithm":
1967             add_to_preamble(document,
1968                             ['% Commands inserted by lyx2lyx for sideways algorithm float',
1969                               '\\usepackage{rotfloat}',
1970                               '\\floatstyle{ruled}',
1971                               '\\newfloat{algorithm}{tbp}{loa}',
1972                               '\\floatname{algorithm}{Algorithm}'])
1973         else:
1974             document.warning("Cannot create preamble definition for custom float" + floattype + ".")
1975         i += addedLines + 1
1976
1977
1978 def revert_widesideways(document):
1979     " Revert wide sideways floats. "
1980     i = 0
1981     while 1:
1982         # whitespace intended (exclude \\begin_inset FloatList)
1983         i = find_token(document.body, '\\begin_inset Float ', i)
1984         if i == -1:
1985             return
1986         line = document.body[i]
1987         r = re.compile(r'\\begin_inset Float (.*)$')
1988         m = r.match(line)
1989         if m == None:
1990             document.warning("Unable to match line " + str(i) + " of body!")
1991             i += 1
1992             continue
1993         floattype = m.group(1)
1994         if floattype != "figure" and floattype != "table":
1995             i += 1
1996             continue
1997         j = find_end_of_inset(document.body, i)
1998         if j == -1:
1999             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_widesideways.")
2000             i += 1
2001             continue
2002         if get_value(document.body, 'sideways', i, j) == "false" or \
2003            get_value(document.body, 'wide', i, j) == "false":
2004              i += 1
2005              continue
2006         l = find_default_layout(document, i + 1, j)
2007         if l == -1:
2008             document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2009             return
2010         subst = ['\\begin_layout Standard', '\\begin_inset ERT', 
2011                   'status collapsed', '', 
2012                   '\\begin_layout Standard', '', '', '\\backslash',
2013                   'end{sideways' + floattype + '*}', 
2014                   '\\end_layout', '', '\\end_inset']
2015         document.body[j : j+1] = subst
2016         addedLines = len(subst) - 1
2017         del document.body[i+1:l-1]
2018         addedLines -= (l-1) - (i+1)
2019         subst = ['\\begin_inset ERT', 'status collapsed', '',
2020                  '\\begin_layout Standard', '', '', '\\backslash',
2021                  'begin{sideways' + floattype + '*}', '\\end_layout', '',
2022                  '\\end_inset', '', '\\end_layout', '']
2023         document.body[i : i+1] = subst
2024         addedLines += len(subst) - 1
2025         add_to_preamble(document, ['\\usepackage{rotfloat}\n'])
2026         i += addedLines + 1
2027
2028
2029 def revert_inset_embedding(document, type):
2030     ' Remove embed tag from certain type of insets'
2031     i = 0
2032     while 1:
2033         i = find_token(document.body, "\\begin_inset %s" % type, i)
2034         if i == -1:
2035             return
2036         j = find_end_of_inset(document.body, i)
2037         if j == -1:
2038             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_inset_embedding.")
2039             i = i + 1
2040             continue
2041         k = find_token(document.body, "\tembed", i, j)
2042         if k == -1:
2043             k = find_token(document.body, "embed", i, j)
2044         if k != -1:
2045             del document.body[k]
2046         i = i + 1
2047
2048
2049 def revert_external_embedding(document):
2050     ' Remove embed tag from external inset '
2051     revert_inset_embedding(document, 'External')
2052
2053
2054 def convert_subfig(document):
2055     " Convert subfigures to subfloats. "
2056     i = 0
2057     while 1:
2058         i = find_token(document.body, '\\begin_inset Graphics', i)
2059         if i == -1:
2060             return
2061         endInset = find_end_of_inset(document.body, i)
2062         if endInset == -1:
2063             document.warning("Malformed lyx document: Missing '\\end_inset' in convert_subfig.")
2064             i += 1
2065             continue
2066         k = find_token(document.body, '\tsubcaption', i, endInset)
2067         if k == -1:
2068             i = endInset
2069             continue
2070         l = find_token(document.body, '\tsubcaptionText', i, endInset)
2071         if l == -1:
2072             document.warning("Malformed lyx document: Can't find subcaptionText!")
2073             i = endInset
2074             continue
2075         caption = document.body[l][16:].strip('"')
2076         del document.body[l]
2077         del document.body[k]
2078         addedLines = -2
2079         subst = ['\\begin_inset Float figure', 'wide false', 'sideways false', 
2080                  'status open', '', '\\begin_layout Plain Layout', '\\begin_inset Caption', 
2081                  '', '\\begin_layout Plain Layout'] + latex2lyx(caption) + \
2082                  [ '\\end_layout', '', '\\end_inset', '', 
2083                  '\\end_layout', '', '\\begin_layout Plain Layout']
2084         document.body[i : i] = subst
2085         addedLines += len(subst)
2086         endInset += addedLines
2087         subst = ['', '\\end_inset', '', '\\end_layout']
2088         document.body[endInset : endInset] = subst
2089         addedLines += len(subst)
2090         i += addedLines + 1
2091
2092
2093 def revert_subfig(document):
2094     " Revert subfloats. "
2095     i = 0
2096     while 1:
2097         # whitespace intended (exclude \\begin_inset FloatList)
2098         i = find_tokens(document.body, ['\\begin_inset Float ', '\\begin_inset Wrap'], i)
2099         if i == -1:
2100             return
2101         j = 0
2102         addedLines = 0
2103         while j != -1:
2104             j = find_end_of_inset(document.body, i)
2105             if j == -1:
2106                 document.warning("Malformed lyx document: Missing '\\end_inset' (float) at line " + str(i + len(document.header)) + ".\n\t" + document.body[i])
2107                 # document.warning(document.body[i-1] + "\n" + document.body[i+1])
2108                 i += 1
2109                 continue # this will get us back to the outer loop, since j == -1
2110             # look for embedded float (= subfloat)
2111             # whitespace intended (exclude \\begin_inset FloatList)
2112             k = find_token(document.body, '\\begin_inset Float ', i + 1, j)
2113             if k == -1:
2114                 break
2115             l = find_end_of_inset(document.body, k)
2116             if l == -1:
2117                 document.warning("Malformed lyx document: Missing '\\end_inset' (embedded float).")
2118                 i += 1
2119                 j == -1
2120                 continue # escape to the outer loop
2121             m = find_default_layout(document, k + 1, l)
2122             # caption?
2123             cap = find_token(document.body, '\\begin_inset Caption', k + 1, l)
2124             caption = ''
2125             shortcap = ''
2126             capend = cap
2127             if cap != -1:
2128                 capend = find_end_of_inset(document.body, cap)
2129                 if capend == -1:
2130                     document.warning("Malformed lyx document: Missing '\\end_inset' (caption).")
2131                     return
2132                 # label?
2133                 label = ''
2134                 lbl = find_token(document.body, '\\begin_inset CommandInset label', cap, capend)
2135                 if lbl != -1:
2136                     lblend = find_end_of_inset(document.body, lbl + 1)
2137                     if lblend == -1:
2138                         document.warning("Malformed lyx document: Missing '\\end_inset' (label).")
2139                         return
2140                     for line in document.body[lbl:lblend + 1]:
2141                         if line.startswith('name '):
2142                             label = line.split()[1].strip('"')
2143                             break
2144                 else:
2145                     lbl = capend
2146                     lblend = capend
2147                     label = ''
2148                 # opt arg?
2149                 opt = find_token(document.body, '\\begin_inset OptArg', cap, capend)
2150                 if opt != -1:
2151                     optend = find_end_of_inset(document.body, opt)
2152                     if optend == -1:
2153                         document.warning("Malformed lyx document: Missing '\\end_inset' (OptArg).")
2154                         return
2155                     optc = find_default_layout(document, opt, optend)
2156                     if optc == -1:
2157                         document.warning("Malformed LyX document: Missing `\\begin_layout' in Float inset.")
2158                         return
2159                     optcend = find_end_of(document.body, optc, "\\begin_layout", "\\end_layout")
2160                     for line in document.body[optc:optcend]:
2161                         if not line.startswith('\\'):
2162                             shortcap += line.strip()
2163                 else:
2164                     opt = capend
2165                     optend = capend
2166                 for line in document.body[cap:capend]:
2167                     if line in document.body[lbl:lblend]:
2168                         continue
2169                     elif line in document.body[opt:optend]:
2170                         continue
2171                     elif not line.startswith('\\'):
2172                         caption += line.strip()
2173                 if len(label) > 0:
2174                     caption += "\\backslash\nlabel{" + label + "}"
2175             subst = '\\begin_layout Plain Layout\n\\begin_inset ERT\nstatus collapsed\n\n' \
2176                       '\\begin_layout Plain Layout\n\n}\n\\end_layout\n\n\\end_inset\n\n' \
2177                       '\\end_layout\n\n\\begin_layout Plain Layout\n'
2178             subst = subst.split('\n')
2179             document.body[l : l+1] = subst
2180             addedLines = len(subst) - 1
2181             # this is before l and so is unchanged by the multiline insertion
2182             if cap != capend:
2183                 del document.body[cap:capend+1]
2184                 addedLines -= (capend + 1 - cap)
2185             del document.body[k+1:m-1]
2186             addedLines -= (m - 1 - (k + 1))
2187             insertion = '\\begin_inset ERT\nstatus collapsed\n\n' \
2188                         '\\begin_layout Plain Layout\n\n\\backslash\n' \
2189                         'subfloat'
2190             if len(shortcap) > 0:
2191                 insertion = insertion + "[" + shortcap + "]"
2192             if len(caption) > 0:
2193                 insertion = insertion + "[" + caption + "]"
2194             insertion = insertion + '{%\n\\end_layout\n\n\\end_inset\n\n\\end_layout\n'
2195             insertion = insertion.split('\n')
2196             document.body[k : k + 1] = insertion
2197             addedLines += len(insertion) - 1
2198             add_to_preamble(document, ['\\usepackage{subfig}\n'])
2199         i += addedLines + 1
2200
2201
2202 def revert_wrapplacement(document):
2203     " Revert placement options wrap floats (wrapfig). "
2204     i = 0
2205     while True:
2206         i = find_token(document.body, "\\begin_inset Wrap figure", i)
2207         if i == -1:
2208             return
2209         e = find_end_of_inset(document.body, i)
2210         j = find_token(document.body, "placement", i + 1, e)
2211         if j == -1:
2212             document.warning("Malformed LyX document: Couldn't find placement parameter of wrap float.")
2213             i += 1
2214             continue
2215         r = re.compile("placement (o|i|l|r)")
2216         m = r.match(document.body[j])
2217         if m == None:
2218             document.warning("Malformed LyX document: Placement option isn't O|I|R|L!")
2219         document.body[j] = "placement " + m.group(1).lower()
2220         i = j
2221
2222
2223 def remove_extra_embedded_files(document):
2224     " Remove \extra_embedded_files from buffer params "
2225     i = find_token(document.header, '\\extra_embedded_files', 0)
2226     if i == -1:
2227         return
2228     document.header.pop(i)
2229
2230
2231 def convert_spaceinset(document):
2232     " Convert '\\InsetSpace foo' to '\\begin_inset Space foo\n\\end_inset' "
2233     i = 0
2234     while i < len(document.body):
2235         m = re.match(r'(.*)\\InsetSpace (.*)', document.body[i])
2236         if m:
2237             before = m.group(1)
2238             after = m.group(2)
2239             subst = [before, "\\begin_inset Space " + after, "\\end_inset"]
2240             document.body[i: i+1] = subst
2241             i = i + len(subst)
2242         else:
2243             i = i + 1
2244
2245
2246 def revert_spaceinset(document):
2247     " Revert '\\begin_inset Space foo\n\\end_inset' to '\\InsetSpace foo' "
2248     i = 0
2249     while True:
2250         i = find_token(document.body, "\\begin_inset Space", i)
2251         if i == -1:
2252             return
2253         j = find_end_of_inset(document.body, i)
2254         if j == -1:
2255             document.warning("Malformed LyX document: Could not find end of space inset.")
2256             continue
2257         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\InsetSpace')
2258         del document.body[j]
2259
2260
2261 def convert_hfill(document):
2262     " Convert hfill to space inset "
2263     i = 0
2264     while True:
2265         i = find_token(document.body, "\\hfill", i)
2266         if i == -1:
2267             return
2268         subst = document.body[i].replace('\\hfill', \
2269                   '\n\\begin_inset Space \\hfill{}\n\\end_inset')
2270         subst = subst.split('\n')
2271         document.body[i : i+1] = subst
2272         i += len(subst)
2273
2274
2275 def revert_hfills(document):
2276     ' Revert \\hfill commands '
2277     hfill = re.compile(r'\\hfill')
2278     dotfill = re.compile(r'\\dotfill')
2279     hrulefill = re.compile(r'\\hrulefill')
2280     i = 0
2281     while True:
2282         i = find_token(document.body, "\\InsetSpace", i)
2283         if i == -1:
2284             return
2285         if hfill.search(document.body[i]):
2286             document.body[i] = \
2287               document.body[i].replace('\\InsetSpace \\hfill{}', '\\hfill')
2288             i += 1
2289             continue
2290         if dotfill.search(document.body[i]):
2291             subst = document.body[i].replace('\\InsetSpace \\dotfill{}', \
2292               '\\begin_inset ERT\nstatus collapsed\n\n' \
2293               '\\begin_layout Standard\n\n\n\\backslash\n' \
2294               'dotfill{}\n\\end_layout\n\n\\end_inset\n\n')
2295             subst = subst.split('\n')
2296             document.body[i : i+1] = subst
2297             i += len(subst)
2298             continue
2299         if hrulefill.search(document.body[i]):
2300             subst = document.body[i].replace('\\InsetSpace \\hrulefill{}', \
2301               '\\begin_inset ERT\nstatus collapsed\n\n' \
2302               '\\begin_layout Standard\n\n\n\\backslash\n' \
2303               'hrulefill{}\n\\end_layout\n\n\\end_inset\n\n')
2304             subst = subst.split('\n')
2305             document.body[i : i+1] = subst
2306             i += len(subst)
2307             continue
2308         i += 1
2309
2310 def revert_hspace(document):
2311     ' Revert \\InsetSpace \\hspace{} to ERT '
2312     i = 0
2313     hspace = re.compile(r'\\hspace{}')
2314     hstar  = re.compile(r'\\hspace\*{}')
2315     while True:
2316         i = find_token(document.body, "\\InsetSpace \\hspace", i)
2317         if i == -1:
2318             return
2319         length = get_value(document.body, '\\length', i+1)
2320         if length == '':
2321             document.warning("Malformed lyx document: Missing '\\length' in Space inset.")
2322             return
2323         del document.body[i+1]
2324         addedLines = -1
2325         if hstar.search(document.body[i]):
2326             subst = document.body[i].replace('\\InsetSpace \\hspace*{}', \
2327               '\\begin_inset ERT\nstatus collapsed\n\n' \
2328               '\\begin_layout Standard\n\n\n\\backslash\n' \
2329               'hspace*{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2330             subst = subst.split('\n')
2331             document.body[i : i+1] = subst
2332             addedLines += len(subst) - 1
2333             i += addedLines + 1
2334             continue
2335         if hspace.search(document.body[i]):
2336             subst = document.body[i].replace('\\InsetSpace \\hspace{}', \
2337               '\\begin_inset ERT\nstatus collapsed\n\n' \
2338               '\\begin_layout Standard\n\n\n\\backslash\n' \
2339               'hspace{' + length + '}\n\\end_layout\n\n\\end_inset\n\n')
2340             subst = subst.split('\n')
2341             document.body[i : i+1] = subst
2342             addedLines += len(subst) - 1
2343             i += addedLines + 1
2344             continue
2345         i += 1
2346
2347
2348 def revert_protected_hfill(document):
2349     ' Revert \\begin_inset Space \\hspace*{\\fill} to ERT '
2350     i = 0
2351     while True:
2352         i = find_token(document.body, '\\begin_inset Space \\hspace*{\\fill}', i)
2353         if i == -1:
2354             return
2355         j = find_end_of_inset(document.body, i)
2356         if j == -1:
2357             document.warning("Malformed LyX document: Could not find end of space inset.")
2358             continue
2359         del document.body[j]
2360         subst = document.body[i].replace('\\begin_inset Space \\hspace*{\\fill}', \
2361           '\\begin_inset ERT\nstatus collapsed\n\n' \
2362           '\\begin_layout Standard\n\n\n\\backslash\n' \
2363           'hspace*{\n\\backslash\nfill}\n\\end_layout\n\n\\end_inset\n\n')
2364         subst = subst.split('\n')
2365         document.body[i : i+1] = subst
2366         i += len(subst)
2367
2368
2369 def revert_leftarrowfill(document):
2370     ' Revert \\begin_inset Space \\leftarrowfill{} to ERT '
2371     i = 0
2372     while True:
2373         i = find_token(document.body, '\\begin_inset Space \\leftarrowfill{}', i)
2374         if i == -1:
2375             return
2376         j = find_end_of_inset(document.body, i)
2377         if j == -1:
2378             document.warning("Malformed LyX document: Could not find end of space inset.")
2379             continue
2380         del document.body[j]
2381         subst = document.body[i].replace('\\begin_inset Space \\leftarrowfill{}', \
2382           '\\begin_inset ERT\nstatus collapsed\n\n' \
2383           '\\begin_layout Standard\n\n\n\\backslash\n' \
2384           'leftarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2385         subst = subst.split('\n')
2386         document.body[i : i+1] = subst
2387         i += len(subst)
2388
2389
2390 def revert_rightarrowfill(document):
2391     ' Revert \\begin_inset Space \\rightarrowfill{} to ERT '
2392     i = 0
2393     while True:
2394         i = find_token(document.body, '\\begin_inset Space \\rightarrowfill{}', i)
2395         if i == -1:
2396             return
2397         j = find_end_of_inset(document.body, i)
2398         if j == -1:
2399             document.warning("Malformed LyX document: Could not find end of space inset.")
2400             continue
2401         del document.body[j]
2402         subst = document.body[i].replace('\\begin_inset Space \\rightarrowfill{}', \
2403           '\\begin_inset ERT\nstatus collapsed\n\n' \
2404           '\\begin_layout Standard\n\n\n\\backslash\n' \
2405           'rightarrowfill{}\n\\end_layout\n\n\\end_inset\n\n')
2406         subst = subst.split('\n')
2407         document.body[i : i+1] = subst
2408         i += len(subst)
2409
2410
2411 def revert_upbracefill(document):
2412     ' Revert \\begin_inset Space \\upbracefill{} to ERT '
2413     i = 0
2414     while True:
2415         i = find_token(document.body, '\\begin_inset Space \\upbracefill{}', i)
2416         if i == -1:
2417             return
2418         j = find_end_of_inset(document.body, i)
2419         if j == -1:
2420             document.warning("Malformed LyX document: Could not find end of space inset.")
2421             continue
2422         del document.body[j]
2423         subst = document.body[i].replace('\\begin_inset Space \\upbracefill{}', \
2424           '\\begin_inset ERT\nstatus collapsed\n\n' \
2425           '\\begin_layout Standard\n\n\n\\backslash\n' \
2426           'upbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2427         subst = subst.split('\n')
2428         document.body[i : i+1] = subst
2429         i += len(subst)
2430
2431
2432 def revert_downbracefill(document):
2433     ' Revert \\begin_inset Space \\downbracefill{} to ERT '
2434     i = 0
2435     while True:
2436         i = find_token(document.body, '\\begin_inset Space \\downbracefill{}', i)
2437         if i == -1:
2438             return
2439         j = find_end_of_inset(document.body, i)
2440         if j == -1:
2441             document.warning("Malformed LyX document: Could not find end of space inset.")
2442             continue
2443         del document.body[j]
2444         subst = document.body[i].replace('\\begin_inset Space \\downbracefill{}', \
2445           '\\begin_inset ERT\nstatus collapsed\n\n' \
2446           '\\begin_layout Standard\n\n\n\\backslash\n' \
2447           'downbracefill{}\n\\end_layout\n\n\\end_inset\n\n')
2448         subst = subst.split('\n')
2449         document.body[i : i+1] = subst
2450         i += len(subst)
2451
2452
2453 def revert_local_layout(document):
2454     ' Revert local layout headers.'
2455     i = 0
2456     while True:
2457         i = find_token(document.header, "\\begin_local_layout", i)
2458         if i == -1:
2459             return
2460         j = find_end_of(document.header, i, "\\begin_local_layout", "\\end_local_layout")
2461         if j == -1:
2462             # this should not happen
2463             break
2464         document.header[i : j + 1] = []
2465
2466
2467 def convert_pagebreaks(document):
2468     ' Convert inline Newpage insets to new format '
2469     i = 0
2470     while True:
2471         i = find_token(document.body, '\\newpage', i)
2472         if i == -1:
2473             break
2474         document.body[i:i+1] = ['\\begin_inset Newpage newpage',
2475                                 '\\end_inset']
2476     i = 0
2477     while True:
2478         i = find_token(document.body, '\\pagebreak', i)
2479         if i == -1:
2480             break
2481         document.body[i:i+1] = ['\\begin_inset Newpage pagebreak',
2482                                 '\\end_inset']
2483     i = 0
2484     while True:
2485         i = find_token(document.body, '\\clearpage', i)
2486         if i == -1:
2487             break
2488         document.body[i:i+1] = ['\\begin_inset Newpage clearpage',
2489                                 '\\end_inset']
2490     i = 0
2491     while True:
2492         i = find_token(document.body, '\\cleardoublepage', i)
2493         if i == -1:
2494             break
2495         document.body[i:i+1] = ['\\begin_inset Newpage cleardoublepage',
2496                                 '\\end_inset']
2497
2498
2499 def revert_pagebreaks(document):
2500     ' Revert \\begin_inset Newpage to previous inline format '
2501     i = 0
2502     while True:
2503         i = find_token(document.body, '\\begin_inset Newpage', i)
2504         if i == -1:
2505             return
2506         j = find_end_of_inset(document.body, i)
2507         if j == -1:
2508             document.warning("Malformed LyX document: Could not find end of Newpage inset.")
2509             continue
2510         del document.body[j]
2511         document.body[i] = document.body[i].replace('\\begin_inset Newpage newpage', '\\newpage')
2512         document.body[i] = document.body[i].replace('\\begin_inset Newpage pagebreak', '\\pagebreak')
2513         document.body[i] = document.body[i].replace('\\begin_inset Newpage clearpage', '\\clearpage')
2514         document.body[i] = document.body[i].replace('\\begin_inset Newpage cleardoublepage', '\\cleardoublepage')
2515
2516
2517 def convert_linebreaks(document):
2518     ' Convert inline Newline insets to new format '
2519     i = 0
2520     while True:
2521         i = find_token(document.body, '\\newline', i)
2522         if i == -1:
2523             break
2524         document.body[i:i+1] = ['\\begin_inset Newline newline',
2525                                 '\\end_inset']
2526     i = 0
2527     while True:
2528         i = find_token(document.body, '\\linebreak', i)
2529         if i == -1:
2530             break
2531         document.body[i:i+1] = ['\\begin_inset Newline linebreak',
2532                                 '\\end_inset']
2533
2534
2535 def revert_linebreaks(document):
2536     ' Revert \\begin_inset Newline to previous inline format '
2537     i = 0
2538     while True:
2539         i = find_token(document.body, '\\begin_inset Newline', i)
2540         if i == -1:
2541             return
2542         j = find_end_of_inset(document.body, i)
2543         if j == -1:
2544             document.warning("Malformed LyX document: Could not find end of Newline inset.")
2545             continue
2546         del document.body[j]
2547         document.body[i] = document.body[i].replace('\\begin_inset Newline newline', '\\newline')
2548         document.body[i] = document.body[i].replace('\\begin_inset Newline linebreak', '\\linebreak')
2549
2550
2551 def convert_japanese_plain(document):
2552     ' Set language japanese-plain to japanese '
2553     i = 0
2554     if document.language == "japanese-plain":
2555         document.language = "japanese"
2556         i = find_token(document.header, "\\language", 0)
2557         if i != -1:
2558             document.header[i] = "\\language japanese"
2559     j = 0
2560     while True:
2561         j = find_token(document.body, "\\lang japanese-plain", j)
2562         if j == -1:
2563             return
2564         document.body[j] = document.body[j].replace("\\lang japanese-plain", "\\lang japanese")
2565         j = j + 1
2566
2567
2568 def revert_pdfpages(document):
2569     ' Revert pdfpages external inset to ERT '
2570     i = 0
2571     while 1:
2572         i = find_token(document.body, "\\begin_inset External", i)
2573         if i == -1:
2574             return
2575         j = find_end_of_inset(document.body, i)
2576         if j == -1:
2577             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_pdfpages.")
2578             i = i + 1
2579             continue
2580         if get_value(document.body, 'template', i, j) == "PDFPages":
2581             filename = get_value(document.body, 'filename', i, j)
2582             extra = ''
2583             r = re.compile(r'\textra PDFLaTeX \"(.*)\"$')
2584             for k in range(i, j):
2585                 m = r.match(document.body[k])
2586                 if m:
2587                     extra = m.group(1)
2588             angle = get_value(document.body, 'rotateAngle', i, j)
2589             width = get_value(document.body, 'width', i, j)
2590             height = get_value(document.body, 'height', i, j)
2591             scale = get_value(document.body, 'scale', i, j)
2592             keepAspectRatio = find_token(document.body, "\tkeepAspectRatio", i, j)
2593             options = extra
2594             if angle != '':
2595                  if options != '':
2596                      options += ",angle=" + angle
2597                  else:
2598                      options += "angle=" + angle
2599             if width != '':
2600                  if options != '':
2601                      options += ",width=" + convert_len(width)
2602                  else:
2603                      options += "width=" + convert_len(width)
2604             if height != '':
2605                  if options != '':
2606                      options += ",height=" + convert_len(height)
2607                  else:
2608                      options += "height=" + convert_len(height)
2609             if scale != '':
2610                  if options != '':
2611                      options += ",scale=" + scale
2612                  else:
2613                      options += "scale=" + scale
2614             if keepAspectRatio != '':
2615                  if options != '':
2616                      options += ",keepaspectratio"
2617                  else:
2618                      options += "keepaspectratio"
2619             if options != '':
2620                      options = '[' + options + ']'
2621             del document.body[i+1:j+1]
2622             document.body[i:i+1] = ['\\begin_inset ERT',
2623                                 'status collapsed',
2624                                 '',
2625                                 '\\begin_layout Standard',
2626                                 '',
2627                                 '\\backslash',
2628                                 'includepdf' + options + '{' + filename + '}',
2629                                 '\\end_layout',
2630                                 '',
2631                                 '\\end_inset']
2632             add_to_preamble(document, ['\\usepackage{pdfpages}\n'])
2633             i = i + 1
2634             continue
2635         i = i + 1
2636
2637
2638 def revert_mexican(document):
2639     ' Set language Spanish(Mexico) to Spanish '
2640     i = 0
2641     if document.language == "spanish-mexico":
2642         document.language = "spanish"
2643         i = find_token(document.header, "\\language", 0)
2644         if i != -1:
2645             document.header[i] = "\\language spanish"
2646     j = 0
2647     while True:
2648         j = find_token(document.body, "\\lang spanish-mexico", j)
2649         if j == -1:
2650             return
2651         document.body[j] = document.body[j].replace("\\lang spanish-mexico", "\\lang spanish")
2652         j = j + 1
2653
2654
2655 def remove_embedding(document):
2656     ' Remove embed tag from all insets '
2657     revert_inset_embedding(document, 'Graphics')
2658     revert_inset_embedding(document, 'External')
2659     revert_inset_embedding(document, 'CommandInset include')
2660     revert_inset_embedding(document, 'CommandInset bibtex')
2661
2662
2663 def revert_master(document):
2664     ' Remove master param '
2665     i = find_token(document.header, "\\master", 0)
2666     if i != -1:
2667         del document.header[i]
2668
2669
2670 def revert_graphics_group(document):
2671     ' Revert group information from graphics insets '
2672     i = 0
2673     while 1:
2674         i = find_token(document.body, "\\begin_inset Graphics", i)
2675         if i == -1:
2676             return
2677         j = find_end_of_inset(document.body, i)
2678         if j == -1:
2679             document.warning("Malformed lyx document: Missing '\\end_inset' in revert_graphics_group.")
2680             i = i + 1
2681             continue
2682         k = find_token(document.body, " groupId", i, j)
2683         if k == -1:
2684             i = i + 1
2685             continue
2686         del document.body[k]
2687         i = i + 1
2688
2689
2690 def update_apa_styles(document):
2691     ' Replace obsolete styles '
2692
2693     if document.textclass != "apa":
2694         return
2695
2696     obsoletedby = { "Acknowledgments": "Acknowledgements",
2697                     "Section*":        "Section",
2698                     "Subsection*":     "Subsection",
2699                     "Subsubsection*":  "Subsubsection",
2700                     "Paragraph*":      "Paragraph",
2701                     "Subparagraph*":   "Subparagraph"}
2702     i = 0
2703     while 1:
2704         i = find_token(document.body, "\\begin_layout", i)
2705         if i == -1:
2706             return
2707
2708         layout = document.body[i][14:]
2709         if layout in obsoletedby:
2710             document.body[i] = "\\begin_layout " + obsoletedby[layout]
2711
2712         i += 1
2713
2714
2715 def convert_paper_sizes(document):
2716     ' exchange size options legalpaper and executivepaper to correct order '
2717     # routine is needed to fix http://bugzilla.lyx.org/show_bug.cgi?id=4868
2718     i = 0
2719     j = 0
2720     i = find_token(document.header, "\\papersize executivepaper", 0)
2721     if i != -1:
2722         document.header[i] = "\\papersize legalpaper"
2723         return
2724     j = find_token(document.header, "\\papersize legalpaper", 0)
2725     if j != -1:
2726         document.header[j] = "\\papersize executivepaper"
2727
2728
2729 def revert_paper_sizes(document):
2730     ' exchange size options legalpaper and executivepaper to correct order '
2731     i = 0
2732     j = 0
2733     i = find_token(document.header, "\\papersize executivepaper", 0)
2734     if i != -1:
2735         document.header[i] = "\\papersize legalpaper"
2736         return
2737     j = find_token(document.header, "\\papersize legalpaper", 0)
2738     if j != -1:
2739         document.header[j] = "\\papersize executivepaper"
2740
2741
2742 def convert_InsetSpace(document):
2743     " Convert '\\begin_inset Space foo' to '\\begin_inset space foo'"
2744     i = 0
2745     while True:
2746         i = find_token(document.body, "\\begin_inset Space", i)
2747         if i == -1:
2748             return
2749         document.body[i] = document.body[i].replace('\\begin_inset Space', '\\begin_inset space')
2750
2751
2752 def revert_InsetSpace(document):
2753     " Revert '\\begin_inset space foo' to '\\begin_inset Space foo'"
2754     i = 0
2755     while True:
2756         i = find_token(document.body, "\\begin_inset space", i)
2757         if i == -1:
2758             return
2759         document.body[i] = document.body[i].replace('\\begin_inset space', '\\begin_inset Space')
2760
2761
2762 def convert_display_enum(document):
2763     " Convert 'display foo' to 'display false/true'"
2764     i = 0
2765     while True:
2766         i = find_token(document.body, "\tdisplay", i)
2767         if i == -1:
2768             return
2769         val = get_value(document.body, 'display', i)
2770         if val == "none":
2771             document.body[i] = document.body[i].replace('none', 'false')
2772         if val == "default":
2773             document.body[i] = document.body[i].replace('default', 'true')
2774         if val == "monochrome":
2775             document.body[i] = document.body[i].replace('monochrome', 'true')
2776         if val == "grayscale":
2777             document.body[i] = document.body[i].replace('grayscale', 'true')
2778         if val == "color":
2779             document.body[i] = document.body[i].replace('color', 'true')
2780         if val == "preview":
2781             document.body[i] = document.body[i].replace('preview', 'true')
2782         i += 1
2783
2784
2785 def revert_display_enum(document):
2786     " Revert 'display false/true' to 'display none/color'"
2787     i = 0
2788     while True:
2789         i = find_token(document.body, "\tdisplay", i)
2790         if i == -1:
2791             return
2792         val = get_value(document.body, 'display', i)
2793         if val == "false":
2794             document.body[i] = document.body[i].replace('false', 'none')
2795         if val == "true":
2796             document.body[i] = document.body[i].replace('true', 'default')
2797         i += 1
2798
2799
2800 def remove_fontsCJK(document):
2801     ' Remove font_cjk param '
2802     i = find_token(document.header, "\\font_cjk", 0)
2803     if i != -1:
2804         del document.header[i]
2805
2806
2807 def convert_plain_layout(document):
2808     " Convert 'PlainLayout' to 'Plain Layout'" 
2809     i = 0
2810     while True:
2811         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2812         if i == -1:
2813             return
2814         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2815           '\\begin_layout Plain Layout')
2816         i += 1
2817
2818
2819 def revert_plain_layout(document):
2820     " Convert 'PlainLayout' to 'Plain Layout'" 
2821     i = 0
2822     while True:
2823         i = find_token(document.body, '\\begin_layout Plain Layout', i)
2824         if i == -1:
2825             return
2826         document.body[i] = document.body[i].replace('\\begin_layout Plain Layout', \
2827           '\\begin_layout PlainLayout')
2828         i += 1
2829
2830
2831 def revert_plainlayout(document):
2832     " Convert 'PlainLayout' to 'Plain Layout'" 
2833     i = 0
2834     while True:
2835         i = find_token(document.body, '\\begin_layout PlainLayout', i)
2836         if i == -1:
2837             return
2838         # This will be incorrect for some document classes, since Standard is not always
2839         # the default. But (a) it is probably the best we can do and (b) it will actually
2840         # work, in fact, since an unknown layout will be converted to default.
2841         document.body[i] = document.body[i].replace('\\begin_layout PlainLayout', \
2842           '\\begin_layout Standard')
2843         i += 1
2844
2845
2846 def revert_polytonicgreek(document):
2847     "Set language polytonic Greek to Greek"
2848     i = 0
2849     if document.language == "polutonikogreek":
2850         document.language = "greek"
2851         i = find_token(document.header, "\\language", 0)
2852         if i != -1:
2853             document.header[i] = "\\language greek"
2854     j = 0
2855     while True:
2856         j = find_token(document.body, "\\lang polutonikogreek", j)
2857         if j == -1:
2858             return
2859         document.body[j] = document.body[j].replace("\\lang polutonikogreek", "\\lang greek")
2860         j = j + 1
2861
2862
2863 ##
2864 # Conversion hub
2865 #
2866
2867 supported_versions = ["1.6.0","1.6"]
2868 convert = [[277, [fix_wrong_tables]],
2869            [278, [close_begin_deeper]],
2870            [279, [long_charstyle_names]],
2871            [280, [axe_show_label]],
2872            [281, []],
2873            [282, []],
2874            [283, [convert_flex]],
2875            [284, []],
2876            [285, []],
2877            [286, []],
2878            [287, [convert_wrapfig_options]],
2879            [288, [convert_inset_command]],
2880            [289, [convert_latexcommand_index]],
2881            [290, []],
2882            [291, []],
2883            [292, [convert_japanese_cjk]],
2884            [293, []],
2885            [294, [convert_pdf_options]],
2886            [295, [convert_htmlurl, convert_url]],
2887            [296, [convert_include]],
2888            [297, [convert_usorbian]],
2889            [298, []],
2890            [299, []],
2891            [300, []],
2892            [301, []],
2893            [302, []],
2894            [303, [convert_serbocroatian]],
2895            [304, [convert_framed_notes]],
2896            [305, []],
2897            [306, []],
2898            [307, []],
2899            [308, []],
2900            [309, []],
2901            [310, []],
2902            [311, [convert_ams_classes]],
2903            [312, []],
2904            [313, [convert_module_names]],
2905            [314, []],
2906            [315, []],
2907            [316, [convert_subfig]],
2908            [317, []],
2909            [318, []],
2910            [319, [convert_spaceinset, convert_hfill]],
2911            [320, []],
2912            [321, [convert_tablines]],
2913            [322, [convert_plain_layout]],
2914            [323, [convert_pagebreaks]],
2915            [324, [convert_linebreaks]],
2916            [325, [convert_japanese_plain]],
2917            [326, []],
2918            [327, []],
2919            [328, [remove_embedding, remove_extra_embedded_files, remove_inzip_options]],
2920            [329, []],
2921            [330, []],
2922            [331, [convert_ltcaption]],
2923            [332, []],
2924            [333, [update_apa_styles]],
2925            [334, [convert_paper_sizes]],
2926            [335, [convert_InsetSpace]],
2927            [336, []],
2928            [337, [convert_display_enum]],
2929            [338, []],
2930           ]
2931
2932 revert =  [[337, [revert_polytonicgreek]],
2933            [336, [revert_display_enum]],
2934            [335, [remove_fontsCJK]],
2935            [334, [revert_InsetSpace]],
2936            [333, [revert_paper_sizes]],
2937            [332, []],
2938            [331, [revert_graphics_group]],
2939            [330, [revert_ltcaption]],
2940            [329, [revert_leftarrowfill, revert_rightarrowfill, revert_upbracefill, revert_downbracefill]],
2941            [328, [revert_master]],
2942            [327, []],
2943            [326, [revert_mexican]],
2944            [325, [revert_pdfpages]],
2945            [324, []],
2946            [323, [revert_linebreaks]],
2947            [322, [revert_pagebreaks]],
2948            [321, [revert_local_layout, revert_plain_layout]],
2949            [320, [revert_tablines]],
2950            [319, [revert_protected_hfill]],
2951            [318, [revert_spaceinset, revert_hfills, revert_hspace]],
2952            [317, [remove_extra_embedded_files]],
2953            [316, [revert_wrapplacement]],
2954            [315, [revert_subfig]],
2955            [314, [revert_colsep, revert_plainlayout]],
2956            [313, []],
2957            [312, [revert_module_names]],
2958            [311, [revert_rotfloat, revert_widesideways]],
2959            [310, [revert_external_embedding]],
2960            [309, [revert_btprintall]],
2961            [308, [revert_nocite]],
2962            [307, [revert_serbianlatin]],
2963            [306, [revert_slash, revert_nobreakdash]],
2964            [305, [revert_interlingua]],
2965            [304, [revert_bahasam]],
2966            [303, [revert_framed_notes]],
2967            [302, []],
2968            [301, [revert_latin, revert_samin]],
2969            [300, [revert_linebreak]],
2970            [299, [revert_pagebreak]],
2971            [298, [revert_hyperlinktype]],
2972            [297, [revert_macro_optional_params]],
2973            [296, [revert_albanian, revert_lowersorbian, revert_uppersorbian]],
2974            [295, [revert_include]],
2975            [294, [revert_href, revert_url]],
2976            [293, [revert_pdf_options_2]],
2977            [292, [revert_inset_info]],
2978            [291, [revert_japanese, revert_japanese_encoding, revert_japanese_cjk]],
2979            [290, [revert_vietnamese]],
2980            [289, [revert_wraptable]],
2981            [288, [revert_latexcommand_index]],
2982            [287, [revert_inset_command]],
2983            [286, [revert_wrapfig_options]],
2984            [285, [revert_pdf_options]],
2985            [284, [remove_inzip_options]],
2986            [283, []],
2987            [282, [revert_flex]],
2988            [281, []],
2989            [280, [revert_begin_modules]],
2990            [279, [revert_show_label]],
2991            [278, [revert_long_charstyle_names]],
2992            [277, []],
2993            [276, []]
2994           ]
2995
2996
2997 if __name__ == "__main__":
2998     pass