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