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